blob: f1f7e521257d7b3ac62f8f3049a57232f5693b27 [file] [log] [blame]
// Copyright (C) 2019 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.plugins.checks.acceptance.api;
import static com.google.common.collect.Iterables.getOnlyElement;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth8.assertThat;
import static com.google.gerrit.extensions.client.ListChangesOption.CURRENT_REVISION;
import com.google.common.collect.ImmutableSet;
import com.google.gerrit.acceptance.PushOneCommit;
import com.google.gerrit.acceptance.RestResponse;
import com.google.gerrit.acceptance.testsuite.request.RequestScopeOperations;
import com.google.gerrit.entities.Change;
import com.google.gerrit.entities.PatchSet;
import com.google.gerrit.entities.Project;
import com.google.gerrit.extensions.common.EditInfo;
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.plugins.checks.CheckKey;
import com.google.gerrit.plugins.checks.CheckerUuid;
import com.google.gerrit.plugins.checks.ListChecksOption;
import com.google.gerrit.plugins.checks.acceptance.AbstractCheckersTest;
import com.google.gerrit.plugins.checks.api.CheckInfo;
import com.google.gerrit.plugins.checks.api.CheckState;
import com.google.gerrit.plugins.checks.api.CheckerStatus;
import com.google.gson.reflect.TypeToken;
import com.google.inject.Inject;
import java.sql.Timestamp;
import java.util.List;
import java.util.Optional;
import org.junit.Before;
import org.junit.Test;
public class ListChecksIT extends AbstractCheckersTest {
@Inject private RequestScopeOperations requestScopeOperations;
private String changeId;
private PatchSet.Id patchSetId;
@Before
public void setUp() throws Exception {
PushOneCommit.Result r = createChange();
changeId = r.getChangeId();
patchSetId = r.getPatchSetId();
}
@Test
public void listAll() throws Exception {
CheckerUuid checkerUuid1 = checkerOperations.newChecker().repository(project).create();
CheckerUuid checkerUuid2 = checkerOperations.newChecker().repository(project).create();
CheckKey checkKey1 = CheckKey.create(project, patchSetId, checkerUuid1);
checkOperations.newCheck(checkKey1).state(CheckState.RUNNING).upsert();
CheckKey checkKey2 = CheckKey.create(project, patchSetId, checkerUuid2);
checkOperations.newCheck(checkKey2).state(CheckState.FAILED).upsert();
assertThat(checksApiFactory.revision(patchSetId).list())
.containsExactly(
checkOperations.check(checkKey1).asInfo(), checkOperations.check(checkKey2).asInfo());
}
@Test
public void listAllWithOptions() throws Exception {
String checkerName1 = "Checker One";
CheckerUuid checkerUuid1 =
checkerOperations.newChecker().name(checkerName1).repository(project).create();
String checkerName2 = "Checker Two";
CheckerUuid checkerUuid2 =
checkerOperations.newChecker().name(checkerName2).repository(project).create();
CheckKey checkKey1 = CheckKey.create(project, patchSetId, checkerUuid1);
checkOperations.newCheck(checkKey1).state(CheckState.RUNNING).upsert();
CheckKey checkKey2 = CheckKey.create(project, patchSetId, checkerUuid2);
checkOperations.newCheck(checkKey2).state(CheckState.FAILED).upsert();
CheckInfo expectedCheckInfo1 = checkOperations.check(checkKey1).asInfo();
expectedCheckInfo1.repository = project.get();
expectedCheckInfo1.checkerName = checkerName1;
expectedCheckInfo1.blocking = ImmutableSet.of();
expectedCheckInfo1.checkerStatus = CheckerStatus.ENABLED;
CheckInfo expectedCheckInfo2 = checkOperations.check(checkKey2).asInfo();
expectedCheckInfo2.repository = project.get();
expectedCheckInfo2.checkerName = checkerName2;
expectedCheckInfo2.blocking = ImmutableSet.of();
expectedCheckInfo2.checkerStatus = CheckerStatus.ENABLED;
assertThat(checksApiFactory.revision(patchSetId).list(ListChecksOption.CHECKER))
.containsExactly(expectedCheckInfo1, expectedCheckInfo2);
}
@Test
public void listAllWithOptionsViaRest() throws Exception {
String checkerName1 = "Checker One";
CheckerUuid checkerUuid1 =
checkerOperations.newChecker().name(checkerName1).repository(project).create();
String checkerName2 = "Checker Two";
CheckerUuid checkerUuid2 =
checkerOperations.newChecker().name(checkerName2).repository(project).create();
CheckKey checkKey1 = CheckKey.create(project, patchSetId, checkerUuid1);
checkOperations.newCheck(checkKey1).state(CheckState.RUNNING).upsert();
CheckKey checkKey2 = CheckKey.create(project, patchSetId, checkerUuid2);
checkOperations.newCheck(checkKey2).state(CheckState.FAILED).upsert();
CheckInfo expectedCheckInfo1 = checkOperations.check(checkKey1).asInfo();
expectedCheckInfo1.repository = project.get();
expectedCheckInfo1.checkerName = checkerName1;
expectedCheckInfo1.blocking = ImmutableSet.of();
expectedCheckInfo1.checkerStatus = CheckerStatus.ENABLED;
CheckInfo expectedCheckInfo2 = checkOperations.check(checkKey2).asInfo();
expectedCheckInfo2.repository = project.get();
expectedCheckInfo2.checkerName = checkerName2;
expectedCheckInfo2.blocking = ImmutableSet.of();
expectedCheckInfo2.checkerStatus = CheckerStatus.ENABLED;
RestResponse r =
adminRestSession.get(
String.format(
"/changes/%s/revisions/%s/checks~checks/?o=CHECKER",
patchSetId.changeId().get(), patchSetId.get()));
r.assertOK();
List<CheckInfo> checkInfos =
newGson().fromJson(r.getReader(), new TypeToken<List<CheckInfo>>() {}.getType());
r.consume();
assertThat(checkInfos).containsExactly(expectedCheckInfo1, expectedCheckInfo2);
r =
adminRestSession.get(
String.format(
"/changes/%s/revisions/%s/checks~checks/?O=1",
patchSetId.changeId().get(), patchSetId.get()));
r.assertOK();
checkInfos = newGson().fromJson(r.getReader(), new TypeToken<List<CheckInfo>>() {}.getType());
r.consume();
assertThat(checkInfos).containsExactly(expectedCheckInfo1, expectedCheckInfo2);
}
@Test
public void listAllWithOptionsSkipsPopulatingCheckerFieldsForInvalidCheckers() throws Exception {
String checkerName1 = "Checker One";
CheckerUuid checkerUuid1 =
checkerOperations.newChecker().name(checkerName1).repository(project).create();
CheckerUuid checkerUuid2 = checkerOperations.newChecker().repository(project).create();
checkOperations.newCheck(CheckKey.create(project, patchSetId, checkerUuid1)).upsert();
checkOperations.newCheck(CheckKey.create(project, patchSetId, checkerUuid2)).upsert();
checkerOperations.checker(checkerUuid2).forInvalidation().nonParseableConfig().invalidate();
List<CheckInfo> checks = checksApiFactory.revision(patchSetId).list(ListChecksOption.CHECKER);
assertThat(checks).hasSize(2);
Optional<CheckInfo> maybeCheck1 =
checks.stream().filter(c -> c.checkerUuid.equals(checkerUuid1.get())).findAny();
assertThat(maybeCheck1).isPresent();
CheckInfo check1 = maybeCheck1.get();
assertThat(check1.checkerName).isEqualTo(checkerName1);
assertThat(check1.blocking).isEmpty();
assertThat(check1.checkerStatus).isEqualTo(CheckerStatus.ENABLED);
Optional<CheckInfo> maybeCheck2 =
checks.stream().filter(c -> c.checkerUuid.equals(checkerUuid2.get())).findAny();
assertThat(maybeCheck2).isPresent();
CheckInfo check2 = maybeCheck2.get();
assertThat(check2.checkerName).isNull();
assertThat(check2.blocking).isNull();
assertThat(check2.checkerStatus).isNull();
}
@Test
public void listIncludesCheckFromCheckerThatDoesNotApplyToTheProject() throws Exception {
CheckerUuid checkerUuid = checkerOperations.newChecker().repository(project).create();
checkOperations.newCheck(CheckKey.create(project, patchSetId, checkerUuid)).upsert();
Project.NameKey otherProject = createProjectOverAPI("other", null, true, null);
checkerOperations.checker(checkerUuid).forUpdate().repository(otherProject).update();
assertThat(checksApiFactory.revision(patchSetId).list()).hasSize(1);
}
@Test
public void listIncludesCheckFromCheckerThatDoesNotApplyToTheChange() throws Exception {
CheckerUuid checkerUuid = checkerOperations.newChecker().repository(project).create();
CheckKey checkKey = CheckKey.create(project, patchSetId, checkerUuid);
checkOperations.newCheck(checkKey).upsert();
checkerOperations.checker(checkerUuid).forUpdate().query("message:not-matching").update();
assertThat(checksApiFactory.revision(patchSetId).list()).hasSize(1);
}
@Test
public void listIncludesCheckFromDisabledChecker() throws Exception {
CheckerUuid checkerUuid = checkerOperations.newChecker().repository(project).create();
checkOperations.newCheck(CheckKey.create(project, patchSetId, checkerUuid)).upsert();
checkerOperations.checker(checkerUuid).forUpdate().disable().update();
assertThat(checksApiFactory.revision(patchSetId).list()).hasSize(1);
}
@Test
public void listIncludesCheckFromInvalidChecker() throws Exception {
CheckerUuid checkerUuid = checkerOperations.newChecker().repository(project).create();
checkOperations.newCheck(CheckKey.create(project, patchSetId, checkerUuid)).upsert();
checkerOperations.checker(checkerUuid).forInvalidation().nonParseableConfig().invalidate();
assertThat(checksApiFactory.revision(patchSetId).list()).hasSize(1);
}
@Test
public void listIncludesCheckFromNonExistingChecker() throws Exception {
CheckerUuid checkerUuid = checkerOperations.newChecker().repository(project).create();
checkOperations.newCheck(CheckKey.create(project, patchSetId, checkerUuid)).upsert();
checkerOperations.checker(checkerUuid).forInvalidation().deleteRef().invalidate();
assertThat(checksApiFactory.revision(patchSetId).list()).hasSize(1);
}
@Test
public void listBackfillsForRelevantChecker() throws Exception {
String topic = name("topic");
CheckerUuid checkerUuid =
checkerOperations.newChecker().repository(project).query("topic:" + topic).create();
assertThat(checksApiFactory.revision(patchSetId).list()).isEmpty();
// Update change to match checker's query.
gApi.changes().id(patchSetId.changeId().get()).topic(topic);
Timestamp psCreated = getPatchSetCreated(patchSetId.changeId());
CheckInfo checkInfo = new CheckInfo();
checkInfo.repository = project.get();
checkInfo.changeNumber = patchSetId.changeId().get();
checkInfo.patchSetId = patchSetId.get();
checkInfo.checkerUuid = checkerUuid.get();
checkInfo.state = CheckState.NOT_STARTED;
checkInfo.created = psCreated;
checkInfo.updated = psCreated;
assertThat(checksApiFactory.revision(patchSetId).list()).containsExactly(checkInfo);
}
@Test
public void listDoesntBackfillForDisabledChecker() throws Exception {
CheckerUuid checkerUuid = checkerOperations.newChecker().repository(project).create();
CheckKey checkKey = CheckKey.create(project, patchSetId, checkerUuid);
Timestamp psCreated = getPatchSetCreated(patchSetId.changeId());
CheckInfo checkInfo = new CheckInfo();
checkInfo.repository = checkKey.repository().get();
checkInfo.changeNumber = checkKey.patchSet().changeId().get();
checkInfo.patchSetId = checkKey.patchSet().get();
checkInfo.checkerUuid = checkKey.checkerUuid().get();
checkInfo.state = CheckState.NOT_STARTED;
checkInfo.created = psCreated;
checkInfo.updated = psCreated;
assertThat(checksApiFactory.revision(patchSetId).list()).containsExactly(checkInfo);
// Disable checker.
checkerOperations.checker(checkerUuid).forUpdate().disable().update();
assertThat(checksApiFactory.revision(patchSetId).list()).isEmpty();
}
@Test
public void listForMultiplePatchSets() throws Exception {
CheckerUuid checkerUuid = checkerOperations.newChecker().repository(project).create();
// create check on the first patch set
CheckKey checkKey1 = CheckKey.create(project, patchSetId, checkerUuid);
checkOperations.newCheck(checkKey1).state(CheckState.SUCCESSFUL).upsert();
// create a second patch set
PatchSet.Id currentPatchSet = createPatchSet();
// create check on the second patch set, we expect that this check is not returned for the first
// patch set
CheckKey checkKey2 = CheckKey.create(project, currentPatchSet, checkerUuid);
checkOperations.newCheck(checkKey2).state(CheckState.RUNNING).upsert();
// list checks for the old patch set
assertThat(checksApiFactory.revision(patchSetId).list())
.containsExactly(checkOperations.check(checkKey1).asInfo());
// list checks for the new patch set (2 ways)
assertThat(checksApiFactory.currentRevision(currentPatchSet.changeId()).list())
.containsExactly(checkOperations.check(checkKey2).asInfo());
assertThat(checksApiFactory.revision(currentPatchSet).list())
.containsExactly(checkOperations.check(checkKey2).asInfo());
}
@Test
public void noBackfillForNonCurrentPatchSet() throws Exception {
checkerOperations.newChecker().repository(project).create();
PatchSet.Id currentPatchSet = createPatchSet();
assertThat(checksApiFactory.revision(patchSetId).list()).isEmpty();
assertThat(checksApiFactory.revision(currentPatchSet).list()).hasSize(1);
}
@Test
public void listAllWithoutAdministrateCheckers() throws Exception {
CheckerUuid checkerUuid = checkerOperations.newChecker().repository(project).create();
checkOperations.newCheck(CheckKey.create(project, patchSetId, checkerUuid)).upsert();
requestScopeOperations.setApiUser(user.id());
assertThat(checksApiFactory.revision(patchSetId).list()).hasSize(1);
}
@Test
public void listAllAnonymously() throws Exception {
CheckerUuid checkerUuid = checkerOperations.newChecker().repository(project).create();
checkOperations.newCheck(CheckKey.create(project, patchSetId, checkerUuid)).upsert();
requestScopeOperations.setApiUserAnonymous();
assertThat(checksApiFactory.revision(patchSetId).list()).hasSize(1);
}
@Test
public void listAllOnChangeEditRejected() throws Exception {
gApi.changes().id(changeId).edit().modifyCommitMessage("new message");
Optional<EditInfo> editInfo = gApi.changes().id(changeId).edit().get();
assertThat(editInfo).isPresent();
RestResponse response =
adminRestSession.get("/changes/" + changeId + "/revisions/edit/checks?o=CHECKER");
response.assertConflict();
assertThat(response.getEntityContent()).isEqualTo("checks are not supported on a change edit");
}
private Timestamp getPatchSetCreated(Change.Id changeId) throws RestApiException {
return getOnlyElement(
gApi.changes().id(changeId.get()).get(CURRENT_REVISION).revisions.values())
.created;
}
private PatchSet.Id createPatchSet() throws Exception {
PushOneCommit.Result r = amendChange(changeId);
PatchSet.Id currentPatchSetId = r.getPatchSetId();
assertThat(patchSetId.changeId()).isEqualTo(currentPatchSetId.changeId());
assertThat(patchSetId.get()).isLessThan(currentPatchSetId.get());
return currentPatchSetId;
}
}