summaryrefslogtreecommitdiffstats
path: root/java/com/google/gerrit/acceptance/PushOneCommit.java
diff options
context:
space:
mode:
Diffstat (limited to 'java/com/google/gerrit/acceptance/PushOneCommit.java')
-rw-r--r--java/com/google/gerrit/acceptance/PushOneCommit.java513
1 files changed, 513 insertions, 0 deletions
diff --git a/java/com/google/gerrit/acceptance/PushOneCommit.java b/java/com/google/gerrit/acceptance/PushOneCommit.java
new file mode 100644
index 0000000000..5e45df24a8
--- /dev/null
+++ b/java/com/google/gerrit/acceptance/PushOneCommit.java
@@ -0,0 +1,513 @@
+// 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.acceptance;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.gerrit.acceptance.GitUtil.pushHead;
+import static java.util.stream.Collectors.toList;
+import static org.junit.Assert.assertEquals;
+
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Sets;
+import com.google.gerrit.common.Nullable;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.server.ApprovalsUtil;
+import com.google.gerrit.server.notedb.ChangeNotes;
+import com.google.gerrit.server.notedb.NotesMigration;
+import com.google.gerrit.server.notedb.ReviewerStateInternal;
+import com.google.gerrit.server.query.change.ChangeData;
+import com.google.gerrit.server.query.change.InternalChangeQuery;
+import com.google.gwtorm.server.OrmException;
+import com.google.inject.Provider;
+import com.google.inject.assistedinject.Assisted;
+import com.google.inject.assistedinject.AssistedInject;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Stream;
+import org.eclipse.jgit.api.TagCommand;
+import org.eclipse.jgit.junit.TestRepository;
+import org.eclipse.jgit.lib.PersonIdent;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.transport.PushResult;
+import org.eclipse.jgit.transport.RemoteRefUpdate;
+import org.eclipse.jgit.transport.RemoteRefUpdate.Status;
+
+public class PushOneCommit {
+ public static final String SUBJECT = "test commit";
+ public static final String FILE_NAME = "a.txt";
+ public static final String FILE_CONTENT = "some content";
+ public static final String PATCH_FILE_ONLY =
+ "diff --git a/a.txt b/a.txt\n"
+ + "new file mode 100644\n"
+ + "index 0000000..f0eec86\n"
+ + "--- /dev/null\n"
+ + "+++ b/a.txt\n"
+ + "@@ -0,0 +1 @@\n"
+ + "+some content\n"
+ + "\\ No newline at end of file\n";
+ public static final String PATCH =
+ "From %s Mon Sep 17 00:00:00 2001\n"
+ + "From: Administrator <admin@example.com>\n"
+ + "Date: %s\n"
+ + "Subject: [PATCH] test commit\n"
+ + "\n"
+ + "Change-Id: %s\n"
+ + "---\n"
+ + "\n"
+ + PATCH_FILE_ONLY;
+
+ public interface Factory {
+ PushOneCommit create(ReviewDb db, PersonIdent i, TestRepository<?> testRepo);
+
+ PushOneCommit create(
+ ReviewDb db,
+ PersonIdent i,
+ TestRepository<?> testRepo,
+ @Assisted("changeId") String changeId);
+
+ PushOneCommit create(
+ ReviewDb db,
+ PersonIdent i,
+ TestRepository<?> testRepo,
+ @Assisted("subject") String subject,
+ @Assisted("fileName") String fileName,
+ @Assisted("content") String content);
+
+ PushOneCommit create(
+ ReviewDb db,
+ PersonIdent i,
+ TestRepository<?> testRepo,
+ @Assisted String subject,
+ @Assisted Map<String, String> files);
+
+ PushOneCommit create(
+ ReviewDb db,
+ PersonIdent i,
+ TestRepository<?> testRepo,
+ @Assisted("subject") String subject,
+ @Assisted("fileName") String fileName,
+ @Assisted("content") String content,
+ @Assisted("changeId") String changeId);
+ }
+
+ public static class Tag {
+ public String name;
+
+ public Tag(String name) {
+ this.name = name;
+ }
+ }
+
+ public static class AnnotatedTag extends Tag {
+ public String message;
+ public PersonIdent tagger;
+
+ public AnnotatedTag(String name, String message, PersonIdent tagger) {
+ super(name);
+ this.message = message;
+ this.tagger = tagger;
+ }
+ }
+
+ private static final AtomicInteger CHANGE_ID_COUNTER = new AtomicInteger();
+
+ private static String nextChangeId() {
+ // Tests use a variety of mechanisms for setting temporary timestamps, so we can't guarantee
+ // that the PersonIdent (or any other field used by the Change-Id generator) for any two test
+ // methods in the same acceptance test class are going to be different. But tests generally
+ // assume that Change-Ids are unique unless otherwise specified. So, don't even bother trying to
+ // reuse JGit's Change-Id generator, just do the simplest possible thing and convert a counter
+ // to hex.
+ return String.format("%040x", CHANGE_ID_COUNTER.incrementAndGet());
+ }
+
+ private final ChangeNotes.Factory notesFactory;
+ private final ApprovalsUtil approvalsUtil;
+ private final Provider<InternalChangeQuery> queryProvider;
+ private final NotesMigration notesMigration;
+ private final ReviewDb db;
+ private final TestRepository<?> testRepo;
+
+ private final String subject;
+ private final Map<String, String> files;
+ private String changeId;
+ private Tag tag;
+ private boolean force;
+ private List<String> pushOptions;
+
+ private final TestRepository<?>.CommitBuilder commitBuilder;
+
+ @AssistedInject
+ PushOneCommit(
+ ChangeNotes.Factory notesFactory,
+ ApprovalsUtil approvalsUtil,
+ Provider<InternalChangeQuery> queryProvider,
+ NotesMigration notesMigration,
+ @Assisted ReviewDb db,
+ @Assisted PersonIdent i,
+ @Assisted TestRepository<?> testRepo)
+ throws Exception {
+ this(
+ notesFactory,
+ approvalsUtil,
+ queryProvider,
+ notesMigration,
+ db,
+ i,
+ testRepo,
+ SUBJECT,
+ FILE_NAME,
+ FILE_CONTENT);
+ }
+
+ @AssistedInject
+ PushOneCommit(
+ ChangeNotes.Factory notesFactory,
+ ApprovalsUtil approvalsUtil,
+ Provider<InternalChangeQuery> queryProvider,
+ NotesMigration notesMigration,
+ @Assisted ReviewDb db,
+ @Assisted PersonIdent i,
+ @Assisted TestRepository<?> testRepo,
+ @Assisted("changeId") String changeId)
+ throws Exception {
+ this(
+ notesFactory,
+ approvalsUtil,
+ queryProvider,
+ notesMigration,
+ db,
+ i,
+ testRepo,
+ SUBJECT,
+ FILE_NAME,
+ FILE_CONTENT,
+ changeId);
+ }
+
+ @AssistedInject
+ PushOneCommit(
+ ChangeNotes.Factory notesFactory,
+ ApprovalsUtil approvalsUtil,
+ Provider<InternalChangeQuery> queryProvider,
+ NotesMigration notesMigration,
+ @Assisted ReviewDb db,
+ @Assisted PersonIdent i,
+ @Assisted TestRepository<?> testRepo,
+ @Assisted("subject") String subject,
+ @Assisted("fileName") String fileName,
+ @Assisted("content") String content)
+ throws Exception {
+ this(
+ notesFactory,
+ approvalsUtil,
+ queryProvider,
+ notesMigration,
+ db,
+ i,
+ testRepo,
+ subject,
+ fileName,
+ content,
+ null);
+ }
+
+ @AssistedInject
+ PushOneCommit(
+ ChangeNotes.Factory notesFactory,
+ ApprovalsUtil approvalsUtil,
+ Provider<InternalChangeQuery> queryProvider,
+ NotesMigration notesMigration,
+ @Assisted ReviewDb db,
+ @Assisted PersonIdent i,
+ @Assisted TestRepository<?> testRepo,
+ @Assisted String subject,
+ @Assisted Map<String, String> files)
+ throws Exception {
+ this(
+ notesFactory,
+ approvalsUtil,
+ queryProvider,
+ notesMigration,
+ db,
+ i,
+ testRepo,
+ subject,
+ files,
+ null);
+ }
+
+ @AssistedInject
+ PushOneCommit(
+ ChangeNotes.Factory notesFactory,
+ ApprovalsUtil approvalsUtil,
+ Provider<InternalChangeQuery> queryProvider,
+ NotesMigration notesMigration,
+ @Assisted ReviewDb db,
+ @Assisted PersonIdent i,
+ @Assisted TestRepository<?> testRepo,
+ @Assisted("subject") String subject,
+ @Assisted("fileName") String fileName,
+ @Assisted("content") String content,
+ @Nullable @Assisted("changeId") String changeId)
+ throws Exception {
+ this(
+ notesFactory,
+ approvalsUtil,
+ queryProvider,
+ notesMigration,
+ db,
+ i,
+ testRepo,
+ subject,
+ ImmutableMap.of(fileName, content),
+ changeId);
+ }
+
+ private PushOneCommit(
+ ChangeNotes.Factory notesFactory,
+ ApprovalsUtil approvalsUtil,
+ Provider<InternalChangeQuery> queryProvider,
+ NotesMigration notesMigration,
+ ReviewDb db,
+ PersonIdent i,
+ TestRepository<?> testRepo,
+ String subject,
+ Map<String, String> files,
+ String changeId)
+ throws Exception {
+ this.db = db;
+ this.testRepo = testRepo;
+ this.notesFactory = notesFactory;
+ this.approvalsUtil = approvalsUtil;
+ this.queryProvider = queryProvider;
+ this.notesMigration = notesMigration;
+ this.subject = subject;
+ this.files = files;
+ this.changeId = changeId;
+ if (changeId != null) {
+ commitBuilder = testRepo.amendRef("HEAD").insertChangeId(changeId.substring(1));
+ } else {
+ commitBuilder = testRepo.branch("HEAD").commit().insertChangeId(nextChangeId());
+ }
+ commitBuilder.message(subject).author(i).committer(new PersonIdent(i, testRepo.getDate()));
+ }
+
+ public PushOneCommit setParents(List<RevCommit> parents) throws Exception {
+ commitBuilder.noParents();
+ for (RevCommit p : parents) {
+ commitBuilder.parent(p);
+ }
+ return this;
+ }
+
+ public PushOneCommit setParent(RevCommit parent) throws Exception {
+ commitBuilder.noParents();
+ commitBuilder.parent(parent);
+ return this;
+ }
+
+ public Result to(String ref) throws Exception {
+ for (Map.Entry<String, String> e : files.entrySet()) {
+ commitBuilder.add(e.getKey(), e.getValue());
+ }
+ return execute(ref);
+ }
+
+ public Result rm(String ref) throws Exception {
+ for (String fileName : files.keySet()) {
+ commitBuilder.rm(fileName);
+ }
+ return execute(ref);
+ }
+
+ public Result execute(String ref) throws Exception {
+ RevCommit c = commitBuilder.create();
+ if (changeId == null) {
+ changeId = GitUtil.getChangeId(testRepo, c).get();
+ }
+ if (tag != null) {
+ TagCommand tagCommand = testRepo.git().tag().setName(tag.name);
+ if (tag instanceof AnnotatedTag) {
+ AnnotatedTag annotatedTag = (AnnotatedTag) tag;
+ tagCommand
+ .setAnnotated(true)
+ .setMessage(annotatedTag.message)
+ .setTagger(annotatedTag.tagger);
+ } else {
+ tagCommand.setAnnotated(false);
+ }
+ tagCommand.call();
+ }
+ return new Result(ref, pushHead(testRepo, ref, tag != null, force, pushOptions), c, subject);
+ }
+
+ public void setTag(Tag tag) {
+ this.tag = tag;
+ }
+
+ public void setForce(boolean force) {
+ this.force = force;
+ }
+
+ public List<String> getPushOptions() {
+ return pushOptions;
+ }
+
+ public void setPushOptions(List<String> pushOptions) {
+ this.pushOptions = pushOptions;
+ }
+
+ public void noParents() {
+ commitBuilder.noParents();
+ }
+
+ public class Result {
+ private final String ref;
+ private final PushResult result;
+ private final RevCommit commit;
+ private final String resSubj;
+
+ private Result(String ref, PushResult resSubj, RevCommit commit, String subject) {
+ this.ref = ref;
+ this.result = resSubj;
+ this.commit = commit;
+ this.resSubj = subject;
+ }
+
+ public ChangeData getChange() throws OrmException {
+ return Iterables.getOnlyElement(queryProvider.get().byKeyPrefix(changeId));
+ }
+
+ public PatchSet getPatchSet() throws OrmException {
+ return getChange().currentPatchSet();
+ }
+
+ public PatchSet.Id getPatchSetId() throws OrmException {
+ return getChange().change().currentPatchSetId();
+ }
+
+ public String getChangeId() {
+ return changeId;
+ }
+
+ public RevCommit getCommit() {
+ return commit;
+ }
+
+ public void assertPushOptions(List<String> pushOptions) {
+ assertEquals(pushOptions, getPushOptions());
+ }
+
+ public void assertChange(
+ Change.Status expectedStatus, String expectedTopic, TestAccount... expectedReviewers)
+ throws OrmException {
+ assertChange(
+ expectedStatus, expectedTopic, Arrays.asList(expectedReviewers), ImmutableList.of());
+ }
+
+ public void assertChange(
+ Change.Status expectedStatus,
+ String expectedTopic,
+ List<TestAccount> expectedReviewers,
+ List<TestAccount> expectedCcs)
+ throws OrmException {
+ Change c = getChange().change();
+ assertThat(c.getSubject()).isEqualTo(resSubj);
+ assertThat(c.getStatus()).isEqualTo(expectedStatus);
+ assertThat(Strings.emptyToNull(c.getTopic())).isEqualTo(expectedTopic);
+ if (notesMigration.readChanges()) {
+ assertReviewers(c, ReviewerStateInternal.REVIEWER, expectedReviewers);
+ assertReviewers(c, ReviewerStateInternal.CC, expectedCcs);
+ } else {
+ assertReviewers(
+ c,
+ ReviewerStateInternal.REVIEWER,
+ Stream.concat(expectedReviewers.stream(), expectedCcs.stream()).collect(toList()));
+ }
+ }
+
+ private void assertReviewers(
+ Change c, ReviewerStateInternal state, List<TestAccount> expectedReviewers)
+ throws OrmException {
+ Iterable<Account.Id> actualIds =
+ approvalsUtil.getReviewers(db, notesFactory.createChecked(db, c)).byState(state);
+ assertThat(actualIds)
+ .containsExactlyElementsIn(Sets.newHashSet(TestAccount.ids(expectedReviewers)));
+ }
+
+ public void assertOkStatus() {
+ assertStatus(Status.OK, null);
+ }
+
+ public void assertErrorStatus(String expectedMessage) {
+ assertStatus(Status.REJECTED_OTHER_REASON, expectedMessage);
+ }
+
+ public void assertErrorStatus() {
+ RemoteRefUpdate refUpdate = result.getRemoteUpdate(ref);
+ assertThat(refUpdate).isNotNull();
+ assertThat(refUpdate.getStatus())
+ .named(message(refUpdate))
+ .isEqualTo(Status.REJECTED_OTHER_REASON);
+ }
+
+ private void assertStatus(Status expectedStatus, String expectedMessage) {
+ RemoteRefUpdate refUpdate = result.getRemoteUpdate(ref);
+ assertThat(refUpdate).isNotNull();
+ assertThat(refUpdate.getStatus()).named(message(refUpdate)).isEqualTo(expectedStatus);
+ if (expectedMessage == null) {
+ assertThat(refUpdate.getMessage()).isNull();
+ } else {
+ assertThat(refUpdate.getMessage()).contains(expectedMessage);
+ }
+ }
+
+ public void assertMessage(String expectedMessage) {
+ RemoteRefUpdate refUpdate = result.getRemoteUpdate(ref);
+ assertThat(refUpdate).isNotNull();
+ assertThat(message(refUpdate).toLowerCase()).contains(expectedMessage.toLowerCase());
+ }
+
+ public void assertNotMessage(String message) {
+ RemoteRefUpdate refUpdate = result.getRemoteUpdate(ref);
+ assertThat(message(refUpdate).toLowerCase()).doesNotContain(message.toLowerCase());
+ }
+
+ public String getMessage() {
+ RemoteRefUpdate refUpdate = result.getRemoteUpdate(ref);
+ assertThat(refUpdate).isNotNull();
+ return message(refUpdate);
+ }
+
+ private String message(RemoteRefUpdate refUpdate) {
+ StringBuilder b = new StringBuilder();
+ if (refUpdate.getMessage() != null) {
+ b.append(refUpdate.getMessage());
+ b.append("\n");
+ }
+ b.append(result.getMessages());
+ return b.toString();
+ }
+ }
+}