blob: fae6fadd87a46d16afd114515a6f6ea811167af9 [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.notedb;
import static com.google.gerrit.server.notedb.ReviewerState.CC;
import static com.google.gerrit.server.notedb.ReviewerState.REVIEWER;
import static com.google.inject.Scopes.SINGLETON;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.easymock.EasyMock.expect;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.Iterables;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Ordering;
import com.google.gerrit.common.data.SubmitRecord;
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.PatchSet;
import com.google.gerrit.reviewdb.client.PatchSetApproval;
import com.google.gerrit.reviewdb.client.PatchSetInfo;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.GerritPersonIdent;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.account.AccountCache;
import com.google.gerrit.server.account.CapabilityControl;
import com.google.gerrit.server.account.GroupBackend;
import com.google.gerrit.server.account.Realm;
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.FactoryModule;
import com.google.gerrit.server.config.GerritServerConfig;
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.VersionedMetaData.BatchMetaDataUpdate;
import com.google.gerrit.server.group.SystemGroupBackend;
import com.google.gerrit.server.project.ChangeControl;
import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.util.TimeUtil;
import com.google.gerrit.testutil.FakeAccountCache;
import com.google.gerrit.testutil.FakeRealm;
import com.google.gerrit.testutil.InMemoryRepositoryManager;
import com.google.gwtorm.client.KeyUtil;
import com.google.gwtorm.server.OrmException;
import com.google.gwtorm.server.StandardKeyEncoder;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.util.Providers;
import org.easymock.EasyMock;
import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
import org.eclipse.jgit.lib.CommitBuilder;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
import org.joda.time.DateTime;
import org.joda.time.DateTimeUtils;
import org.joda.time.DateTimeUtils.MillisProvider;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.sql.Timestamp;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;
import java.util.concurrent.atomic.AtomicLong;
public class ChangeNotesTest {
private static final TimeZone TZ =
TimeZone.getTimeZone("America/Los_Angeles");
private PersonIdent serverIdent;
private Project.NameKey project;
private InMemoryRepositoryManager repoManager;
private InMemoryRepository repo;
private FakeAccountCache accountCache;
private IdentifiedUser changeOwner;
private IdentifiedUser otherUser;
private Injector injector;
private String systemTimeZone;
private volatile long clockStepMs;
@Before
public void setUp() throws Exception {
setTimeForTesting();
KeyUtil.setEncoderImpl(new StandardKeyEncoder());
serverIdent = new PersonIdent(
"Gerrit Server", "noreply@gerrit.com", TimeUtil.nowTs(), TZ);
project = new Project.NameKey("test-project");
repoManager = new InMemoryRepositoryManager();
repo = repoManager.createRepository(project);
accountCache = new FakeAccountCache();
Account co = new Account(new Account.Id(1), TimeUtil.nowTs());
co.setFullName("Change Owner");
co.setPreferredEmail("change@owner.com");
accountCache.put(co);
Account ou = new Account(new Account.Id(2), TimeUtil.nowTs());
ou.setFullName("Other Account");
ou.setPreferredEmail("other@account.com");
accountCache.put(ou);
injector = Guice.createInjector(new FactoryModule() {
@Override
public void configure() {
install(new GitModule());
bind(NotesMigration.class).toInstance(NotesMigration.allEnabled());
bind(GitRepositoryManager.class).toInstance(repoManager);
bind(ProjectCache.class).toProvider(Providers.<ProjectCache> of(null));
bind(CapabilityControl.Factory.class)
.toProvider(Providers.<CapabilityControl.Factory> of(null));
bind(Config.class).annotatedWith(GerritServerConfig.class)
.toInstance(new Config());
bind(String.class).annotatedWith(AnonymousCowardName.class)
.toProvider(AnonymousCowardNameProvider.class);
bind(String.class).annotatedWith(CanonicalWebUrl.class)
.toInstance("http://localhost:8080/");
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.DISABLED);
}
});
IdentifiedUser.GenericFactory userFactory =
injector.getInstance(IdentifiedUser.GenericFactory.class);
changeOwner = userFactory.create(co.getId());
otherUser = userFactory.create(ou.getId());
}
private void setTimeForTesting() {
systemTimeZone = System.setProperty("user.timezone", "US/Eastern");
clockStepMs = MILLISECONDS.convert(1, SECONDS);
final AtomicLong clockMs = new AtomicLong(
new DateTime(2009, 9, 30, 17, 0, 0).getMillis());
DateTimeUtils.setCurrentMillisProvider(new MillisProvider() {
@Override
public long getMillis() {
return clockMs.getAndAdd(clockStepMs);
}
});
}
@After
public void resetTime() {
DateTimeUtils.setCurrentMillisSystem();
System.setProperty("user.timezone", systemTimeZone);
}
@Test
public void approvalsCommitFormatSimple() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
update.putApproval("Verified", (short) 1);
update.putApproval("Code-Review", (short) -1);
update.putReviewer(changeOwner.getAccount().getId(), REVIEWER);
update.putReviewer(otherUser.getAccount().getId(), CC);
update.commit();
assertEquals("refs/changes/01/1/meta", update.getRefName());
RevWalk walk = new RevWalk(repo);
try {
RevCommit commit = walk.parseCommit(update.getRevision());
walk.parseBody(commit);
assertEquals("Update patch set 1\n"
+ "\n"
+ "Patch-set: 1\n"
+ "Reviewer: Change Owner <1@gerrit>\n"
+ "CC: Other Account <2@gerrit>\n"
+ "Label: Code-Review=-1\n"
+ "Label: Verified=+1\n",
commit.getFullMessage());
PersonIdent author = commit.getAuthorIdent();
assertEquals("Change Owner", author.getName());
assertEquals("1@gerrit", author.getEmailAddress());
assertEquals(new Date(c.getCreatedOn().getTime() + 1000),
author.getWhen());
assertEquals(TimeZone.getTimeZone("GMT-7:00"), author.getTimeZone());
PersonIdent committer = commit.getCommitterIdent();
assertEquals("Gerrit Server", committer.getName());
assertEquals("noreply@gerrit.com", committer.getEmailAddress());
assertEquals(author.getWhen(), committer.getWhen());
assertEquals(author.getTimeZone(), committer.getTimeZone());
} finally {
walk.close();
}
}
@Test
public void approvalTombstoneCommitFormat() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
update.removeApproval("Code-Review");
update.commit();
RevWalk walk = new RevWalk(repo);
try {
RevCommit commit = walk.parseCommit(update.getRevision());
walk.parseBody(commit);
assertEquals("Update patch set 1\n"
+ "\n"
+ "Patch-set: 1\n"
+ "Label: -Code-Review\n",
commit.getFullMessage());
} finally {
walk.close();
}
}
@Test
public void submitCommitFormat() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
update.setSubject("Submit patch set 1");
update.submit(ImmutableList.of(
submitRecord("NOT_READY", null,
submitLabel("Verified", "OK", changeOwner.getAccountId()),
submitLabel("Code-Review", "NEED", null)),
submitRecord("NOT_READY", null,
submitLabel("Verified", "OK", changeOwner.getAccountId()),
submitLabel("Alternative-Code-Review", "NEED", null))));
update.commit();
RevWalk walk = new RevWalk(repo);
try {
RevCommit commit = walk.parseCommit(update.getRevision());
walk.parseBody(commit);
assertEquals("Submit patch set 1\n"
+ "\n"
+ "Patch-set: 1\n"
+ "Status: submitted\n"
+ "Submitted-with: NOT_READY\n"
+ "Submitted-with: OK: Verified: Change Owner <1@gerrit>\n"
+ "Submitted-with: NEED: Code-Review\n"
+ "Submitted-with: NOT_READY\n"
+ "Submitted-with: OK: Verified: Change Owner <1@gerrit>\n"
+ "Submitted-with: NEED: Alternative-Code-Review\n",
commit.getFullMessage());
PersonIdent author = commit.getAuthorIdent();
assertEquals("Change Owner", author.getName());
assertEquals("1@gerrit", author.getEmailAddress());
assertEquals(new Date(c.getCreatedOn().getTime() + 1000),
author.getWhen());
assertEquals(TimeZone.getTimeZone("GMT-7:00"), author.getTimeZone());
PersonIdent committer = commit.getCommitterIdent();
assertEquals("Gerrit Server", committer.getName());
assertEquals("noreply@gerrit.com", committer.getEmailAddress());
assertEquals(author.getWhen(), committer.getWhen());
assertEquals(author.getTimeZone(), committer.getTimeZone());
} finally {
walk.close();
}
}
@Test
public void submitWithErrorMessage() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
update.setSubject("Submit patch set 1");
update.submit(ImmutableList.of(
submitRecord("RULE_ERROR", "Problem with patch set:\n1")));
update.commit();
RevWalk walk = new RevWalk(repo);
try {
RevCommit commit = walk.parseCommit(update.getRevision());
walk.parseBody(commit);
assertEquals("Submit patch set 1\n"
+ "\n"
+ "Patch-set: 1\n"
+ "Status: submitted\n"
+ "Submitted-with: RULE_ERROR Problem with patch set: 1\n",
commit.getFullMessage());
} finally {
walk.close();
}
}
@Test
public void approvalsOnePatchSet() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
update.putApproval("Verified", (short) 1);
update.putApproval("Code-Review", (short) -1);
update.commit();
ChangeNotes notes = newNotes(c);
assertEquals(1, notes.getApprovals().keySet().size());
List<PatchSetApproval> psas =
notes.getApprovals().get(c.currentPatchSetId());
assertEquals(2, psas.size());
assertEquals(c.currentPatchSetId(), psas.get(0).getPatchSetId());
assertEquals(1, psas.get(0).getAccountId().get());
assertEquals("Code-Review", psas.get(0).getLabel());
assertEquals((short) -1, psas.get(0).getValue());
assertEquals(truncate(after(c, 1000)), psas.get(0).getGranted());
assertEquals(c.currentPatchSetId(), psas.get(1).getPatchSetId());
assertEquals(1, psas.get(1).getAccountId().get());
assertEquals("Verified", psas.get(1).getLabel());
assertEquals((short) 1, psas.get(1).getValue());
assertEquals(psas.get(0).getGranted(), psas.get(1).getGranted());
}
@Test
public void approvalsMultiplePatchSets() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
update.putApproval("Code-Review", (short) -1);
update.commit();
PatchSet.Id ps1 = c.currentPatchSetId();
incrementPatchSet(c);
update = newUpdate(c, changeOwner);
update.putApproval("Code-Review", (short) 1);
update.commit();
PatchSet.Id ps2 = c.currentPatchSetId();
ChangeNotes notes = newNotes(c);
ListMultimap<PatchSet.Id, PatchSetApproval> psas = notes.getApprovals();
assertEquals(2, notes.getApprovals().keySet().size());
PatchSetApproval psa1 = Iterables.getOnlyElement(psas.get(ps1));
assertEquals(ps1, psa1.getPatchSetId());
assertEquals(1, psa1.getAccountId().get());
assertEquals("Code-Review", psa1.getLabel());
assertEquals((short) -1, psa1.getValue());
assertEquals(truncate(after(c, 1000)), psa1.getGranted());
PatchSetApproval psa2 = Iterables.getOnlyElement(psas.get(ps2));
assertEquals(ps2, psa2.getPatchSetId());
assertEquals(1, psa2.getAccountId().get());
assertEquals("Code-Review", psa2.getLabel());
assertEquals((short) +1, psa2.getValue());
assertEquals(truncate(after(c, 2000)), psa2.getGranted());
}
@Test
public void approvalsMultipleApprovals() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
update.putApproval("Code-Review", (short) -1);
update.commit();
ChangeNotes notes = newNotes(c);
PatchSetApproval psa = Iterables.getOnlyElement(
notes.getApprovals().get(c.currentPatchSetId()));
assertEquals("Code-Review", psa.getLabel());
assertEquals((short) -1, psa.getValue());
update = newUpdate(c, changeOwner);
update.putApproval("Code-Review", (short) 1);
update.commit();
notes = newNotes(c);
psa = Iterables.getOnlyElement(
notes.getApprovals().get(c.currentPatchSetId()));
assertEquals("Code-Review", psa.getLabel());
assertEquals((short) 1, psa.getValue());
}
@Test
public void approvalsMultipleUsers() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
update.putApproval("Code-Review", (short) -1);
update.commit();
update = newUpdate(c, otherUser);
update.putApproval("Code-Review", (short) 1);
update.commit();
ChangeNotes notes = newNotes(c);
assertEquals(1, notes.getApprovals().keySet().size());
List<PatchSetApproval> psas =
notes.getApprovals().get(c.currentPatchSetId());
assertEquals(2, psas.size());
assertEquals(c.currentPatchSetId(), psas.get(0).getPatchSetId());
assertEquals(1, psas.get(0).getAccountId().get());
assertEquals("Code-Review", psas.get(0).getLabel());
assertEquals((short) -1, psas.get(0).getValue());
assertEquals(truncate(after(c, 1000)), psas.get(0).getGranted());
assertEquals(c.currentPatchSetId(), psas.get(1).getPatchSetId());
assertEquals(2, psas.get(1).getAccountId().get());
assertEquals("Code-Review", psas.get(1).getLabel());
assertEquals((short) 1, psas.get(1).getValue());
assertEquals(truncate(after(c, 2000)), psas.get(1).getGranted());
}
@Test
public void approvalsTombstone() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
update.putApproval("Not-For-Long", (short) 1);
update.commit();
ChangeNotes notes = newNotes(c);
PatchSetApproval psa = Iterables.getOnlyElement(
notes.getApprovals().get(c.currentPatchSetId()));
assertEquals(1, psa.getAccountId().get());
assertEquals("Not-For-Long", psa.getLabel());
assertEquals((short) 1, psa.getValue());
update = newUpdate(c, changeOwner);
update.removeApproval("Not-For-Long");
update.commit();
notes = newNotes(c);
assertTrue(notes.getApprovals().isEmpty());
}
@Test
public void multipleReviewers() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
update.putReviewer(changeOwner.getAccount().getId(), REVIEWER);
update.putReviewer(otherUser.getAccount().getId(), REVIEWER);
update.commit();
ChangeNotes notes = newNotes(c);
assertEquals(ImmutableSetMultimap.of(
REVIEWER, new Account.Id(1),
REVIEWER, new Account.Id(2)),
notes.getReviewers());
}
@Test
public void reviewerTypes() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
update.putReviewer(changeOwner.getAccount().getId(), REVIEWER);
update.putReviewer(otherUser.getAccount().getId(), CC);
update.commit();
ChangeNotes notes = newNotes(c);
assertEquals(ImmutableSetMultimap.of(
REVIEWER, new Account.Id(1),
CC, new Account.Id(2)),
notes.getReviewers());
}
@Test
public void oneReviewerMultipleTypes() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
update.putReviewer(otherUser.getAccount().getId(), REVIEWER);
update.commit();
ChangeNotes notes = newNotes(c);
assertEquals(ImmutableSetMultimap.of(
REVIEWER, new Account.Id(2)),
notes.getReviewers());
update = newUpdate(c, otherUser);
update.putReviewer(otherUser.getAccount().getId(), CC);
update.commit();
notes = newNotes(c);
assertEquals(ImmutableSetMultimap.of(
CC, new Account.Id(2)),
notes.getReviewers());
}
@Test
public void removeReviewer() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
update.putReviewer(otherUser.getAccount().getId(), REVIEWER);
update.commit();
update = newUpdate(c, changeOwner);
update.putApproval("Code-Review", (short) 1);
update.commit();
update = newUpdate(c, otherUser);
update.putApproval("Code-Review", (short) 1);
update.commit();
ChangeNotes notes = newNotes(c);
List<PatchSetApproval> psas =
notes.getApprovals().get(c.currentPatchSetId());
assertEquals(2, psas.size());
assertEquals(changeOwner.getAccount().getId(), psas.get(0).getAccountId());
assertEquals(otherUser.getAccount().getId(), psas.get(1).getAccountId());
update = newUpdate(c, changeOwner);
update.removeReviewer(otherUser.getAccount().getId());
update.commit();
notes = newNotes(c);
psas = notes.getApprovals().get(c.currentPatchSetId());
assertEquals(1, psas.size());
assertEquals(changeOwner.getAccount().getId(), psas.get(0).getAccountId());
}
@Test
public void submitRecords() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
update.setSubject("Submit patch set 1");
update.submit(ImmutableList.of(
submitRecord("NOT_READY", null,
submitLabel("Verified", "OK", changeOwner.getAccountId()),
submitLabel("Code-Review", "NEED", null)),
submitRecord("NOT_READY", null,
submitLabel("Verified", "OK", changeOwner.getAccountId()),
submitLabel("Alternative-Code-Review", "NEED", null))));
update.commit();
ChangeNotes notes = newNotes(c);
List<SubmitRecord> recs = notes.getSubmitRecords();
assertEquals(2, recs.size());
assertEquals(submitRecord("NOT_READY", null,
submitLabel("Verified", "OK", changeOwner.getAccountId()),
submitLabel("Code-Review", "NEED", null)), recs.get(0));
assertEquals(submitRecord("NOT_READY", null,
submitLabel("Verified", "OK", changeOwner.getAccountId()),
submitLabel("Alternative-Code-Review", "NEED", null)), recs.get(1));
}
@Test
public void latestSubmitRecordsOnly() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
update.setSubject("Submit patch set 1");
update.submit(ImmutableList.of(
submitRecord("OK", null,
submitLabel("Code-Review", "OK", otherUser.getAccountId()))));
update.commit();
incrementPatchSet(c);
update = newUpdate(c, changeOwner);
update.setSubject("Submit patch set 2");
update.submit(ImmutableList.of(
submitRecord("OK", null,
submitLabel("Code-Review", "OK", changeOwner.getAccountId()))));
update.commit();
ChangeNotes notes = newNotes(c);
assertEquals(submitRecord("OK", null,
submitLabel("Code-Review", "OK", changeOwner.getAccountId())),
Iterables.getOnlyElement(notes.getSubmitRecords()));
}
@Test
public void multipleUpdatesInBatch() throws Exception {
Change c = newChange();
ChangeUpdate update1 = newUpdate(c, changeOwner);
update1.putApproval("Verified", (short) 1);
ChangeUpdate update2 = newUpdate(c, otherUser);
update2.putApproval("Code-Review", (short) 2);
BatchMetaDataUpdate batch = update1.openUpdate();
try {
batch.write(update1, new CommitBuilder());
batch.write(update2, new CommitBuilder());
batch.commit();
} finally {
batch.close();
}
ChangeNotes notes = newNotes(c);
List<PatchSetApproval> psas =
notes.getApprovals().get(c.currentPatchSetId());
assertEquals(2, psas.size());
assertEquals(changeOwner.getAccount().getId(), psas.get(0).getAccountId());
assertEquals("Verified", psas.get(0).getLabel());
assertEquals((short) 1, psas.get(0).getValue());
assertEquals(otherUser.getAccount().getId(), psas.get(1).getAccountId());
assertEquals("Code-Review", psas.get(1).getLabel());
assertEquals((short) 2, psas.get(1).getValue());
}
private Change newChange() {
Change.Id changeId = new Change.Id(1);
Change c = new Change(
new Change.Key("Iabcd1234abcd1234abcd1234abcd1234abcd1234"),
changeId,
changeOwner.getAccount().getId(),
new Branch.NameKey(project, "master"),
TimeUtil.nowTs());
incrementPatchSet(c);
return c;
}
private ChangeUpdate newUpdate(Change c, final IdentifiedUser user)
throws Exception {
return injector.createChildInjector(new FactoryModule() {
@Override
public void configure() {
factory(ChangeUpdate.Factory.class);
bind(IdentifiedUser.class).toInstance(user);
}
}).getInstance(ChangeUpdate.Factory.class).create(
stubChangeControl(c, user), TimeUtil.nowTs(),
Ordering.<String> natural());
}
private ChangeNotes newNotes(Change c) throws OrmException {
return new ChangeNotes(repoManager, c).load();
}
private static void incrementPatchSet(Change change) {
PatchSet.Id curr = change.currentPatchSetId();
PatchSetInfo ps = new PatchSetInfo(new PatchSet.Id(
change.getId(), curr != null ? curr.get() + 1 : 1));
ps.setSubject("Change subject");
change.setCurrentPatchSet(ps);
}
private static Timestamp truncate(Timestamp ts) {
return new Timestamp((ts.getTime() / 1000) * 1000);
}
private static Timestamp after(Change c, long millis) {
return new Timestamp(c.getCreatedOn().getTime() + millis);
}
private ChangeControl stubChangeControl(Change c, IdentifiedUser user) {
ChangeControl ctl = EasyMock.createNiceMock(ChangeControl.class);
expect(ctl.getChange()).andStubReturn(c);
expect(ctl.getCurrentUser()).andStubReturn(user);
EasyMock.replay(ctl);
return ctl;
}
private 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;
}
private 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;
}
}