blob: 3b158a98a729b4133910c4a1ceebb2848aca0d77 [file] [log] [blame]
// Copyright (C) 2021 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.git;
import static com.google.common.truth.Truth.assertThat;
import static com.google.gerrit.testing.TestActionRefUpdateContext.testRefAction;
import static org.eclipse.jgit.lib.Constants.HEAD;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.GitUtil;
import com.google.gerrit.acceptance.PushOneCommit;
import com.google.gerrit.common.RawInputUtil;
import com.google.gerrit.entities.RefNames;
import com.google.gerrit.extensions.common.ChangeInput;
import com.google.gerrit.extensions.common.MergeInput;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.RefUpdate;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.junit.Before;
import org.junit.Test;
/** Ensures that auto merge commits are created when a new patch set or change is uploaded. */
public class AutoMergeIT extends AbstractDaemonTest {
private RevCommit parent1;
private RevCommit parent2;
@Before
public void setup() throws Exception {
ObjectId initial = repo().exactRef(HEAD).getLeaf().getObjectId();
PushOneCommit.Result p1 =
pushFactory
.create(
admin.newIdent(),
testRepo,
"parent 1",
ImmutableMap.of("foo", "foo-1.2", "bar", "bar-1.2"))
.to("refs/for/master");
parent1 = p1.getCommit();
// reset HEAD in order to create a sibling of the first change
testRepo.reset(initial);
PushOneCommit.Result p2 =
pushFactory
.create(
admin.newIdent(),
testRepo,
"parent 2",
ImmutableMap.of("foo", "foo-2.2", "bar", "bar-2.2"))
.to("refs/for/master");
parent2 = p2.getCommit();
}
@Test
public void autoMergeCreatedWhenPushingNewChange() throws Exception {
PushOneCommit m =
pushFactory.create(
admin.newIdent(), testRepo, "merge", ImmutableMap.of("foo", "foo-1", "bar", "bar-2"));
m.setParents(ImmutableList.of(parent1, parent2));
PushOneCommit.Result result = m.to("refs/for/master");
result.assertOkStatus();
assertAutoMergeCreated(result.getCommit());
}
@Test
public void autoMergeCreatedWhenPushingNewPatchSet() throws Exception {
PushOneCommit m =
pushFactory.create(
admin.newIdent(), testRepo, "merge", ImmutableMap.of("foo", "foo-1", "bar", "bar-2"));
m.setParents(ImmutableList.of(parent1, parent2));
PushOneCommit.Result ps1 = m.to("refs/for/master");
RevCommit ps2 =
testRepo
.amend(ps1.getCommit())
.message("PS2")
.insertChangeId(ps1.getChangeId().substring(1))
.create();
testRepo.reset(ps2);
GitUtil.pushHead(testRepo, "refs/for/master");
// Make sure we have two patch sets
assertThat(ps2.getParents().length).isEqualTo(2);
assertThat(gApi.changes().id(ps1.getChangeId()).get().revisions.size()).isEqualTo(2);
assertAutoMergeCreated(ps2);
}
@Test
public void autoMergeCreatedWhenChangeCreatedOnApi() throws Exception {
ChangeInput ci = new ChangeInput(project.get(), "master", "Merge commit");
ci.merge = new MergeInput();
ci.merge.source = parent1.name();
String newChangePatchSetSha1 = gApi.changes().create(ci).get().currentRevision;
assertAutoMergeCreated(ObjectId.fromString(newChangePatchSetSha1));
}
@Test
public void autoMergeCreatedWhenNewPatchSetCreatedOnApi() throws Exception {
ChangeInput ci = new ChangeInput(project.get(), "master", "Merge commit");
ci.merge = new MergeInput();
ci.merge.source = parent1.name();
String changeId = gApi.changes().create(ci).get().changeId;
gApi.changes().id(changeId).setMessage("New Commit Message\n\nChange-Id: " + changeId);
assertThat(gApi.changes().id(changeId).get().revisions.size()).isEqualTo(2);
String newChangePatchSetSha1 = gApi.changes().id(changeId).get().currentRevision;
assertAutoMergeCreated(ObjectId.fromString(newChangePatchSetSha1));
}
@Test
public void autoMergeCreatedWhenChangeEditIsPublished() throws Exception {
PushOneCommit m =
pushFactory.create(
admin.newIdent(), testRepo, "merge", ImmutableMap.of("foo", "foo-1", "bar", "bar-2"));
m.setParents(ImmutableList.of(parent1, parent2));
PushOneCommit.Result result = m.to("refs/for/master");
result.assertOkStatus();
assertAutoMergeCreated(result.getCommit());
gApi.changes()
.id(result.getChangeId())
.edit()
.modifyFile("new-file", RawInputUtil.create("content"));
gApi.changes().id(result.getChangeId()).edit().publish();
assertThat(gApi.changes().id(result.getChangeId()).get().revisions.size()).isEqualTo(2);
String newChangePatchSetSha1 = gApi.changes().id(result.getChangeId()).get().currentRevision;
assertAutoMergeCreated(ObjectId.fromString(newChangePatchSetSha1));
}
@Test
public void noAutoMergeCreatedWhenPushingNonMergeCommit() throws Exception {
PushOneCommit.Result change = createChange();
change.assertOkStatus();
assertNoAutoMergeCreated(change.getCommit());
}
@Test
public void autoMergeComputedInMemoryWhenMissing() throws Exception {
PushOneCommit m =
pushFactory.create(
admin.newIdent(), testRepo, "merge", ImmutableMap.of("foo", "foo-1", "bar", "bar-2"));
m.setParents(ImmutableList.of(parent1, parent2));
PushOneCommit.Result result = m.to("refs/for/master");
result.assertOkStatus();
assertAutoMergeCreated(result.getCommit());
// Delete auto merge branch
deleteAutoMergeBranch(result.getCommit());
// Trigger AutoMerge computation
assertThat(gApi.changes().id(result.getChangeId()).revision(1).file("foo").blameRequest().get())
.isNotEmpty();
assertNoAutoMergeCreated(result.getCommit());
}
@Test
public void pushWorksIfAutoMergeExists() throws Exception {
PushOneCommit m =
pushFactory.create(
admin.newIdent(), testRepo, "merge", ImmutableMap.of("foo", "foo-1", "bar", "bar-2"));
m.setParents(ImmutableList.of(parent1, parent2));
PushOneCommit.Result result = m.to("refs/for/master");
result.assertOkStatus();
assertAutoMergeCreated(result.getCommit());
// Delete change and push commit again.
gApi.changes().id(result.getChangeId()).delete();
// Push again successfully and check that AutoMerge commit is still there
result = m.to("refs/for/master");
result.assertOkStatus();
assertAutoMergeCreated(result.getCommit());
}
private void assertAutoMergeCreated(ObjectId mergeCommit) throws Exception {
try (Repository repo = repoManager.openRepository(project)) {
assertThat(repo.exactRef(RefNames.refsCacheAutomerge(mergeCommit.name()))).isNotNull();
}
}
private void assertNoAutoMergeCreated(ObjectId mergeCommit) throws Exception {
try (Repository repo = repoManager.openRepository(project)) {
assertThat(repo.exactRef(RefNames.refsCacheAutomerge(mergeCommit.name()))).isNull();
}
}
private void deleteAutoMergeBranch(ObjectId mergeCommit) throws Exception {
try (Repository repo = repoManager.openRepository(project)) {
RefUpdate ru = repo.updateRef(RefNames.refsCacheAutomerge(mergeCommit.name()));
ru.setForceUpdate(true);
testRefAction(() -> assertThat(ru.delete()).isEqualTo(RefUpdate.Result.FORCED));
}
assertNoAutoMergeCreated(mergeCommit);
}
}