private void setupJobWithTasks(CruiseConfig config, Task... tasks) throws Exception { goConfigMother.addPipeline(config, "cruise", "dev", "linux-firefox"); JobConfig job = config.jobConfigByName("cruise", "dev", "linux-firefox", true); for (Task task : tasks) { job.addTask(task); } }
@Test public void shouldEncryptSecurePropertiesForOnlyFetchExternalArtifactTask() { JobConfig jobConfig = new JobConfig(new CaseInsensitiveString("job")); FetchPluggableArtifactTask mockFetchExternalArtifactTask = mock(FetchPluggableArtifactTask.class); jobConfig.addTask(mockFetchExternalArtifactTask); jobConfig.encryptSecureProperties(new BasicCruiseConfig(), new PipelineConfig(), jobConfig); verify(mockFetchExternalArtifactTask).encryptSecureProperties(any(CruiseConfig.class), any(PipelineConfig.class), any(FetchPluggableArtifactTask.class)); }
@Test public void shouldGetAllFetchTasks() { PipelineConfig pipelineConfig = PipelineConfigMother.createPipelineConfig("foo bar", "stage1", "job1"); FetchTask firstFetch = new FetchTask(); JobConfig firstJob = pipelineConfig.getFirstStageConfig().getJobs().get(0); firstJob.addTask(firstFetch); firstJob.addTask(new AntTask()); JobConfig secondJob = new JobConfig(); secondJob.addTask(new ExecTask()); FetchTask secondFetch = new FetchTask(); secondJob.addTask(secondFetch); pipelineConfig.add(new StageConfig(new CaseInsensitiveString("stage-2"), new JobConfigs(secondJob))); List<FetchTask> fetchTasks = pipelineConfig.getFetchTasks(); assertThat(fetchTasks.size(), is(2)); assertThat(fetchTasks.contains(firstFetch), is(true)); assertThat(fetchTasks.contains(secondFetch), is(true)); }
@Test(timeout = 1000) public void shouldValidateLeadingAndTrailingSpacesOnExecCommandInReasonableTime() throws Exception { // See https://github.com/gocd/gocd/issues/3551 // This is only reproducible on longish strings, so don't try shortening the exec task length... String longPath = StringUtils.repeat("f", 100); CruiseConfig config = GoConfigMother.configWithPipelines("pipeline1"); config.findJob("pipeline1", "stage", "job").addTask(new ExecTask(longPath + " ", "arg1", (String) null)); output = new ByteArrayOutputStream(); try { xmlWriter.write(config, output, false); fail("expected to blow up"); } catch (XsdValidationException e) { assertThat(e.getMessage(), containsString("should conform to the pattern - \\S(.*\\S)?")); } }
@Test public void shouldValidateWorkingDirectory() { ExecTask task = new ExecTask("ls", "-l", "../../../assertTaskInvalid"); CruiseConfig config = GoConfigMother.configWithPipelines("pipeline"); PipelineConfig pipeline = config.pipelineConfigByName(new CaseInsensitiveString("pipeline")); StageConfig stage = pipeline.get(0); JobConfig job = stage.getJobs().get(0); job.addTask(task); List<ConfigErrors> errors = config.validateAfterPreprocess(); assertThat(errors.size(), is(1)); String message = "The path of the working directory for the custom command in job 'job' in stage 'stage' of pipeline 'pipeline' is outside the agent sandbox."; assertThat(errors.get(0).firstError(), is(message)); assertThat(task.errors().on(ExecTask.WORKING_DIR), is(message)); }
private static void addTask(JobConfig jobConfig) { jobConfig.setVariables(EnvironmentVariablesConfigMother.environmentVariables()); AntTask task = new AntTask(); task.setBuildFile("build-file"); task.setTarget("target"); task.setWorkingDirectory("working-directory"); jobConfig.addTask(task); }
@Test public void shouldEnsureStageNameUniqueness() { CruiseConfig cruiseConfig = new BasicCruiseConfig(); PipelineConfig pipelineConfig = goConfigMother.addPipeline(cruiseConfig, "pipeline1", "stage", "build"); JobConfig jobConfig = new JobConfig("my-build"); jobConfig.addTask(new ExecTask("ls", "-la", "tmp")); StageConfig stageConfig = new StageConfig(new CaseInsensitiveString("stage"), new JobConfigs(jobConfig)); pipelineConfig.addStageWithoutValidityAssertion(stageConfig); pipelineConfig.validate(null); assertThat(stageConfig.errors().getAllOn("name"), is(singletonList("You have defined multiple stages called 'stage'. Stage names are case-insensitive and must be unique."))); assertThat(pipelineConfig.get(0).errors().getAllOn("name"), is(singletonList("You have defined multiple stages called 'stage'. Stage names are case-insensitive and must be unique."))); assertThat(cruiseConfig.validateAfterPreprocess().get(0).getAllOn("name"), is(singletonList("You have defined multiple stages called 'stage'. Stage names are case-insensitive and must be unique."))); }
private StageConfig getStageConfig(String stageName, String jobName) { JobConfig jobConfig = new JobConfig(new CaseInsensitiveString(jobName)); jobConfig.addTask(new AntTask()); jobConfig.addTask(new ExecTask("command", "", "workingDir")); jobConfig.artifactConfigs().add(new BuildArtifactConfig("src", "dest")); jobConfig.addVariable("env1", "val1"); jobConfig.addResourceConfig("powerful"); JobConfigs jobConfigs = new JobConfigs(jobConfig); return new StageConfig(new CaseInsensitiveString(stageName), jobConfigs); }
@Test public void shouldErrorOutIfWorkingDirectoryIsOutsideTheCurrentWorkingDirectoryForTemplates() { CruiseConfig config = GoConfigMother.configWithPipelines("pipeline-blah"); BuildTask task = new AntTask(); task.setWorkingDirectory("/blah"); StageConfig stageConfig = StageConfigMother.manualStage("manualStage"); stageConfig.getJobs().get(0).addTask(task); PipelineTemplateConfig template = new PipelineTemplateConfig(new CaseInsensitiveString("some-template"), stageConfig); config.addTemplate(template); List<ConfigErrors> errors = config.validateAfterPreprocess(); assertThat(errors.size(), is(1)); String message = "Task of job 'default' in stage 'manualStage' of template 'some-template' has path '/blah' which is outside the working directory."; assertThat(task.errors().on(BuildTask.WORKING_DIRECTORY), is(message)); } }
@Test public void shouldNotSetTasksIfNoTasksGiven() throws Exception { config = new JobConfig(); AntTask task = new AntTask(); task.setTarget("hello"); config.addTask(task); config.setConfigAttributes(m()); AntTask taskAfterUpdate = (AntTask) config.getTasks().get(0); assertThat(taskAfterUpdate.getTarget(), is("hello")); assertThat(config.getTasks().size(), is(1)); config.setConfigAttributes(m(JobConfig.TASKS, null)); assertThat(config.getTasks().size(), is(0)); }
@Test public void shouldErrorOutForTemplates_WhenItHasATaskWithInvalidWorkingDirectory() { CruiseConfig cruiseConfig = GoConfigMother.configWithPipelines("some_pipeline"); StageConfig templateStage = StageConfigMother.stageWithTasks("templateStage"); ExecTask execTask = new ExecTask("ls", "-la", "/"); templateStage.getJobs().first().addTask(execTask); PipelineTemplateConfig template = new PipelineTemplateConfig(new CaseInsensitiveString("template_name"), templateStage); cruiseConfig.addTemplate(template); try { execTask.validateTask(ConfigSaveValidationContext.forChain(cruiseConfig, template, templateStage, templateStage.getJobs().first())); assertThat(execTask.errors().isEmpty(), is(false)); assertThat(execTask.errors().on(ExecTask.WORKING_DIR), is("The path of the working directory for the custom command in job 'job' in stage 'templateStage' of template 'template_name' is outside the agent sandbox.")); } catch (Exception e) { fail("should not have failed. Exception: " + e.getMessage()); } }
@Test public void shouldUseValidationErrorKeyAnnotationForFieldNameInCaseOfException() throws NoSuchFieldException { PipelineConfig pipelineConfig = PipelineConfigMother.createPipelineConfig("cruise", "dev", "ant","nant"); FetchTask task = new FetchTask(new CaseInsensitiveString("cruise"), new CaseInsensitiveString("dev"), new CaseInsensitiveString("ant"), "#a", "dest"); pipelineConfig.get(0).getJobs().getJob(new CaseInsensitiveString("nant")).addTask(task); new ParamResolver(new ParamSubstitutionHandlerFactory(params(param("foo", "pavan"), param("bar", "jj"))), fieldCache).resolve(pipelineConfig); assertThat(task.errors().isEmpty(), is(false)); assertThat(task.errors().on(FetchTask.SRC), is("Error when processing params for '#a' used in field 'src', # must be followed by a parameter pattern or escaped by another #")); }
@Test public void shouldValidateFetchTasksOfATemplateInTheContextOfPipelinesUsingTheTemplate() throws Exception { JobConfig jobConfig = new JobConfig(new CaseInsensitiveString("defaultJob")); jobConfig.addTask(new FetchTask(new CaseInsensitiveString("non-existent-pipeline"), new CaseInsensitiveString("stage"), new CaseInsensitiveString("job"), "src", "dest")); JobConfigs jobConfigs = new JobConfigs(jobConfig); StageConfig stageConfig = StageConfigMother.custom("stage", jobConfigs); PipelineTemplateConfig template = PipelineTemplateConfigMother.createTemplate("template", stageConfig); PipelineConfig pipelineConfig = PipelineConfigMother.pipelineConfigWithTemplate("pipeline", "template"); pipelineConfig.usingTemplate(template); BasicCruiseConfig cruiseConfig = GoConfigMother.defaultCruiseConfig(); cruiseConfig.addTemplate(template); cruiseConfig.addPipelineWithoutValidation("group", pipelineConfig); template.validateTree(ConfigSaveValidationContext.forChain(cruiseConfig), cruiseConfig, false); assertThat(template.errors().getAllOn("pipeline"), is(Arrays.asList("\"pipeline :: stage :: defaultJob\" tries to fetch artifact from pipeline \"non-existent-pipeline\" which does not exist."))); }
@Test public void shouldValidateFetchPluggableTasksOfATemplateInTheContextOfPipelinesUsingTheTemplate() throws Exception { JobConfig jobConfig = new JobConfig(new CaseInsensitiveString("defaultJob")); jobConfig.addTask(new FetchPluggableArtifactTask(new CaseInsensitiveString("non-existent-pipeline"), new CaseInsensitiveString("stage"), new CaseInsensitiveString("job"), "artifactId")); JobConfigs jobConfigs = new JobConfigs(jobConfig); StageConfig stageConfig = StageConfigMother.custom("stage", jobConfigs); PipelineTemplateConfig template = PipelineTemplateConfigMother.createTemplate("template", stageConfig); PipelineConfig pipelineConfig = PipelineConfigMother.pipelineConfigWithTemplate("pipeline", "template"); pipelineConfig.usingTemplate(template); BasicCruiseConfig cruiseConfig = GoConfigMother.defaultCruiseConfig(); cruiseConfig.addTemplate(template); cruiseConfig.addPipelineWithoutValidation("group", pipelineConfig); template.validateTree(ConfigSaveValidationContext.forChain(cruiseConfig), cruiseConfig, false); assertThat(template.errors().getAllOn("pipeline"), is(Arrays.asList("\"pipeline :: stage :: defaultJob\" tries to fetch artifact from pipeline \"non-existent-pipeline\" which does not exist."))); }
@Test public void shouldValidateTemplateStageUsedInDownstreamPipelines() { JobConfig jobConfigWithExecTask = new JobConfig(new CaseInsensitiveString("defaultJob")); jobConfigWithExecTask.addTask(new ExecTask("ls", "l", "server/config")); JobConfigs jobConfigs = new JobConfigs(jobConfigWithExecTask); StageConfig stageConfig = StageConfigMother.custom("stage", jobConfigs); PipelineTemplateConfig template = PipelineTemplateConfigMother.createTemplate("template", stageConfig); PipelineConfig upstreamPipelineUsingTemplate = PipelineConfigMother.pipelineConfigWithTemplate("pipeline", "template"); upstreamPipelineUsingTemplate.usingTemplate(template); //Pipeline and stage of upstreamPipelineUsingTemplate MaterialConfig dependency = new DependencyMaterialConfig(new CaseInsensitiveString("pipeline"), new CaseInsensitiveString("non-existent-stage")); PipelineConfig downStreamPipeline = PipelineConfigMother.pipelineConfig("downstreamPipeline", new MaterialConfigs(dependency)); BasicCruiseConfig cruiseConfig = GoConfigMother.defaultCruiseConfig(); cruiseConfig.addTemplate(template); cruiseConfig.addPipelineWithoutValidation("group", upstreamPipelineUsingTemplate); cruiseConfig.addPipelineWithoutValidation("group", downStreamPipeline); template.validateTree(ConfigSaveValidationContext.forChain(cruiseConfig), cruiseConfig, false); assertThat(template.errors().getAllOn("base"), is(Arrays.asList("Stage with name 'non-existent-stage' does not exist on pipeline 'pipeline', it is being referred to from pipeline 'downstreamPipeline' (cruise-config.xml)"))); }
@Test public void shouldFailValidationIfFetchArtifactPipelineIsNotAMaterial_PipelineConfigSave() { PipelineConfig upstream = new PipelineConfig(new CaseInsensitiveString("upstream-pipeline"), new MaterialConfigs(), new StageConfig(new CaseInsensitiveString("upstream-stage"), new JobConfigs(new JobConfig(new CaseInsensitiveString("upstream-job"))))); JobConfig job = new JobConfig(new CaseInsensitiveString("downstream-job")); FetchTask fetchTask = new FetchTask(new CaseInsensitiveString("upstream-pipeline"), new CaseInsensitiveString("upstream-stage"), new CaseInsensitiveString("upstream-job"), "quux.c", "bang-file"); job.addTask(fetchTask); PipelineConfig downstream = new PipelineConfig(new CaseInsensitiveString("downstream-pipeline"), new MaterialConfigs(), new StageConfig(new CaseInsensitiveString("downstream-stage"), new JobConfigs(job))); fetchTask.validateTree(PipelineConfigSaveValidationContext.forChain(true, "group", new BasicCruiseConfig(new BasicPipelineConfigs(upstream, downstream)), downstream, downstream.getFirstStageConfig(), downstream.getFirstStageConfig().getJobs().first())); assertThat(fetchTask.errors().isEmpty(), is(false)); assertThat(fetchTask.errors().on(FetchTask.PIPELINE_NAME), is("Pipeline \"downstream-pipeline\" tries to fetch artifact from pipeline \"upstream-pipeline\" which is not an upstream pipeline")); }
@Test public void shouldFailValidationIfFetchArtifactPipelineAndStageExistsButJobDoesNot_PipelineConfigSave() { PipelineConfig upstream = new PipelineConfig(new CaseInsensitiveString("upstream-pipeline"), new MaterialConfigs(), new StageConfig(new CaseInsensitiveString("upstream-stage"), new JobConfigs(new JobConfig(new CaseInsensitiveString("upstream-job"))))); JobConfig job = new JobConfig(new CaseInsensitiveString("downstream-job")); FetchTask fetchTask = new FetchTask(new CaseInsensitiveString("upstream-pipeline"), new CaseInsensitiveString("upstream-stage"), new CaseInsensitiveString("some-random-job"), "quux.c", "bang-file"); job.addTask(fetchTask); PipelineConfig downstream = new PipelineConfig(new CaseInsensitiveString("downstream-pipeline"), new MaterialConfigs(new DependencyMaterialConfig(upstream.name(), upstream.getFirstStageConfig().name())), new StageConfig(new CaseInsensitiveString("downstream-stage"), new JobConfigs(job))); fetchTask.validateTree(PipelineConfigSaveValidationContext.forChain(true, "group", new BasicCruiseConfig(new BasicPipelineConfigs(upstream, downstream)), downstream, downstream.getFirstStageConfig(), downstream.getFirstStageConfig().getJobs().first())); assertThat(fetchTask.errors().isEmpty(), is(false)); assertThat(fetchTask.errors().on(FetchTask.JOB), is("\"downstream-pipeline :: downstream-stage :: downstream-job\" tries to fetch artifact from job \"upstream-pipeline :: upstream-stage :: some-random-job\" which does not exist.")); }
@Test public void shouldAddValidationErrorsFromStagesOntoPipelineIfPipelineIsAssociatedToATemplate() { BasicCruiseConfig cruiseConfig = GoConfigMother.configWithPipelines("p1", "p2", "p3"); PipelineConfig p1 = cruiseConfig.getPipelineConfigByName(new CaseInsensitiveString("p1")); PipelineConfig p2 = cruiseConfig.getPipelineConfigByName(new CaseInsensitiveString("p2")); PipelineConfig p3 = cruiseConfig.getPipelineConfigByName(new CaseInsensitiveString("p3")); p2.addMaterialConfig(new DependencyMaterialConfig(p1.name(), p1.first().name())); p3.addMaterialConfig(new DependencyMaterialConfig(p2.name(), p2.first().name())); p3.first().getJobs().first().addTask(new FetchTask(new CaseInsensitiveString("p1/p2"), p1.first().name(), p1.first().getJobs().first().name(), "src", "dest")); StageConfig stageConfig = new StageConfig(new CaseInsensitiveString("stage"), new JobConfigs(new JobConfig(new CaseInsensitiveString("new-job")))); PipelineConfig pipelineConfig = new PipelineConfig(p1.name(), new MaterialConfigs(), stageConfig); String group = cruiseConfig.getGroups().first().getGroup(); cruiseConfig.update(group, pipelineConfig.name().toString(), pipelineConfig); PipelineConfigSaveValidationContext validationContext = PipelineConfigSaveValidationContext.forChain(false, group, cruiseConfig, pipelineConfig); pipelineConfig.validateTree(validationContext); assertThat(pipelineConfig.errors().on("base"), is("\"p3 :: stage :: job\" tries to fetch artifact from job \"p1 :: stage :: job\" which does not exist.")); }
@Test public void shouldNotFailValidationIfUpstreamExists_PipelineConfigSave() { PipelineConfig upstream = new PipelineConfig(new CaseInsensitiveString("upstream-pipeline"), new MaterialConfigs(), new StageConfig(new CaseInsensitiveString("upstream-stage"), new JobConfigs(new JobConfig(new CaseInsensitiveString("upstream-job"))))); JobConfig job = new JobConfig(new CaseInsensitiveString("downstream-job")); FetchTask fetchTask = new FetchTask(new CaseInsensitiveString("upstream-pipeline"), new CaseInsensitiveString("upstream-stage"), new CaseInsensitiveString("upstream-job"), "quux.c", "bang-file"); job.addTask(fetchTask); PipelineConfig downstream = new PipelineConfig(new CaseInsensitiveString("downstream-pipeline"), new MaterialConfigs(new DependencyMaterialConfig(upstream.name(), upstream.getFirstStageConfig().name())), new StageConfig(new CaseInsensitiveString("downstream-stage"), new JobConfigs(job))); fetchTask.validateTree(PipelineConfigSaveValidationContext.forChain(true, "group", new BasicCruiseConfig(new BasicPipelineConfigs(upstream, downstream)), downstream, downstream.getFirstStageConfig(), downstream.getFirstStageConfig().getJobs().first())); assertThat(fetchTask.errors().isEmpty(), is(true)); }