| // Copyright (C) 2016 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.rest.project; |
| |
| import static com.google.common.truth.Truth.assertThat; |
| |
| import com.google.common.base.Strings; |
| import com.google.gerrit.acceptance.AbstractDaemonTest; |
| import com.google.gerrit.acceptance.PushOneCommit; |
| import com.google.gerrit.acceptance.RestResponse; |
| import com.google.gerrit.acceptance.testsuite.project.ProjectOperations; |
| import com.google.gerrit.entities.BranchNameKey; |
| import com.google.gerrit.extensions.api.changes.ChangeApi; |
| import com.google.gerrit.extensions.api.changes.CherryPickInput; |
| import com.google.gerrit.extensions.api.changes.ReviewInput; |
| import com.google.gerrit.extensions.api.projects.BranchInput; |
| import com.google.gerrit.extensions.common.MergeableInfo; |
| import com.google.inject.Inject; |
| import org.eclipse.jgit.lib.ObjectId; |
| import org.eclipse.jgit.revwalk.RevCommit; |
| import org.eclipse.jgit.transport.RefSpec; |
| import org.junit.Before; |
| import org.junit.Test; |
| |
| public class CheckMergeabilityIT extends AbstractDaemonTest { |
| |
| @Inject private ProjectOperations projectOperations; |
| |
| private BranchNameKey branch; |
| |
| @Before |
| public void setUp() throws Exception { |
| branch = BranchNameKey.create(project, "test"); |
| gApi.projects().name(branch.project().get()).branch(branch.branch()).create(new BranchInput()); |
| } |
| |
| @Test |
| public void checkMergeableCommit() throws Exception { |
| RevCommit initialHead = projectOperations.project(project).getHead("master"); |
| testRepo |
| .branch("HEAD") |
| .commit() |
| .insertChangeId() |
| .message("some change in a") |
| .add("a.txt", "a contents ") |
| .create(); |
| testRepo |
| .git() |
| .push() |
| .setRemote("origin") |
| .setRefSpecs(new RefSpec("HEAD:refs/heads/master")) |
| .call(); |
| |
| testRepo.reset(initialHead); |
| testRepo |
| .branch("HEAD") |
| .commit() |
| .insertChangeId() |
| .message("some change in b") |
| .add("b.txt", "b contents ") |
| .create(); |
| testRepo |
| .git() |
| .push() |
| .setRemote("origin") |
| .setRefSpecs(new RefSpec("HEAD:refs/heads/test")) |
| .call(); |
| |
| assertMergeable("master", "test", "recursive"); |
| } |
| |
| @Test |
| public void checkUnMergeableCommit() throws Exception { |
| RevCommit initialHead = projectOperations.project(project).getHead("master"); |
| testRepo |
| .branch("HEAD") |
| .commit() |
| .insertChangeId() |
| .message("some change in a") |
| .add("a.txt", "a contents ") |
| .create(); |
| testRepo |
| .git() |
| .push() |
| .setRemote("origin") |
| .setRefSpecs(new RefSpec("HEAD:refs/heads/master")) |
| .call(); |
| |
| testRepo.reset(initialHead); |
| testRepo |
| .branch("HEAD") |
| .commit() |
| .insertChangeId() |
| .message("some change in a too") |
| .add("a.txt", "a contents too") |
| .create(); |
| testRepo |
| .git() |
| .push() |
| .setRemote("origin") |
| .setRefSpecs(new RefSpec("HEAD:refs/heads/test")) |
| .call(); |
| |
| assertUnMergeable("master", "test", "recursive", "a.txt"); |
| } |
| |
| @Test |
| public void checkOursMergeStrategy() throws Exception { |
| RevCommit initialHead = projectOperations.project(project).getHead("master"); |
| testRepo |
| .branch("HEAD") |
| .commit() |
| .insertChangeId() |
| .message("some change in a") |
| .add("a.txt", "a contents ") |
| .create(); |
| testRepo |
| .git() |
| .push() |
| .setRemote("origin") |
| .setRefSpecs(new RefSpec("HEAD:refs/heads/master")) |
| .call(); |
| |
| testRepo.reset(initialHead); |
| testRepo |
| .branch("HEAD") |
| .commit() |
| .insertChangeId() |
| .message("some change in a too") |
| .add("a.txt", "a contents too") |
| .create(); |
| testRepo |
| .git() |
| .push() |
| .setRemote("origin") |
| .setRefSpecs(new RefSpec("HEAD:refs/heads/test")) |
| .call(); |
| |
| assertMergeable("master", "test", "ours"); |
| } |
| |
| @Test |
| public void checkAlreadyMergedCommit() throws Exception { |
| ObjectId c0 = |
| testRepo |
| .branch("HEAD") |
| .commit() |
| .insertChangeId() |
| .message("first commit") |
| .add("a.txt", "a contents ") |
| .create(); |
| testRepo |
| .git() |
| .push() |
| .setRemote("origin") |
| .setRefSpecs(new RefSpec("HEAD:refs/heads/master")) |
| .call(); |
| |
| testRepo |
| .branch("HEAD") |
| .commit() |
| .insertChangeId() |
| .message("second commit") |
| .add("b.txt", "b contents ") |
| .create(); |
| testRepo |
| .git() |
| .push() |
| .setRemote("origin") |
| .setRefSpecs(new RefSpec("HEAD:refs/heads/master")) |
| .call(); |
| |
| assertCommitMerged("master", c0.getName(), ""); |
| } |
| |
| @Test |
| public void checkContentMergedCommit() throws Exception { |
| testRepo |
| .branch("HEAD") |
| .commit() |
| .insertChangeId() |
| .message("first commit") |
| .add("a.txt", "a contents ") |
| .create(); |
| testRepo |
| .git() |
| .push() |
| .setRemote("origin") |
| .setRefSpecs(new RefSpec("HEAD:refs/heads/master")) |
| .call(); |
| |
| // create a change, and cherrypick into master |
| PushOneCommit.Result cId = createChange(); |
| RevCommit commitId = cId.getCommit(); |
| CherryPickInput cpi = new CherryPickInput(); |
| cpi.destination = "master"; |
| cpi.message = "cherry pick the commit"; |
| ChangeApi orig = gApi.changes().id(cId.getChangeId()); |
| ChangeApi cherry = orig.current().cherryPick(cpi); |
| cherry.current().review(ReviewInput.approve()); |
| cherry.current().submit(); |
| |
| ObjectId remoteId = projectOperations.project(project).getHead("master"); |
| assertThat(remoteId).isNotEqualTo(commitId); |
| assertContentMerged("master", commitId.getName(), "recursive"); |
| } |
| |
| @Test |
| public void checkInvalidSource() throws Exception { |
| testRepo |
| .branch("HEAD") |
| .commit() |
| .insertChangeId() |
| .message("first commit") |
| .add("a.txt", "a contents ") |
| .create(); |
| testRepo |
| .git() |
| .push() |
| .setRemote("origin") |
| .setRefSpecs(new RefSpec("HEAD:refs/heads/master")) |
| .call(); |
| |
| assertBadRequest( |
| "master", |
| "fdsafsdf", |
| "recursive", |
| "Error resolving: 'fdsafsdf'. Do not have read permission, or failed to resolve to a commit."); |
| } |
| |
| @Test |
| public void checkInvalidStrategy() throws Exception { |
| RevCommit initialHead = projectOperations.project(project).getHead("master"); |
| testRepo |
| .branch("HEAD") |
| .commit() |
| .insertChangeId() |
| .message("first commit") |
| .add("a.txt", "a contents ") |
| .create(); |
| testRepo |
| .git() |
| .push() |
| .setRemote("origin") |
| .setRefSpecs(new RefSpec("HEAD:refs/heads/master")) |
| .call(); |
| |
| testRepo.reset(initialHead); |
| testRepo |
| .branch("HEAD") |
| .commit() |
| .insertChangeId() |
| .message("some change in a too") |
| .add("a.txt", "a contents too") |
| .create(); |
| testRepo |
| .git() |
| .push() |
| .setRemote("origin") |
| .setRefSpecs(new RefSpec("HEAD:refs/heads/test")) |
| .call(); |
| |
| assertBadRequest("master", "test", "octopus", "invalid merge strategy: octopus"); |
| } |
| |
| private void assertMergeable(String targetBranch, String source, String strategy) |
| throws Exception { |
| MergeableInfo mergeableInfo = getMergeableInfo(targetBranch, source, strategy); |
| assertThat(mergeableInfo.mergeable).isTrue(); |
| } |
| |
| private void assertUnMergeable( |
| String targetBranch, String source, String strategy, String... conflicts) throws Exception { |
| MergeableInfo mergeableInfo = getMergeableInfo(targetBranch, source, strategy); |
| assertThat(mergeableInfo.mergeable).isFalse(); |
| assertThat(mergeableInfo.conflicts).containsExactly((Object[]) conflicts); |
| } |
| |
| private void assertCommitMerged(String targetBranch, String source, String strategy) |
| throws Exception { |
| MergeableInfo mergeableInfo = getMergeableInfo(targetBranch, source, strategy); |
| assertThat(mergeableInfo.mergeable).isTrue(); |
| assertThat(mergeableInfo.commitMerged).isTrue(); |
| } |
| |
| private void assertContentMerged(String targetBranch, String source, String strategy) |
| throws Exception { |
| MergeableInfo mergeableInfo = getMergeableInfo(targetBranch, source, strategy); |
| assertThat(mergeableInfo.mergeable).isTrue(); |
| assertThat(mergeableInfo.contentMerged).isTrue(); |
| } |
| |
| private void assertBadRequest(String targetBranch, String source, String strategy, String errMsg) |
| throws Exception { |
| String url = "/projects/" + project.get() + "/branches/" + targetBranch; |
| url += "/mergeable?source=" + source; |
| if (!Strings.isNullOrEmpty(strategy)) { |
| url += "&strategy=" + strategy; |
| } |
| |
| RestResponse r = userRestSession.get(url); |
| r.assertBadRequest(); |
| assertThat(r.getEntityContent()).isEqualTo(errMsg); |
| } |
| |
| private MergeableInfo getMergeableInfo(String targetBranch, String source, String strategy) |
| throws Exception { |
| String url = "/projects/" + project.get() + "/branches/" + targetBranch; |
| url += "/mergeable?source=" + source; |
| if (!Strings.isNullOrEmpty(strategy)) { |
| url += "&strategy=" + strategy; |
| } |
| |
| RestResponse r = userRestSession.get(url); |
| r.assertOK(); |
| MergeableInfo result = newGson().fromJson(r.getReader(), MergeableInfo.class); |
| r.consume(); |
| return result; |
| } |
| } |