blob: 96a485a458be3739f2206a7bfe3f96b8931b0cbb [file] [log] [blame]
// Copyright (C) 2014 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.notedb;
import static com.google.gerrit.testing.TestActionRefUpdateContext.testRefAction;
import static com.google.inject.Scopes.SINGLETON;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.mockito.Mockito.mock;
import com.google.common.collect.ImmutableList;
import com.google.gerrit.entities.Account;
import com.google.gerrit.entities.Change;
import com.google.gerrit.entities.Comment;
import com.google.gerrit.entities.CommentRange;
import com.google.gerrit.entities.HumanComment;
import com.google.gerrit.entities.PatchSet;
import com.google.gerrit.entities.Project;
import com.google.gerrit.entities.SubmitRecord;
import com.google.gerrit.extensions.config.FactoryModule;
import com.google.gerrit.metrics.DisabledMetricMaker;
import com.google.gerrit.metrics.MetricMaker;
import com.google.gerrit.server.ChangeDraftUpdate;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.DefaultRefLogIdentityProvider;
import com.google.gerrit.server.FanOutExecutor;
import com.google.gerrit.server.GerritPersonIdent;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.InternalUser;
import com.google.gerrit.server.account.AccountCache;
import com.google.gerrit.server.account.FakeRealm;
import com.google.gerrit.server.account.GroupBackend;
import com.google.gerrit.server.account.Realm;
import com.google.gerrit.server.account.ServiceUserClassifier;
import com.google.gerrit.server.account.externalids.ExternalIdCache;
import com.google.gerrit.server.account.externalids.storage.notedb.DisabledExternalIdCache;
import com.google.gerrit.server.approval.PatchSetApprovalUuidGenerator;
import com.google.gerrit.server.approval.testing.TestPatchSetApprovalUuidGenerator;
import com.google.gerrit.server.config.AllUsersName;
import com.google.gerrit.server.config.AllUsersNameProvider;
import com.google.gerrit.server.config.AnonymousCowardName;
import com.google.gerrit.server.config.AnonymousCowardNameProvider;
import com.google.gerrit.server.config.CanonicalWebUrl;
import com.google.gerrit.server.config.DefaultUrlFormatter.DefaultUrlFormatterModule;
import com.google.gerrit.server.config.EnablePeerIPInReflogRecord;
import com.google.gerrit.server.config.GerritImportedServerIds;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.config.GerritServerId;
import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
import com.google.gerrit.server.git.GitModule;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.RepositoryCaseMismatchException;
import com.google.gerrit.server.group.SystemGroupBackend;
import com.google.gerrit.server.project.NullProjectCache;
import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.query.change.InternalChangeQuery;
import com.google.gerrit.server.util.time.TimeUtil;
import com.google.gerrit.testing.AssertableExecutorService;
import com.google.gerrit.testing.ConfigSuite;
import com.google.gerrit.testing.FakeAccountCache;
import com.google.gerrit.testing.InMemoryRepositoryManager;
import com.google.gerrit.testing.TestChanges;
import com.google.gerrit.testing.TestTimeUtil;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Module;
import com.google.inject.TypeLiteral;
import java.time.Instant;
import java.time.ZoneId;
import java.util.Optional;
import java.util.concurrent.ExecutorService;
import org.eclipse.jgit.errors.RepositoryNotFoundException;
import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
import org.eclipse.jgit.junit.TestRepository;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.revwalk.RevWalk;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.runner.RunWith;
@Ignore
@RunWith(ConfigSuite.class)
public abstract class AbstractChangeNotesTest {
protected static final String LOCAL_SERVER_ID = "gerrit";
protected static final String FQ_USER_IDENT =
"Gerrit User 1000000 \\u003c1000000@" + LOCAL_SERVER_ID;
private static final ZoneId ZONE_ID = ZoneId.of("America/Los_Angeles");
@ConfigSuite.Parameter public Config testConfig;
protected Account.Id changeOwnerId;
protected Account.Id otherUserId;
protected FakeAccountCache accountCache;
protected IdentifiedUser changeOwner;
protected IdentifiedUser otherUser;
protected InMemoryRepository repo;
protected InMemoryRepositoryManager repoManager;
protected PersonIdent serverIdent;
protected InternalUser internalUser;
protected Project.NameKey project;
protected RevWalk rw;
protected TestRepository<InMemoryRepository> tr;
protected AssertableExecutorService assertableFanOutExecutor;
protected GitReferenceUpdated gitReferenceUpdated;
@Inject protected IdentifiedUser.GenericFactory userFactory;
@Inject protected NoteDbUpdateManager.Factory updateManagerFactory;
@Inject protected AllUsersName allUsers;
@Inject protected AbstractChangeNotes.Args args;
@Inject @GerritServerId protected String serverId;
@Inject protected ExternalIdCache externalIdCache;
protected Injector injector;
private String systemTimeZone;
@Inject protected ChangeNotes.Factory changeNotesFactory;
@Before
public void setUpTestEnvironment() throws Exception {
setupTestPrerequisites();
injector = createTestInjector(LOCAL_SERVER_ID);
createAllUsers(injector);
injector.injectMembers(this);
}
protected void setupTestPrerequisites() throws Exception {
setTimeForTesting();
serverIdent = new PersonIdent("Gerrit Server", "noreply@gerrit.com", TimeUtil.now(), ZONE_ID);
project = Project.nameKey("test-project");
repoManager = new InMemoryRepositoryManager();
repo = repoManager.createRepository(project);
tr = new TestRepository<>(repo);
rw = tr.getRevWalk();
accountCache = new FakeAccountCache();
Account.Builder co = Account.builder(Account.id(1), TimeUtil.now());
co.setFullName("Change Owner");
co.setPreferredEmail("change@owner.com");
accountCache.put(co.build());
Account.Builder ou = Account.builder(Account.id(2), TimeUtil.now());
ou.setFullName("Other Account");
ou.setPreferredEmail("other@account.com");
accountCache.put(ou.build());
assertableFanOutExecutor = new AssertableExecutorService();
gitReferenceUpdated = mock(GitReferenceUpdated.class);
changeOwnerId = co.id();
otherUserId = ou.id();
internalUser = new InternalUser();
}
protected Injector createTestInjector(String serverId, String... importedServerIds)
throws Exception {
return createTestInjector(DisabledExternalIdCache.module(), serverId, importedServerIds);
}
protected Injector createTestInjector(
Module extraGuiceModule, String serverId, String... importedServerIds) throws Exception {
return Guice.createInjector(
new FactoryModule() {
@Override
public void configure() {
install(extraGuiceModule);
install(new GitModule());
install(new DefaultUrlFormatterModule());
install(NoteDbModule.forTest());
install(new DefaultRefLogIdentityProvider.Module());
bind(AllUsersName.class).toProvider(AllUsersNameProvider.class);
bind(String.class).annotatedWith(GerritServerId.class).toInstance(serverId);
bind(new TypeLiteral<ImmutableList<String>>() {})
.annotatedWith(GerritImportedServerIds.class)
.toInstance(new ImmutableList.Builder<String>().add(importedServerIds).build());
bind(GitRepositoryManager.class).toInstance(repoManager);
bind(ProjectCache.class).to(NullProjectCache.class);
bind(Config.class).annotatedWith(GerritServerConfig.class).toInstance(testConfig);
bind(String.class)
.annotatedWith(AnonymousCowardName.class)
.toProvider(AnonymousCowardNameProvider.class);
bind(String.class)
.annotatedWith(CanonicalWebUrl.class)
.toInstance("http://localhost:8080/");
bind(Boolean.class)
.annotatedWith(EnablePeerIPInReflogRecord.class)
.toInstance(Boolean.FALSE);
bind(Realm.class).to(FakeRealm.class);
bind(GroupBackend.class).to(SystemGroupBackend.class).in(SINGLETON);
bind(AccountCache.class).toInstance(accountCache);
bind(PersonIdent.class).annotatedWith(GerritPersonIdent.class).toInstance(serverIdent);
bind(GitReferenceUpdated.class).toInstance(gitReferenceUpdated);
bind(MetricMaker.class).to(DisabledMetricMaker.class);
bind(ExecutorService.class)
.annotatedWith(FanOutExecutor.class)
.toInstance(assertableFanOutExecutor);
bind(ServiceUserClassifier.class).to(ServiceUserClassifier.NoOp.class);
bind(InternalChangeQuery.class)
.toProvider(
() -> {
throw new UnsupportedOperationException();
});
bind(PatchSetApprovalUuidGenerator.class).to(TestPatchSetApprovalUuidGenerator.class);
bind(ChangeDraftUpdate.ChangeDraftUpdateFactory.class)
.to(ChangeDraftNotesUpdate.Factory.class);
}
});
}
protected void createAllUsers(Injector injector)
throws RepositoryCaseMismatchException, RepositoryNotFoundException {
AllUsersName allUsersName = injector.getInstance(AllUsersName.class);
repoManager.createRepository(allUsersName);
IdentifiedUser.GenericFactory identifiedUserFactory =
injector.getInstance(IdentifiedUser.GenericFactory.class);
changeOwner = identifiedUserFactory.create(changeOwnerId);
otherUser = identifiedUserFactory.create(otherUserId);
}
private void setTimeForTesting() {
systemTimeZone = System.setProperty("user.timezone", "US/Eastern");
TestTimeUtil.resetWithClockStep(1, SECONDS);
}
@After
public void resetTime() {
TestTimeUtil.useSystemTime();
System.setProperty("user.timezone", systemTimeZone);
}
protected Change newChange(boolean workInProgress) throws Exception {
return newChange(injector, workInProgress);
}
protected Change newChange(Injector injector, boolean workInProgress) throws Exception {
return testRefAction(
() -> {
Change c = TestChanges.newChange(project, changeOwner.getAccountId());
ChangeUpdate u = newUpdate(injector, c, changeOwner, false);
u.setChangeId(c.getKey().get());
u.setBranch(c.getDest().branch());
u.setWorkInProgress(workInProgress);
u.commit();
return c;
});
}
protected Change newWorkInProgressChange() throws Exception {
return newChange(true);
}
protected Change newChange() throws Exception {
return newChange(false);
}
protected ChangeUpdate newUpdateForNewChange(Change c, CurrentUser user) throws Exception {
return newUpdate(injector, c, user, false);
}
protected ChangeUpdate newUpdate(Change c, CurrentUser user) throws Exception {
return newUpdate(injector, c, user, true);
}
protected ChangeUpdate newUpdate(Change c, CurrentUser user, boolean shouldExist)
throws Exception {
return newUpdate(injector, c, user, shouldExist);
}
protected ChangeUpdate newUpdate(
Injector injector, Change c, CurrentUser user, boolean shouldExist) throws Exception {
ChangeUpdate update = TestChanges.newUpdate(injector, c, Optional.of(user), shouldExist);
update.setPatchSetId(c.currentPatchSetId());
update.setAllowWriteToNewRef(true);
return update;
}
protected ChangeNotes newNotes(Change c) {
return new ChangeNotes(args, c, true, null).load();
}
protected ChangeNotes newNotes(AbstractChangeNotes.Args cArgs, Change c) {
return new ChangeNotes(cArgs, c, true, null).load();
}
protected static SubmitRecord submitRecord(
String status, String errorMessage, SubmitRecord.Label... labels) {
SubmitRecord rec = new SubmitRecord();
rec.status = SubmitRecord.Status.valueOf(status);
rec.errorMessage = errorMessage;
if (labels.length > 0) {
rec.labels = ImmutableList.copyOf(labels);
}
return rec;
}
protected static SubmitRecord.Label submitLabel(
String name, String status, Account.Id appliedBy) {
SubmitRecord.Label label = new SubmitRecord.Label();
label.label = name;
label.status = SubmitRecord.Label.Status.valueOf(status);
label.appliedBy = appliedBy;
return label;
}
protected HumanComment newComment(
PatchSet.Id psId,
String filename,
String UUID,
CommentRange range,
int line,
IdentifiedUser commenter,
String parentUUID,
Instant t,
String message,
short side,
ObjectId commitId,
boolean unresolved,
String serverId) {
HumanComment c =
new HumanComment(
new Comment.Key(UUID, filename, psId.get()),
commenter.getAccountId(),
t,
side,
message,
serverId,
unresolved);
c.lineNbr = line;
c.parentUuid = parentUUID;
c.setCommitId(commitId);
c.setRange(range);
return c;
}
protected HumanComment newComment(
PatchSet.Id psId,
String filename,
String UUID,
CommentRange range,
int line,
IdentifiedUser commenter,
String parentUUID,
Instant t,
String message,
short side,
ObjectId commitId,
boolean unresolved) {
return newComment(
psId,
filename,
UUID,
range,
line,
commenter,
parentUUID,
t,
message,
side,
commitId,
unresolved,
serverId);
}
protected static Instant truncate(Instant ts) {
return Instant.ofEpochMilli((ts.toEpochMilli() / 1000) * 1000);
}
protected static Instant after(Change c, long millis) {
return Instant.ofEpochMilli(c.getCreatedOn().toEpochMilli() + millis);
}
}