| // Copyright (C) 2022 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.project; | |
| import static com.google.common.truth.Truth.assertThat; | |
| import static com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.allow; | |
| import static com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.block; | |
| import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS; | |
| import static com.google.gerrit.testing.GerritJUnit.assertThrows; | |
| import com.google.gerrit.acceptance.AbstractDaemonTest; | |
| import com.google.gerrit.acceptance.NoHttpd; | |
| import com.google.gerrit.acceptance.testsuite.project.ProjectOperations; | |
| import com.google.gerrit.acceptance.testsuite.request.RequestScopeOperations; | |
| import com.google.gerrit.entities.Permission; | |
| import com.google.gerrit.extensions.common.SubmitRequirementInfo; | |
| import com.google.gerrit.extensions.common.SubmitRequirementInput; | |
| import com.google.gerrit.extensions.restapi.AuthException; | |
| import com.google.gerrit.extensions.restapi.BadRequestException; | |
| import com.google.gerrit.extensions.restapi.ResourceNotFoundException; | |
| import com.google.gerrit.extensions.restapi.RestApiException; | |
| import com.google.inject.Inject; | |
| import java.util.List; | |
| import java.util.stream.Collectors; | |
| import org.junit.Test; | |
| @NoHttpd | |
| public class SubmitRequirementsAPIIT extends AbstractDaemonTest { | |
| @Inject private RequestScopeOperations requestScopeOperations; | |
| @Inject private ProjectOperations projectOperations; | |
| @Test | |
| public void cannotGetANonExistingSR() throws Exception { | |
| ResourceNotFoundException thrown = | |
| assertThrows( | |
| ResourceNotFoundException.class, | |
| () -> gApi.projects().name(project.get()).submitRequirement("code-review").get()); | |
| assertThat(thrown) | |
| .hasMessageThat() | |
| .isEqualTo("Submit requirement 'code-review' does not exist"); | |
| } | |
| @Test | |
| public void getExistingSR() throws Exception { | |
| SubmitRequirementInput input = new SubmitRequirementInput(); | |
| input.name = "code-review"; | |
| input.applicabilityExpression = "topic:foo"; | |
| input.submittabilityExpression = "label:code-review=+2"; | |
| gApi.projects().name(project.get()).submitRequirement("code-review").create(input).get(); | |
| SubmitRequirementInfo info = | |
| gApi.projects().name(project.get()).submitRequirement("code-review").get(); | |
| assertThat(info.name).isEqualTo("code-review"); | |
| assertThat(info.applicabilityExpression).isEqualTo("topic:foo"); | |
| assertThat(info.submittabilityExpression).isEqualTo("label:code-review=+2"); | |
| assertThat(info.allowOverrideInChildProjects).isEqualTo(false); | |
| } | |
| @Test | |
| public void updateSubmitRequirement() throws Exception { | |
| SubmitRequirementInput input = new SubmitRequirementInput(); | |
| input.name = "code-review"; | |
| input.applicabilityExpression = "topic:foo"; | |
| input.submittabilityExpression = "label:code-review=+2"; | |
| gApi.projects().name(project.get()).submitRequirement("code-review").create(input).get(); | |
| input.submittabilityExpression = "label:code-review=+1"; | |
| SubmitRequirementInfo info = | |
| gApi.projects().name(project.get()).submitRequirement("code-review").update(input); | |
| assertThat(info.submittabilityExpression).isEqualTo("label:code-review=+1"); | |
| } | |
| @Test | |
| public void updateSRWithEmptyApplicabilityExpression_isAllowed() throws Exception { | |
| SubmitRequirementInput input = new SubmitRequirementInput(); | |
| input.name = "code-review"; | |
| input.applicabilityExpression = "topic:foo"; | |
| input.submittabilityExpression = "label:code-review=+2"; | |
| gApi.projects().name(project.get()).submitRequirement("code-review").create(input).get(); | |
| input.applicabilityExpression = null; | |
| SubmitRequirementInfo info = | |
| gApi.projects().name(project.get()).submitRequirement("code-review").update(input); | |
| assertThat(info.applicabilityExpression).isNull(); | |
| } | |
| @Test | |
| public void updateSRWithEmptyOverrideExpression_isAllowed() throws Exception { | |
| SubmitRequirementInput input = new SubmitRequirementInput(); | |
| input.name = "code-review"; | |
| input.overrideExpression = "topic:foo"; | |
| input.submittabilityExpression = "label:code-review=+2"; | |
| gApi.projects().name(project.get()).submitRequirement("code-review").create(input).get(); | |
| input.overrideExpression = null; | |
| SubmitRequirementInfo info = | |
| gApi.projects().name(project.get()).submitRequirement("code-review").update(input); | |
| assertThat(info.overrideExpression).isNull(); | |
| } | |
| @Test | |
| public void allowOverrideInChildProjectsDefaultsToFalse_updateSR() throws Exception { | |
| SubmitRequirementInput input = new SubmitRequirementInput(); | |
| input.name = "code-review"; | |
| input.submittabilityExpression = "label:code-review=+2"; | |
| gApi.projects().name(project.get()).submitRequirement("code-review").create(input).get(); | |
| input.overrideExpression = "topic:foo"; | |
| SubmitRequirementInfo info = | |
| gApi.projects().name(project.get()).submitRequirement("code-review").update(input); | |
| assertThat(info.allowOverrideInChildProjects).isFalse(); | |
| } | |
| @Test | |
| public void cannotUpdateSRAsAnonymousUser() throws Exception { | |
| SubmitRequirementInput input = new SubmitRequirementInput(); | |
| input.name = "code-review"; | |
| input.submittabilityExpression = "label:code-review=+2"; | |
| gApi.projects().name(project.get()).submitRequirement("code-review").create(input).get(); | |
| input.submittabilityExpression = "label:code-review=+1"; | |
| requestScopeOperations.setApiUserAnonymous(); | |
| AuthException thrown = | |
| assertThrows( | |
| AuthException.class, | |
| () -> | |
| gApi.projects() | |
| .name(project.get()) | |
| .submitRequirement("code-review") | |
| .update(new SubmitRequirementInput())); | |
| assertThat(thrown).hasMessageThat().contains("Authentication required"); | |
| } | |
| @Test | |
| public void cannotUpdateSRtIfSRDoesNotExist() throws Exception { | |
| SubmitRequirementInput input = new SubmitRequirementInput(); | |
| input.name = "code-review"; | |
| input.description = "At least one +2 vote to the code-review label"; | |
| input.submittabilityExpression = "label:code-review=+2"; | |
| ResourceNotFoundException thrown = | |
| assertThrows( | |
| ResourceNotFoundException.class, | |
| () -> | |
| gApi.projects().name(project.get()).submitRequirement("code-review").update(input)); | |
| assertThat(thrown) | |
| .hasMessageThat() | |
| .isEqualTo("Submit requirement 'code-review' does not exist"); | |
| } | |
| @Test | |
| public void cannotUpdateSRWithEmptySubmittableIf() throws Exception { | |
| SubmitRequirementInput input = new SubmitRequirementInput(); | |
| input.name = "code-review"; | |
| input.submittabilityExpression = "project:foo AND branch:refs/heads/main"; | |
| gApi.projects().name(project.get()).submitRequirement("code-review").create(input).get(); | |
| input.submittabilityExpression = null; | |
| BadRequestException thrown = | |
| assertThrows( | |
| BadRequestException.class, | |
| () -> | |
| gApi.projects().name(project.get()).submitRequirement("code-review").update(input)); | |
| assertThat(thrown).hasMessageThat().isEqualTo("submittability_expression is required"); | |
| } | |
| @Test | |
| public void cannotUpdateSRWithInvalidSubmittableIfExpression() throws Exception { | |
| SubmitRequirementInput input = new SubmitRequirementInput(); | |
| input.name = "code-review"; | |
| input.submittabilityExpression = "project:foo AND branch:refs/heads/main"; | |
| gApi.projects().name(project.get()).submitRequirement("code-review").create(input).get(); | |
| input.submittabilityExpression = "invalid_field:invalid_value"; | |
| BadRequestException thrown = | |
| assertThrows( | |
| BadRequestException.class, | |
| () -> | |
| gApi.projects().name(project.get()).submitRequirement("code-review").update(input)); | |
| assertThat(thrown) | |
| .hasMessageThat() | |
| .isEqualTo( | |
| "Invalid submit requirement input: " | |
| + "[Invalid project configuration, " | |
| + "project.config: Expression 'invalid_field:invalid_value' of " | |
| + "submit requirement 'code-review' " | |
| + "(parameter submit-requirement.code-review.submittableIf) is invalid: " | |
| + "Unsupported operator invalid_field:invalid_value]"); | |
| } | |
| @Test | |
| public void cannotUpdateSRWithInvalidOverrideIfExpression() throws Exception { | |
| SubmitRequirementInput input = new SubmitRequirementInput(); | |
| input.name = "code-review"; | |
| input.submittabilityExpression = "project:foo AND branch:refs/heads/main"; | |
| gApi.projects().name(project.get()).submitRequirement("code-review").create(input).get(); | |
| input.overrideExpression = "invalid_field:invalid_value"; | |
| BadRequestException thrown = | |
| assertThrows( | |
| BadRequestException.class, | |
| () -> | |
| gApi.projects().name(project.get()).submitRequirement("code-review").update(input)); | |
| assertThat(thrown) | |
| .hasMessageThat() | |
| .isEqualTo( | |
| "Invalid submit requirement input: " | |
| + "[Invalid project configuration, " | |
| + "project.config: Expression 'invalid_field:invalid_value' of " | |
| + "submit requirement 'code-review' " | |
| + "(parameter submit-requirement.code-review.overrideIf) is invalid: " | |
| + "Unsupported operator invalid_field:invalid_value]"); | |
| } | |
| @Test | |
| public void cannotUpdateSRWithInvalidApplicableIfExpression() throws Exception { | |
| SubmitRequirementInput input = new SubmitRequirementInput(); | |
| input.name = "code-review"; | |
| input.submittabilityExpression = "project:foo AND branch:refs/heads/main"; | |
| gApi.projects().name(project.get()).submitRequirement("code-review").create(input).get(); | |
| input.applicabilityExpression = "invalid_field:invalid_value"; | |
| BadRequestException thrown = | |
| assertThrows( | |
| BadRequestException.class, | |
| () -> | |
| gApi.projects().name(project.get()).submitRequirement("code-review").update(input)); | |
| assertThat(thrown) | |
| .hasMessageThat() | |
| .isEqualTo( | |
| "Invalid submit requirement input: " | |
| + "[Invalid project configuration, " | |
| + "project.config: Expression 'invalid_field:invalid_value' of " | |
| + "submit requirement 'code-review' " | |
| + "(parameter submit-requirement.code-review.applicableIf) is invalid: " | |
| + "Unsupported operator invalid_field:invalid_value]"); | |
| } | |
| @Test | |
| public void createSubmitRequirement() throws Exception { | |
| SubmitRequirementInput input = new SubmitRequirementInput(); | |
| input.name = "code-review"; | |
| input.description = "At least one +2 vote to the code-review label"; | |
| input.applicabilityExpression = "project:foo AND branch:refs/heads/main"; | |
| input.submittabilityExpression = "label:code-review=+2"; | |
| input.overrideExpression = "label:build-cop-override=+1"; | |
| input.allowOverrideInChildProjects = true; | |
| SubmitRequirementInfo info = | |
| gApi.projects().name(project.get()).submitRequirement("code-review").create(input).get(); | |
| assertThat(info.name).isEqualTo("code-review"); | |
| assertThat(info.description).isEqualTo(input.description); | |
| assertThat(info.applicabilityExpression).isEqualTo(input.applicabilityExpression); | |
| assertThat(info.applicabilityExpression).isEqualTo(input.applicabilityExpression); | |
| assertThat(info.submittabilityExpression).isEqualTo(input.submittabilityExpression); | |
| assertThat(info.overrideExpression).isEqualTo(input.overrideExpression); | |
| assertThat(info.allowOverrideInChildProjects).isEqualTo(true); | |
| } | |
| @Test | |
| public void createSRWithEmptyApplicabilityExpression_isAllowed() throws Exception { | |
| SubmitRequirementInput input = new SubmitRequirementInput(); | |
| input.name = "code-review"; | |
| input.description = "At least one +2 vote to the code-review label"; | |
| input.submittabilityExpression = "label:code-review=+2"; | |
| input.overrideExpression = "label:build-cop-override=+1"; | |
| SubmitRequirementInfo info = | |
| gApi.projects().name(project.get()).submitRequirement("code-review").create(input).get(); | |
| assertThat(info.name).isEqualTo("code-review"); | |
| assertThat(info.applicabilityExpression).isNull(); | |
| } | |
| @Test | |
| public void createSRWithEmptyOverrideExpression_isAllowed() throws Exception { | |
| SubmitRequirementInput input = new SubmitRequirementInput(); | |
| input.name = "code-review"; | |
| input.description = "At least one +2 vote to the code-review label"; | |
| input.applicabilityExpression = "project:foo AND branch:refs/heads/main"; | |
| input.submittabilityExpression = "label:code-review=+2"; | |
| SubmitRequirementInfo info = | |
| gApi.projects().name(project.get()).submitRequirement("code-review").create(input).get(); | |
| assertThat(info.name).isEqualTo("code-review"); | |
| assertThat(info.overrideExpression).isNull(); | |
| } | |
| @Test | |
| public void allowOverrideInChildProjectsDefaultsToFalse_createSR() throws Exception { | |
| SubmitRequirementInput input = new SubmitRequirementInput(); | |
| input.name = "code-review"; | |
| input.description = "At least one +2 vote to the code-review label"; | |
| input.submittabilityExpression = "label:code-review=+2"; | |
| SubmitRequirementInfo info = | |
| gApi.projects().name(project.get()).submitRequirement("code-review").create(input).get(); | |
| assertThat(info.allowOverrideInChildProjects).isEqualTo(false); | |
| } | |
| @Test | |
| public void cannotCreateSRAsAnonymousUser() throws Exception { | |
| SubmitRequirementInput input = new SubmitRequirementInput(); | |
| input.name = "code-review"; | |
| input.description = "At least one +2 vote to the code-review label"; | |
| input.applicabilityExpression = "project:foo AND branch:refs/heads/main"; | |
| input.submittabilityExpression = "label:code-review=+2"; | |
| input.overrideExpression = "label:build-cop-override=+1"; | |
| requestScopeOperations.setApiUserAnonymous(); | |
| AuthException thrown = | |
| assertThrows( | |
| AuthException.class, | |
| () -> | |
| gApi.projects() | |
| .name(project.get()) | |
| .submitRequirement("code-review") | |
| .create(new SubmitRequirementInput())); | |
| assertThat(thrown).hasMessageThat().contains("Authentication required"); | |
| } | |
| @Test | |
| public void cannotCreateSRtIfNameInInputDoesNotMatchResource() throws Exception { | |
| SubmitRequirementInput input = new SubmitRequirementInput(); | |
| input.name = "code-review"; | |
| input.description = "At least one +2 vote to the code-review label"; | |
| input.submittabilityExpression = "label:code-review=+2"; | |
| BadRequestException thrown = | |
| assertThrows( | |
| BadRequestException.class, | |
| () -> | |
| gApi.projects() | |
| .name(project.get()) | |
| .submitRequirement("other-requirement") | |
| .create(input) | |
| .get()); | |
| assertThat(thrown).hasMessageThat().isEqualTo("name in input must match name in URL"); | |
| } | |
| @Test | |
| public void cannotCreateSRWithInvalidName() throws Exception { | |
| SubmitRequirementInput input = new SubmitRequirementInput(); | |
| input.name = "wrong$%"; | |
| input.submittabilityExpression = "label:code-review=+2"; | |
| BadRequestException thrown = | |
| assertThrows( | |
| BadRequestException.class, | |
| () -> | |
| gApi.projects() | |
| .name(project.get()) | |
| .submitRequirement("wrong$%") | |
| .create(input) | |
| .get()); | |
| assertThat(thrown) | |
| .hasMessageThat() | |
| .isEqualTo( | |
| "Illegal submit requirement name \"wrong$%\". " | |
| + "Name can only consist of alphanumeric characters and '-'." | |
| + " Name cannot start with '-' or number."); | |
| } | |
| @Test | |
| public void cannotCreateSRWithEmptySubmittableIf() throws Exception { | |
| SubmitRequirementInput input = new SubmitRequirementInput(); | |
| input.name = "code-review"; | |
| input.description = "At least one +2 vote to the code-review label"; | |
| input.applicabilityExpression = "project:foo AND branch:refs/heads/main"; | |
| input.overrideExpression = "label:build-cop-override=+1"; | |
| BadRequestException thrown = | |
| assertThrows( | |
| BadRequestException.class, | |
| () -> | |
| gApi.projects() | |
| .name(project.get()) | |
| .submitRequirement("code-review") | |
| .create(input) | |
| .get()); | |
| assertThat(thrown).hasMessageThat().isEqualTo("submittability_expression is required"); | |
| } | |
| @Test | |
| public void cannotCreateSRWithInvalidSubmittableIfExpression() throws Exception { | |
| SubmitRequirementInput input = new SubmitRequirementInput(); | |
| input.name = "code-review"; | |
| input.description = "At least one +2 vote to the code-review label"; | |
| input.submittabilityExpression = "invalid_field:invalid_value"; | |
| BadRequestException exception = | |
| assertThrows( | |
| BadRequestException.class, | |
| () -> | |
| gApi.projects() | |
| .name(project.get()) | |
| .submitRequirement("code-review") | |
| .create(input) | |
| .get()); | |
| assertThat(exception) | |
| .hasMessageThat() | |
| .isEqualTo( | |
| "Invalid submit requirement input: " | |
| + "[Invalid project configuration, " | |
| + "project.config: Expression 'invalid_field:invalid_value' of " | |
| + "submit requirement 'code-review' " | |
| + "(parameter submit-requirement.code-review.submittableIf) is invalid: " | |
| + "Unsupported operator invalid_field:invalid_value]"); | |
| } | |
| @Test | |
| public void cannotCreateSRWithInvalidOverrideIfExpression() throws Exception { | |
| SubmitRequirementInput input = new SubmitRequirementInput(); | |
| input.name = "code-review"; | |
| input.description = "At least one +2 vote to the code-review label"; | |
| input.submittabilityExpression = "label:Code-Review=+2"; | |
| input.overrideExpression = "invalid_field:invalid_value"; | |
| BadRequestException exception = | |
| assertThrows( | |
| BadRequestException.class, | |
| () -> | |
| gApi.projects() | |
| .name(project.get()) | |
| .submitRequirement("code-review") | |
| .create(input) | |
| .get()); | |
| assertThat(exception) | |
| .hasMessageThat() | |
| .isEqualTo( | |
| "Invalid submit requirement input: " | |
| + "[Invalid project configuration, " | |
| + "project.config: Expression 'invalid_field:invalid_value' of " | |
| + "submit requirement 'code-review' " | |
| + "(parameter submit-requirement.code-review.overrideIf) is invalid: " | |
| + "Unsupported operator invalid_field:invalid_value]"); | |
| } | |
| @Test | |
| public void cannotCreateSRWithInvalidApplicableIfExpression() throws Exception { | |
| SubmitRequirementInput input = new SubmitRequirementInput(); | |
| input.name = "code-review"; | |
| input.description = "At least one +2 vote to the code-review label"; | |
| input.applicabilityExpression = "invalid_field:invalid_value"; | |
| input.submittabilityExpression = "label:Code-Review=+2"; | |
| BadRequestException exception = | |
| assertThrows( | |
| BadRequestException.class, | |
| () -> | |
| gApi.projects() | |
| .name(project.get()) | |
| .submitRequirement("code-review") | |
| .create(input) | |
| .get()); | |
| assertThat(exception) | |
| .hasMessageThat() | |
| .isEqualTo( | |
| "Invalid submit requirement input: " | |
| + "[Invalid project configuration, " | |
| + "project.config: Expression 'invalid_field:invalid_value' of " | |
| + "submit requirement 'code-review' " | |
| + "(parameter submit-requirement.code-review.applicableIf) is invalid: " | |
| + "Unsupported operator invalid_field:invalid_value]"); | |
| } | |
| @Test | |
| public void cannotListSRsAsAnonymous() throws Exception { | |
| requestScopeOperations.setApiUserAnonymous(); | |
| AuthException thrown = | |
| assertThrows( | |
| AuthException.class, | |
| () -> gApi.projects().name(project.get()).submitRequirements().get()); | |
| assertThat(thrown).hasMessageThat().contains("Authentication required"); | |
| } | |
| @Test | |
| public void cannotListSRs_withMissingReadPermissionsToRefsConfig() throws Exception { | |
| requestScopeOperations.setApiUser(user.id()); | |
| AuthException thrown = | |
| assertThrows( | |
| AuthException.class, | |
| () -> gApi.projects().name(project.get()).submitRequirements().get()); | |
| assertThat(thrown).hasMessageThat().contains("read refs/meta/config not permitted"); | |
| } | |
| @Test | |
| public void cannotListSRs_withMissingReadPermissionsInParent_withInheritance() throws Exception { | |
| projectOperations | |
| .project(project) | |
| .forUpdate() | |
| .add(allow(Permission.READ).ref("refs/meta/config").group(REGISTERED_USERS)) | |
| .update(); | |
| projectOperations | |
| .project(project) | |
| .forUpdate() | |
| .add(block(Permission.READ).ref("refs/meta/config").group(REGISTERED_USERS)) | |
| .update(); | |
| requestScopeOperations.setApiUser(user.id()); | |
| AuthException thrown = | |
| assertThrows( | |
| AuthException.class, | |
| () -> | |
| gApi.projects().name(project.get()).submitRequirements().withInherited(true).get()); | |
| assertThat(thrown).hasMessageThat().contains("read refs/meta/config not permitted"); | |
| } | |
| @Test | |
| public void canListSRs_withReadPermissionsInAllParentProjects_withInheritance() throws Exception { | |
| projectOperations | |
| .project(allProjects) | |
| .forUpdate() | |
| .add(allow(Permission.READ).ref("refs/meta/config").group(REGISTERED_USERS)) | |
| .update(); | |
| projectOperations | |
| .project(project) | |
| .forUpdate() | |
| .add(allow(Permission.READ).ref("refs/meta/config").group(REGISTERED_USERS)) | |
| .update(); | |
| requestScopeOperations.setApiUser(user.id()); | |
| gApi.projects().name(project.get()).submitRequirements().get(); | |
| } | |
| @Test | |
| public void canListSRs_withMissingReadPermissionsInParent_withoutInheritance() throws Exception { | |
| projectOperations | |
| .project(project) | |
| .forUpdate() | |
| .add(allow(Permission.READ).ref("refs/meta/config").group(REGISTERED_USERS)) | |
| .update(); | |
| projectOperations | |
| .project(project) | |
| .forUpdate() | |
| .add(block(Permission.READ).ref("refs/meta/config").group(REGISTERED_USERS)) | |
| .update(); | |
| requestScopeOperations.setApiUser(user.id()); | |
| gApi.projects().name(project.get()).submitRequirements().withInherited(false).get(); | |
| } | |
| @Test | |
| public void listSRs() throws Exception { | |
| createSubmitRequirement("sr-1"); | |
| createSubmitRequirement("sr-2"); | |
| List<SubmitRequirementInfo> infos = | |
| gApi.projects().name(project.get()).submitRequirements().get(); | |
| assertThat(names(infos)).containsExactly("sr-1", "sr-2"); | |
| } | |
| @Test | |
| public void listSRsWithInheritance() throws Exception { | |
| createSubmitRequirement(allProjects.get(), "base-sr"); | |
| createSubmitRequirement(project.get(), "sr-1"); | |
| createSubmitRequirement(project.get(), "sr-2"); | |
| List<SubmitRequirementInfo> infos = | |
| gApi.projects().name(project.get()).submitRequirements().withInherited(false).get(); | |
| assertThat(names(infos)).containsExactly("sr-1", "sr-2"); | |
| infos = gApi.projects().name(project.get()).submitRequirements().withInherited(true).get(); | |
| assertThat(names(infos)).containsExactly("base-sr", "sr-1", "sr-2"); | |
| } | |
| @Test | |
| public void cannotDeleteSRAsAnonymousUser() throws Exception { | |
| createSubmitRequirement("code-review"); | |
| requestScopeOperations.setApiUserAnonymous(); | |
| AuthException thrown = | |
| assertThrows( | |
| AuthException.class, | |
| () -> gApi.projects().name(project.get()).submitRequirement("code-review").delete()); | |
| assertThat(thrown).hasMessageThat().contains("Authentication required"); | |
| } | |
| @Test | |
| public void cannotDeleteSRWithMissingWritePermissionsToRefsConfig() throws Exception { | |
| createSubmitRequirement("sr-1"); | |
| projectOperations | |
| .project(project) | |
| .forUpdate() | |
| .add(allow(Permission.READ).ref("refs/meta/config").group(REGISTERED_USERS)) | |
| .add(block("write").ref("refs/meta/config").group(REGISTERED_USERS)) | |
| .update(); | |
| requestScopeOperations.setApiUser(user.id()); | |
| AuthException thrown = | |
| assertThrows( | |
| AuthException.class, | |
| () -> gApi.projects().name(project.get()).submitRequirement("sr-1").delete()); | |
| assertThat(thrown).hasMessageThat().contains("write refs/meta/config not permitted"); | |
| } | |
| @Test | |
| public void cannotDeleteNonExistingSR() throws Exception { | |
| ResourceNotFoundException thrown = | |
| assertThrows( | |
| ResourceNotFoundException.class, | |
| () -> gApi.projects().name(project.get()).submitRequirement("non-existing").delete()); | |
| assertThat(thrown) | |
| .hasMessageThat() | |
| .contains("Submit requirement 'non-existing' does not exist"); | |
| } | |
| @Test | |
| public void deleteSubmitRequirement() throws Exception { | |
| createSubmitRequirement("code-review"); | |
| createSubmitRequirement("verified"); | |
| List<SubmitRequirementInfo> infos = | |
| gApi.projects().name(project.get()).submitRequirements().get(); | |
| assertThat(names(infos)).containsExactly("code-review", "verified"); | |
| gApi.projects().name(project.get()).submitRequirement("code-review").delete(); | |
| infos = gApi.projects().name(project.get()).submitRequirements().get(); | |
| assertThat(names(infos)).containsExactly("verified"); | |
| } | |
| private SubmitRequirementInfo createSubmitRequirement(String srName) throws RestApiException { | |
| return createSubmitRequirement(project.get(), srName); | |
| } | |
| private SubmitRequirementInfo createSubmitRequirement(String project, String srName) | |
| throws RestApiException { | |
| SubmitRequirementInput input = new SubmitRequirementInput(); | |
| input.name = srName; | |
| input.submittabilityExpression = "label:dummy=+2"; | |
| return gApi.projects().name(project).submitRequirement(srName).create(input).get(); | |
| } | |
| private List<String> names(List<SubmitRequirementInfo> infos) { | |
| return infos.stream().map(sr -> sr.name).collect(Collectors.toList()); | |
| } | |
| } |