|  | // 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.pgm; | 
|  |  | 
|  | import static com.google.common.truth.Truth.assertThat; | 
|  | import static com.google.gerrit.testing.GerritJUnit.assertThrows; | 
|  |  | 
|  | import com.google.common.collect.ImmutableList; | 
|  | import com.google.common.collect.ImmutableMap; | 
|  | import com.google.errorprone.annotations.CanIgnoreReturnValue; | 
|  | import com.google.gerrit.acceptance.AbstractDaemonTest; | 
|  | import com.google.gerrit.acceptance.Sandboxed; | 
|  | import com.google.gerrit.acceptance.testsuite.project.ProjectOperations; | 
|  | import com.google.gerrit.entities.RefNames; | 
|  | import com.google.gerrit.extensions.api.projects.SubmitRequirementApi; | 
|  | import com.google.gerrit.extensions.common.LabelDefinitionInfo; | 
|  | import com.google.gerrit.extensions.common.LabelDefinitionInput; | 
|  | import com.google.gerrit.extensions.common.SubmitRequirementInfo; | 
|  | import com.google.gerrit.extensions.common.SubmitRequirementInput; | 
|  | import com.google.gerrit.extensions.restapi.BadRequestException; | 
|  | import com.google.gerrit.extensions.restapi.ResourceNotFoundException; | 
|  | import com.google.gerrit.server.restapi.project.CreateLabel; | 
|  | import com.google.gerrit.server.schema.MigrateLabelFunctionsToSubmitRequirement; | 
|  | import com.google.gerrit.server.schema.MigrateLabelFunctionsToSubmitRequirement.Status; | 
|  | import com.google.gerrit.server.schema.UpdateUI; | 
|  | import com.google.inject.Inject; | 
|  | import java.util.Map; | 
|  | import java.util.Set; | 
|  | import org.eclipse.jgit.lib.Repository; | 
|  | import org.eclipse.jgit.revwalk.RevCommit; | 
|  | import org.junit.Test; | 
|  |  | 
|  | /** Test for {@link com.google.gerrit.server.schema.MigrateLabelFunctionsToSubmitRequirement}. */ | 
|  | @Sandboxed | 
|  | public class MigrateLabelFunctionsToSubmitRequirementIT extends AbstractDaemonTest { | 
|  | @Inject private ProjectOperations projectOperations; | 
|  | @Inject private CreateLabel createLabel; | 
|  |  | 
|  | @Test | 
|  | public void migrateBlockingLabel_maxWithBlock() throws Exception { | 
|  | createLabel("Foo", "MaxWithBlock", /* ignoreSelfApproval= */ false); | 
|  | assertNonExistentSr(/* srName= */ "Foo"); | 
|  |  | 
|  | TestUpdateUI updateUI = runMigration(/* expectedResult= */ Status.MIGRATED); | 
|  | assertThat(updateUI.newlyCreatedSrs).isEqualTo(1); | 
|  | assertThat(updateUI.existingSrsMismatchingWithMigration).isEqualTo(0); | 
|  |  | 
|  | assertExistentSr( | 
|  | /* srName */ "Foo", | 
|  | /* applicabilityExpression= */ null, | 
|  | /* submittabilityExpression= */ "label:Foo=MAX AND -label:Foo=MIN", | 
|  | /* canOverride= */ true); | 
|  | assertLabelFunction("Foo", "NoBlock"); | 
|  | } | 
|  |  | 
|  | @Test | 
|  | public void migrateBlockingLabel_maxNoBlock() throws Exception { | 
|  | createLabel("Foo", "MaxNoBlock", /* ignoreSelfApproval= */ false); | 
|  | assertNonExistentSr(/* srName= */ "Foo"); | 
|  |  | 
|  | TestUpdateUI updateUI = runMigration(/* expectedResult= */ Status.MIGRATED); | 
|  | assertThat(updateUI.newlyCreatedSrs).isEqualTo(1); | 
|  | assertThat(updateUI.existingSrsMismatchingWithMigration).isEqualTo(0); | 
|  |  | 
|  | assertExistentSr( | 
|  | /* srName */ "Foo", | 
|  | /* applicabilityExpression= */ null, | 
|  | /* submittabilityExpression= */ "label:Foo=MAX", | 
|  | /* canOverride= */ true); | 
|  | assertLabelFunction("Foo", "NoBlock"); | 
|  | } | 
|  |  | 
|  | @Test | 
|  | public void migrateBlockingLabel_anyWithBlock() throws Exception { | 
|  | createLabel("Foo", "AnyWithBlock", /* ignoreSelfApproval= */ false); | 
|  | assertNonExistentSr(/* srName= */ "Foo"); | 
|  |  | 
|  | TestUpdateUI updateUI = runMigration(/* expectedResult= */ Status.MIGRATED); | 
|  | assertThat(updateUI.newlyCreatedSrs).isEqualTo(1); | 
|  | assertThat(updateUI.existingSrsMismatchingWithMigration).isEqualTo(0); | 
|  |  | 
|  | assertExistentSr( | 
|  | /* srName */ "Foo", | 
|  | /* applicabilityExpression= */ null, | 
|  | /* submittabilityExpression= */ "-label:Foo=MIN", | 
|  | /* canOverride= */ true); | 
|  | assertLabelFunction("Foo", "NoBlock"); | 
|  | } | 
|  |  | 
|  | @Test | 
|  | public void migrateBlockingLabel_maxWithBlock_withIgnoreSelfApproval() throws Exception { | 
|  | createLabel("Foo", "MaxWithBlock", /* ignoreSelfApproval= */ true); | 
|  | assertNonExistentSr(/* srName= */ "Foo"); | 
|  |  | 
|  | TestUpdateUI updateUI = runMigration(/* expectedResult= */ Status.MIGRATED); | 
|  | assertThat(updateUI.newlyCreatedSrs).isEqualTo(1); | 
|  | assertThat(updateUI.existingSrsMismatchingWithMigration).isEqualTo(0); | 
|  |  | 
|  | assertExistentSr( | 
|  | /* srName */ "Foo", | 
|  | /* applicabilityExpression= */ null, | 
|  | /* submittabilityExpression= */ "label:Foo=MAX,user=non_uploader AND -label:Foo=MIN", | 
|  | /* canOverride= */ true); | 
|  | assertLabelFunction("Foo", "NoBlock"); | 
|  | } | 
|  |  | 
|  | @Test | 
|  | public void migrateBlockingLabel_maxNoBlock_withIgnoreSelfApproval() throws Exception { | 
|  | createLabel("Foo", "MaxNoBlock", /* ignoreSelfApproval= */ true); | 
|  | assertNonExistentSr(/* srName= */ "Foo"); | 
|  |  | 
|  | TestUpdateUI updateUI = runMigration(/* expectedResult= */ Status.MIGRATED); | 
|  | assertThat(updateUI.newlyCreatedSrs).isEqualTo(1); | 
|  | assertThat(updateUI.existingSrsMismatchingWithMigration).isEqualTo(0); | 
|  |  | 
|  | assertExistentSr( | 
|  | /* srName */ "Foo", | 
|  | /* applicabilityExpression= */ null, | 
|  | /* submittabilityExpression= */ "label:Foo=MAX,user=non_uploader", | 
|  | /* canOverride= */ true); | 
|  | assertLabelFunction("Foo", "NoBlock"); | 
|  | } | 
|  |  | 
|  | @Test | 
|  | public void migrateNonBlockingLabel_noBlock() throws Exception { | 
|  | // NoBlock labels are left as is, i.e. we don't create a "submit requirement" for them. Those | 
|  | // labels will then be treated as trigger votes in the change page. | 
|  | createLabel("Foo", "NoBlock", /* ignoreSelfApproval= */ false); | 
|  | assertNonExistentSr(/* srName= */ "Foo"); | 
|  |  | 
|  | TestUpdateUI updateUI = runMigration(/* expectedResult= */ Status.NO_CHANGE); | 
|  | assertThat(updateUI.newlyCreatedSrs).isEqualTo(0); | 
|  | assertThat(updateUI.existingSrsMismatchingWithMigration).isEqualTo(0); | 
|  |  | 
|  | // No SR was created for the label. Label will be treated as a trigger vote. | 
|  | assertNonExistentSr("Foo"); | 
|  | // Label function has not changed. | 
|  | assertLabelFunction("Foo", "NoBlock"); | 
|  | } | 
|  |  | 
|  | @Test | 
|  | public void migrateNonBlockingLabel_noOp() throws Exception { | 
|  | // NoOp labels are left as is, i.e. we don't create a "submit requirement" for them. Those | 
|  | // labels will then be treated as trigger votes in the change page. | 
|  | createLabel("Foo", "NoOp", /* ignoreSelfApproval= */ false); | 
|  | assertNonExistentSr(/* srName= */ "Foo"); | 
|  |  | 
|  | TestUpdateUI updateUI = runMigration(/* expectedResult= */ Status.MIGRATED); | 
|  | assertThat(updateUI.newlyCreatedSrs).isEqualTo(0); | 
|  | assertThat(updateUI.existingSrsMismatchingWithMigration).isEqualTo(0); | 
|  |  | 
|  | // No SR was created for the label. Label will be treated as a trigger vote. | 
|  | assertNonExistentSr("Foo"); | 
|  | // The NoOp function is converted to NoBlock. Both are same. | 
|  | assertLabelFunction("Foo", "NoBlock"); | 
|  | } | 
|  |  | 
|  | @Test | 
|  | public void migrateNoBlockLabel_withSingleZeroValue() throws Exception { | 
|  | // Labels that have a single "zero" value are skipped in the project. The migrator creates | 
|  | // non-applicable SR for these labels. | 
|  | createLabel("Foo", "NoBlock", /* ignoreSelfApproval= */ false, ImmutableMap.of("0", "No vote")); | 
|  | assertNonExistentSr(/* srName= */ "Foo"); | 
|  |  | 
|  | TestUpdateUI updateUI = runMigration(/* expectedResult= */ Status.MIGRATED); | 
|  | assertThat(updateUI.newlyCreatedSrs).isEqualTo(1); | 
|  | assertThat(updateUI.existingSrsMismatchingWithMigration).isEqualTo(0); | 
|  |  | 
|  | // a non-applicable SR was created for the skipped label. | 
|  | assertExistentSr( | 
|  | /* srName */ "Foo", | 
|  | /* applicabilityExpression= */ "is:false", | 
|  | /* submittabilityExpression= */ "is:true", | 
|  | /* canOverride= */ true); | 
|  |  | 
|  | assertLabelFunction("Foo", "NoBlock"); | 
|  | } | 
|  |  | 
|  | @Test | 
|  | public void migrateMaxWithBlockLabel_withSingleZeroValue() throws Exception { | 
|  | // Labels that have a single "zero" value are skipped in the project. The migrator creates | 
|  | // non-applicable SRs for these labels. | 
|  | createLabel( | 
|  | "Foo", "MaxWithBlock", /* ignoreSelfApproval= */ false, ImmutableMap.of("0", "No vote")); | 
|  | assertNonExistentSr(/* srName= */ "Foo"); | 
|  |  | 
|  | TestUpdateUI updateUI = runMigration(/* expectedResult= */ Status.MIGRATED); | 
|  | assertThat(updateUI.newlyCreatedSrs).isEqualTo(1); | 
|  | assertThat(updateUI.existingSrsMismatchingWithMigration).isEqualTo(0); | 
|  |  | 
|  | // a non-applicable SR was created for the skipped label. | 
|  | assertExistentSr( | 
|  | /* srName */ "Foo", | 
|  | /* applicabilityExpression= */ "is:false", | 
|  | /* submittabilityExpression= */ "is:true", | 
|  | /* canOverride= */ true); | 
|  |  | 
|  | // The MaxWithBlock function is converted to NoBlock. This has no effect anyway because the | 
|  | // label was originally skipped. | 
|  | assertLabelFunction("Foo", "NoBlock"); | 
|  | } | 
|  |  | 
|  | @Test | 
|  | public void cannotCreateLabelsWithNoValues() { | 
|  | // This test just asserts the server's behaviour for visibility; admins cannot create a label | 
|  | // without any defined values. | 
|  | Exception thrown = | 
|  | assertThrows( | 
|  | BadRequestException.class, | 
|  | () -> | 
|  | createLabel("Foo", "NoBlock", /* ignoreSelfApproval= */ false, ImmutableMap.of())); | 
|  | assertThat(thrown).hasMessageThat().isEqualTo("values are required"); | 
|  | } | 
|  |  | 
|  | @Test | 
|  | public void migrateNonBlockingLabel_patchSetLock_doesNothing() throws Exception { | 
|  | createLabel("Foo", "PatchSetLock", /* ignoreSelfApproval= */ false); | 
|  | assertNonExistentSr(/* srName= */ "Foo"); | 
|  |  | 
|  | TestUpdateUI updateUI = runMigration(/* expectedResult= */ Status.NO_CHANGE); | 
|  | // No submit requirement created for the patchset lock label function | 
|  | assertThat(updateUI.newlyCreatedSrs).isEqualTo(0); | 
|  | assertThat(updateUI.existingSrsMismatchingWithMigration).isEqualTo(0); | 
|  |  | 
|  | assertNonExistentSr(/* srName= */ "Foo"); | 
|  | assertLabelFunction("Foo", "PatchSetLock"); | 
|  | } | 
|  |  | 
|  | @Test | 
|  | public void migrationIsCommittedWithServerIdent() throws Exception { | 
|  | RevCommit oldMetaCommit = projectOperations.project(project).getHead(RefNames.REFS_CONFIG); | 
|  | createLabel("Foo", "MaxWithBlock", /* ignoreSelfApproval= */ false); | 
|  | assertNonExistentSr(/* srName= */ "Foo"); | 
|  |  | 
|  | TestUpdateUI updateUI = runMigration(/* expectedResult= */ Status.MIGRATED); | 
|  | assertThat(updateUI.newlyCreatedSrs).isEqualTo(1); | 
|  | assertThat(updateUI.existingSrsMismatchingWithMigration).isEqualTo(0); | 
|  |  | 
|  | assertExistentSr( | 
|  | /* srName */ "Foo", | 
|  | /* applicabilityExpression= */ null, | 
|  | /* submittabilityExpression= */ "label:Foo=MAX AND -label:Foo=MIN", | 
|  | /* canOverride= */ true); | 
|  | assertLabelFunction("Foo", "NoBlock"); | 
|  |  | 
|  | RevCommit newMetaCommit = projectOperations.project(project).getHead(RefNames.REFS_CONFIG); | 
|  | assertThat(newMetaCommit).isNotEqualTo(oldMetaCommit); | 
|  | assertThat(newMetaCommit.getCommitterIdent().getEmailAddress()) | 
|  | .isEqualTo(serverIdent.get().getEmailAddress()); | 
|  | } | 
|  |  | 
|  | @Test | 
|  | public void migrateBlockingLabel_withBranchAttribute() throws Exception { | 
|  | createLabelWithBranch( | 
|  | "Foo", | 
|  | "MaxWithBlock", | 
|  | /* ignoreSelfApproval= */ false, | 
|  | ImmutableList.of("refs/heads/master")); | 
|  |  | 
|  | assertNonExistentSr(/* srName= */ "Foo"); | 
|  |  | 
|  | TestUpdateUI updateUI = runMigration(/* expectedResult= */ Status.MIGRATED); | 
|  | assertThat(updateUI.newlyCreatedSrs).isEqualTo(1); | 
|  | assertThat(updateUI.existingSrsMismatchingWithMigration).isEqualTo(0); | 
|  |  | 
|  | assertExistentSr( | 
|  | /* srName */ "Foo", | 
|  | /* applicabilityExpression= */ "branch:\\\"refs/heads/master\\\"", | 
|  | /* submittabilityExpression= */ "label:Foo=MAX AND -label:Foo=MIN", | 
|  | /* canOverride= */ true); | 
|  | assertLabelFunction("Foo", "NoBlock"); | 
|  | } | 
|  |  | 
|  | @Test | 
|  | public void migrateBlockingLabel_withMultipleBranchAttributes() throws Exception { | 
|  | createLabelWithBranch( | 
|  | "Foo", | 
|  | "MaxWithBlock", | 
|  | /* ignoreSelfApproval= */ false, | 
|  | ImmutableList.of("refs/heads/master", "refs/heads/develop")); | 
|  |  | 
|  | assertNonExistentSr(/* srName= */ "Foo"); | 
|  |  | 
|  | TestUpdateUI updateUI = runMigration(/* expectedResult= */ Status.MIGRATED); | 
|  | assertThat(updateUI.newlyCreatedSrs).isEqualTo(1); | 
|  | assertThat(updateUI.existingSrsMismatchingWithMigration).isEqualTo(0); | 
|  |  | 
|  | assertExistentSr( | 
|  | /* srName */ "Foo", | 
|  | /* applicabilityExpression= */ "branch:\\\"refs/heads/master\\\" " | 
|  | + "OR branch:\\\"refs/heads/develop\\\"", | 
|  | /* submittabilityExpression= */ "label:Foo=MAX AND -label:Foo=MIN", | 
|  | /* canOverride= */ true); | 
|  | assertLabelFunction("Foo", "NoBlock"); | 
|  | } | 
|  |  | 
|  | @Test | 
|  | public void migrateBlockingLabel_withRegexBranchAttribute() throws Exception { | 
|  | createLabelWithBranch( | 
|  | "Foo", | 
|  | "MaxWithBlock", | 
|  | /* ignoreSelfApproval= */ false, | 
|  | ImmutableList.of("^refs/heads/main-.*")); | 
|  |  | 
|  | assertNonExistentSr(/* srName= */ "Foo"); | 
|  |  | 
|  | TestUpdateUI updateUI = runMigration(/* expectedResult= */ Status.MIGRATED); | 
|  | assertThat(updateUI.newlyCreatedSrs).isEqualTo(1); | 
|  | assertThat(updateUI.existingSrsMismatchingWithMigration).isEqualTo(0); | 
|  |  | 
|  | assertExistentSr( | 
|  | /* srName */ "Foo", | 
|  | /* applicabilityExpression= */ "branch:\\\"^refs/heads/main-.*\\\"", | 
|  | /* submittabilityExpression= */ "label:Foo=MAX AND -label:Foo=MIN", | 
|  | /* canOverride= */ true); | 
|  | assertLabelFunction("Foo", "NoBlock"); | 
|  | } | 
|  |  | 
|  | @Test | 
|  | public void migrateBlockingLabel_withRegexAndNonRegexBranchAttributes() throws Exception { | 
|  | createLabelWithBranch( | 
|  | "Foo", | 
|  | "MaxWithBlock", | 
|  | /* ignoreSelfApproval= */ false, | 
|  | ImmutableList.of("refs/heads/master", "^refs/heads/main-.*")); | 
|  |  | 
|  | assertNonExistentSr(/* srName= */ "Foo"); | 
|  |  | 
|  | TestUpdateUI updateUI = runMigration(/* expectedResult= */ Status.MIGRATED); | 
|  | assertThat(updateUI.newlyCreatedSrs).isEqualTo(1); | 
|  | assertThat(updateUI.existingSrsMismatchingWithMigration).isEqualTo(0); | 
|  |  | 
|  | assertExistentSr( | 
|  | /* srName */ "Foo", | 
|  | /* applicabilityExpression= */ "branch:\\\"refs/heads/master\\\" " | 
|  | + "OR branch:\\\"^refs/heads/main-.*\\\"", | 
|  | /* submittabilityExpression= */ "label:Foo=MAX AND -label:Foo=MIN", | 
|  | /* canOverride= */ true); | 
|  | assertLabelFunction("Foo", "NoBlock"); | 
|  | } | 
|  |  | 
|  | @Test | 
|  | public void migrationIsIdempotent() throws Exception { | 
|  | String oldRefsConfigId; | 
|  | try (Repository repo = repoManager.openRepository(project)) { | 
|  | oldRefsConfigId = repo.exactRef(RefNames.REFS_CONFIG).getObjectId().toString(); | 
|  | } | 
|  | createLabel("Foo", "MaxWithBlock", /* ignoreSelfApproval= */ false); | 
|  | assertNonExistentSr(/* srName= */ "Foo"); | 
|  |  | 
|  | // Running the migration causes REFS_CONFIG to change. | 
|  | TestUpdateUI updateUI = runMigration(/* expectedResult= */ Status.MIGRATED); | 
|  | assertThat(updateUI.newlyCreatedSrs).isEqualTo(1); | 
|  | assertThat(updateUI.existingSrsMismatchingWithMigration).isEqualTo(0); | 
|  | try (Repository repo = repoManager.openRepository(project)) { | 
|  | assertThat(oldRefsConfigId) | 
|  | .isNotEqualTo(repo.exactRef(RefNames.REFS_CONFIG).getObjectId().toString()); | 
|  | oldRefsConfigId = repo.exactRef(RefNames.REFS_CONFIG).getObjectId().toString(); | 
|  | } | 
|  |  | 
|  | // No new SRs will be created. No conflicting submit requirements either since the migration | 
|  | // detects that a previous run was made and skips the migration. | 
|  | updateUI = runMigration(/* expectedResult= */ Status.PREVIOUSLY_MIGRATED); | 
|  | assertThat(updateUI.newlyCreatedSrs).isEqualTo(0); | 
|  | assertThat(updateUI.existingSrsMismatchingWithMigration).isEqualTo(0); | 
|  | // Running the migration a second time won't update REFS_CONFIG. | 
|  | try (Repository repo = repoManager.openRepository(project)) { | 
|  | assertThat(oldRefsConfigId) | 
|  | .isEqualTo(repo.exactRef(RefNames.REFS_CONFIG).getObjectId().toString()); | 
|  | } | 
|  | } | 
|  |  | 
|  | @Test | 
|  | public void migrationDoesNotCreateANewSubmitRequirement_ifSRAlreadyExists_matchingWithMigration() | 
|  | throws Exception { | 
|  | createLabel("Foo", "MaxWithBlock", /* ignoreSelfApproval= */ false); | 
|  | createSubmitRequirement("Foo", "label:Foo=MAX AND -label:Foo=MIN", /* canOverride= */ true); | 
|  | assertExistentSr( | 
|  | /* srName */ "Foo", | 
|  | /* applicabilityExpression= */ null, | 
|  | /* submittabilityExpression= */ "label:Foo=MAX AND -label:Foo=MIN", | 
|  | /* canOverride= */ true); | 
|  |  | 
|  | TestUpdateUI updateUI = runMigration(/* expectedResult= */ Status.MIGRATED); | 
|  | // No new submit requirements are created. | 
|  | assertThat(updateUI.newlyCreatedSrs).isEqualTo(0); | 
|  | // No conflicting submit requirements from migration vs. what was previously configured. | 
|  | assertThat(updateUI.existingSrsMismatchingWithMigration).isEqualTo(0); | 
|  |  | 
|  | // The existing SR was left as is. | 
|  | assertExistentSr( | 
|  | /* srName */ "Foo", | 
|  | /* applicabilityExpression= */ null, | 
|  | /* submittabilityExpression= */ "label:Foo=MAX AND -label:Foo=MIN", | 
|  | /* canOverride= */ true); | 
|  | } | 
|  |  | 
|  | @Test | 
|  | public void | 
|  | migrationDoesNotCreateANewSubmitRequirement_ifSRAlreadyExists_mismatchingWithMigration() | 
|  | throws Exception { | 
|  | createLabel("Foo", "MaxWithBlock", /* ignoreSelfApproval= */ false); | 
|  | createSubmitRequirement("Foo", "project:" + project, /* canOverride= */ true); | 
|  | assertExistentSr( | 
|  | /* srName */ "Foo", | 
|  | /* applicabilityExpression= */ null, | 
|  | /* submittabilityExpression= */ "project:" + project, | 
|  | /* canOverride= */ true); | 
|  |  | 
|  | TestUpdateUI updateUI = runMigration(/* expectedResult= */ Status.MIGRATED); | 
|  | // One conflicting submit requirement between migration vs. what was previously configured. | 
|  | assertThat(updateUI.existingSrsMismatchingWithMigration).isEqualTo(1); | 
|  |  | 
|  | // The existing SR was left as is. | 
|  | assertExistentSr( | 
|  | /* srName */ "Foo", | 
|  | /* applicabilityExpression= */ null, | 
|  | /* submittabilityExpression= */ "project:" + project, | 
|  | /* canOverride= */ true); | 
|  | } | 
|  |  | 
|  | @Test | 
|  | public void migrationResetsBlockingLabel_ifSRAlreadyExists() throws Exception { | 
|  | createLabel("Foo", "MaxWithBlock", /* ignoreSelfApproval= */ false); | 
|  | createSubmitRequirement("Foo", "owner:" + admin.email(), /* canOverride= */ true); | 
|  |  | 
|  | TestUpdateUI updateUI = runMigration(/* expectedResult= */ Status.MIGRATED); | 
|  | assertThat(updateUI.newlyCreatedSrs).isEqualTo(0); | 
|  |  | 
|  | // The label function was reset | 
|  | assertLabelFunction("Foo", "NoBlock"); | 
|  | } | 
|  |  | 
|  | private TestUpdateUI runMigration(Status expectedResult) throws Exception { | 
|  | TestUpdateUI updateUi = new TestUpdateUI(); | 
|  | MigrateLabelFunctionsToSubmitRequirement executor = | 
|  | new MigrateLabelFunctionsToSubmitRequirement(repoManager, serverIdent.get()); | 
|  | Status status = executor.executeMigration(project, updateUi); | 
|  | assertThat(status).isEqualTo(expectedResult); | 
|  | projectCache.evictAndReindex(project); | 
|  | return updateUi; | 
|  | } | 
|  |  | 
|  | private void createLabel(String labelName, String function, boolean ignoreSelfApproval) | 
|  | throws Exception { | 
|  | createLabel( | 
|  | labelName, | 
|  | function, | 
|  | ignoreSelfApproval, | 
|  | ImmutableMap.of("+1", "Looks Good", " 0", "Don't Know", "-1", "Looks Bad")); | 
|  | } | 
|  |  | 
|  | private void createLabel( | 
|  | String labelName, String function, boolean ignoreSelfApproval, Map<String, String> values) | 
|  | throws Exception { | 
|  | LabelDefinitionInput input = new LabelDefinitionInput(); | 
|  | input.name = labelName; | 
|  | input.function = function; | 
|  | input.ignoreSelfApproval = ignoreSelfApproval; | 
|  | input.values = values; | 
|  | createLabel.createLabelWithoutInputValidation(project, labelName, input); | 
|  | } | 
|  |  | 
|  | private void createLabelWithBranch( | 
|  | String labelName, | 
|  | String function, | 
|  | boolean ignoreSelfApproval, | 
|  | ImmutableList<String> refPatterns) | 
|  | throws Exception { | 
|  | LabelDefinitionInput input = new LabelDefinitionInput(); | 
|  | input.name = labelName; | 
|  | input.function = function; | 
|  | input.ignoreSelfApproval = ignoreSelfApproval; | 
|  | input.values = ImmutableMap.of("+1", "Looks Good", " 0", "Don't Know", "-1", "Looks Bad"); | 
|  | input.branches = refPatterns; | 
|  | createLabel.createLabelWithoutInputValidation(project, labelName, input); | 
|  | } | 
|  |  | 
|  | @CanIgnoreReturnValue | 
|  | private SubmitRequirementApi createSubmitRequirement( | 
|  | String name, String submitExpression, boolean canOverride) throws Exception { | 
|  | SubmitRequirementInput input = new SubmitRequirementInput(); | 
|  | input.name = name; | 
|  | input.submittabilityExpression = submitExpression; | 
|  | input.allowOverrideInChildProjects = canOverride; | 
|  | return gApi.projects().name(project.get()).submitRequirement(name).create(input); | 
|  | } | 
|  |  | 
|  | private void assertLabelFunction(String labelName, String function) throws Exception { | 
|  | LabelDefinitionInfo info = gApi.projects().name(project.get()).label(labelName).get(); | 
|  | assertThat(info.function).isEqualTo(function); | 
|  | } | 
|  |  | 
|  | private void assertNonExistentSr(String srName) { | 
|  | ResourceNotFoundException foo = | 
|  | assertThrows( | 
|  | ResourceNotFoundException.class, | 
|  | () -> gApi.projects().name(project.get()).submitRequirement("Foo").get()); | 
|  | assertThat(foo.getMessage()).isEqualTo("Submit requirement '" + srName + "' does not exist"); | 
|  | } | 
|  |  | 
|  | private void assertExistentSr( | 
|  | String srName, | 
|  | String applicabilityExpression, | 
|  | String submittabilityExpression, | 
|  | boolean canOverride) | 
|  | throws Exception { | 
|  | SubmitRequirementInfo sr = gApi.projects().name(project.get()).submitRequirement(srName).get(); | 
|  | assertThat(sr.applicabilityExpression).isEqualTo(applicabilityExpression); | 
|  | assertThat(sr.submittabilityExpression).isEqualTo(submittabilityExpression); | 
|  | assertThat(sr.allowOverrideInChildProjects).isEqualTo(canOverride); | 
|  | } | 
|  |  | 
|  | private static class TestUpdateUI implements UpdateUI { | 
|  | int existingSrsMismatchingWithMigration = 0; | 
|  | int newlyCreatedSrs = 0; | 
|  |  | 
|  | @Override | 
|  | public void message(String message) { | 
|  | if (message.startsWith("Warning")) { | 
|  | existingSrsMismatchingWithMigration += 1; | 
|  | } else if (message.startsWith("Project")) { | 
|  | newlyCreatedSrs += 1; | 
|  | } | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public boolean yesno(boolean defaultValue, String message) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public void waitForUser() {} | 
|  |  | 
|  | @Override | 
|  | public String readString(String defaultValue, Set<String> allowedValues, String message) { | 
|  | return null; | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public boolean isBatch() { | 
|  | return false; | 
|  | } | 
|  | } | 
|  | } |