Rewrite LabelTypeIT and rename to StickyApprovalsIT
The new test covers more variations of sticky approvals based on label configuration and change kinds and is also easier to read. Change-Id: Iddf949bf779e3c531553968b9c489e94370241ad Signed-off-by: Edwin Kempin <ekempin@google.com>
This commit is contained in:
@@ -334,6 +334,15 @@ public class ChangeIT extends AbstractDaemonTest {
|
||||
assertThat(query(r.getChangeId())).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void voteOnClosedChange() throws Exception {
|
||||
PushOneCommit.Result r = createChange();
|
||||
merge(r);
|
||||
exception.expect(ResourceConflictException.class);
|
||||
exception.expectMessage("change is closed");
|
||||
revision(r).review(ReviewInput.reject());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void voteOnBehalfOf() throws Exception {
|
||||
ProjectConfig cfg = projectCache.checkedGet(project).getConfig();
|
||||
|
||||
@@ -0,0 +1,444 @@
|
||||
// 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.api.change;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.gerrit.extensions.client.ChangeKind.MERGE_FIRST_PARENT_UPDATE;
|
||||
import static com.google.gerrit.extensions.client.ChangeKind.NO_CODE_CHANGE;
|
||||
import static com.google.gerrit.extensions.client.ChangeKind.REWORK;
|
||||
import static com.google.gerrit.extensions.client.ChangeKind.TRIVIAL_REBASE;
|
||||
import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
|
||||
import static com.google.gerrit.server.project.Util.category;
|
||||
import static com.google.gerrit.server.project.Util.value;
|
||||
import static org.eclipse.jgit.lib.Constants.HEAD;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.gerrit.acceptance.AbstractDaemonTest;
|
||||
import com.google.gerrit.acceptance.GitUtil;
|
||||
import com.google.gerrit.acceptance.NoHttpd;
|
||||
import com.google.gerrit.acceptance.PushOneCommit;
|
||||
import com.google.gerrit.acceptance.TestAccount;
|
||||
import com.google.gerrit.common.data.LabelType;
|
||||
import com.google.gerrit.common.data.Permission;
|
||||
import com.google.gerrit.extensions.api.changes.CherryPickInput;
|
||||
import com.google.gerrit.extensions.api.changes.ReviewInput;
|
||||
import com.google.gerrit.extensions.api.changes.RevisionApi;
|
||||
import com.google.gerrit.extensions.client.ChangeKind;
|
||||
import com.google.gerrit.extensions.client.ListChangesOption;
|
||||
import com.google.gerrit.extensions.common.ApprovalInfo;
|
||||
import com.google.gerrit.extensions.common.ChangeInfo;
|
||||
import com.google.gerrit.extensions.common.CommitInfo;
|
||||
import com.google.gerrit.reviewdb.client.AccountGroup;
|
||||
import com.google.gerrit.reviewdb.client.RefNames;
|
||||
import com.google.gerrit.server.git.ProjectConfig;
|
||||
import com.google.gerrit.server.group.SystemGroupBackend;
|
||||
import com.google.gerrit.server.project.Util;
|
||||
|
||||
import org.eclipse.jgit.junit.TestRepository;
|
||||
import org.eclipse.jgit.lib.ObjectId;
|
||||
import org.eclipse.jgit.lib.PersonIdent;
|
||||
import org.eclipse.jgit.revwalk.RevCommit;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@NoHttpd
|
||||
public class StickyApprovalsIT extends AbstractDaemonTest {
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
ProjectConfig cfg = projectCache.checkedGet(project).getConfig();
|
||||
|
||||
// Overwrite "Code-Review" label that is inherited from All-Projects.
|
||||
// This way changes to the "Code Review" label don't affect other tests.
|
||||
LabelType codeReview =
|
||||
category("Code-Review", value(2, "Looks good to me, approved"),
|
||||
value(1, "Looks good to me, but someone else must approve"),
|
||||
value(0, "No score"),
|
||||
value(-1, "I would prefer that you didn't submit this"),
|
||||
value(-2, "Do not submit"));
|
||||
cfg.getLabelSections().put(codeReview.getName(), codeReview);
|
||||
|
||||
LabelType verified = category("Verified", value(1, "Passes"),
|
||||
value(0, "No score"), value(-1, "Failed"));
|
||||
cfg.getLabelSections().put(verified.getName(), verified);
|
||||
|
||||
AccountGroup.UUID registeredUsers =
|
||||
SystemGroupBackend.getGroup(REGISTERED_USERS).getUUID();
|
||||
String heads = RefNames.REFS_HEADS + "*";
|
||||
Util.allow(cfg, Permission.forLabel(Util.codeReview().getName()), -2, 2,
|
||||
registeredUsers, heads);
|
||||
Util.allow(cfg, Permission.forLabel(Util.verified().getName()), -1, 1,
|
||||
registeredUsers, heads);
|
||||
saveProjectConfig(project, cfg);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void notSticky() throws Exception {
|
||||
assertNotSticky(EnumSet.of(REWORK, TRIVIAL_REBASE, NO_CODE_CHANGE,
|
||||
MERGE_FIRST_PARENT_UPDATE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void stickyOnMinScore() throws Exception {
|
||||
ProjectConfig cfg = projectCache.checkedGet(project).getConfig();
|
||||
cfg.getLabelSections().get("Code-Review").setCopyMinScore(true);
|
||||
saveProjectConfig(project, cfg);
|
||||
|
||||
for (ChangeKind changeKind : EnumSet.of(REWORK, TRIVIAL_REBASE,
|
||||
NO_CODE_CHANGE, MERGE_FIRST_PARENT_UPDATE)) {
|
||||
testRepo.reset(getRemoteHead());
|
||||
|
||||
String changeId = createChange(changeKind);
|
||||
vote(admin, changeId, -1, 1);
|
||||
vote(user, changeId, -2, -1);
|
||||
|
||||
updateChange(changeId, changeKind);
|
||||
ChangeInfo c = detailedChange(changeId);
|
||||
assertVotes(c, admin, 0, 0, changeKind);
|
||||
assertVotes(c, user, -2, 0, changeKind);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void stickyOnMaxScore() throws Exception {
|
||||
ProjectConfig cfg = projectCache.checkedGet(project).getConfig();
|
||||
cfg.getLabelSections().get("Code-Review").setCopyMaxScore(true);
|
||||
saveProjectConfig(project, cfg);
|
||||
|
||||
for (ChangeKind changeKind : EnumSet.of(REWORK, TRIVIAL_REBASE,
|
||||
NO_CODE_CHANGE, MERGE_FIRST_PARENT_UPDATE)) {
|
||||
testRepo.reset(getRemoteHead());
|
||||
|
||||
String changeId = createChange(changeKind);
|
||||
vote(admin, changeId, 2, 1);
|
||||
vote(user, changeId, 1, -1);
|
||||
|
||||
updateChange(changeId, changeKind);
|
||||
ChangeInfo c = detailedChange(changeId);
|
||||
assertVotes(c, admin, 2, 0, changeKind);
|
||||
assertVotes(c, user, 0, 0, changeKind);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void stickyOnTrivialRebase() throws Exception {
|
||||
ProjectConfig cfg = projectCache.checkedGet(project).getConfig();
|
||||
cfg.getLabelSections().get("Code-Review")
|
||||
.setCopyAllScoresOnTrivialRebase(true);
|
||||
saveProjectConfig(project, cfg);
|
||||
|
||||
String changeId = createChange(TRIVIAL_REBASE);
|
||||
vote(admin, changeId, 2, 1);
|
||||
vote(user, changeId, -2, -1);
|
||||
|
||||
updateChange(changeId, TRIVIAL_REBASE);
|
||||
ChangeInfo c = detailedChange(changeId);
|
||||
assertVotes(c, admin, 2, 0, TRIVIAL_REBASE);
|
||||
assertVotes(c, user, -2, 0, TRIVIAL_REBASE);
|
||||
|
||||
assertNotSticky(
|
||||
EnumSet.of(REWORK, NO_CODE_CHANGE, MERGE_FIRST_PARENT_UPDATE));
|
||||
|
||||
// check that votes are sticky when trivial rebase is done by cherry-pick
|
||||
testRepo.reset(getRemoteHead());
|
||||
changeId = createChange().getChangeId();
|
||||
vote(admin, changeId, 2, 1);
|
||||
vote(user, changeId, -2, -1);
|
||||
|
||||
String cherryPickChangeId = cherryPick(changeId, TRIVIAL_REBASE);
|
||||
c = detailedChange(cherryPickChangeId);
|
||||
assertVotes(c, admin, 2, 0);
|
||||
assertVotes(c, user, -2, 0);
|
||||
|
||||
// check that votes are not sticky when rework is done by cherry-pick
|
||||
testRepo.reset(getRemoteHead());
|
||||
changeId = createChange().getChangeId();
|
||||
vote(admin, changeId, 2, 1);
|
||||
vote(user, changeId, -2, -1);
|
||||
|
||||
cherryPickChangeId = cherryPick(changeId, REWORK);
|
||||
c = detailedChange(cherryPickChangeId);
|
||||
assertVotes(c, admin, 0, 0);
|
||||
assertVotes(c, user, 0, 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void stickyOnNoCodeChange() throws Exception {
|
||||
ProjectConfig cfg = projectCache.checkedGet(project).getConfig();
|
||||
cfg.getLabelSections().get("Verified")
|
||||
.setCopyAllScoresIfNoCodeChange(true);
|
||||
saveProjectConfig(project, cfg);
|
||||
|
||||
String changeId = createChange(NO_CODE_CHANGE);
|
||||
vote(admin, changeId, 2, 1);
|
||||
vote(user, changeId, -2, -1);
|
||||
|
||||
updateChange(changeId, NO_CODE_CHANGE);
|
||||
ChangeInfo c = detailedChange(changeId);
|
||||
assertVotes(c, admin, 0, 1, NO_CODE_CHANGE);
|
||||
assertVotes(c, user, 0, -1, NO_CODE_CHANGE);
|
||||
|
||||
assertNotSticky(
|
||||
EnumSet.of(REWORK, TRIVIAL_REBASE, MERGE_FIRST_PARENT_UPDATE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void stickyOnMergeFirstParentUpdate() throws Exception {
|
||||
ProjectConfig cfg = projectCache.checkedGet(project).getConfig();
|
||||
cfg.getLabelSections().get("Code-Review")
|
||||
.setCopyAllScoresOnMergeFirstParentUpdate(true);
|
||||
saveProjectConfig(project, cfg);
|
||||
|
||||
String changeId = createChange(MERGE_FIRST_PARENT_UPDATE);
|
||||
vote(admin, changeId, 2, 1);
|
||||
vote(user, changeId, -2, -1);
|
||||
|
||||
updateChange(changeId, MERGE_FIRST_PARENT_UPDATE);
|
||||
ChangeInfo c = detailedChange(changeId);
|
||||
assertVotes(c, admin, 2, 0, MERGE_FIRST_PARENT_UPDATE);
|
||||
assertVotes(c, user, -2, 0, MERGE_FIRST_PARENT_UPDATE);
|
||||
|
||||
assertNotSticky(EnumSet.of(REWORK, NO_CODE_CHANGE, TRIVIAL_REBASE));
|
||||
}
|
||||
|
||||
private ChangeInfo detailedChange(String changeId) throws Exception {
|
||||
return gApi.changes().id(changeId)
|
||||
.get(EnumSet.of(ListChangesOption.DETAILED_LABELS,
|
||||
ListChangesOption.CURRENT_REVISION,
|
||||
ListChangesOption.CURRENT_COMMIT));
|
||||
}
|
||||
|
||||
private void assertNotSticky(Set<ChangeKind> changeKinds) throws Exception {
|
||||
for (ChangeKind changeKind : changeKinds) {
|
||||
testRepo.reset(getRemoteHead());
|
||||
|
||||
String changeId = createChange(changeKind);
|
||||
vote(admin, changeId, +2, 1);
|
||||
vote(user, changeId, -2, -1);
|
||||
|
||||
updateChange(changeId, changeKind);
|
||||
ChangeInfo c = detailedChange(changeId);
|
||||
assertVotes(c, admin, 0, 0, changeKind);
|
||||
assertVotes(c, user, 0, 0, changeKind);
|
||||
}
|
||||
}
|
||||
|
||||
private String createChange(ChangeKind kind) throws Exception {
|
||||
switch (kind) {
|
||||
case NO_CODE_CHANGE:
|
||||
case REWORK:
|
||||
case TRIVIAL_REBASE:
|
||||
case NO_CHANGE:
|
||||
return createChange().getChangeId();
|
||||
case MERGE_FIRST_PARENT_UPDATE:
|
||||
return createChangeForMergeCommit();
|
||||
default:
|
||||
throw new IllegalStateException("unexpected change kind: " + kind);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateChange(String changeId, ChangeKind changeKind)
|
||||
throws Exception {
|
||||
switch (changeKind) {
|
||||
case NO_CODE_CHANGE:
|
||||
noCodeChange(changeId);
|
||||
return;
|
||||
case REWORK:
|
||||
rework(changeId);
|
||||
return;
|
||||
case TRIVIAL_REBASE:
|
||||
trivialRebase(changeId);
|
||||
return;
|
||||
case MERGE_FIRST_PARENT_UPDATE:
|
||||
updateFirstParent(changeId);
|
||||
return;
|
||||
case NO_CHANGE:
|
||||
default:
|
||||
fail("unexpected change kind: " + changeKind);
|
||||
}
|
||||
}
|
||||
|
||||
private void noCodeChange(String changeId) throws Exception {
|
||||
TestRepository<?>.CommitBuilder commitBuilder =
|
||||
testRepo.amendRef("HEAD").insertChangeId(changeId.substring(1));
|
||||
commitBuilder.message("New subject " + System.nanoTime())
|
||||
.author(admin.getIdent())
|
||||
.committer(new PersonIdent(admin.getIdent(), testRepo.getDate()));
|
||||
commitBuilder.create();
|
||||
GitUtil.pushHead(testRepo, "refs/for/master", false);
|
||||
assertThat(getChangeKind(changeId)).isEqualTo(NO_CODE_CHANGE);
|
||||
}
|
||||
|
||||
private void rework(String changeId) throws Exception {
|
||||
PushOneCommit push = pushFactory.create(db, admin.getIdent(), testRepo,
|
||||
PushOneCommit.SUBJECT, PushOneCommit.FILE_NAME,
|
||||
"new content " + System.nanoTime(), changeId);
|
||||
push.to("refs/for/master").assertOkStatus();
|
||||
assertThat(getChangeKind(changeId)).isEqualTo(REWORK);
|
||||
}
|
||||
|
||||
private void trivialRebase(String changeId) throws Exception {
|
||||
setApiUser(admin);
|
||||
testRepo.reset(getRemoteHead());
|
||||
PushOneCommit push =
|
||||
pushFactory.create(db, admin.getIdent(), testRepo, "Other Change",
|
||||
"a" + System.nanoTime() + ".txt", PushOneCommit.FILE_CONTENT);
|
||||
PushOneCommit.Result r = push.to("refs/for/master");
|
||||
r.assertOkStatus();
|
||||
RevisionApi revision = gApi.changes()
|
||||
.id(r.getChangeId())
|
||||
.current();
|
||||
ReviewInput in = new ReviewInput()
|
||||
.label("Code-Review", 2)
|
||||
.label("Verified", 1);
|
||||
revision.review(in);
|
||||
revision.submit();
|
||||
|
||||
gApi.changes()
|
||||
.id(changeId)
|
||||
.current()
|
||||
.rebase();
|
||||
assertThat(getChangeKind(changeId)).isEqualTo(TRIVIAL_REBASE);
|
||||
}
|
||||
|
||||
private String createChangeForMergeCommit() throws Exception {
|
||||
ObjectId initial = repo().exactRef(HEAD).getLeaf().getObjectId();
|
||||
|
||||
PushOneCommit.Result parent1 =
|
||||
createChange("parent 1", "p1.txt", "content 1");
|
||||
|
||||
testRepo.reset(initial);
|
||||
PushOneCommit.Result parent2 =
|
||||
createChange("parent 2", "p2.txt", "content 2");
|
||||
|
||||
testRepo.reset(parent1.getCommit());
|
||||
|
||||
PushOneCommit merge = pushFactory.create(db, admin.getIdent(), testRepo);
|
||||
merge.setParents(
|
||||
ImmutableList.of(parent1.getCommit(), parent2.getCommit()));
|
||||
PushOneCommit.Result result = merge.to("refs/for/master");
|
||||
result.assertOkStatus();
|
||||
return result.getChangeId();
|
||||
}
|
||||
|
||||
private void updateFirstParent(String changeId) throws Exception {
|
||||
ChangeInfo c = detailedChange(changeId);
|
||||
List<CommitInfo> parents = c.revisions.get(c.currentRevision).commit.parents;
|
||||
String parent1 = parents.get(0).commit;
|
||||
String parent2 = parents.get(1).commit;
|
||||
RevCommit commitParent2 =
|
||||
testRepo.getRevWalk().parseCommit(ObjectId.fromString(parent2));
|
||||
|
||||
testRepo.reset(parent1);
|
||||
PushOneCommit.Result newParent1 =
|
||||
createChange("new parent 1", "p1-1.txt", "content 1-1");
|
||||
|
||||
PushOneCommit merge =
|
||||
pushFactory.create(db, admin.getIdent(), testRepo, changeId);
|
||||
merge.setParents(
|
||||
ImmutableList.of(newParent1.getCommit(), commitParent2));
|
||||
PushOneCommit.Result result = merge.to("refs/for/master");
|
||||
result.assertOkStatus();
|
||||
|
||||
assertThat(getChangeKind(changeId)).isEqualTo(MERGE_FIRST_PARENT_UPDATE);
|
||||
}
|
||||
|
||||
private String cherryPick(String changeId, ChangeKind changeKind) throws Exception {
|
||||
switch (changeKind) {
|
||||
case REWORK:
|
||||
case TRIVIAL_REBASE:
|
||||
break;
|
||||
case NO_CODE_CHANGE:
|
||||
case NO_CHANGE:
|
||||
case MERGE_FIRST_PARENT_UPDATE:
|
||||
default:
|
||||
fail("unexpected change kind: " + changeKind);
|
||||
}
|
||||
|
||||
testRepo.reset(getRemoteHead());
|
||||
PushOneCommit.Result r = pushFactory
|
||||
.create(db, admin.getIdent(), testRepo, PushOneCommit.SUBJECT,
|
||||
"other.txt", "new content " + System.nanoTime())
|
||||
.to("refs/for/master");
|
||||
r.assertOkStatus();
|
||||
vote(admin, r.getChangeId(), 2, 1);
|
||||
merge(r);
|
||||
|
||||
String subject = TRIVIAL_REBASE.equals(changeKind)
|
||||
? PushOneCommit.SUBJECT
|
||||
: "Reworked change " + System.nanoTime();
|
||||
CherryPickInput in = new CherryPickInput();
|
||||
in.destination = "master";
|
||||
in.message =
|
||||
String.format("%s\n\nChange-Id: %s", subject, changeId);
|
||||
ChangeInfo c = gApi.changes()
|
||||
.id(changeId)
|
||||
.revision("current")
|
||||
.cherryPick(in)
|
||||
.get();
|
||||
return c.changeId;
|
||||
}
|
||||
|
||||
private ChangeKind getChangeKind(String changeId) throws Exception {
|
||||
ChangeInfo c = gApi.changes().id(changeId)
|
||||
.get(EnumSet.of(ListChangesOption.CURRENT_REVISION));
|
||||
return c.revisions.get(c.currentRevision).kind;
|
||||
}
|
||||
|
||||
private void vote(TestAccount user, String changeId, int codeReviewVote,
|
||||
int verifiedVote) throws Exception {
|
||||
setApiUser(user);
|
||||
ReviewInput in = new ReviewInput()
|
||||
.label("Code-Review", codeReviewVote)
|
||||
.label("Verified", verifiedVote);
|
||||
gApi.changes().id(changeId).current().review(in);
|
||||
}
|
||||
|
||||
private void assertVotes(ChangeInfo c, TestAccount user, int codeReviewVote,
|
||||
int verifiedVote) {
|
||||
assertVotes(c, user, codeReviewVote, verifiedVote, null);
|
||||
}
|
||||
|
||||
private void assertVotes(ChangeInfo c, TestAccount user, int codeReviewVote,
|
||||
int verifiedVote, ChangeKind changeKind) {
|
||||
assertVotes(c, user, "Code-Review", codeReviewVote, changeKind);
|
||||
assertVotes(c, user, "Verified", verifiedVote, changeKind);
|
||||
}
|
||||
|
||||
private void assertVotes(ChangeInfo c, TestAccount user, String label,
|
||||
int expectedVote, ChangeKind changeKind) {
|
||||
Integer vote = 0;
|
||||
if (c.labels.get(label) != null && c.labels.get(label).all != null) {
|
||||
for (ApprovalInfo approval : c.labels.get(label).all) {
|
||||
if (approval._accountId == user.id.get()) {
|
||||
vote = approval.value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String name = "label = " + label;
|
||||
if (changeKind != null) {
|
||||
name += "; changeKind = " + changeKind.name();
|
||||
}
|
||||
assertThat(vote)
|
||||
.named(name)
|
||||
.isEqualTo(expectedVote);
|
||||
}
|
||||
}
|
||||
@@ -1,446 +0,0 @@
|
||||
// Copyright (C) 2014 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.server.project;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
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.common.data.LabelType;
|
||||
import com.google.gerrit.extensions.api.changes.CherryPickInput;
|
||||
import com.google.gerrit.extensions.api.changes.ReviewInput;
|
||||
import com.google.gerrit.extensions.common.ChangeInfo;
|
||||
import com.google.gerrit.extensions.common.LabelInfo;
|
||||
import com.google.gerrit.extensions.restapi.ResourceConflictException;
|
||||
import com.google.gerrit.server.git.ProjectConfig;
|
||||
import com.google.gerrit.server.project.Util;
|
||||
|
||||
import org.eclipse.jgit.lib.Repository;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
@NoHttpd
|
||||
public class LabelTypeIT extends AbstractDaemonTest {
|
||||
private LabelType codeReview;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
ProjectConfig cfg = projectCache.checkedGet(project).getConfig();
|
||||
codeReview = Util.codeReview();
|
||||
codeReview.setDefaultValue((short)-1);
|
||||
cfg.getLabelSections().put(codeReview.getName(), codeReview);
|
||||
saveProjectConfig(cfg);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void failChangedLabelValueOnClosedChange() throws Exception {
|
||||
PushOneCommit.Result r = createChange();
|
||||
merge(r);
|
||||
exception.expect(ResourceConflictException.class);
|
||||
exception.expectMessage("change is closed");
|
||||
revision(r).review(ReviewInput.reject());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noCopyMinScoreOnRework() throws Exception {
|
||||
codeReview.setCopyMinScore(false);
|
||||
saveLabelConfig();
|
||||
|
||||
PushOneCommit.Result r = createChange();
|
||||
revision(r).review(ReviewInput.reject());
|
||||
assertApproval(r, -2);
|
||||
r = amendChange(r.getChangeId());
|
||||
assertApproval(r, 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void copyMinScoreOnRework() throws Exception {
|
||||
codeReview.setCopyMinScore(true);
|
||||
saveLabelConfig();
|
||||
PushOneCommit.Result r = createChange();
|
||||
revision(r).review(ReviewInput.reject());
|
||||
assertApproval(r, -2);
|
||||
r = amendChange(r.getChangeId());
|
||||
assertApproval(r, -2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noCopyMaxScoreOnRework() throws Exception {
|
||||
PushOneCommit.Result r = createChange();
|
||||
revision(r).review(ReviewInput.approve());
|
||||
assertApproval(r, 2);
|
||||
r = amendChange(r.getChangeId());
|
||||
assertApproval(r, 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void copyMaxScoreOnRework() throws Exception {
|
||||
codeReview.setCopyMaxScore(true);
|
||||
saveLabelConfig();
|
||||
PushOneCommit.Result r = createChange();
|
||||
revision(r).review(ReviewInput.approve());
|
||||
assertApproval(r, 2);
|
||||
r = amendChange(r.getChangeId());
|
||||
assertApproval(r, 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noCopyNonMaxScoreOnRework() throws Exception {
|
||||
codeReview.setCopyMinScore(true);
|
||||
codeReview.setCopyMaxScore(true);
|
||||
saveLabelConfig();
|
||||
|
||||
PushOneCommit.Result r = createChange();
|
||||
revision(r).review(ReviewInput.recommend());
|
||||
assertApproval(r, 1);
|
||||
r = amendChange(r.getChangeId());
|
||||
assertApproval(r, 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noCopyNonMinScoreOnRework() throws Exception {
|
||||
codeReview.setCopyMinScore(true);
|
||||
codeReview.setCopyMaxScore(true);
|
||||
saveLabelConfig();
|
||||
|
||||
PushOneCommit.Result r = createChange();
|
||||
revision(r).review(ReviewInput.dislike());
|
||||
assertApproval(r, -1);
|
||||
r = amendChange(r.getChangeId());
|
||||
assertApproval(r, 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noCopyAllScoresIfNoChange() throws Exception {
|
||||
codeReview.setCopyAllScoresIfNoChange(false);
|
||||
saveLabelConfig();
|
||||
PushOneCommit.Result patchSet = readyPatchSetForNoChangeRebase();
|
||||
rebase(patchSet);
|
||||
assertApproval(patchSet, 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void copyAllScoresIfNoCodeChangeAppliesToNoChange() throws Exception {
|
||||
codeReview.setCopyAllScoresIfNoCodeChange(true);
|
||||
codeReview.setCopyAllScoresIfNoChange(false);
|
||||
saveLabelConfig();
|
||||
|
||||
PushOneCommit.Result patchSet = readyPatchSetForNoChangeRebase();
|
||||
rebase(patchSet);
|
||||
assertApproval(patchSet, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void copyAllScoresOnTrivialRebaseAppliesToNoChange() throws Exception {
|
||||
codeReview.setCopyAllScoresOnTrivialRebase(true);
|
||||
codeReview.setCopyAllScoresIfNoChange(false);
|
||||
saveLabelConfig();
|
||||
|
||||
PushOneCommit.Result patchSet = readyPatchSetForNoChangeRebase();
|
||||
rebase(patchSet);
|
||||
assertApproval(patchSet, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void copyAllScoresOnMergeFirstParentUpdateAppliesToNoChange()
|
||||
throws Exception {
|
||||
codeReview.setCopyAllScoresOnMergeFirstParentUpdate(true);
|
||||
codeReview.setCopyAllScoresIfNoChange(false);
|
||||
saveLabelConfig();
|
||||
|
||||
PushOneCommit.Result patchSet = readyPatchSetForNoChangeRebase();
|
||||
rebase(patchSet);
|
||||
assertApproval(patchSet, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void copyAllScoresOnMergeFirstParentUpdateAppliesToMergeParentUpdate()
|
||||
throws Exception {
|
||||
codeReview.setCopyAllScoresOnMergeFirstParentUpdate(true);
|
||||
saveLabelConfig();
|
||||
|
||||
PushOneCommit.Result merge = createMergeCommitAndUpdateFirstParent();
|
||||
assertApproval(merge, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void copyAllScoresOnMergeFirstParentUpdateNotAppliesIfNotSet()
|
||||
throws Exception {
|
||||
codeReview.setCopyAllScoresOnMergeFirstParentUpdate(false);
|
||||
saveLabelConfig();
|
||||
|
||||
PushOneCommit.Result merge = createMergeCommitAndUpdateFirstParent();
|
||||
assertApproval(merge, 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void copyAllScoresIfNoChange() throws Exception {
|
||||
PushOneCommit.Result patchSet = readyPatchSetForNoChangeRebase();
|
||||
rebase(patchSet);
|
||||
assertApproval(patchSet, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noCopyAllScoresIfNoCodeChange() throws Exception {
|
||||
String file = "a.txt";
|
||||
String contents = "contents";
|
||||
|
||||
PushOneCommit push = pushFactory.create(db, admin.getIdent(), testRepo,
|
||||
"first subject", file, contents);
|
||||
PushOneCommit.Result r = push.to("refs/for/master");
|
||||
revision(r).review(ReviewInput.recommend());
|
||||
assertApproval(r, 1);
|
||||
|
||||
push = pushFactory.create(db, admin.getIdent(), testRepo,
|
||||
"second subject", file, contents, r.getChangeId());
|
||||
r = push.to("refs/for/master");
|
||||
assertApproval(r, 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void copyAllScoresIfNoCodeChange() throws Exception {
|
||||
String file = "a.txt";
|
||||
String contents = "contents";
|
||||
codeReview.setCopyAllScoresIfNoCodeChange(true);
|
||||
saveLabelConfig();
|
||||
|
||||
PushOneCommit push = pushFactory.create(db, admin.getIdent(), testRepo,
|
||||
"first subject", file, contents);
|
||||
PushOneCommit.Result r = push.to("refs/for/master");
|
||||
revision(r).review(ReviewInput.recommend());
|
||||
assertApproval(r, 1);
|
||||
|
||||
push = pushFactory.create(db, admin.getIdent(), testRepo,
|
||||
"second subject", file, contents, r.getChangeId());
|
||||
r = push.to("refs/for/master");
|
||||
assertApproval(r, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noCopyAllScoresOnTrivialRebase() throws Exception {
|
||||
String subject = "test commit";
|
||||
String file = "a.txt";
|
||||
String contents = "contents";
|
||||
|
||||
PushOneCommit push = pushFactory.create(db, admin.getIdent(), testRepo);
|
||||
PushOneCommit.Result r1 = push.to("refs/for/master");
|
||||
merge(r1);
|
||||
|
||||
push = pushFactory.create(db, admin.getIdent(), testRepo,
|
||||
"non-conflicting", "b.txt", "other contents");
|
||||
PushOneCommit.Result r2 = push.to("refs/for/master");
|
||||
merge(r2);
|
||||
|
||||
testRepo.reset(r1.getCommit());
|
||||
push = pushFactory.create(db, admin.getIdent(), testRepo, subject, file, contents);
|
||||
PushOneCommit.Result r3 = push.to("refs/for/master");
|
||||
revision(r3).review(ReviewInput.recommend());
|
||||
assertApproval(r3, 1);
|
||||
|
||||
rebase(r3);
|
||||
assertApproval(r3, 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void copyAllScoresOnTrivialRebase() throws Exception {
|
||||
String subject = "test commit";
|
||||
String file = "a.txt";
|
||||
String contents = "contents";
|
||||
codeReview.setCopyAllScoresOnTrivialRebase(true);
|
||||
saveLabelConfig();
|
||||
|
||||
PushOneCommit push = pushFactory.create(db, admin.getIdent(), testRepo);
|
||||
PushOneCommit.Result r1 = push.to("refs/for/master");
|
||||
merge(r1);
|
||||
|
||||
push = pushFactory.create(db, admin.getIdent(), testRepo,
|
||||
"non-conflicting", "b.txt", "other contents");
|
||||
PushOneCommit.Result r2 = push.to("refs/for/master");
|
||||
merge(r2);
|
||||
|
||||
testRepo.reset(r1.getCommit());
|
||||
push = pushFactory.create(db, admin.getIdent(), testRepo, subject, file, contents);
|
||||
PushOneCommit.Result r3 = push.to("refs/for/master");
|
||||
revision(r3).review(ReviewInput.recommend());
|
||||
assertApproval(r3, 1);
|
||||
|
||||
rebase(r3);
|
||||
assertApproval(r3, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void copyAllScoresOnTrivialRebaseAndCherryPick() throws Exception {
|
||||
codeReview.setCopyAllScoresOnTrivialRebase(true);
|
||||
saveLabelConfig();
|
||||
|
||||
PushOneCommit.Result r1 = createChange();
|
||||
testRepo.reset(r1.getCommit());
|
||||
|
||||
PushOneCommit push = pushFactory.create(db, admin.getIdent(), testRepo,
|
||||
PushOneCommit.SUBJECT, "b.txt", "other contents");
|
||||
PushOneCommit.Result r2 = push.to("refs/for/master");
|
||||
|
||||
revision(r2).review(ReviewInput.recommend());
|
||||
|
||||
CherryPickInput in = new CherryPickInput();
|
||||
in.destination = "master";
|
||||
in.message = String.format("%s\n\nChange-Id: %s",
|
||||
PushOneCommit.SUBJECT,
|
||||
r2.getChangeId());
|
||||
|
||||
doAssertApproval(1,
|
||||
gApi.changes()
|
||||
.id(r2.getChangeId())
|
||||
.revision(r2.getCommit().name())
|
||||
.cherryPick(in)
|
||||
.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void copyNoScoresOnReworkAndCherryPick()
|
||||
throws Exception {
|
||||
codeReview.setCopyAllScoresOnTrivialRebase(true);
|
||||
saveLabelConfig();
|
||||
|
||||
PushOneCommit.Result r1 = createChange();
|
||||
|
||||
testRepo.reset(r1.getCommit());
|
||||
|
||||
PushOneCommit push = pushFactory.create(db, admin.getIdent(), testRepo,
|
||||
PushOneCommit.SUBJECT, "b.txt", "other contents");
|
||||
PushOneCommit.Result r2 = push.to("refs/for/master");
|
||||
|
||||
revision(r2).review(ReviewInput.recommend());
|
||||
|
||||
CherryPickInput in = new CherryPickInput();
|
||||
in.destination = "master";
|
||||
in.message = String.format("Cherry pick\n\nChange-Id: %s",
|
||||
r2.getChangeId());
|
||||
|
||||
doAssertApproval(0,
|
||||
gApi.changes()
|
||||
.id(r2.getChangeId())
|
||||
.revision(r2.getCommit().name())
|
||||
.cherryPick(in)
|
||||
.get());
|
||||
}
|
||||
|
||||
private PushOneCommit.Result createMergeCommitAndUpdateFirstParent()
|
||||
throws Exception {
|
||||
String file = "m.txt";
|
||||
String contents = "contents";
|
||||
PushOneCommit.Result base = pushToMaster(file, contents);
|
||||
|
||||
// create feature commit and push it to feature branch
|
||||
PushOneCommit push = pushFactory.create(db, admin.getIdent(), testRepo,
|
||||
PushOneCommit.SUBJECT, file, contents + "feature");
|
||||
PushOneCommit.Result feature = push.to("refs/heads/feature");
|
||||
|
||||
// create merge commit and push it for review
|
||||
testRepo.reset(base.getCommit());
|
||||
push = pushFactory.create(db, admin.getIdent(), testRepo,
|
||||
PushOneCommit.SUBJECT, PushOneCommit.FILE_NAME, PushOneCommit.FILE_CONTENT);
|
||||
push.setParents(ImmutableList.of(base.getCommit(), feature.getCommit()));
|
||||
PushOneCommit.Result merge = push.to("refs/for/master");
|
||||
revision(merge).review(ReviewInput.recommend());
|
||||
|
||||
// advance master
|
||||
testRepo.reset(base.getCommit());
|
||||
PushOneCommit.Result advanced = pushToMaster(file, contents + "master_advances");
|
||||
|
||||
// update first parent of merge commit
|
||||
push = pushFactory.create(db, admin.getIdent(), testRepo,
|
||||
PushOneCommit.SUBJECT, PushOneCommit.FILE_NAME, PushOneCommit.FILE_CONTENT,
|
||||
merge.getChangeId());
|
||||
push.setParents(ImmutableList.of(advanced.getCommit(), feature.getCommit()));
|
||||
merge = push.to("refs/for/master");
|
||||
return merge;
|
||||
}
|
||||
|
||||
private PushOneCommit.Result pushToMaster(String file, String contents)
|
||||
throws Exception {
|
||||
PushOneCommit push = pushFactory.create(db, admin.getIdent(), testRepo,
|
||||
PushOneCommit.SUBJECT, file, contents);
|
||||
PushOneCommit.Result base = push.to("refs/for/master");
|
||||
merge(base);
|
||||
return base;
|
||||
}
|
||||
|
||||
private PushOneCommit.Result readyPatchSetForNoChangeRebase()
|
||||
throws Exception {
|
||||
String file = "a.txt";
|
||||
String contents = "contents";
|
||||
|
||||
PushOneCommit push = pushFactory.create(db, admin.getIdent(), testRepo,
|
||||
PushOneCommit.SUBJECT, file, contents);
|
||||
PushOneCommit.Result base = push.to("refs/for/master");
|
||||
merge(base);
|
||||
|
||||
push = pushFactory.create(db, admin.getIdent(), testRepo,
|
||||
PushOneCommit.SUBJECT, file, contents + "M");
|
||||
PushOneCommit.Result basePlusM = push.to("refs/for/master");
|
||||
merge(basePlusM);
|
||||
|
||||
push = pushFactory.create(db, admin.getIdent(), testRepo,
|
||||
PushOneCommit.SUBJECT, file, contents);
|
||||
PushOneCommit.Result basePlusMMinusM = push.to("refs/for/master");
|
||||
merge(basePlusMMinusM);
|
||||
|
||||
testRepo.reset(base.getCommit());
|
||||
push = pushFactory.create(db, admin.getIdent(), testRepo,
|
||||
PushOneCommit.SUBJECT, file, contents + "MM");
|
||||
PushOneCommit.Result patchSet = push.to("refs/for/master");
|
||||
revision(patchSet).review(ReviewInput.recommend());
|
||||
return patchSet;
|
||||
}
|
||||
|
||||
private void saveLabelConfig() throws Exception {
|
||||
ProjectConfig cfg = projectCache.checkedGet(project).getConfig();
|
||||
cfg.getLabelSections().clear();
|
||||
cfg.getLabelSections().put(codeReview.getName(), codeReview);
|
||||
saveProjectConfig(cfg);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void merge(PushOneCommit.Result r) throws Exception {
|
||||
super.merge(r);
|
||||
try (Repository repo = repoManager.openRepository(project)) {
|
||||
assertThat(repo.exactRef("refs/heads/master").getObjectId()).isEqualTo(
|
||||
r.getCommit());
|
||||
}
|
||||
}
|
||||
|
||||
private void rebase(PushOneCommit.Result r) throws Exception {
|
||||
revision(r).rebase();
|
||||
}
|
||||
|
||||
private void assertApproval(PushOneCommit.Result r, int expected)
|
||||
throws Exception {
|
||||
// Don't use asserts from PushOneCommit so we can test the round-trip
|
||||
// through JSON instead of querying the DB directly.
|
||||
ChangeInfo c = get(r.getChangeId());
|
||||
doAssertApproval(expected, c);
|
||||
}
|
||||
|
||||
private void doAssertApproval(int expected, ChangeInfo c) {
|
||||
LabelInfo cr = c.labels.get("Code-Review");
|
||||
assertThat((int) cr.defaultValue).isEqualTo(-1);
|
||||
assertThat(cr.all).hasSize(1);
|
||||
assertThat(cr.all.get(0).name).isEqualTo("Administrator");
|
||||
assertThat(cr.all.get(0).value).isEqualTo(expected);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user