/* * Copyright 2017 ThoughtWorks, Inc. * * 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.thoughtworks.go.config.merge; import com.thoughtworks.go.config.*; import com.thoughtworks.go.config.remote.ConfigOrigin; import com.thoughtworks.go.config.remote.FileConfigOrigin; import com.thoughtworks.go.config.remote.RepoConfigOrigin; import com.thoughtworks.go.helper.PipelineConfigMother; import org.hamcrest.Matchers; import org.junit.Test; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import static com.thoughtworks.go.util.DataStructureUtils.a; import static com.thoughtworks.go.util.DataStructureUtils.m; import static org.hamcrest.Matchers.hasItem; import static org.hamcrest.Matchers.is; import static org.junit.Assert.*; public class MergePipelineConfigsTest extends PipelineConfigsTestBase { @Override protected PipelineConfigs createWithPipeline(PipelineConfig pipelineConfig) { BasicPipelineConfigs pipelineConfigsLocal = new BasicPipelineConfigs(pipelineConfig); pipelineConfigsLocal.setOrigin(new FileConfigOrigin()); BasicPipelineConfigs pipelineConfigsRemote = new BasicPipelineConfigs(); pipelineConfigsRemote.setOrigin(new RepoConfigOrigin()); return new MergePipelineConfigs(pipelineConfigsRemote,pipelineConfigsLocal); } @Override protected PipelineConfigs createEmpty() { BasicPipelineConfigs pipelineConfigs = new BasicPipelineConfigs(); pipelineConfigs.setOrigin(new FileConfigOrigin()); return new MergePipelineConfigs(pipelineConfigs); } @Override protected PipelineConfigs createWithPipelines(PipelineConfig first, PipelineConfig second) { BasicPipelineConfigs pipelineConfigsLocal = new BasicPipelineConfigs(first, second); pipelineConfigsLocal.setOrigin(new FileConfigOrigin()); BasicPipelineConfigs pipelineConfigsRemote = new BasicPipelineConfigs(); pipelineConfigsRemote.setOrigin(new RepoConfigOrigin()); return new MergePipelineConfigs(pipelineConfigsLocal,pipelineConfigsRemote); } @Test public void shouldReturnNullForGetLocalWhenOnlyRemoteParts() { BasicPipelineConfigs firstPart = new BasicPipelineConfigs(); firstPart.setOrigin(new RepoConfigOrigin()); BasicPipelineConfigs secondPart = new BasicPipelineConfigs(); secondPart.setOrigin(new RepoConfigOrigin()); MergePipelineConfigs merge = new MergePipelineConfigs(firstPart, secondPart); assertNull(merge.getLocal()); } @Test public void shouldReturnFilePartForGetLocalWhenHasRemoteAndFilePart() { BasicPipelineConfigs filePart = new BasicPipelineConfigs(); filePart.setOrigin(new FileConfigOrigin()); BasicPipelineConfigs secondPart = new BasicPipelineConfigs(); secondPart.setOrigin(new RepoConfigOrigin()); MergePipelineConfigs merge = new MergePipelineConfigs(filePart, secondPart); assertThat(merge.getLocal(), Matchers.<PipelineConfigs>is(filePart)); } @Test public void shouldSetAuthorizationInFile() { BasicPipelineConfigs filePart = new BasicPipelineConfigs(); filePart.setOrigin(new FileConfigOrigin()); MergePipelineConfigs merge = new MergePipelineConfigs(filePart,new BasicPipelineConfigs()); Authorization auth = new Authorization(new AdminsConfig(new AdminUser(new CaseInsensitiveString("buddy")))); merge.setAuthorization(auth); assertThat(filePart.getAuthorization(),is(auth)); } @Test public void shouldAddToFirstEditableWhenAddToTop() { BasicPipelineConfigs filePart = new BasicPipelineConfigs(PipelineConfigMother.pipelineConfig("pipeline2")); filePart.setOrigin(new FileConfigOrigin()); PipelineConfigs group = new MergePipelineConfigs(new BasicPipelineConfigs(PipelineConfigMother.pipelineConfig("pipeline1")),filePart); group.addToTop(PipelineConfigMother.pipelineConfig("pipeline3")); assertThat(filePart.hasPipeline(new CaseInsensitiveString("pipeline3")),is(true)); assertThat(group.hasPipeline(new CaseInsensitiveString("pipeline3")),is(true)); } @Test public void shouldReturnIndexOfPipeline() { PipelineConfigs group = new MergePipelineConfigs(new BasicPipelineConfigs( PipelineConfigMother.pipelineConfig("pipeline1"),PipelineConfigMother.pipelineConfig("pipeline2"))); PipelineConfig pipelineConfig = group.findBy(new CaseInsensitiveString("pipeline2")); assertThat(group.indexOf(pipelineConfig),is(1)); } @Test public void shouldApplyChangesToPipelineWhenPartEditable() { BasicPipelineConfigs filePart = new BasicPipelineConfigs(PipelineConfigMother.pipelineConfig("pipeline1")); filePart.setOrigin(new FileConfigOrigin()); PipelineConfigs group = new MergePipelineConfigs(filePart); PipelineConfig pipelineConfig = (PipelineConfig) group.get(0).clone(); pipelineConfig.setLabelTemplate("blah"); group.update(group.getGroup(), pipelineConfig, "pipeline1"); assertThat(group.get(0).getLabelTemplate(), is("blah")); } @Test(expected = RuntimeException.class) public void shouldFailToUpdateName() { PipelineConfigs group = new MergePipelineConfigs( new BasicPipelineConfigs(PipelineConfigMother.pipelineConfig("pipeline1")), new BasicPipelineConfigs(PipelineConfigMother.pipelineConfig("pipeline2"))); group.setConfigAttributes(m(BasicPipelineConfigs.GROUP, "my-new-group")); assertThat(group.getGroup(), is("my-new-group")); } @Test(expected = RuntimeException.class) public void shouldSetToDefaultGroupWithGroupNameIsEmptyString() { PipelineConfigs pipelineConfigs = new MergePipelineConfigs(new BasicPipelineConfigs()); pipelineConfigs.setGroup(""); assertThat(pipelineConfigs.getGroup(), is(BasicPipelineConfigs.DEFAULT_GROUP)); } private List privileges(final Authorization.PrivilegeState admin, final Authorization.PrivilegeState operate, final Authorization.PrivilegeState view) { return a(m(Authorization.PrivilegeType.ADMIN.toString(), admin.toString(), Authorization.PrivilegeType.OPERATE.toString(), operate.toString(), Authorization.PrivilegeType.VIEW.toString(), view.toString())); } // 2 parts and more cases @Test public void shouldReturnTrueIfPipelineExist_When2ConfigParts() { PipelineConfigs part1 = new BasicPipelineConfigs(PipelineConfigMother.pipelineConfig("pipeline1")); PipelineConfigs part2 = new BasicPipelineConfigs(PipelineConfigMother.pipelineConfig("pipeline2")); MergePipelineConfigs merge = new MergePipelineConfigs(part1,part2); assertThat("shouldReturnTrueIfPipelineExist", merge.hasPipeline(new CaseInsensitiveString("pipeline1")), is(true)); assertThat("shouldReturnTrueIfPipelineExist", merge.hasPipeline(new CaseInsensitiveString("pipeline2")), is(true)); } @Test public void shouldReturnFalseIfPipelineNotExist_When2ConfigParts() { PipelineConfigs part1 = new BasicPipelineConfigs(PipelineConfigMother.pipelineConfig("pipeline1")); PipelineConfigs part2 = new BasicPipelineConfigs(PipelineConfigMother.pipelineConfig("pipeline2")); MergePipelineConfigs merge = new MergePipelineConfigs(part2); assertThat("shouldReturnFalseIfPipelineNotExist", merge.hasPipeline(new CaseInsensitiveString("not-exist")), is(false)); } @Test public void shouldReturnTrueIfAuthorizationIsNotDefined_When2ConfigParts() { BasicPipelineConfigs filePart = new BasicPipelineConfigs(); filePart.setOrigin(new FileConfigOrigin()); MergePipelineConfigs merge = new MergePipelineConfigs(new BasicPipelineConfigs(), filePart); assertThat(merge.hasViewPermission(new CaseInsensitiveString("anyone"), null), is(true)); } @Test public void shouldReturnAuthorizationFromFileIfDefined_When2ConfigParts() { BasicPipelineConfigs part1 = new BasicPipelineConfigs(); Authorization fileAuth = new Authorization(); part1.setAuthorization(fileAuth); part1.setOrigin(new FileConfigOrigin()); BasicPipelineConfigs part2 = new BasicPipelineConfigs(); part2.setAuthorization(new Authorization()); MergePipelineConfigs merge = new MergePipelineConfigs(part1,part2); assertThat(merge.getAuthorization(),is(fileAuth)); } @Test public void shouldReturnFalseIfViewPermissionIsNotDefined_When2ConfigParts() { BasicPipelineConfigs filePart = new BasicPipelineConfigs(PipelineConfigMother.pipelineConfig("pipeline3")); filePart.setOrigin(new FileConfigOrigin()); PipelineConfigs group = new MergePipelineConfigs( new BasicPipelineConfigs(PipelineConfigMother.pipelineConfig("pipeline1")), new BasicPipelineConfigs(PipelineConfigMother.pipelineConfig("pipeline2")),filePart); group.getAuthorization().getOperationConfig().add(new AdminUser(new CaseInsensitiveString("jez"))); assertThat(group.hasViewPermission(new CaseInsensitiveString("jez"), null), is(false)); } @Test public void shouldReturnTrueForOperatePermissionIfAuthorizationIsNotDefined_When2ConfigParts() { BasicPipelineConfigs filePart = new BasicPipelineConfigs(); filePart.setOrigin(new FileConfigOrigin()); assertThat(new MergePipelineConfigs(filePart, new BasicPipelineConfigs()) .hasOperatePermission(new CaseInsensitiveString("anyone"), null), is(true)); } @Test public void validate_shouldMakeSureTheNameIsAppropriate_When2ConfigParts() { PipelineConfigs group = new MergePipelineConfigs(new BasicPipelineConfigs(),new BasicPipelineConfigs()); group.validate(null); assertThat(group.errors().on(BasicPipelineConfigs.GROUP), is("Invalid group name 'null'. This must be alphanumeric and can contain underscores and periods (however, it cannot start with a period). The maximum allowed length is 255 characters.")); } @Test(expected = IllegalArgumentException.class) public void shouldThrowOnPartsWithDifferentGroupNames(){ PipelineConfigs group = new MergePipelineConfigs(new BasicPipelineConfigs("one",null),new BasicPipelineConfigs("two",null)); } @Test public void shouldValidateThatPipelineNameIsUnique_When2ConfigParts() { PipelineConfig first = PipelineConfigMother.pipelineConfig("first"); PipelineConfig duplicate = PipelineConfigMother.pipelineConfig("first"); PipelineConfigs group = new MergePipelineConfigs( new BasicPipelineConfigs(first, PipelineConfigMother.pipelineConfig("second")), new BasicPipelineConfigs(duplicate, PipelineConfigMother.pipelineConfig("third"))); group.validate(null); assertThat(duplicate.errors().on(PipelineConfig.NAME), is("You have defined multiple pipelines called 'first'. Pipeline names are case-insensitive and must be unique.")); assertThat(first.errors().on(PipelineConfig.NAME), is("You have defined multiple pipelines called 'first'. Pipeline names are case-insensitive and must be unique.")); } @Test public void shouldValidateNameUniqueness_When2ConfigParts() { PipelineConfig first = PipelineConfigMother.pipelineConfig("first"); PipelineConfig duplicate = PipelineConfigMother.pipelineConfig("first"); PipelineConfigs group = new MergePipelineConfigs( new BasicPipelineConfigs(first, PipelineConfigMother.pipelineConfig("second")), new BasicPipelineConfigs(duplicate, PipelineConfigMother.pipelineConfig("third"))); Map<String, PipelineConfigs> nameToConfig = new HashMap<>(); List<PipelineConfigs> visited = new ArrayList(); group.validateNameUniqueness(nameToConfig); } @Test public void shouldReturnSizeSummedFrom2ConfigParts(){ PipelineConfigs group = new MergePipelineConfigs( new BasicPipelineConfigs(PipelineConfigMother.pipelineConfig("pipeline1")), new BasicPipelineConfigs(PipelineConfigMother.pipelineConfig("pipeline2"))); assertThat(group.size(),is(2)); } @Test public void shouldReturnTrueWhenAllPartsEmpty(){ PipelineConfigs group = new MergePipelineConfigs( new BasicPipelineConfigs(), new BasicPipelineConfigs()); assertThat(group.isEmpty(),is(true)); } @Test public void shouldReturnFalseSomePartIsNotEmpty(){ PipelineConfigs group = new MergePipelineConfigs( new BasicPipelineConfigs(PipelineConfigMother.pipelineConfig("pipeline1")), new BasicPipelineConfigs()); assertThat(group.isEmpty(),is(false)); } @Test public void shouldReturnTrueWhenContainsPipeline() { PipelineConfig pipe1 = PipelineConfigMother.pipelineConfig("pipeline1"); PipelineConfigs group = new MergePipelineConfigs( new BasicPipelineConfigs(pipe1), new BasicPipelineConfigs()); assertThat(group.contains(pipe1),is(true)); } @Test public void shouldReturnFalseWhenDoesNotContainPipeline() { PipelineConfig pipe1 = PipelineConfigMother.pipelineConfig("pipeline1"); PipelineConfigs group = new MergePipelineConfigs( new BasicPipelineConfigs(pipe1), new BasicPipelineConfigs()); assertThat(group.contains(PipelineConfigMother.pipelineConfig("pipeline2")),is(false)); } @Test public void shouldReturnPipelinesInOrder(){ PipelineConfig pipeline1 = PipelineConfigMother.pipelineConfig("pipeline1"); PipelineConfig pipeline3 = PipelineConfigMother.pipelineConfig("pipeline3"); PipelineConfig pipeline5 = PipelineConfigMother.pipelineConfig("pipeline5"); PipelineConfig pipeline2 = PipelineConfigMother.pipelineConfig("pipeline2"); PipelineConfig pipeline4 = PipelineConfigMother.pipelineConfig("pipeline4"); PipelineConfigs group = new MergePipelineConfigs( new BasicPipelineConfigs(pipeline1, pipeline2), new BasicPipelineConfigs(pipeline3), new BasicPipelineConfigs(pipeline4, pipeline5)); assertThat(group.get(0),is(pipeline1)); assertThat(group.get(1),is(pipeline2)); assertThat(group.get(2),is(pipeline3)); assertThat(group.get(3),is(pipeline4)); assertThat(group.get(4),is(pipeline5)); } @Test public void shouldReturnFirstEditablePartWhenExists(){ PipelineConfig pipe1 = PipelineConfigMother.pipelineConfig("pipeline1"); BasicPipelineConfigs part1 = new BasicPipelineConfigs(pipe1); part1.setOrigin(new FileConfigOrigin()); MergePipelineConfigs group = new MergePipelineConfigs( part1, new BasicPipelineConfigs()); assertThat(group.getFirstEditablePartOrNull(), Matchers.<PipelineConfigs>is(part1)); } @Test public void shouldReturnNullWhenFirstEditablePartNotExists(){ PipelineConfig pipe1 = PipelineConfigMother.pipelineConfig("pipeline1"); BasicPipelineConfigs part1 = new BasicPipelineConfigs(pipe1); MergePipelineConfigs group = new MergePipelineConfigs( part1, new BasicPipelineConfigs()); assertNull(group.getFirstEditablePartOrNull()); } @Test public void shouldReturnPartWithPipelineWhenExists(){ PipelineConfig pipe1 = PipelineConfigMother.pipelineConfig("pipeline1"); BasicPipelineConfigs part1 = new BasicPipelineConfigs(pipe1); part1.setOrigin(new FileConfigOrigin()); MergePipelineConfigs group = new MergePipelineConfigs( part1, new BasicPipelineConfigs(PipelineConfigMother.pipelineConfig("pipeline2"))); assertThat(group.getPartWithPipeline(new CaseInsensitiveString("pipeline1")), Matchers.<PipelineConfigs>is(part1)); } @Test public void shouldReturnNullPartWithPipelineNotExists(){ PipelineConfig pipe1 = PipelineConfigMother.pipelineConfig("pipeline1"); BasicPipelineConfigs part1 = new BasicPipelineConfigs(pipe1); MergePipelineConfigs group = new MergePipelineConfigs( part1, new BasicPipelineConfigs()); assertNull(group.getPartWithPipeline(new CaseInsensitiveString("pipelineX"))); } @Test public void shouldAddPipelineToFirstEditablePartWhenExists(){ PipelineConfig pipe1 = PipelineConfigMother.pipelineConfig("pipeline1"); BasicPipelineConfigs part1 = new BasicPipelineConfigs(pipe1); part1.setOrigin(new FileConfigOrigin()); MergePipelineConfigs group = new MergePipelineConfigs( part1, new BasicPipelineConfigs()); PipelineConfig pipeline2 = PipelineConfigMother.pipelineConfig("pipeline2"); group.add(pipeline2); assertThat(group.contains(pipeline2),is(true)); } @Test public void shouldBombWhenAddPipelineAndNoEditablePartExists(){ PipelineConfig pipe1 = PipelineConfigMother.pipelineConfig("pipeline1"); BasicPipelineConfigs part1 = new BasicPipelineConfigs(pipe1); MergePipelineConfigs group = new MergePipelineConfigs( part1, new BasicPipelineConfigs()); PipelineConfig pipeline2 = PipelineConfigMother.pipelineConfig("pipeline2"); try { group.add(pipeline2); } catch (Exception ex) { assertThat(ex.getMessage(),is("No editable configuration sources")); return; } fail("exception not thrown"); } @Test public void shouldFailToAddPipelineAtIndex_WhenWouldLandInNonEditablePart() { PipelineConfig pipeline0 = PipelineConfigMother.pipelineConfig("pipeline0"); PipelineConfig pipeline1 = PipelineConfigMother.pipelineConfig("pipeline1"); PipelineConfig pipeline3 = PipelineConfigMother.pipelineConfig("pipeline3"); PipelineConfig pipeline5 = PipelineConfigMother.pipelineConfig("pipeline5"); PipelineConfig pipeline2 = PipelineConfigMother.pipelineConfig("pipeline2"); PipelineConfig pipeline4 = PipelineConfigMother.pipelineConfig("pipeline4"); BasicPipelineConfigs pipelineConfigsMiddle = new BasicPipelineConfigs(pipeline3); pipelineConfigsMiddle.setOrigin(new FileConfigOrigin()); BasicPipelineConfigs bottom = new BasicPipelineConfigs(pipeline0, pipeline1, pipeline2); BasicPipelineConfigs top = new BasicPipelineConfigs(pipeline4, pipeline5); bottom.setOrigin(new RepoConfigOrigin()); top.setOrigin(new RepoConfigOrigin()); PipelineConfigs group = new MergePipelineConfigs( bottom, pipelineConfigsMiddle, top); PipelineConfig p1 = PipelineConfigMother.pipelineConfig("pipelineToInsert"); tryAddAndAssertThatFailed(group, p1, 0); tryAddAndAssertThatFailed(group, p1, 1); tryAddAndAssertThatFailed(group, p1, 2); tryAddAndAssertThatFailed(group, p1, 5); tryAddAndAssertThatFailed(group, p1, 4); } @Test public void shouldReturnOriginAsASumOfAllOrigins() { BasicPipelineConfigs fileConfigs = new BasicPipelineConfigs(PipelineConfigMother.pipelineConfig("pipeline1")); fileConfigs.setOrigin(new FileConfigOrigin()); BasicPipelineConfigs remoteConfigs = new BasicPipelineConfigs(PipelineConfigMother.pipelineConfig("pipeline2")); remoteConfigs.setOrigin(new RepoConfigOrigin()); PipelineConfigs group = new MergePipelineConfigs(fileConfigs, remoteConfigs); ConfigOrigin allOrigins = group.getOrigin(); assertThat(allOrigins instanceof MergeConfigOrigin,is(true)); MergeConfigOrigin mergeConfigOrigin = (MergeConfigOrigin)allOrigins; assertThat(mergeConfigOrigin.size(),is(2)); assertThat(mergeConfigOrigin.contains(new FileConfigOrigin()),is(true)); assertThat(mergeConfigOrigin.contains(new RepoConfigOrigin()),is(true)); } private void tryAddAndAssertThatFailed(PipelineConfigs group, PipelineConfig p1, int index) { try { group.add(index,p1); } catch (Exception ex) { assertThat(ex.getMessage(),is("Cannot add pipeline to non-editable configuration part")); return; } fail(String.format("should have thrown when adding at %s",index)); } @Test public void shouldAddPipelineAtIndex_WhenWouldLandInEditablePart() { PipelineConfig pipeline0 = PipelineConfigMother.pipelineConfig("pipeline0"); PipelineConfig pipeline1 = PipelineConfigMother.pipelineConfig("pipeline1"); PipelineConfig pipeline3 = PipelineConfigMother.pipelineConfig("pipeline3"); PipelineConfig pipeline5 = PipelineConfigMother.pipelineConfig("pipeline5"); PipelineConfig pipeline2 = PipelineConfigMother.pipelineConfig("pipeline2"); PipelineConfig pipeline4 = PipelineConfigMother.pipelineConfig("pipeline4"); BasicPipelineConfigs pipelineConfigsMiddle = new BasicPipelineConfigs(pipeline3); pipelineConfigsMiddle.setOrigin(new FileConfigOrigin()); BasicPipelineConfigs bottom = new BasicPipelineConfigs(pipeline0, pipeline1, pipeline2); BasicPipelineConfigs top = new BasicPipelineConfigs(pipeline4, pipeline5); bottom.setOrigin(new RepoConfigOrigin()); top.setOrigin(new RepoConfigOrigin()); PipelineConfigs group = new MergePipelineConfigs( bottom, pipelineConfigsMiddle, top); PipelineConfig p1 = PipelineConfigMother.pipelineConfig("pipelineToInsert"); group.add(3,p1); assertThat(group, hasItem(p1)); assertThat(pipelineConfigsMiddle, hasItem(p1)); } }