// 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.base.Preconditions.checkNotNull; import static org.junit.Assert.assertEquals; 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.server.config.AllProjectsName; import com.google.gerrit.server.git.GitRepositoryManager; import com.google.gerrit.server.git.MetaDataUpdate; import com.google.gerrit.server.git.ProjectConfig; import com.google.gerrit.server.project.ProjectCache; import com.google.gerrit.testutil.ConfigSuite; import com.google.inject.Inject; import org.eclipse.jgit.lib.Config; import org.eclipse.jgit.lib.Repository; import org.junit.Before; import org.junit.Test; @NoHttpd public class LabelTypeIT extends AbstractDaemonTest { @ConfigSuite.Config public static Config noteDbEnabled() { Config cfg = new Config(); cfg.setBoolean("notedb", null, "write", true); cfg.setBoolean("notedb", "patchSetApprovals", "read", true); return cfg; } @Inject private GitRepositoryManager repoManager; @Inject private ProjectCache projectCache; @Inject private AllProjectsName allProjects; @Inject private MetaDataUpdate.Server metaDataUpdateFactory; private LabelType codeReview; @Before public void setUp() throws Exception { ProjectConfig cfg = projectCache.checkedGet(allProjects).getConfig(); codeReview = checkNotNull(cfg.getLabelSections().get("Code-Review")); codeReview.setCopyMinScore(false); codeReview.setCopyMaxScore(false); codeReview.setCopyAllScoresOnTrivialRebase(false); codeReview.setCopyAllScoresIfNoCodeChange(false); codeReview.setDefaultValue((short)-1); saveProjectConfig(cfg); } @Test public void noCopyMinScoreOnRework() throws Exception { 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 noCopyAllScoresIfNoCodeChange() throws Exception { String file = "a.txt"; String contents = "contents"; PushOneCommit push = pushFactory.create(db, admin.getIdent(), "first subject", file, contents); PushOneCommit.Result r = push.to(git, "refs/for/master"); revision(r).review(ReviewInput.recommend()); assertApproval(r, 1); push = pushFactory.create(db, admin.getIdent(), "second subject", file, contents, r.getChangeId()); r = push.to(git, "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(), "first subject", file, contents); PushOneCommit.Result r = push.to(git, "refs/for/master"); revision(r).review(ReviewInput.recommend()); assertApproval(r, 1); push = pushFactory.create(db, admin.getIdent(), "second subject", file, contents, r.getChangeId()); r = push.to(git, "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()); PushOneCommit.Result r1 = push.to(git, "refs/for/master"); merge(r1); push = pushFactory.create(db, admin.getIdent(), "non-conflicting", "b.txt", "other contents"); PushOneCommit.Result r2 = push.to(git, "refs/for/master"); merge(r2); git.checkout().setName(r1.getCommit().name()).call(); push = pushFactory.create(db, admin.getIdent(), subject, file, contents); PushOneCommit.Result r3 = push.to(git, "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()); PushOneCommit.Result r1 = push.to(git, "refs/for/master"); merge(r1); push = pushFactory.create(db, admin.getIdent(), "non-conflicting", "b.txt", "other contents"); PushOneCommit.Result r2 = push.to(git, "refs/for/master"); merge(r2); git.checkout().setName(r1.getCommit().name()).call(); push = pushFactory.create(db, admin.getIdent(), subject, file, contents); PushOneCommit.Result r3 = push.to(git, "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(); git.checkout().setName(r1.getCommit().name()).call(); PushOneCommit push = pushFactory.create(db, admin.getIdent(), PushOneCommit.SUBJECT, "b.txt", "other contents"); PushOneCommit.Result r2 = push.to(git, "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(); git.checkout().setName(r1.getCommit().name()).call(); PushOneCommit push = pushFactory.create(db, admin.getIdent(), PushOneCommit.SUBJECT, "b.txt", "other contents"); PushOneCommit.Result r2 = push.to(git, "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 void saveLabelConfig() throws Exception { ProjectConfig cfg = projectCache.checkedGet(allProjects).getConfig(); cfg.getLabelSections().clear(); cfg.getLabelSections().put(codeReview.getName(), codeReview); saveProjectConfig(cfg); } private void saveProjectConfig(ProjectConfig cfg) throws Exception { MetaDataUpdate md = metaDataUpdateFactory.create(allProjects); try { cfg.commit(md); } finally { md.close(); } } private void merge(PushOneCommit.Result r) throws Exception { revision(r).review(ReviewInput.approve()); revision(r).submit(); Repository repo = repoManager.openRepository(project); try { assertEquals(r.getCommitId(), repo.getRef("refs/heads/master").getObjectId()); } finally { repo.close(); } } 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"); assertEquals(-1, (int) cr.defaultValue); assertEquals(1, cr.all.size()); assertEquals("Administrator", cr.all.get(0).name); assertEquals(expected, cr.all.get(0).value.intValue()); } }