summaryrefslogtreecommitdiffstats
path: root/javatests/com/google/gerrit/acceptance/api/change/SubmitTypeRuleIT.java
diff options
context:
space:
mode:
Diffstat (limited to 'javatests/com/google/gerrit/acceptance/api/change/SubmitTypeRuleIT.java')
-rw-r--r--javatests/com/google/gerrit/acceptance/api/change/SubmitTypeRuleIT.java301
1 files changed, 301 insertions, 0 deletions
diff --git a/javatests/com/google/gerrit/acceptance/api/change/SubmitTypeRuleIT.java b/javatests/com/google/gerrit/acceptance/api/change/SubmitTypeRuleIT.java
new file mode 100644
index 0000000000..507205d972
--- /dev/null
+++ b/javatests/com/google/gerrit/acceptance/api/change/SubmitTypeRuleIT.java
@@ -0,0 +1,301 @@
+// Copyright (C) 2015 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.api.change;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.gerrit.extensions.client.SubmitType.CHERRY_PICK;
+import static com.google.gerrit.extensions.client.SubmitType.FAST_FORWARD_ONLY;
+import static com.google.gerrit.extensions.client.SubmitType.MERGE_ALWAYS;
+import static com.google.gerrit.extensions.client.SubmitType.MERGE_IF_NECESSARY;
+import static com.google.gerrit.extensions.client.SubmitType.REBASE_ALWAYS;
+import static com.google.gerrit.extensions.client.SubmitType.REBASE_IF_NECESSARY;
+
+import com.google.common.collect.ImmutableList;
+import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.acceptance.NoHttpd;
+import com.google.gerrit.acceptance.PushOneCommit;
+import com.google.gerrit.extensions.api.changes.ReviewInput;
+import com.google.gerrit.extensions.api.projects.BranchInput;
+import com.google.gerrit.extensions.client.SubmitType;
+import com.google.gerrit.extensions.common.TestSubmitRuleInfo;
+import com.google.gerrit.extensions.common.TestSubmitRuleInput;
+import com.google.gerrit.extensions.restapi.ResourceConflictException;
+import com.google.gerrit.extensions.restapi.RestApiException;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.RefNames;
+import com.google.gerrit.server.git.meta.MetaDataUpdate;
+import com.google.gerrit.server.git.meta.VersionedMetaData;
+import com.google.gerrit.testing.ConfigSuite;
+import java.io.IOException;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.lib.CommitBuilder;
+import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.junit.Before;
+import org.junit.Test;
+
+@NoHttpd
+public class SubmitTypeRuleIT extends AbstractDaemonTest {
+ @ConfigSuite.Default
+ public static Config submitWholeTopicEnabled() {
+ return submitWholeTopicEnabledConfig();
+ }
+
+ private class RulesPl extends VersionedMetaData {
+ private static final String FILENAME = "rules.pl";
+
+ private String rule;
+
+ @Override
+ protected String getRefName() {
+ return RefNames.REFS_CONFIG;
+ }
+
+ @Override
+ protected void onLoad() throws IOException, ConfigInvalidException {
+ rule = readUTF8(FILENAME);
+ }
+
+ @Override
+ protected boolean onSave(CommitBuilder commit) throws IOException, ConfigInvalidException {
+ TestSubmitRuleInput in = new TestSubmitRuleInput();
+ in.rule = rule;
+ try {
+ gApi.changes().id(testChangeId.get()).current().testSubmitType(in);
+ } catch (RestApiException e) {
+ throw new ConfigInvalidException("Invalid submit type rule", e);
+ }
+
+ saveUTF8(FILENAME, rule);
+ return true;
+ }
+ }
+
+ private AtomicInteger fileCounter;
+ private Change.Id testChangeId;
+
+ @Before
+ public void setUp() throws Exception {
+ fileCounter = new AtomicInteger();
+ gApi.projects().name(project.get()).branch("test").create(new BranchInput());
+ testChangeId = createChange("test", "test change").getChange().getId();
+ }
+
+ private void setRulesPl(String rule) throws Exception {
+ try (MetaDataUpdate md = metaDataUpdateFactory.create(project)) {
+ RulesPl r = new RulesPl();
+ r.load(md);
+ r.rule = rule;
+ r.commit(md);
+ }
+ }
+
+ private static final String SUBMIT_TYPE_FROM_SUBJECT =
+ "submit_type(fast_forward_only) :-"
+ + "gerrit:commit_message(M),"
+ + "regex_matches('.*FAST_FORWARD_ONLY.*', M),"
+ + "!.\n"
+ + "submit_type(merge_if_necessary) :-"
+ + "gerrit:commit_message(M),"
+ + "regex_matches('.*MERGE_IF_NECESSARY.*', M),"
+ + "!.\n"
+ + "submit_type(rebase_if_necessary) :-"
+ + "gerrit:commit_message(M),"
+ + "regex_matches('.*REBASE_IF_NECESSARY.*', M),"
+ + "!.\n"
+ + "submit_type(rebase_always) :-"
+ + "gerrit:commit_message(M),"
+ + "regex_matches('.*REBASE_ALWAYS.*', M),"
+ + "!.\n"
+ + "submit_type(merge_always) :-"
+ + "gerrit:commit_message(M),"
+ + "regex_matches('.*MERGE_ALWAYS.*', M),"
+ + "!.\n"
+ + "submit_type(cherry_pick) :-"
+ + "gerrit:commit_message(M),"
+ + "regex_matches('.*CHERRY_PICK.*', M),"
+ + "!.\n"
+ + "submit_type(T) :- gerrit:project_default_submit_type(T).";
+
+ private PushOneCommit.Result createChange(String dest, String subject) throws Exception {
+ PushOneCommit push =
+ pushFactory.create(
+ db,
+ admin.getIdent(),
+ testRepo,
+ subject,
+ "file" + fileCounter.incrementAndGet(),
+ PushOneCommit.FILE_CONTENT);
+ PushOneCommit.Result r = push.to("refs/for/" + dest);
+ r.assertOkStatus();
+ return r;
+ }
+
+ @Test
+ public void unconditionalCherryPick() throws Exception {
+ PushOneCommit.Result r = createChange();
+ assertSubmitType(MERGE_IF_NECESSARY, r.getChangeId());
+ setRulesPl("submit_type(cherry_pick).");
+ assertSubmitType(CHERRY_PICK, r.getChangeId());
+ }
+
+ @Test
+ public void submitTypeFromSubject() throws Exception {
+ PushOneCommit.Result r1 = createChange("master", "Default 1");
+ PushOneCommit.Result r2 = createChange("master", "FAST_FORWARD_ONLY 2");
+ PushOneCommit.Result r3 = createChange("master", "MERGE_IF_NECESSARY 3");
+ PushOneCommit.Result r4 = createChange("master", "REBASE_IF_NECESSARY 4");
+ PushOneCommit.Result r5 = createChange("master", "REBASE_ALWAYS 5");
+ PushOneCommit.Result r6 = createChange("master", "MERGE_ALWAYS 6");
+ PushOneCommit.Result r7 = createChange("master", "CHERRY_PICK 7");
+
+ assertSubmitType(MERGE_IF_NECESSARY, r1.getChangeId());
+ assertSubmitType(MERGE_IF_NECESSARY, r2.getChangeId());
+ assertSubmitType(MERGE_IF_NECESSARY, r3.getChangeId());
+ assertSubmitType(MERGE_IF_NECESSARY, r4.getChangeId());
+ assertSubmitType(MERGE_IF_NECESSARY, r5.getChangeId());
+ assertSubmitType(MERGE_IF_NECESSARY, r6.getChangeId());
+ assertSubmitType(MERGE_IF_NECESSARY, r7.getChangeId());
+
+ setRulesPl(SUBMIT_TYPE_FROM_SUBJECT);
+
+ assertSubmitType(MERGE_IF_NECESSARY, r1.getChangeId());
+ assertSubmitType(FAST_FORWARD_ONLY, r2.getChangeId());
+ assertSubmitType(MERGE_IF_NECESSARY, r3.getChangeId());
+ assertSubmitType(REBASE_IF_NECESSARY, r4.getChangeId());
+ assertSubmitType(REBASE_ALWAYS, r5.getChangeId());
+ assertSubmitType(MERGE_ALWAYS, r6.getChangeId());
+ assertSubmitType(CHERRY_PICK, r7.getChangeId());
+ }
+
+ @Test
+ public void submitTypeIsUsedForSubmit() throws Exception {
+ setRulesPl(SUBMIT_TYPE_FROM_SUBJECT);
+
+ PushOneCommit.Result r = createChange("master", "CHERRY_PICK 1");
+
+ gApi.changes().id(r.getChangeId()).current().review(ReviewInput.approve());
+ gApi.changes().id(r.getChangeId()).current().submit();
+
+ List<RevCommit> log = log("master", 1);
+ assertThat(log.get(0).getShortMessage()).isEqualTo("CHERRY_PICK 1");
+ assertThat(log.get(0).name()).isNotEqualTo(r.getCommit().name());
+ assertThat(log.get(0).getFullMessage()).contains("Change-Id: " + r.getChangeId());
+ assertThat(log.get(0).getFullMessage()).contains("Reviewed-on: ");
+ }
+
+ @Test
+ public void mixingSubmitTypesAcrossBranchesSucceeds() throws Exception {
+ setRulesPl(SUBMIT_TYPE_FROM_SUBJECT);
+
+ PushOneCommit.Result r1 = createChange("master", "MERGE_IF_NECESSARY 1");
+
+ RevCommit initialCommit = r1.getCommit().getParent(0);
+ BranchInput bin = new BranchInput();
+ bin.revision = initialCommit.name();
+ gApi.projects().name(project.get()).branch("branch").create(bin);
+
+ testRepo.reset(initialCommit);
+ PushOneCommit.Result r2 = createChange("branch", "MERGE_ALWAYS 1");
+
+ gApi.changes().id(r1.getChangeId()).topic(name("topic"));
+ gApi.changes().id(r1.getChangeId()).current().review(ReviewInput.approve());
+ gApi.changes().id(r2.getChangeId()).topic(name("topic"));
+ gApi.changes().id(r2.getChangeId()).current().review(ReviewInput.approve());
+ gApi.changes().id(r2.getChangeId()).current().submit();
+
+ assertThat(log("master", 1).get(0).name()).isEqualTo(r1.getCommit().name());
+
+ List<RevCommit> branchLog = log("branch", 1);
+ assertThat(branchLog.get(0).getParents()).hasLength(2);
+ assertThat(branchLog.get(0).getParent(1).name()).isEqualTo(r2.getCommit().name());
+ }
+
+ @Test
+ public void mixingSubmitTypesOnOneBranchFails() throws Exception {
+ setRulesPl(SUBMIT_TYPE_FROM_SUBJECT);
+
+ PushOneCommit.Result r1 = createChange("master", "CHERRY_PICK 1");
+ PushOneCommit.Result r2 = createChange("master", "MERGE_IF_NECESSARY 2");
+
+ gApi.changes().id(r1.getChangeId()).current().review(ReviewInput.approve());
+ gApi.changes().id(r2.getChangeId()).current().review(ReviewInput.approve());
+
+ try {
+ gApi.changes().id(r2.getChangeId()).current().submit();
+ fail("Expected ResourceConflictException");
+ } catch (ResourceConflictException e) {
+ assertThat(e)
+ .hasMessageThat()
+ .isEqualTo(
+ "Failed to submit 2 changes due to the following problems:\n"
+ + "Change "
+ + r1.getChange().getId()
+ + ": Change has submit type "
+ + "CHERRY_PICK, but previously chose submit type MERGE_IF_NECESSARY "
+ + "from change "
+ + r2.getChange().getId()
+ + " in the same batch");
+ }
+ }
+
+ @Test
+ public void invalidSubmitRuleWithNoRulesInProject() throws Exception {
+ String changeId = createChange("master", "change 1").getChangeId();
+
+ TestSubmitRuleInput in = new TestSubmitRuleInput();
+ in.rule = "invalid prolog rule";
+ // We have no rules.pl by default. The fact that the default rules are showing up here is a bug.
+ List<TestSubmitRuleInfo> response = gApi.changes().id(changeId).current().testSubmitRule(in);
+ assertThat(response).containsExactly(invalidPrologRuleInfo());
+ }
+
+ @Test
+ public void invalidSubmitRuleWithRulesInProject() throws Exception {
+ setRulesPl(SUBMIT_TYPE_FROM_SUBJECT);
+
+ String changeId = createChange("master", "change 1").getChangeId();
+
+ TestSubmitRuleInput in = new TestSubmitRuleInput();
+ in.rule = "invalid prolog rule";
+ List<TestSubmitRuleInfo> response = gApi.changes().id(changeId).current().testSubmitRule(in);
+ assertThat(response).containsExactly(invalidPrologRuleInfo());
+ }
+
+ private static TestSubmitRuleInfo invalidPrologRuleInfo() {
+ TestSubmitRuleInfo info = new TestSubmitRuleInfo();
+ info.status = "RULE_ERROR";
+ info.errorMessage = "operator expected after expression at: invalid prolog rule end_of_file.";
+ return info;
+ }
+
+ private List<RevCommit> log(String commitish, int n) throws Exception {
+ try (Repository repo = repoManager.openRepository(project);
+ Git git = new Git(repo)) {
+ ObjectId id = repo.resolve(commitish);
+ assertThat(id).isNotNull();
+ return ImmutableList.copyOf(git.log().add(id).setMaxCount(n).call());
+ }
+ }
+
+ private void assertSubmitType(SubmitType expected, String id) throws Exception {
+ assertThat(gApi.changes().id(id).current().submitType()).isEqualTo(expected);
+ }
+}