aboutsummaryrefslogtreecommitdiffstats
path: root/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtStageIT.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtStageIT.java')
-rw-r--r--src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtStageIT.java294
1 files changed, 294 insertions, 0 deletions
diff --git a/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtStageIT.java b/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtStageIT.java
new file mode 100644
index 0000000..60be674
--- /dev/null
+++ b/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtStageIT.java
@@ -0,0 +1,294 @@
+// Copyright (C) 2019 The Qt Company
+
+package com.googlesource.gerrit.plugins.qtcodereview;
+
+import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.collect.ImmutableList;
+import com.google.gerrit.acceptance.LightweightPluginDaemonTest;
+import com.google.gerrit.acceptance.PushOneCommit;
+import com.google.gerrit.acceptance.RestResponse;
+import com.google.gerrit.acceptance.TestPlugin;
+import com.google.gerrit.acceptance.UseSsh;
+
+import com.google.gerrit.common.data.Permission;
+import com.google.gerrit.extensions.api.changes.SubmitInput;
+import com.google.gerrit.reviewdb.client.Branch;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.ChangeMessage;
+
+import org.apache.http.HttpStatus;
+
+import org.eclipse.jgit.revwalk.RevCommit;
+
+import java.util.ArrayList;
+
+import org.junit.Before;
+import org.junit.Test;
+
+@TestPlugin(
+ name = "gerrit-plugin-qt-workflow",
+ sysModule = "com.googlesource.gerrit.plugins.qtcodereview.QtModule",
+ sshModule = "com.googlesource.gerrit.plugins.qtcodereview.QtSshModule"
+)
+
+@UseSsh
+public class QtStageIT extends QtCodeReviewIT {
+
+ private final String STAGED_MSG = "Staged for CI";
+
+ @Before
+ public void SetDefaultPermissions() throws Exception {
+ createBranch(new Branch.NameKey(project, "feature"));
+
+ grant(project, "refs/heads/master", Permission.QT_STAGE, false, REGISTERED_USERS);
+ grant(project, "refs/heads/feature", Permission.QT_STAGE, false, REGISTERED_USERS);
+ }
+
+ @Test
+ public void singleChange_Stage() throws Exception {
+ RevCommit initialHead = getRemoteHead();
+ PushOneCommit.Result c = pushCommit("master", "commitmsg1", "file1", "content1");
+ approve(c.getChangeId());
+ RevCommit stagingHead = qtStage(c);
+ assertApproval(c.getChangeId(), admin);
+ }
+
+ @Test
+ public void multiChange_Stage() throws Exception {
+ RevCommit initialHead;
+ RevCommit stagingHead;
+
+ // Push 3 independent commits
+ initialHead = getRemoteHead();
+ PushOneCommit.Result c1 = pushCommit("master", "commitmsg1", "file1", "content1");
+ testRepo.reset(initialHead);
+ PushOneCommit.Result c2 = pushCommit("master", "commitmsg2", "file2", "content2");
+ testRepo.reset(initialHead);
+ PushOneCommit.Result c3 = pushCommit("master", "commitmsg3", "file3", "content3");
+
+ approve(c1.getChangeId());
+ approve(c2.getChangeId());
+ approve(c3.getChangeId());
+
+ stagingHead = qtStage(c1);
+ stagingHead = qtStage(c2);
+ stagingHead = qtStage(c3);
+ }
+
+ @Test
+ public void mergeCommit_Stage() throws Exception {
+ RevCommit initialHead = getRemoteHead();
+
+ // make changes on feature branch
+ PushOneCommit.Result f1 = pushCommit("feature", "commitmsg1", "file1", "content1");
+ PushOneCommit.Result f2 = pushCommit("feature", "commitmsg2", "file2", "content2");
+ approve(f1.getChangeId());
+ gApi.changes().id(f1.getChangeId()).current().submit();
+ approve(f2.getChangeId());
+ gApi.changes().id(f2.getChangeId()).current().submit();
+
+ // make a change on master branch
+ testRepo.reset(initialHead);
+ PushOneCommit.Result c1 = pushCommit("master", "commitmsg3", "file3", "content3");
+ approve(c1.getChangeId());
+ gApi.changes().id(c1.getChangeId()).current().submit();
+
+ // merge feature branch into master
+ PushOneCommit mm = pushFactory.create(db, admin.getIdent(), testRepo);
+ mm.setParents(ImmutableList.of(c1.getCommit(), f2.getCommit()));
+ PushOneCommit.Result m = mm.to("refs/for/master");
+ m.assertOkStatus();
+ approve(m.getChangeId());
+ RevCommit stagingHead = qtStageExpectMerge(m);
+
+ // check that all commits are in staging ref
+ String gitLog = getRemoteLog("refs/staging/master").toString();
+ assertThat(gitLog).contains(initialHead.getId().name());
+ assertThat(gitLog).contains(c1.getCommit().getId().name());
+ assertThat(gitLog).contains(f1.getCommit().getId().name());
+ assertThat(gitLog).contains(f2.getCommit().getId().name());
+ assertThat(gitLog).contains(m.getCommit().getId().name());
+ }
+
+ @Test
+ public void emptyChange_Stage() throws Exception {
+ RevCommit initialHead = getRemoteHead();
+ PushOneCommit.Result c = pushCommit("master", "1st commit", "afile", "");
+ approve(c.getChangeId());
+ RevCommit stagingHead = qtStage(c);
+ assertApproval(c.getChangeId(), admin);
+
+ // no changes in this commit
+ c = pushCommit("master", "no content", "afile", "");
+ approve(c.getChangeId());
+ stagingHead = qtStage(c);
+ assertApproval(c.getChangeId(), admin);
+ }
+
+ @Test
+ public void errorStage_No_Permission() throws Exception {
+ deny(project, "refs/heads/master", Permission.QT_STAGE, REGISTERED_USERS);
+
+ RevCommit initialHead = getRemoteHead();
+ PushOneCommit.Result c = pushCommit("master", "commitmsg1", "file1", "content1");
+ approve(c.getChangeId());
+
+ RestResponse response = qtStageExpectFail(c, initialHead, initialHead, HttpStatus.SC_FORBIDDEN);
+ assertThat(response.getEntityContent()).contains("not permitted");
+
+ grant(project, "refs/heads/master", Permission.QT_STAGE, false, REGISTERED_USERS);
+ }
+
+ @Test
+ public void errorStage_Wrong_Status() throws Exception {
+ RevCommit initialHead = getRemoteHead();
+ PushOneCommit.Result c = pushCommit("master", "commitmsg1", "file1", "content1");
+ approve(c.getChangeId());
+
+ grant(project, "refs/heads/master", Permission.ABANDON, false, REGISTERED_USERS);
+ QtDefer(c);
+ deny(project, "refs/heads/master", Permission.ABANDON, REGISTERED_USERS);
+
+ RestResponse response = qtStageExpectFail(c, initialHead, initialHead, HttpStatus.SC_CONFLICT);
+ assertThat(response.getEntityContent()).contains("change is DEFERRED");
+ }
+
+ @Test
+ public void errorStage_Invalid_ChangeId() throws Exception {
+ PushOneCommit.Result c = pushCommit("master", "commitmsg1", "file1", "content1");
+
+ RestResponse response = call_REST_API_Stage("thischangeidnotfound", c.getCommit().getName());
+ response.assertStatus(HttpStatus.SC_NOT_FOUND);
+ assertThat(response.getEntityContent()).contains("Not found: thischangeidnotfound");
+ }
+
+ @Test
+ public void errorStage_Invalid_RevisionId() throws Exception {
+ PushOneCommit.Result c = pushCommit("master", "commitmsg1", "file1", "content1");
+
+ RestResponse response = call_REST_API_Stage(c.getChangeId(), "thisrevisionidnotfound");
+ response.assertStatus(HttpStatus.SC_NOT_FOUND);
+ assertThat(response.getEntityContent()).contains("Not found: thisrevisionidnotfound");
+ }
+
+ @Test
+ public void errorStage_Revision_Not_Current() throws Exception {
+ PushOneCommit.Result c1 = pushCommit("master", "commitmsg1", "file1", "content1");
+ PushOneCommit.Result c2 = amendCommit(c1.getChangeId());
+
+ RestResponse response = call_REST_API_Stage(c1.getChangeId(), c1.getCommit().getName());
+ response.assertStatus(HttpStatus.SC_CONFLICT);
+ assertThat(response.getEntityContent()).contains("is not current revision");
+ }
+
+ @Test
+ public void errorStage_Not_Reviewed() throws Exception {
+ RevCommit initialHead = getRemoteHead();
+ PushOneCommit.Result c = pushCommit("master", "commitmsg1", "file1", "content1");
+
+ RestResponse response = qtStageExpectFail(c, initialHead, initialHead, HttpStatus.SC_CONFLICT);
+ assertThat(response.getEntityContent()).contains("needs Code-Review");
+ }
+
+ @Test
+ public void errorAmend_Status_Staged() throws Exception {
+ RevCommit initialHead = getRemoteHead();
+ PushOneCommit.Result c1 = pushCommit("master", "commitmsg1", "file1", "content1");
+ approve(c1.getChangeId());
+ RevCommit stagingHead = qtStage(c1);
+
+ PushOneCommit.Result c2 = amendCommit(c1.getChangeId());
+ c2.assertErrorStatus(" closed");
+
+ RevCommit updatedHead = getRemoteHead(project, "refs/staging/master");
+ assertThat(updatedHead.getId()).isEqualTo(stagingHead.getId()); // not updated
+ }
+
+ @Test
+ public void errorStage_Merge_Conlict() throws Exception {
+ RevCommit initialHead = getRemoteHead();
+ PushOneCommit.Result c1 = pushCommit("master", "commitmsg1", "thesamefile", "content");
+ approve(c1.getChangeId());
+ RevCommit stagingHead1 = qtStage(c1);
+
+ testRepo.reset(initialHead);
+ PushOneCommit.Result c2 = pushCommit("master", "commitmsg2", "thesamefile", "conficting content");
+ approve(c2.getChangeId());
+ RestResponse response = qtStageExpectFail(c2, initialHead, stagingHead1, HttpStatus.SC_CONFLICT);
+ assertThat(response.getEntityContent()).contains("merge conflict");
+
+ Change change = c2.getChange().change();
+ assertThat(change.getStatus()).isEqualTo(Change.Status.NEW);
+ }
+
+ private RevCommit qtStage(PushOneCommit.Result c) throws Exception {
+ return qtStage(c, false);
+ }
+
+ private RevCommit qtStageExpectMerge(PushOneCommit.Result c) throws Exception {
+ return qtStage(c, true);
+ }
+
+ private RevCommit qtStage(PushOneCommit.Result c, boolean merge) throws Exception {
+ String branch = getBranchNameFromRef(c.getChange().change().getDest().get());
+ String stagingRef = R_STAGING + branch;
+ String branchRef = R_HEADS + branch;
+ RevCommit originalCommit = c.getCommit();
+ RevCommit initialHead = getRemoteHead(project, branchRef);
+ RevCommit oldStagingHead = getRemoteHead(project, stagingRef);
+ if (oldStagingHead==null) oldStagingHead = initialHead;
+
+ RestResponse response = call_REST_API_Stage(c.getChangeId(), originalCommit.getName());
+ response.assertOK();
+
+ RevCommit branchHead = getRemoteHead(project, branchRef);
+ assertThat(branchHead.getId()).isEqualTo(initialHead.getId()); // master is not updated
+
+ RevCommit stagingHead = getRemoteHead(project, stagingRef);
+
+ if (merge) {
+ assertThat(stagingHead.getParentCount()).isEqualTo(2);
+ assertThat(stagingHead.getParent(1)).isEqualTo(originalCommit);
+ } else {
+ assertCherryPick(stagingHead, originalCommit, getCurrentPatchSHA(c));
+ }
+ assertThat(stagingHead.getParent(0)).isEqualTo(oldStagingHead);
+ assertRefUpdatedEvents(stagingRef, oldStagingHead, stagingHead);
+ resetEvents();
+
+ Change change = c.getChange().change();
+ assertThat(change.getStatus()).isEqualTo(Change.Status.STAGED);
+
+ ArrayList<ChangeMessage> messages = new ArrayList(c.getChange().messages());
+ assertThat(messages.get(messages.size()-1).getMessage()).isEqualTo(STAGED_MSG); // check last message
+
+ return stagingHead;
+ }
+
+ private RestResponse qtStageExpectFail(PushOneCommit.Result c,
+ RevCommit initialHead,
+ RevCommit oldStagingHead,
+ int expectedStatus)
+ throws Exception {
+ String branch = getBranchNameFromRef(c.getChange().change().getDest().get());
+ String stagingRef = R_STAGING + branch;
+ String branchRef = R_HEADS + branch;
+
+ RestResponse response = call_REST_API_Stage(c.getChangeId(), c.getCommit().getName());
+ response.assertStatus(expectedStatus);
+
+ RevCommit branchHead = getRemoteHead(project, branchRef);
+ assertThat(branchHead.getId()).isEqualTo(initialHead.getId()); // master is not updated
+
+ RevCommit stagingHead = getRemoteHead(project, stagingRef);
+ if (stagingHead != null) assertThat(stagingHead.getId()).isEqualTo(oldStagingHead.getId()); // staging is not updated
+
+ assertRefUpdatedEvents(branchRef); // no events
+ assertRefUpdatedEvents(stagingRef); // no events
+
+ return response;
+ }
+
+}