blob: db6301df91d1a0764bdb3079765a231d0107edf4 [file] [log] [blame]
// Copyright (C) 2013 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.gerrit.server.query.change;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.TruthJUnit.assume;
import static com.google.gerrit.extensions.client.ListChangesOption.REVIEWED;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.concurrent.TimeUnit.HOURS;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.MINUTES;
import com.google.common.base.Function;
import com.google.common.base.MoreObjects;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.hash.Hashing;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.common.TimeUtil;
import com.google.gerrit.extensions.api.GerritApi;
import com.google.gerrit.extensions.api.changes.Changes.QueryRequest;
import com.google.gerrit.extensions.api.changes.HashtagsInput;
import com.google.gerrit.extensions.api.changes.ReviewInput;
import com.google.gerrit.extensions.api.groups.GroupInput;
import com.google.gerrit.extensions.common.ChangeInfo;
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.lifecycle.LifecycleManager;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.Branch;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.Patch;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.account.AccountManager;
import com.google.gerrit.server.account.AuthRequest;
import com.google.gerrit.server.account.GroupCache;
import com.google.gerrit.server.change.ChangeInserter;
import com.google.gerrit.server.change.ChangeTriplet;
import com.google.gerrit.server.change.PatchSetInserter;
import com.google.gerrit.server.git.BatchUpdate;
import com.google.gerrit.server.git.validators.CommitValidators;
import com.google.gerrit.server.group.AddMembers;
import com.google.gerrit.server.index.IndexCollection;
import com.google.gerrit.server.notedb.NotesMigration;
import com.google.gerrit.server.project.ChangeControl;
import com.google.gerrit.server.project.ProjectControl;
import com.google.gerrit.server.project.RefControl;
import com.google.gerrit.server.schema.SchemaCreator;
import com.google.gerrit.server.util.RequestContext;
import com.google.gerrit.server.util.ThreadLocalRequestContext;
import com.google.gerrit.testutil.ConfigSuite;
import com.google.gerrit.testutil.DisabledReviewDb;
import com.google.gerrit.testutil.InMemoryDatabase;
import com.google.gerrit.testutil.InMemoryRepositoryManager;
import com.google.gerrit.testutil.InMemoryRepositoryManager.Repo;
import com.google.gerrit.testutil.TestTimeUtil;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Provider;
import com.google.inject.util.Providers;
import org.eclipse.jgit.junit.TestRepository;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.revwalk.RevCommit;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@Ignore
@RunWith(ConfigSuite.class)
public abstract class AbstractQueryChangesTest {
@ConfigSuite.Default
public static Config defaultConfig() {
return updateConfig(new Config());
}
@ConfigSuite.Config
public static Config noteDbEnabled() {
return updateConfig(NotesMigration.allEnabledConfig());
}
@Rule
public ExpectedException exception = ExpectedException.none();
private static Config updateConfig(Config cfg) {
cfg.setInt("index", null, "maxPages", 10);
return cfg;
}
@ConfigSuite.Parameter public Config config;
@Inject protected AccountManager accountManager;
@Inject protected BatchUpdate.Factory updateFactory;
@Inject protected ChangeInserter.Factory changeFactory;
@Inject protected PatchSetInserter.Factory patchSetFactory;
@Inject protected ChangeControl.GenericFactory changeControlFactory;
@Inject protected GerritApi gApi;
@Inject protected IdentifiedUser.GenericFactory userFactory;
@Inject protected IndexCollection indexes;
@Inject protected InMemoryDatabase schemaFactory;
@Inject protected InMemoryRepositoryManager repoManager;
@Inject protected InternalChangeQuery internalChangeQuery;
@Inject protected NotesMigration notesMigration;
@Inject protected ProjectControl.GenericFactory projectControlFactory;
@Inject protected ChangeQueryBuilder queryBuilder;
@Inject protected QueryProcessor queryProcessor;
@Inject protected SchemaCreator schemaCreator;
@Inject protected ThreadLocalRequestContext requestContext;
@Inject protected GroupCache groupCache;
@Inject protected AddMembers addMembers;
protected LifecycleManager lifecycle;
protected ReviewDb db;
protected Account.Id userId;
protected CurrentUser user;
private String systemTimeZone;
protected abstract Injector createInjector();
@Before
public void setUpInjector() throws Exception {
lifecycle = new LifecycleManager();
Injector injector = createInjector();
lifecycle.add(injector);
injector.injectMembers(this);
lifecycle.start();
db = schemaFactory.open();
schemaCreator.create(db);
userId = accountManager.authenticate(AuthRequest.forUser("user"))
.getAccountId();
Account userAccount = db.accounts().get(userId);
userAccount.setPreferredEmail("user@example.com");
db.accounts().update(ImmutableList.of(userAccount));
user = userFactory.create(Providers.of(db), userId);
requestContext.setContext(newRequestContext(userAccount.getId()));
}
protected RequestContext newRequestContext(Account.Id requestUserId) {
final CurrentUser requestUser =
userFactory.create(Providers.of(db), requestUserId);
return new RequestContext() {
@Override
public CurrentUser getUser() {
return requestUser;
}
@Override
public Provider<ReviewDb> getReviewDbProvider() {
return Providers.of(db);
}
};
}
@After
public void tearDownInjector() {
if (lifecycle != null) {
lifecycle.stop();
}
requestContext.setContext(null);
if (db != null) {
db.close();
}
InMemoryDatabase.drop(schemaFactory);
}
@Before
public void setTimeForTesting() {
systemTimeZone = System.setProperty("user.timezone", "US/Eastern");
TestTimeUtil.resetWithClockStep(1, MILLISECONDS);
}
@After
public void resetTime() {
TestTimeUtil.useSystemTime();
System.setProperty("user.timezone", systemTimeZone);
}
@Test
public void byId() throws Exception {
TestRepository<Repo> repo = createProject("repo");
Change change1 = insert(newChange(repo, null, null, null, null));
Change change2 = insert(newChange(repo, null, null, null, null));
assertQuery("12345");
assertQuery(change1.getId().get(), change1);
assertQuery(change2.getId().get(), change2);
}
@Test
public void byKey() throws Exception {
TestRepository<Repo> repo = createProject("repo");
Change change = insert(newChange(repo, null, null, null, null));
String key = change.getKey().get();
assertQuery("I0000000000000000000000000000000000000000");
for (int i = 0; i <= 36; i++) {
String q = key.substring(0, 41 - i);
assertQuery(q, change);
}
}
@Test
public void byTriplet() throws Exception {
TestRepository<Repo> repo = createProject("repo");
Change change = insert(newChange(repo, null, null, null, "branch"));
String k = change.getKey().get();
assertQuery("repo~branch~" + k, change);
assertQuery("change:repo~branch~" + k, change);
assertQuery("repo~refs/heads/branch~" + k, change);
assertQuery("change:repo~refs/heads/branch~" + k, change);
assertQuery("repo~branch~" + k.substring(0, 10), change);
assertQuery("change:repo~branch~" + k.substring(0, 10), change);
assertQuery("foo~bar");
assertBadQuery("change:foo~bar");
assertQuery("otherrepo~branch~" + k);
assertQuery("change:otherrepo~branch~" + k);
assertQuery("repo~otherbranch~" + k);
assertQuery("change:repo~otherbranch~" + k);
assertQuery("repo~branch~I0000000000000000000000000000000000000000");
assertQuery("change:repo~branch~I0000000000000000000000000000000000000000");
}
@Test
public void byStatus() throws Exception {
TestRepository<Repo> repo = createProject("repo");
ChangeInserter ins1 = newChange(repo, null, null, null, null);
Change change1 = ins1.getChange();
change1.setStatus(Change.Status.NEW);
insert(ins1);
ChangeInserter ins2 = newChange(repo, null, null, null, null);
Change change2 = ins2.getChange();
change2.setStatus(Change.Status.MERGED);
insert(ins2);
assertQuery("status:new", change1);
assertQuery("status:NEW", change1);
assertQuery("is:new", change1);
assertQuery("status:merged", change2);
assertQuery("is:merged", change2);
}
@Test
public void byStatusOpen() throws Exception {
TestRepository<Repo> repo = createProject("repo");
ChangeInserter ins1 = newChange(repo, null, null, null, null);
Change change1 = ins1.getChange();
change1.setStatus(Change.Status.NEW);
insert(ins1);
ChangeInserter ins2 = newChange(repo, null, null, null, null);
Change change2 = ins2.getChange();
change2.setStatus(Change.Status.DRAFT);
insert(ins2);
ChangeInserter ins3 = newChange(repo, null, null, null, null);
Change change3 = ins3.getChange();
change3.setStatus(Change.Status.MERGED);
insert(ins3);
Change[] expected = new Change[] {change2, change1};
assertQuery("status:open", expected);
assertQuery("status:OPEN", expected);
assertQuery("status:o", expected);
assertQuery("status:op", expected);
assertQuery("status:ope", expected);
assertQuery("status:pending", expected);
assertQuery("status:PENDING", expected);
assertQuery("status:p", expected);
assertQuery("status:pe", expected);
assertQuery("status:pen", expected);
assertQuery("is:open", expected);
}
@Test
public void byStatusDraft() throws Exception {
TestRepository<Repo> repo = createProject("repo");
ChangeInserter ins1 = newChange(repo, null, null, null, null);
Change change1 = ins1.getChange();
change1.setStatus(Change.Status.NEW);
insert(ins1);
ChangeInserter ins2 = newChange(repo, null, null, null, null);
Change change2 = ins2.getChange();
change2.setStatus(Change.Status.DRAFT);
insert(ins2);
Change[] expected = new Change[] {change2};
assertQuery("status:draft", expected);
assertQuery("status:DRAFT", expected);
assertQuery("status:d", expected);
assertQuery("status:dr", expected);
assertQuery("status:dra", expected);
assertQuery("status:draf", expected);
assertQuery("is:draft", expected);
}
@Test
public void byStatusClosed() throws Exception {
TestRepository<Repo> repo = createProject("repo");
ChangeInserter ins1 = newChange(repo, null, null, null, null);
Change change1 = ins1.getChange();
change1.setStatus(Change.Status.MERGED);
insert(ins1);
ChangeInserter ins2 = newChange(repo, null, null, null, null);
Change change2 = ins2.getChange();
change2.setStatus(Change.Status.ABANDONED);
insert(ins2);
ChangeInserter ins3 = newChange(repo, null, null, null, null);
Change change3 = ins3.getChange();
change3.setStatus(Change.Status.NEW);
insert(ins3);
Change[] expected = new Change[] {change2, change1};
assertQuery("status:closed", expected);
assertQuery("status:CLOSED", expected);
assertQuery("status:c", expected);
assertQuery("status:cl", expected);
assertQuery("status:clo", expected);
assertQuery("status:clos", expected);
assertQuery("status:close", expected);
assertQuery("status:closed", expected);
assertQuery("is:closed", expected);
}
@Test
public void byStatusPrefix() throws Exception {
TestRepository<Repo> repo = createProject("repo");
ChangeInserter ins1 = newChange(repo, null, null, null, null);
Change change1 = ins1.getChange();
change1.setStatus(Change.Status.NEW);
insert(ins1);
ChangeInserter ins2 = newChange(repo, null, null, null, null);
Change change2 = ins2.getChange();
change2.setStatus(Change.Status.MERGED);
insert(ins2);
assertQuery("status:n", change1);
assertQuery("status:ne", change1);
assertQuery("status:new", change1);
assertQuery("status:N", change1);
assertQuery("status:nE", change1);
assertQuery("status:neW", change1);
assertBadQuery("status:nx");
assertBadQuery("status:newx");
}
@Test
public void byCommit() throws Exception {
TestRepository<Repo> repo = createProject("repo");
ChangeInserter ins = newChange(repo, null, null, null, null);
insert(ins);
String sha = ins.getPatchSet().getRevision().get();
assertQuery("0000000000000000000000000000000000000000");
for (int i = 0; i <= 36; i++) {
String q = sha.substring(0, 40 - i);
assertQuery(q, ins.getChange());
}
}
@Test
public void byOwner() throws Exception {
TestRepository<Repo> repo = createProject("repo");
Change change1 = insert(newChange(repo, null, null, userId.get(), null));
int user2 = accountManager.authenticate(AuthRequest.forUser("anotheruser"))
.getAccountId().get();
Change change2 = insert(newChange(repo, null, null, user2, null));
assertQuery("owner:" + userId.get(), change1);
assertQuery("owner:" + user2, change2);
}
@Test
public void byAuthor() throws Exception {
TestRepository<Repo> repo = createProject("repo");
Change change1 = insert(newChange(repo, null, null, userId.get(), null));
// By exact email address
assertQuery("author:jauthor@example.com", change1);
// By email address part
assertQuery("author:jauthor", change1);
assertQuery("author:example", change1);
assertQuery("author:example.com", change1);
// By name part
assertQuery("author:Author", change1);
// Case insensitive
assertQuery("author:jAuThOr", change1);
assertQuery("author:ExAmPlE", change1);
// By non-existing email address / name / part
assertQuery("author:jcommitter@example.com");
assertQuery("author:somewhere.com");
assertQuery("author:jcommitter");
assertQuery("author:Committer");
}
@Test
public void byCommitter() throws Exception {
TestRepository<Repo> repo = createProject("repo");
Change change1 = insert(newChange(repo, null, null, userId.get(), null));
// By exact email address
assertQuery("committer:jcommitter@example.com", change1);
// By email address part
assertQuery("committer:jcommitter", change1);
assertQuery("committer:example", change1);
assertQuery("committer:example.com", change1);
// By name part
assertQuery("committer:Committer", change1);
// Case insensitive
assertQuery("committer:jCoMmItTeR", change1);
assertQuery("committer:ExAmPlE", change1);
// By non-existing email address / name / part
assertQuery("committer:jauthor@example.com");
assertQuery("committer:somewhere.com");
assertQuery("committer:jauthor");
assertQuery("committer:Author");
}
@Test
public void byOwnerIn() throws Exception {
TestRepository<Repo> repo = createProject("repo");
Change change1 = insert(newChange(repo, null, null, userId.get(), null));
int user2 = accountManager.authenticate(AuthRequest.forUser("anotheruser"))
.getAccountId().get();
Change change2 = insert(newChange(repo, null, null, user2, null));
assertQuery("ownerin:Administrators", change1);
assertQuery("ownerin:\"Registered Users\"", change2, change1);
}
@Test
public void byProject() throws Exception {
TestRepository<Repo> repo1 = createProject("repo1");
TestRepository<Repo> repo2 = createProject("repo2");
Change change1 = insert(newChange(repo1, null, null, null, null));
Change change2 = insert(newChange(repo2, null, null, null, null));
assertQuery("project:foo");
assertQuery("project:repo");
assertQuery("project:repo1", change1);
assertQuery("project:repo2", change2);
}
@Test
public void byProjectPrefix() throws Exception {
TestRepository<Repo> repo1 = createProject("repo1");
TestRepository<Repo> repo2 = createProject("repo2");
Change change1 = insert(newChange(repo1, null, null, null, null));
Change change2 = insert(newChange(repo2, null, null, null, null));
assertQuery("projects:foo");
assertQuery("projects:repo1", change1);
assertQuery("projects:repo2", change2);
assertQuery("projects:repo", change2, change1);
}
@Test
public void byBranchAndRef() throws Exception {
TestRepository<Repo> repo = createProject("repo");
Change change1 = insert(newChange(repo, null, null, null, "master"));
Change change2 = insert(newChange(repo, null, null, null, "branch"));
assertQuery("branch:foo");
assertQuery("branch:master", change1);
assertQuery("branch:refs/heads/master", change1);
assertQuery("ref:master");
assertQuery("ref:refs/heads/master", change1);
assertQuery("branch:refs/heads/master", change1);
assertQuery("branch:branch", change2);
assertQuery("branch:refs/heads/branch", change2);
assertQuery("ref:branch");
assertQuery("ref:refs/heads/branch", change2);
}
@Test
public void byTopic() throws Exception {
TestRepository<Repo> repo = createProject("repo");
ChangeInserter ins1 = newChange(repo, null, null, null, null);
Change change1 = ins1.getChange();
change1.setTopic("feature1");
insert(ins1);
ChangeInserter ins2 = newChange(repo, null, null, null, null);
Change change2 = ins2.getChange();
change2.setTopic("feature2");
insert(ins2);
ChangeInserter ins3 = newChange(repo, null, null, null, null);
Change change3 = ins3.getChange();
change3.setTopic("Cherrypick-feature2");
insert(ins3);
ChangeInserter ins4 = newChange(repo, null, null, null, null);
Change change4 = ins4.getChange();
change4.setTopic("feature2-fixup");
insert(ins4);
Change change5 = insert(newChange(repo, null, null, null, null));
assertQuery("intopic:foo");
assertQuery("intopic:feature1", change1);
assertQuery("intopic:feature2", change4, change3, change2);
assertQuery("topic:feature2", change2);
assertQuery("intopic:feature2", change4, change3, change2);
assertQuery("intopic:fixup", change4);
assertQuery("topic:\"\"", change5);
assertQuery("intopic:\"\"", change5);
assertQuery("intopic:^feature2.*", change4, change2);
assertQuery("intopic:{^.*feature2$}", change3, change2);
}
@Test
public void byMessageExact() throws Exception {
TestRepository<Repo> repo = createProject("repo");
RevCommit commit1 = repo.parseBody(repo.commit().message("one").create());
Change change1 = insert(newChange(repo, commit1, null, null, null));
RevCommit commit2 = repo.parseBody(repo.commit().message("two").create());
Change change2 = insert(newChange(repo, commit2, null, null, null));
assertQuery("message:foo");
assertQuery("message:one", change1);
assertQuery("message:two", change2);
}
@Test
public void fullTextWithNumbers() throws Exception {
TestRepository<Repo> repo = createProject("repo");
RevCommit commit1 =
repo.parseBody(repo.commit().message("12345 67890").create());
Change change1 = insert(newChange(repo, commit1, null, null, null));
RevCommit commit2 =
repo.parseBody(repo.commit().message("12346 67891").create());
Change change2 = insert(newChange(repo, commit2, null, null, null));
assertQuery("message:1234");
assertQuery("message:12345", change1);
assertQuery("message:12346", change2);
}
@Test
public void byLabel() throws Exception {
accountManager.authenticate(AuthRequest.forUser("anotheruser"));
TestRepository<Repo> repo = createProject("repo");
ChangeInserter ins = newChange(repo, null, null, null, null);
ChangeInserter ins2 = newChange(repo, null, null, null, null);
ChangeInserter ins3 = newChange(repo, null, null, null, null);
ChangeInserter ins4 = newChange(repo, null, null, null, null);
ChangeInserter ins5 = newChange(repo, null, null, null, null);
Change reviewMinus2Change = insert(ins);
gApi.changes().id(reviewMinus2Change.getId().get()).current()
.review(ReviewInput.reject());
Change reviewMinus1Change = insert(ins2);
gApi.changes().id(reviewMinus1Change.getId().get()).current()
.review(ReviewInput.dislike());
Change noLabelChange = insert(ins3);
Change reviewPlus1Change = insert(ins4);
gApi.changes().id(reviewPlus1Change.getId().get()).current()
.review(ReviewInput.recommend());
Change reviewPlus2Change = insert(ins5);
gApi.changes().id(reviewPlus2Change.getId().get()).current()
.review(ReviewInput.approve());
Map<Integer, Change> changes = new LinkedHashMap<>(5);
changes.put(2, reviewPlus2Change);
changes.put(1, reviewPlus1Change);
changes.put(-1, reviewMinus1Change);
changes.put(-2, reviewMinus2Change);
changes.put(0, noLabelChange);
assertQuery("label:Code-Review=-2", reviewMinus2Change);
assertQuery("label:Code-Review-2", reviewMinus2Change);
assertQuery("label:Code-Review=-1", reviewMinus1Change);
assertQuery("label:Code-Review-1", reviewMinus1Change);
assertQuery("label:Code-Review=0", noLabelChange);
assertQuery("label:Code-Review=+1", reviewPlus1Change);
assertQuery("label:Code-Review=1", reviewPlus1Change);
assertQuery("label:Code-Review+1", reviewPlus1Change);
assertQuery("label:Code-Review=+2", reviewPlus2Change);
assertQuery("label:Code-Review=2", reviewPlus2Change);
assertQuery("label:Code-Review+2", reviewPlus2Change);
assertQuery("label:Code-Review>-3", codeReviewInRange(changes, -2, 2));
assertQuery("label:Code-Review>=-2", codeReviewInRange(changes, -2, 2));
assertQuery("label:Code-Review>-2", codeReviewInRange(changes, -1, 2));
assertQuery("label:Code-Review>=-1", codeReviewInRange(changes, -1, 2));
assertQuery("label:Code-Review>-1", codeReviewInRange(changes, 0, 2));
assertQuery("label:Code-Review>=0", codeReviewInRange(changes, 0, 2));
assertQuery("label:Code-Review>0", codeReviewInRange(changes, 1, 2));
assertQuery("label:Code-Review>=1", codeReviewInRange(changes, 1, 2));
assertQuery("label:Code-Review>1", reviewPlus2Change);
assertQuery("label:Code-Review>=2", reviewPlus2Change);
assertQuery("label:Code-Review>2");
assertQuery("label:Code-Review<=2", codeReviewInRange(changes, -2, 2));
assertQuery("label:Code-Review<2", codeReviewInRange(changes, -2, 1));
assertQuery("label:Code-Review<=1", codeReviewInRange(changes, -2, 1));
assertQuery("label:Code-Review<1", codeReviewInRange(changes, -2, 0));
assertQuery("label:Code-Review<=0", codeReviewInRange(changes, -2, 0));
assertQuery("label:Code-Review<0", codeReviewInRange(changes, -2, -1));
assertQuery("label:Code-Review<=-1", codeReviewInRange(changes, -2, -1));
assertQuery("label:Code-Review<-1", reviewMinus2Change);
assertQuery("label:Code-Review<=-2", reviewMinus2Change);
assertQuery("label:Code-Review<-2");
assertQuery("label:Code-Review=+1,anotheruser");
assertQuery("label:Code-Review=+1,user", reviewPlus1Change);
assertQuery("label:Code-Review=+1,user=user", reviewPlus1Change);
assertQuery("label:Code-Review=+1,Administrators", reviewPlus1Change);
assertQuery("label:Code-Review=+1,group=Administrators", reviewPlus1Change);
}
private Change[] codeReviewInRange(Map<Integer, Change> changes, int start,
int end) {
int size = 0;
Change[] range = new Change[end - start + 1];
for (int i : changes.keySet()) {
if (i >= start && i <= end) {
range[size] = changes.get(i);
size++;
}
}
return range;
}
private String createGroup(String name, String owner) throws Exception {
GroupInput in = new GroupInput();
in.name = name;
in.ownerId = owner;
gApi.groups().create(in);
return name;
}
private Account.Id createAccount(String name) throws Exception {
return accountManager.authenticate(
AuthRequest.forUser(name)).getAccountId();
}
@Test
public void byLabelGroup() throws Exception {
Account.Id user1 = createAccount("user1");
createAccount("user2");
TestRepository<Repo> repo = createProject("repo");
// create group and add users
String g1 = createGroup("group1", "Administrators");
String g2 = createGroup("group2", "Administrators");
gApi.groups().id(g1).addMembers("user1");
gApi.groups().id(g2).addMembers("user2");
// create a change
ChangeInserter ins = newChange(repo, null, null, user1.get(), null);
Change change1 = insert(ins);
// post a review with user1
requestContext.setContext(newRequestContext(user1));
gApi.changes().id(change1.getId().get()).current()
.review(new ReviewInput().label("Code-Review", 1));
// verify that query with user1 will return results.
requestContext.setContext(newRequestContext(userId));
assertQuery("label:Code-Review=+1,group1", change1);
assertQuery("label:Code-Review=+1,group=group1", change1);
assertQuery("label:Code-Review=+1,user=user1", change1);
assertQuery("label:Code-Review=+1,user=user2");
assertQuery("label:Code-Review=+1,group=group2");
}
@Test
public void limit() throws Exception {
TestRepository<Repo> repo = createProject("repo");
Change last = null;
int n = 5;
for (int i = 0; i < n; i++) {
last = insert(newChange(repo, null, null, null, null));
}
for (int i = 1; i <= n + 2; i++) {
int expectedSize;
Boolean expectedMoreChanges;
if (i < n) {
expectedSize = i;
expectedMoreChanges = true;
} else {
expectedSize = n;
expectedMoreChanges = null;
}
String q = "status:new limit:" + i;
List<ChangeInfo> results = newQuery(q).get();
assertThat(results).named(q).hasSize(expectedSize);
assertThat(results.get(results.size() - 1)._moreChanges).named(q)
.isEqualTo(expectedMoreChanges);
assertThat(results.get(0)._number).isEqualTo(last.getId().get());
}
}
@Test
public void start() throws Exception {
TestRepository<Repo> repo = createProject("repo");
List<Change> changes = Lists.newArrayList();
for (int i = 0; i < 2; i++) {
changes.add(insert(newChange(repo, null, null, null, null)));
}
assertQuery("status:new", changes.get(1), changes.get(0));
assertQuery(newQuery("status:new").withStart(1), changes.get(0));
assertQuery(newQuery("status:new").withStart(2));
assertQuery(newQuery("status:new").withStart(3));
}
@Test
public void startWithLimit() throws Exception {
TestRepository<Repo> repo = createProject("repo");
List<Change> changes = Lists.newArrayList();
for (int i = 0; i < 3; i++) {
changes.add(insert(newChange(repo, null, null, null, null)));
}
assertQuery("status:new limit:2", changes.get(2), changes.get(1));
assertQuery(
newQuery("status:new limit:2").withStart(1),
changes.get(1), changes.get(0));
assertQuery(newQuery("status:new limit:2").withStart(2), changes.get(0));
assertQuery(newQuery("status:new limit:2").withStart(3));
}
@Test
public void maxPages() throws Exception {
TestRepository<Repo> repo = createProject("repo");
Change change = insert(newChange(repo, null, null, null, null));
QueryRequest query = newQuery("status:new").withLimit(10);
assertQuery(query, change);
assertQuery(query.withStart(1));
assertQuery(query.withStart(99));
assertBadQuery(query.withStart(100));
assertQuery(query.withLimit(100).withStart(100));
}
@Test
public void updateOrder() throws Exception {
TestTimeUtil.resetWithClockStep(2, MINUTES);
TestRepository<Repo> repo = createProject("repo");
List<ChangeInserter> inserters = Lists.newArrayList();
List<Change> changes = Lists.newArrayList();
for (int i = 0; i < 5; i++) {
inserters.add(newChange(repo, null, null, null, null));
changes.add(insert(inserters.get(i)));
}
for (int i : ImmutableList.of(2, 0, 1, 4, 3)) {
gApi.changes().id(changes.get(i).getId().get()).current()
.review(new ReviewInput().message("modifying " + i));
}
assertQuery(
"status:new",
changes.get(3),
changes.get(4),
changes.get(1),
changes.get(0),
changes.get(2));
}
@Test
public void updatedOrderWithMinuteResolution() throws Exception {
TestTimeUtil.resetWithClockStep(2, MINUTES);
TestRepository<Repo> repo = createProject("repo");
ChangeInserter ins1 = newChange(repo, null, null, null, null);
Change change1 = insert(ins1);
Change change2 = insert(newChange(repo, null, null, null, null));
assertThat(lastUpdatedMs(change1)).isLessThan(lastUpdatedMs(change2));
assertQuery("status:new", change2, change1);
gApi.changes().id(change1.getId().get()).current()
.review(new ReviewInput());
change1 = db.changes().get(change1.getId());
assertThat(lastUpdatedMs(change1)).isGreaterThan(lastUpdatedMs(change2));
assertThat(lastUpdatedMs(change1) - lastUpdatedMs(change2))
.isGreaterThan(MILLISECONDS.convert(1, MINUTES));
// change1 moved to the top.
assertQuery("status:new", change1, change2);
}
@Test
public void updatedOrderWithSubMinuteResolution() throws Exception {
TestRepository<Repo> repo = createProject("repo");
ChangeInserter ins1 = newChange(repo, null, null, null, null);
Change change1 = insert(ins1);
Change change2 = insert(newChange(repo, null, null, null, null));
assertThat(lastUpdatedMs(change1)).isLessThan(lastUpdatedMs(change2));
assertQuery("status:new", change2, change1);
gApi.changes().id(change1.getId().get()).current()
.review(new ReviewInput());
change1 = db.changes().get(change1.getId());
assertThat(lastUpdatedMs(change1)).isGreaterThan(lastUpdatedMs(change2));
assertThat(lastUpdatedMs(change1) - lastUpdatedMs(change2))
.isLessThan(MILLISECONDS.convert(1, MINUTES));
// change1 moved to the top.
assertQuery("status:new", change1, change2);
}
@Test
public void filterOutMoreThanOnePageOfResults() throws Exception {
TestRepository<Repo> repo = createProject("repo");
Change change = insert(newChange(repo, null, null, userId.get(), null));
int user2 = accountManager.authenticate(AuthRequest.forUser("anotheruser"))
.getAccountId().get();
for (int i = 0; i < 5; i++) {
insert(newChange(repo, null, null, user2, null));
}
assertQuery("status:new ownerin:Administrators", change);
assertQuery("status:new ownerin:Administrators limit:2", change);
}
@Test
public void filterOutAllResults() throws Exception {
TestRepository<Repo> repo = createProject("repo");
int user2 = accountManager.authenticate(AuthRequest.forUser("anotheruser"))
.getAccountId().get();
for (int i = 0; i < 5; i++) {
insert(newChange(repo, null, null, user2, null));
}
assertQuery("status:new ownerin:Administrators");
assertQuery("status:new ownerin:Administrators limit:2");
}
@Test
public void byFileExact() throws Exception {
TestRepository<Repo> repo = createProject("repo");
RevCommit commit = repo.parseBody(
repo.commit().message("one")
.add("dir/file1", "contents1").add("dir/file2", "contents2")
.create());
Change change = insert(newChange(repo, commit, null, null, null));
assertQuery("file:file");
assertQuery("file:dir", change);
assertQuery("file:file1", change);
assertQuery("file:file2", change);
assertQuery("file:dir/file1", change);
assertQuery("file:dir/file2", change);
}
@Test
public void byFileRegex() throws Exception {
TestRepository<Repo> repo = createProject("repo");
RevCommit commit = repo.parseBody(
repo.commit().message("one")
.add("dir/file1", "contents1").add("dir/file2", "contents2")
.create());
Change change = insert(newChange(repo, commit, null, null, null));
assertQuery("file:.*file.*");
assertQuery("file:^file.*"); // Whole path only.
assertQuery("file:^dir.file.*", change);
}
@Test
public void byPathExact() throws Exception {
TestRepository<Repo> repo = createProject("repo");
RevCommit commit = repo.parseBody(
repo.commit().message("one")
.add("dir/file1", "contents1").add("dir/file2", "contents2")
.create());
Change change = insert(newChange(repo, commit, null, null, null));
assertQuery("path:file");
assertQuery("path:dir");
assertQuery("path:file1");
assertQuery("path:file2");
assertQuery("path:dir/file1", change);
assertQuery("path:dir/file2", change);
}
@Test
public void byPathRegex() throws Exception {
TestRepository<Repo> repo = createProject("repo");
RevCommit commit = repo.parseBody(
repo.commit().message("one")
.add("dir/file1", "contents1").add("dir/file2", "contents2")
.create());
Change change = insert(newChange(repo, commit, null, null, null));
assertQuery("path:.*file.*");
assertQuery("path:^dir.file.*", change);
}
@Test
public void byComment() throws Exception {
TestRepository<Repo> repo = createProject("repo");
ChangeInserter ins = newChange(repo, null, null, null, null);
Change change = insert(ins);
ReviewInput input = new ReviewInput();
input.message = "toplevel";
ReviewInput.CommentInput comment = new ReviewInput.CommentInput();
comment.line = 1;
comment.message = "inline";
input.comments = ImmutableMap.<String, List<ReviewInput.CommentInput>> of(
Patch.COMMIT_MSG, ImmutableList.<ReviewInput.CommentInput> of(comment));
gApi.changes().id(change.getId().get()).current().review(input);
assertQuery("comment:foo");
assertQuery("comment:toplevel", change);
assertQuery("comment:inline", change);
}
@Test
public void byAge() throws Exception {
long thirtyHoursInMs = MILLISECONDS.convert(30, HOURS);
TestTimeUtil.resetWithClockStep(thirtyHoursInMs, MILLISECONDS);
TestRepository<Repo> repo = createProject("repo");
Change change1 = insert(newChange(repo, null, null, null, null));
Change change2 = insert(newChange(repo, null, null, null, null));
// Queried by AgePredicate constructor.
TestTimeUtil.setClockStep(0, MILLISECONDS);
long now = TimeUtil.nowMs();
assertThat(lastUpdatedMs(change2) - lastUpdatedMs(change1))
.isEqualTo(thirtyHoursInMs);
assertThat(now - lastUpdatedMs(change2)).isEqualTo(thirtyHoursInMs);
assertThat(TimeUtil.nowMs()).isEqualTo(now);
assertQuery("-age:1d");
assertQuery("-age:" + (30 * 60 - 1) + "m");
assertQuery("-age:2d", change2);
assertQuery("-age:3d", change2, change1);
assertQuery("age:3d");
assertQuery("age:2d", change1);
assertQuery("age:1d", change2, change1);
}
@Test
public void byBefore() throws Exception {
TestTimeUtil.resetWithClockStep(30, HOURS);
TestRepository<Repo> repo = createProject("repo");
Change change1 = insert(newChange(repo, null, null, null, null));
Change change2 = insert(newChange(repo, null, null, null, null));
TestTimeUtil.setClockStep(0, MILLISECONDS);
assertQuery("before:2009-09-29");
assertQuery("before:2009-09-30");
assertQuery("before:\"2009-09-30 16:59:00 -0400\"");
assertQuery("before:\"2009-09-30 20:59:00 -0000\"");
assertQuery("before:\"2009-09-30 20:59:00\"");
assertQuery("before:\"2009-09-30 17:02:00 -0400\"", change1);
assertQuery("before:\"2009-10-01 21:02:00 -0000\"", change1);
assertQuery("before:\"2009-10-01 21:02:00\"", change1);
assertQuery("before:2009-10-01", change1);
assertQuery("before:2009-10-03", change2, change1);
}
@Test
public void byAfter() throws Exception {
TestTimeUtil.resetWithClockStep(30, HOURS);
TestRepository<Repo> repo = createProject("repo");
Change change1 = insert(newChange(repo, null, null, null, null));
Change change2 = insert(newChange(repo, null, null, null, null));
TestTimeUtil.setClockStep(0, MILLISECONDS);
assertQuery("after:2009-10-03");
assertQuery("after:\"2009-10-01 20:59:59 -0400\"", change2);
assertQuery("after:\"2009-10-01 20:59:59 -0000\"", change2);
assertQuery("after:2009-10-01", change2);
assertQuery("after:2009-09-30", change2, change1);
}
@Test
public void bySize() throws Exception {
TestRepository<Repo> repo = createProject("repo");
// added = 3, deleted = 0, delta = 3
RevCommit commit1 = repo.parseBody(
repo.commit().add("file1", "foo\n\foo\nfoo").create());
// added = 0, deleted = 2, delta = 2
RevCommit commit2 = repo.parseBody(
repo.commit().parent(commit1).add("file1", "foo").create());
Change change1 = insert(newChange(repo, commit1, null, null, null));
Change change2 = insert(newChange(repo, commit2, null, null, null));
assertQuery("added:>4");
assertQuery("-added:<=4");
assertQuery("added:3", change1);
assertQuery("-(added:<3 OR added>3)", change1);
assertQuery("added:>2", change1);
assertQuery("-added:<=2", change1);
assertQuery("added:>=3", change1);
assertQuery("-added:<3", change1);
assertQuery("added:<1", change2);
assertQuery("-added:>=1", change2);
assertQuery("added:<=0", change2);
assertQuery("-added:>0", change2);
assertQuery("deleted:>3");
assertQuery("-deleted:<=3");
assertQuery("deleted:2", change2);
assertQuery("-(deleted:<2 OR deleted>2)", change2);
assertQuery("deleted:>1", change2);
assertQuery("-deleted:<=1", change2);
assertQuery("deleted:>=2", change2);
assertQuery("-deleted:<2", change2);
assertQuery("deleted:<1", change1);
assertQuery("-deleted:>=1", change1);
assertQuery("deleted:<=0", change1);
for (String str : Lists.newArrayList("delta", "size")) {
assertQuery(str + ":<2");
assertQuery(str + ":3", change1);
assertQuery(str + ":>2", change1);
assertQuery(str + ":>=3", change1);
assertQuery(str + ":<3", change2);
assertQuery(str + ":<=2", change2);
}
}
private List<Change> setUpHashtagChanges() throws Exception {
TestRepository<Repo> repo = createProject("repo");
Change change1 = insert(newChange(repo, null, null, null, null));
Change change2 = insert(newChange(repo, null, null, null, null));
HashtagsInput in = new HashtagsInput();
in.add = ImmutableSet.of("foo");
gApi.changes().id(change1.getId().get()).setHashtags(in);
in.add = ImmutableSet.of("foo", "bar", "a tag");
gApi.changes().id(change2.getId().get()).setHashtags(in);
return ImmutableList.of(change1, change2);
}
@Test
public void byHashtagWithNotedb() throws Exception {
assume().that(notesMigration.enabled()).isTrue();
List<Change> changes = setUpHashtagChanges();
assertQuery("hashtag:foo", changes.get(1), changes.get(0));
assertQuery("hashtag:bar", changes.get(1));
assertQuery("hashtag:\"a tag\"", changes.get(1));
assertQuery("hashtag:\"a tag \"", changes.get(1));
assertQuery("hashtag:\" a tag \"", changes.get(1));
assertQuery("hashtag:\"#a tag\"", changes.get(1));
assertQuery("hashtag:\"# #a tag\"", changes.get(1));
}
@Test
public void byHashtagWithoutNotedb() throws Exception {
assume().that(notesMigration.enabled()).isFalse();
setUpHashtagChanges();
assertQuery("hashtag:foo");
assertQuery("hashtag:bar");
assertQuery("hashtag:\" bar \"");
assertQuery("hashtag:\"a tag\"");
assertQuery("hashtag:\" a tag \"");
assertQuery("hashtag:#foo");
assertQuery("hashtag:\"# #foo\"");
}
@Test
public void byDefault() throws Exception {
TestRepository<Repo> repo = createProject("repo");
Change change1 = insert(newChange(repo, null, null, null, null));
RevCommit commit2 = repo.parseBody(
repo.commit().message("foosubject").create());
Change change2 = insert(newChange(repo, commit2, null, null, null));
RevCommit commit3 = repo.parseBody(
repo.commit()
.add("Foo.java", "foo contents")
.create());
Change change3 = insert(newChange(repo, commit3, null, null, null));
ChangeInserter ins4 = newChange(repo, null, null, null, null);
Change change4 = insert(ins4);
ReviewInput ri4 = new ReviewInput();
ri4.message = "toplevel";
ri4.labels = ImmutableMap.<String, Short> of("Code-Review", (short) 1);
gApi.changes().id(change4.getId().get()).current().review(ri4);
ChangeInserter ins5 = newChange(repo, null, null, null, null);
Change change5 = ins5.getChange();
change5.setTopic("feature5");
insert(ins5);
Change change6 = insert(newChange(repo, null, null, null, "branch6"));
assertQuery(change1.getId().get(), change1);
assertQuery(ChangeTriplet.format(change1), change1);
assertQuery("foosubject", change2);
assertQuery("Foo.java", change3);
assertQuery("Code-Review+1", change4);
assertQuery("toplevel", change4);
assertQuery("feature5", change5);
assertQuery("branch6", change6);
assertQuery("refs/heads/branch6", change6);
Change[] expected =
new Change[] {change6, change5, change4, change3, change2, change1};
assertQuery("user@example.com", expected);
assertQuery("repo", expected);
}
@Test
public void implicitVisibleTo() throws Exception {
TestRepository<Repo> repo = createProject("repo");
Change change1 = insert(newChange(repo, null, null, userId.get(), null));
ChangeInserter ins2 = newChange(repo, null, null, userId.get(), null);
Change change2 = ins2.getChange();
change2.setStatus(Change.Status.DRAFT);
insert(ins2);
String q = "project:repo";
assertQuery(q, change2, change1);
// Second user cannot see first user's drafts.
requestContext.setContext(newRequestContext(accountManager
.authenticate(AuthRequest.forUser("anotheruser")).getAccountId()));
assertQuery(q, change1);
}
@Test
public void explicitVisibleTo() throws Exception {
TestRepository<Repo> repo = createProject("repo");
Change change1 = insert(newChange(repo, null, null, userId.get(), null));
ChangeInserter ins2 = newChange(repo, null, null, userId.get(), null);
Change change2 = ins2.getChange();
change2.setStatus(Change.Status.DRAFT);
insert(ins2);
String q = "project:repo";
assertQuery(q, change2, change1);
// Second user cannot see first user's drafts.
Account.Id user2 = accountManager
.authenticate(AuthRequest.forUser("anotheruser"))
.getAccountId();
assertQuery(q + " visibleto:" + user2.get(), change1);
}
@Test
public void byCommentBy() throws Exception {
TestRepository<Repo> repo = createProject("repo");
Change change1 = insert(newChange(repo, null, null, null, null));
Change change2 = insert(newChange(repo, null, null, null, null));
int user2 = accountManager.authenticate(AuthRequest.forUser("anotheruser"))
.getAccountId().get();
ReviewInput input = new ReviewInput();
input.message = "toplevel";
ReviewInput.CommentInput comment = new ReviewInput.CommentInput();
comment.line = 1;
comment.message = "inline";
input.comments = ImmutableMap.<String, List<ReviewInput.CommentInput>> of(
Patch.COMMIT_MSG, ImmutableList.<ReviewInput.CommentInput> of(comment));
gApi.changes().id(change1.getId().get()).current().review(input);
input = new ReviewInput();
input.message = "toplevel";
gApi.changes().id(change2.getId().get()).current().review(input);
assertQuery("commentby:" + userId.get(), change2, change1);
assertQuery("commentby:" + user2);
}
@Test
public void byFrom() throws Exception {
TestRepository<Repo> repo = createProject("repo");
Change change1 = insert(newChange(repo, null, null, null, null));
int user2 = accountManager.authenticate(AuthRequest.forUser("anotheruser"))
.getAccountId().get();
ChangeInserter ins2 = newChange(repo, null, null, user2, null);
Change change2 = insert(ins2);
ReviewInput input = new ReviewInput();
input.message = "toplevel";
ReviewInput.CommentInput comment = new ReviewInput.CommentInput();
comment.line = 1;
comment.message = "inline";
input.comments = ImmutableMap.<String, List<ReviewInput.CommentInput>> of(
Patch.COMMIT_MSG, ImmutableList.<ReviewInput.CommentInput> of(comment));
gApi.changes().id(change2.getId().get()).current().review(input);
assertQuery("from:" + userId.get(), change2, change1);
assertQuery("from:" + user2, change2);
}
@Test
public void conflicts() throws Exception {
TestRepository<Repo> repo = createProject("repo");
RevCommit commit1 = repo.parseBody(
repo.commit()
.add("file1", "contents1")
.add("dir/file2", "contents2")
.add("dir/file3", "contents3")
.create());
RevCommit commit2 = repo.parseBody(
repo.commit()
.add("file1", "contents1")
.create());
RevCommit commit3 = repo.parseBody(
repo.commit()
.add("dir/file2", "contents2 different")
.create());
RevCommit commit4 = repo.parseBody(
repo.commit()
.add("file4", "contents4")
.create());
Change change1 = insert(newChange(repo, commit1, null, null, null));
Change change2 = insert(newChange(repo, commit2, null, null, null));
Change change3 = insert(newChange(repo, commit3, null, null, null));
Change change4 = insert(newChange(repo, commit4, null, null, null));
assertQuery("conflicts:" + change1.getId().get(), change3);
assertQuery("conflicts:" + change2.getId().get());
assertQuery("conflicts:" + change3.getId().get(), change1);
assertQuery("conflicts:" + change4.getId().get());
}
@Test
public void reviewedBy() throws Exception {
TestTimeUtil.resetWithClockStep(2, MINUTES);
TestRepository<Repo> repo = createProject("repo");
Change change1 = insert(newChange(repo, null, null, null, null));
Change change2 = insert(newChange(repo, null, null, null, null));
Change change3 = insert(newChange(repo, null, null, null, null));
gApi.changes()
.id(change1.getId().get())
.current()
.review(new ReviewInput().message("comment"));
Account.Id user2 = accountManager
.authenticate(AuthRequest.forUser("anotheruser"))
.getAccountId();
requestContext.setContext(newRequestContext(user2));
gApi.changes()
.id(change2.getId().get())
.current()
.review(new ReviewInput().message("comment"));
PatchSet.Id ps3_1 = change3.currentPatchSetId();
change3 = newPatchSet(repo, change3);
assertThat(change3.currentPatchSetId()).isNotEqualTo(ps3_1);
// Response to previous patch set still counts as reviewing.
gApi.changes()
.id(change3.getId().get())
.revision(ps3_1.get())
.review(new ReviewInput().message("comment"));
List<ChangeInfo> actual;
actual = assertQuery(
newQuery("is:reviewed").withOption(REVIEWED),
change3, change2);
assertThat(actual.get(0).reviewed).isTrue();
assertThat(actual.get(1).reviewed).isTrue();
actual = assertQuery(
newQuery("-is:reviewed").withOption(REVIEWED),
change1);
assertThat(actual.get(0).reviewed).isNull();
actual = assertQuery("reviewedby:" + userId.get());
actual = assertQuery(
newQuery("reviewedby:" + user2.get()).withOption(REVIEWED),
change3, change2);
assertThat(actual.get(0).reviewed).isTrue();
assertThat(actual.get(1).reviewed).isTrue();
}
@Test
public void byCommitsOnBranchNotMerged() throws Exception {
TestRepository<Repo> repo = createProject("repo");
int n = 10;
List<String> shas = new ArrayList<>(n);
List<Integer> expectedIds = new ArrayList<>(n);
Branch.NameKey dest = null;
for (int i = 0; i < n; i++) {
ChangeInserter ins = newChange(repo, null, null, null, null);
insert(ins);
if (dest == null) {
dest = ins.getChange().getDest();
}
shas.add(ins.getPatchSet().getRevision().get());
expectedIds.add(ins.getChange().getId().get());
}
for (int i = 1; i <= 11; i++) {
Iterable<ChangeData> cds = internalChangeQuery.byCommitsOnBranchNotMerged(
repo.getRepository(), db, dest, shas, i);
Iterable<Integer> ids = FluentIterable.from(cds).transform(
new Function<ChangeData, Integer>() {
@Override
public Integer apply(ChangeData in) {
return in.getId().get();
}
});
String name = "limit " + i;
assertThat(ids).named(name).hasSize(n);
assertThat(ids).named(name)
.containsExactlyElementsIn(expectedIds);
}
}
@Test
public void prepopulatedFields() throws Exception {
assume().that(notesMigration.enabled()).isFalse();
TestRepository<Repo> repo = createProject("repo");
Change change = insert(newChange(repo, null, null, null, null));
db = new DisabledReviewDb();
requestContext.setContext(newRequestContext(userId));
// Use QueryProcessor directly instead of API so we get ChangeDatas back.
List<ChangeData> cds = queryProcessor
.queryChanges(queryBuilder.parse(change.getId().toString()))
.changes();
assertThat(cds).hasSize(1);
ChangeData cd = cds.get(0);
cd.change();
cd.patchSets();
cd.currentApprovals();
cd.changedLines();
cd.reviewedBy();
// TODO(dborowitz): Swap out GitRepositoryManager somehow? Will probably be
// necessary for notedb anyway.
cd.isMergeable();
exception.expect(DisabledReviewDb.Disabled.class);
cd.messages();
}
protected ChangeInserter newChange(
TestRepository<Repo> repo,
@Nullable RevCommit commit, @Nullable String key, @Nullable Integer owner,
@Nullable String branch) throws Exception {
if (commit == null) {
commit = repo.parseBody(repo.commit().message("message").create());
}
Account.Id ownerId = owner != null ? new Account.Id(owner) : userId;
branch = MoreObjects.firstNonNull(branch, "refs/heads/master");
if (!branch.startsWith("refs/heads/")) {
branch = "refs/heads/" + branch;
}
Project.NameKey project = new Project.NameKey(
repo.getRepository().getDescription().getRepositoryName());
Change.Id id = new Change.Id(db.nextChangeId());
if (key == null) {
key = "I" + Hashing.sha1().newHasher()
.putInt(id.get())
.putString(project.get(), UTF_8)
.putString(commit.name(), UTF_8)
.putInt(ownerId.get())
.putString(branch, UTF_8)
.hash()
.toString();
}
Change change = new Change(new Change.Key(key), id, ownerId,
new Branch.NameKey(project, branch), TimeUtil.nowTs());
IdentifiedUser user = userFactory.create(Providers.of(db), ownerId);
RefControl refControl = projectControlFactory.controlFor(project, user)
.controlForRef(change.getDest());
return changeFactory.create(refControl, change, commit)
.setValidatePolicy(CommitValidators.Policy.NONE);
}
protected Change insert(ChangeInserter ins) throws Exception {
try (BatchUpdate bu = updateFactory.create(
db, ins.getChange().getProject(), ins.getUser(),
ins.getChange().getCreatedOn())) {
bu.insertChange(ins);
bu.execute();
return ins.getChange();
}
}
protected Change newPatchSet(TestRepository<Repo> repo, Change c)
throws Exception {
// Add a new file so the patch set is not a trivial rebase, to avoid default
// Code-Review label copying.
int n = c.currentPatchSetId().get() + 1;
RevCommit commit = repo.parseBody(
repo.commit()
.message("message")
.add("file" + n, "contents " + n)
.create());
RefControl ctl = projectControlFactory.controlFor(c.getProject(), user)
.controlForRef(c.getDest());
PatchSetInserter inserter = patchSetFactory.create(
ctl, new PatchSet.Id(c.getId(), n), commit)
.setSendMail(false)
.setRunHooks(false)
.setValidatePolicy(CommitValidators.Policy.NONE);
try (BatchUpdate bu = updateFactory.create(
db, c.getProject(), user, TimeUtil.nowTs());
ObjectInserter oi = repo.getRepository().newObjectInserter()) {
bu.setRepository(repo.getRepository(), repo.getRevWalk(), oi);
bu.addOp(c.getId(), inserter);
bu.execute();
}
return inserter.getChange();
}
protected void assertBadQuery(Object query) throws Exception {
assertBadQuery(newQuery(query));
}
protected void assertBadQuery(QueryRequest query) throws Exception {
exception.expect(BadRequestException.class);
query.get();
}
protected TestRepository<Repo> createProject(String name) throws Exception {
gApi.projects().create(name).get();
return new TestRepository<>(
repoManager.openRepository(new Project.NameKey(name)));
}
protected QueryRequest newQuery(Object query) {
return gApi.changes().query(query.toString());
}
protected List<ChangeInfo> assertQuery(Object query, Change... changes)
throws Exception {
return assertQuery(newQuery(query), changes);
}
protected List<ChangeInfo> assertQuery(QueryRequest query, Change... changes)
throws Exception {
List<ChangeInfo> result = query.get();
Iterable<Integer> ids = ids(result);
assertThat(ids).named(query.getQuery())
.containsExactlyElementsIn(ids(changes)).inOrder();
return result;
}
protected static Iterable<Integer> ids(Change... changes) {
return FluentIterable.from(Arrays.asList(changes)).transform(
new Function<Change, Integer>() {
@Override
public Integer apply(Change in) {
return in.getId().get();
}
});
}
protected static Iterable<Integer> ids(Iterable<ChangeInfo> changes) {
return FluentIterable.from(changes).transform(
new Function<ChangeInfo, Integer>() {
@Override
public Integer apply(ChangeInfo in) {
return in._number;
}
});
}
protected static long lastUpdatedMs(Change c) {
return c.getLastUpdatedOn().getTime();
}
}