diff options
Diffstat (limited to 'javatests/com/google/gerrit/acceptance/api/change/SubmitTypeRuleIT.java')
-rw-r--r-- | javatests/com/google/gerrit/acceptance/api/change/SubmitTypeRuleIT.java | 301 |
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); + } +} |