/* * 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.server.service.builders; import com.thoughtworks.go.config.*; import com.thoughtworks.go.config.materials.MaterialConfigs; import com.thoughtworks.go.config.materials.dependency.DependencyMaterial; import com.thoughtworks.go.domain.*; import com.thoughtworks.go.domain.buildcause.BuildCause; import com.thoughtworks.go.domain.builder.FetchArtifactBuilder; import com.thoughtworks.go.domain.materials.dependency.DependencyMaterialRevision; import com.thoughtworks.go.helper.*; import com.thoughtworks.go.server.service.UpstreamPipelineResolver; import org.hamcrest.Matchers; import org.junit.After; import org.junit.Before; import org.junit.Test; import java.io.File; import java.util.Date; import static org.hamcrest.Matchers.is; import static org.junit.Assert.*; import static org.mockito.Mockito.*; public class FetchTaskBuilderTest { private static final String LABEL = "1.01"; private UpstreamPipelineResolver resolver; private FetchTaskBuilder fetchTaskBuilder; private BuilderFactory builderFactory; @Before public void setUp() { CruiseConfig config = GoConfigMother.configWithPipelines("random_pipeline", "uppest_lookalike", "uppest_stream", "upstreams_peer", "upstream", "downstream", "dummy"); PipelineConfig randomPipeline = config.pipelineConfigByName(new CaseInsensitiveString("random_pipeline")); randomPipeline.add(StageConfigMother.stageConfig("random-stage1", new JobConfigs(new JobConfig("random-job1")))); PipelineConfig uppestLookalike = config.pipelineConfigByName(new CaseInsensitiveString("uppest_lookalike")); uppestLookalike.add(StageConfigMother.stageConfig("uppest-stage1", new JobConfigs(new JobConfig("uppest-job1")))); PipelineConfig uppestStream = config.pipelineConfigByName(new CaseInsensitiveString("uppest_stream")); uppestStream.add(StageConfigMother.stageConfig("uppest-stage1", new JobConfigs(new JobConfig("uppest-job1")))); uppestStream.add(StageConfigMother.stageConfig("uppest-stage2", new JobConfigs(new JobConfig("uppest-job2")))); uppestStream.add(StageConfigMother.stageConfig("uppest-stage3", new JobConfigs(new JobConfig("uppest-job3")))); PipelineConfig upstream = config.pipelineConfigByName(new CaseInsensitiveString("upstream")); upstream.setMaterialConfigs(new MaterialConfigs(MaterialConfigsMother.dependencyMaterialConfig("uppest_stream", "uppest-stage2"))); upstream.add(StageConfigMother.stageConfig("up-stage1", new JobConfigs(new JobConfig("up-job1")))); upstream.add(StageConfigMother.stageConfig("up-stage2", new JobConfigs(new JobConfig("up-job2")))); PipelineConfig downstream = config.pipelineConfigByName(new CaseInsensitiveString("downstream")); downstream.setMaterialConfigs(new MaterialConfigs(MaterialConfigsMother.dependencyMaterialConfig("upstream", "up-stage1"))); downstream.get(0).getJobs().get(0).addTask(new FetchTask(new CaseInsensitiveString("foo"), new CaseInsensitiveString("bar"), new CaseInsensitiveString("baz"), "abcd", "efg")); resolver = mock(UpstreamPipelineResolver.class); builderFactory = mock(BuilderFactory.class); fetchTaskBuilder = new FetchTaskBuilder(); } @After public void tearDown() { verifyNoMoreInteractions(resolver); } @Test public void shouldUseNameAndLabelFromPipelineWhenPipelineNameOfFetchTaskIsEmpty() { FetchTask fetchTask = new FetchTask(); fetchTask.setSrcfile("a.txt"); Pipeline pipeline = pipeline(LABEL); FetchArtifactBuilder builder = (FetchArtifactBuilder) fetchTaskBuilder.createBuilder(builderFactory, fetchTask, pipeline, resolver); assertThat(builder.getJobIdentifier().getPipelineName(), is("cruise")); assertThat(builder.getJobIdentifier().getPipelineLabel(), is(LABEL)); } @Test public void shouldUseCorrectStageCounterWhenFetchingFromSamePipelineAndStageThatHasBeenRun() { FetchTask fetchTask = new FetchTask(new CaseInsensitiveString("mingle"), new CaseInsensitiveString("dev"), new CaseInsensitiveString("linux-firefox"), "", ""); Pipeline pipeline = pipelineWithStage("mingle", 1, "label-1", "dev", 2); FetchArtifactBuilder builder = (FetchArtifactBuilder) fetchTaskBuilder.createBuilder(builderFactory, fetchTask, pipeline, resolver); assertThat(builder.getJobIdentifier(), Matchers.is(new JobIdentifier("mingle", 1, "label-1", "dev", "2", "linux-firefox", 0L))); } @Test public void shouldUseCorrectStageCounterWhenFetchingFromDependencyStage() { FetchTask fetchTask = new FetchTask(new CaseInsensitiveString("mingle"), new CaseInsensitiveString("dev"), new CaseInsensitiveString("linux-firefox"), "", ""); Pipeline pipeline = pipelineWithDepencencyMaterial("cruise", "mingle", 1, "label-1", "dev", 2); FetchArtifactBuilder builder = (FetchArtifactBuilder) fetchTaskBuilder.createBuilder(builderFactory, fetchTask, pipeline, resolver); assertThat(builder.getJobIdentifier(), is(new JobIdentifier("mingle", 1, "label-1", "dev", "2", "linux-firefox", 0L))); } @Test public void shouldUseLatestStageWhenFetchingFromDifferentStageInDependencyPipeline() { FetchTask fetchTask = new FetchTask(new CaseInsensitiveString("mingle"), new CaseInsensitiveString("ft"), new CaseInsensitiveString("linux-firefox"), "", ""); Pipeline pipeline = pipelineWithDepencencyMaterial("cruise", "mingle", 1, "label-1", "dev", 2); FetchArtifactBuilder builder = (FetchArtifactBuilder) fetchTaskBuilder.createBuilder(builderFactory, fetchTask, pipeline, resolver); assertThat(builder.getJobIdentifier(), is(new JobIdentifier("mingle", 1, "label-1", "ft", "latest", "linux-firefox", 0L))); } @Test public void shouldNotSupportFetchingArtifactsFromPipelineWhichIsNotADependentMaterial() { FetchTask fetchTask = new FetchTask(new CaseInsensitiveString("any-pipeline"), new CaseInsensitiveString("ft"), new CaseInsensitiveString("linux-firefox"), "", ""); Pipeline pipeline = pipelineWithDepencencyMaterial("cruise", "mingle", 1, "10", "dev", 2); try { fetchTaskBuilder.createBuilder(builderFactory, fetchTask, pipeline, resolver); fail("should not support fetching artifacts from a pipeline which is not dependency material"); } catch (Exception e) { assertThat(e.getMessage(), is("Pipeline [cruise] tries to fetch artifact from " + "job [any-pipeline/ft/linux-firefox] which is not a dependency material")); } } @Test public void shouldFindStageCounterFromDependenciesWhenPipelineNameIsDifferent() { FetchTask fetchTask = new FetchTask(new CaseInsensitiveString("mingle"), new CaseInsensitiveString("dev"), new CaseInsensitiveString(""), "", ""); Pipeline pipeline = pipelineWithDepencencyMaterial("cruise", "mingle", 1, "10", "dev", 2); FetchArtifactBuilder builder = (FetchArtifactBuilder) fetchTaskBuilder.createBuilder(builderFactory, fetchTask, pipeline, resolver); assertThat(builder.getJobIdentifier().getStageCounter(), is("2")); } @Test public void shouldFetchFromCorrectAncestorStageInstance_InCaseOfLinerDependency() { FetchTask fetchTask = new FetchTask(new CaseInsensitiveString("uppest/up/down"), new CaseInsensitiveString("uppest-stage"), new CaseInsensitiveString("uppest-job"), "src", "dest"); Pipeline pipeline = pipelineWithDepencencyMaterial("downest", "down", 1, "down-1", "down-stage", 2); DependencyMaterialRevision revisionOfDown = DependencyMaterialRevision.create("down/1/down-stage/2", "down-1"); when(resolver.buildCauseFor(revisionOfDown.getPipelineName(), revisionOfDown.getPipelineCounter())).thenReturn(pipelineWithDepencencyMaterial("down", "up", 5, "up-5", "up-stage", 3).getBuildCause()); DependencyMaterialRevision revisionOfUp = DependencyMaterialRevision.create("up/5/up-stage/3", "up-5"); when(resolver.buildCauseFor(revisionOfUp.getPipelineName(), revisionOfUp.getPipelineCounter())).thenReturn(pipelineWithDepencencyMaterial("up", "uppest", 3, "uppest-3", "uppest-stage", 4).getBuildCause()); FetchArtifactBuilder builder = (FetchArtifactBuilder) fetchTaskBuilder.createBuilder(builderFactory, fetchTask, pipeline, resolver); verify(resolver).buildCauseFor(revisionOfDown.getPipelineName(), revisionOfDown.getPipelineCounter()); verify(resolver).buildCauseFor(revisionOfUp.getPipelineName(), revisionOfUp.getPipelineCounter()); assertThat(builder.getJobIdentifier(), is(new JobIdentifier("uppest", 3, "uppest-3", "uppest-stage", "4", "uppest-job", 0l))); } @Test public void shouldGetTheRightDestAndJobLocatorOnAgent() { Pipeline pipeline = pipelineWithDepencencyMaterial("cruise", "mingle", 1, "label-1", "dev", 2); FetchTask fetchTask = new FetchTask(new CaseInsensitiveString("mingle"), new CaseInsensitiveString("dev"), new CaseInsensitiveString("one"), "", "dest"); FetchHandler fetchHandler = fetchTaskBuilder.getHandler(fetchTask, pipeline.getName()); FetchArtifactBuilder builder = (FetchArtifactBuilder) fetchTaskBuilder.createBuilder(builderFactory, fetchTask, pipeline, resolver); assertThat(fetchHandler, is(new FileHandler(new File("pipelines/cruise/dest"), getSrc()))); assertThat(builder.jobLocatorForDisplay(), is("mingle/label-1/dev/2/one")); } @Test public void shouldUsePipelineCounterWhenFetchingArtifactFromDependentPipeline() { FetchTask fetchTask = new FetchTask(new CaseInsensitiveString("mingle"), new CaseInsensitiveString("dev"), new CaseInsensitiveString("linux-firefox"), "log.xml", "dest"); Pipeline pipeline = pipelineWithDepencencyMaterial("cruise", "mingle", 1, "label-1", "dev", 2); FetchArtifactBuilder builder = (FetchArtifactBuilder) fetchTaskBuilder.createBuilder(builderFactory, fetchTask, pipeline, resolver); assertThat(builder.artifactLocator(), is("mingle/1/dev/2/linux-firefox/log.xml")); } @Test public void describeForSamePipeline() throws Exception { FetchTask fetchTask = new FetchTask(new CaseInsensitiveString(""), new CaseInsensitiveString("dev"), new CaseInsensitiveString("windows-3"), "cruise.zip", "dest\\subfolder"); fetchTaskBuilder.createBuilder(builderFactory, fetchTask, pipeline(LABEL), resolver); assertThat(fetchTask.describe(), is("fetch artifact [cruise.zip] => [dest/subfolder] from [cruise/dev/windows-3]")); } @Test public void shouldNormalizeDestOnAgent() { FetchTask fetchTask = new FetchTask(new CaseInsensitiveString("mingle"), new CaseInsensitiveString("dev"), new CaseInsensitiveString("one"), "", "dest\\pavan"); FetchHandler fetchHandler = fetchTaskBuilder.getHandler(fetchTask, "cruise"); assertThat(fetchHandler, is(new FileHandler(new File("pipelines/cruise/dest/pavan"), getSrc()))); } @Test public void shouldSupportNullForDest() { FetchTask fetchTask = new FetchTask(new CaseInsensitiveString("mingle"), new CaseInsensitiveString("dev"), new CaseInsensitiveString("one"), "", null); FetchHandler fetchHandler = fetchTaskBuilder.getHandler(fetchTask, "cruise"); assertThat(fetchHandler, is(new FileHandler(new File("pipelines/cruise"), getSrc()))); } @Test public void shouldUseTheDirectoryHandler() { Pipeline pipeline = pipelineWithStage("mingle", 1, LABEL, "dev", 1); FetchTask fetchTask = new FetchTask(new CaseInsensitiveString(pipeline.getName()), new CaseInsensitiveString(pipeline.getFirstStage().getName()), new CaseInsensitiveString("windows-3"), "", "dest\\subfolder"); fetchTask.setSrcdir("log"); FetchHandler actual = fetchTaskBuilder.getHandler(fetchTask, pipeline.getName()); File folderOnAgent = new File("pipelines/mingle/dest/subfolder"); assertThat(actual, is(new DirHandler("log", folderOnAgent))); } @Test public void shouldUseTheFileHandler() { Pipeline pipeline = pipelineWithStage("mingle", 1, LABEL, "dev", 1); FetchTask fetchTask = new FetchTask(new CaseInsensitiveString(pipeline.getName()), new CaseInsensitiveString(pipeline.getFirstStage().getName()), new CaseInsensitiveString("windows-3"), "cruise.zip", "dest\\subfolder"); FetchHandler actual = fetchTaskBuilder.getHandler(fetchTask, pipeline.getName()); File folderOnAgent = new File("pipelines/mingle/dest/subfolder"); assertThat(actual, is(new FileHandler(new File(folderOnAgent, "cruise.zip"), getSrc()))); } @Test public void shouldThrowExceptionWithAppropriateMessageWhenAncestorPipelineChanged() { Pipeline downInstance = pipelineWithDepencencyMaterial("down", "up3", 1, "up3-label", "up3-stage", 1); Pipeline up3Instance = pipelineWithDepencencyMaterial("up3", "up2", 1, "up2-label", "up2-stage", 1); Pipeline up2Instance = pipelineWithDepencencyMaterial("up2", "old", 1, "old-label", "old-stage", 1); when(resolver.buildCauseFor("up3", 1)).thenReturn(up3Instance.getBuildCause()); when(resolver.buildCauseFor("up2", 1)).thenReturn(up2Instance.getBuildCause()); FetchTask fetchTask = new FetchTask(new CaseInsensitiveString("up1/up2/up3"), new CaseInsensitiveString("up3-stage"), new CaseInsensitiveString("up3-job"), "src", "dest"); try { fetchTaskBuilder.createBuilder(builderFactory, fetchTask, downInstance, resolver); fail("should have failed"); } catch (Exception e) { assertEquals(String.format("Pipeline [down] could not fetch artifact [%s]. Unable to resolve revision for [up1] from build cause", fetchTask), e.getMessage()); } finally { verify(resolver).buildCauseFor("up3", 1); verify(resolver).buildCauseFor("up2", 1); } } @Test public void shouldThrowExceptionWithAppropriateMessageWhenFetchArtifactPipelinePathBroken() { Pipeline downInstance = pipelineWithDepencencyMaterial("down", "up3", 1, "up3-label", "up3-stage", 1); Pipeline up3Instance = pipelineWithDepencencyMaterial("up3", "old", 1, "old-label", "old-stage", 1); when(resolver.buildCauseFor("up3", 1)).thenReturn(up3Instance.getBuildCause()); FetchTask fetchTask = new FetchTask(new CaseInsensitiveString("up1/up2/up3"), new CaseInsensitiveString("up3-stage"), new CaseInsensitiveString("up3-job"), "src", "dest"); try { fetchTaskBuilder.createBuilder(builderFactory, fetchTask, downInstance, resolver); fail("should have failed"); } catch (Exception e) { assertEquals(String.format("Pipeline [down] could not fetch artifact [%s]. Unable to resolve revision for [up2] from build cause", fetchTask), e.getMessage()); } finally { verify(resolver).buildCauseFor("up3", 1); } } private Pipeline pipelineWithStage(String pipelineName, int pipelineCounter, String label, String stagename, int stageCounter) { Stage stage = StageMother.custom(stagename); stage.setCounter(stageCounter); Pipeline pipeline = PipelineMother.pipeline(pipelineName, stage); pipeline.setCounter(pipelineCounter); pipeline.setLabel(label); return pipeline; } private Pipeline pipelineWithDepencencyMaterial(String currentPipeline, String upstreamPipelineName, int upstreamPipelineCounter, String upstreamPipelineLabel, String upstreamStageName, int upstreamStageCounter) { Pipeline pipeline = PipelineMother.pipeline(currentPipeline, new NullStage("Stage")); pipeline.setBuildCause( buildCauseWithDependencyMaterial(upstreamPipelineName, upstreamPipelineCounter, upstreamPipelineLabel, upstreamStageName, upstreamStageCounter)); return pipeline; } private BuildCause buildCauseWithDependencyMaterial(String upstreamPipelineName, int upstreamPipelineCounter, String upstreamPipelineLabel, String upstreamStageName, int upstreamStageCounter) { BuildCause buildCause = BuildCause.createWithEmptyModifications(); MaterialRevisions materialRevisions = new MaterialRevisions(); DependencyMaterialRevision materialRevision = DependencyMaterialRevision.create(upstreamPipelineName, upstreamPipelineCounter, upstreamPipelineLabel, upstreamStageName, upstreamStageCounter); MaterialRevision withRevision = materialRevision.convert(new DependencyMaterial( new CaseInsensitiveString(upstreamPipelineName), new CaseInsensitiveString(upstreamStageName)), new Date()); materialRevisions.addRevision(withRevision); buildCause.setMaterialRevisions(materialRevisions); return buildCause; } private String getSrc() { return ""; } private Pipeline pipeline(String label) { Pipeline pipeline = PipelineMother.pipeline("cruise", new NullStage("Stage")); pipeline.setLabel(label); return pipeline; } }