/* * Copyright 2015 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; import com.thoughtworks.go.config.*; import com.thoughtworks.go.domain.*; import com.thoughtworks.go.domain.activity.JobStatusCache; import com.thoughtworks.go.domain.buildcause.BuildCause; import com.thoughtworks.go.fixture.PipelineWithTwoStages; import com.thoughtworks.go.fixture.SchedulerFixture; import com.thoughtworks.go.helper.BuildPlanMother; import com.thoughtworks.go.helper.PipelineMother; import com.thoughtworks.go.helper.StageConfigMother; import com.thoughtworks.go.server.dao.DatabaseAccessHelper; import com.thoughtworks.go.server.dao.JobInstanceDao; import com.thoughtworks.go.server.dao.StageDao; import com.thoughtworks.go.server.domain.JobStatusListener; import com.thoughtworks.go.server.persistence.MaterialRepository; import com.thoughtworks.go.server.scheduling.ScheduleHelper; import com.thoughtworks.go.server.transaction.TransactionTemplate; import com.thoughtworks.go.server.ui.SortOrder; import com.thoughtworks.go.util.GoConfigFileHelper; import com.thoughtworks.go.util.TimeProvider; import org.joda.time.DateTime; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.TransactionCallbackWithoutResult; import java.sql.SQLException; import java.util.Date; import java.util.List; import java.util.UUID; import static com.thoughtworks.go.helper.AgentMother.localAgentWithResources; import static com.thoughtworks.go.helper.BuildPlanMother.withBuildPlans; import static com.thoughtworks.go.helper.JobInstanceMother.*; import static com.thoughtworks.go.helper.ModificationsMother.modifyOneFile; import static com.thoughtworks.go.helper.ModificationsMother.modifySomeFiles; import static com.thoughtworks.go.util.DataStructureUtils.listOf; import static com.thoughtworks.go.util.GoConstants.DEFAULT_APPROVED_BY; import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.hasProperty; import static org.hamcrest.collection.IsArrayContaining.hasItemInArray; import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; import static org.junit.matchers.JUnitMatchers.hasItem; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = { "classpath:WEB-INF/applicationContext-global.xml", "classpath:WEB-INF/applicationContext-dataLocalAccess.xml", "classpath:WEB-INF/applicationContext-acegi-security.xml" }) public class JobInstanceServiceIntegrationTest { @Autowired private GoConfigDao goConfigDao; @Autowired private JobInstanceDao jobInstanceDao; @Autowired private JobStatusCache jobStatusCache; @Autowired private JobInstanceService jobInstanceService; @Autowired private StageService stageService; @Autowired private ScheduleService scheduleService; @Autowired private EnvironmentConfigService environmentConfigService; @Autowired private DatabaseAccessHelper dbHelper; @Autowired private MaterialRepository materialRepository; @Autowired private ScheduleHelper scheduleHelper; @Autowired private TransactionTemplate transactionTemplate; @Autowired private StageDao stageDao; @Autowired private InstanceFactory instanceFactory; private static GoConfigFileHelper configHelper = new GoConfigFileHelper(); private PipelineWithTwoStages pipelineFixture; private SchedulerFixture schedulerFixture; @Before public void setUp() throws Exception { dbHelper.onSetUp(); pipelineFixture = new PipelineWithTwoStages(materialRepository, transactionTemplate); configHelper.onSetUp(); configHelper.usingCruiseConfigDao(goConfigDao); pipelineFixture.usingConfigHelper(configHelper).usingDbHelper(dbHelper).onSetUp(); schedulerFixture = new SchedulerFixture(dbHelper, stageDao, scheduleService); } @After public void teardown() throws Exception { dbHelper.onTearDown(); pipelineFixture.onTearDown(); jobStatusCache.clear(); } @Test public void shouldOnlyLoad25JobsFromLatestStage() throws Exception { StageConfig devStage = pipelineFixture.devStage(); Pipeline pipeline = pipelineFixture.createdPipelineWithAllStagesPassed(); Stage stage = pipeline.getStages().byName(CaseInsensitiveString.str(devStage.name())); for (int i = 0; i < 50; i++) { Pipeline pipeline1 = pipelineFixture.createdPipelineWithAllStagesPassed(); schedulerFixture.rerunAndPassStage(pipeline1, devStage); } JobInstances jobs1 = jobInstanceService.latestCompletedJobs( pipelineFixture.pipelineName, pipelineFixture.devStage, stage.getJobInstances().first().getName()); assertThat(jobs1.size(), is(25)); } @Test public void shouldClearOutStageByIdCacheOnJobUpdate() { StageConfig ftStage = pipelineFixture.ftStage(); Pipeline pipeline = pipelineFixture.createPipelineWithFirstStagePassedAndSecondStageRunning(); Stage stage = pipeline.getStages().byName(CaseInsensitiveString.str(ftStage.name())); long stageId = stage.getId(); Stage stageLoadedBeforeJobUpdate = stageService.stageById(stageId); assertThat(stageLoadedBeforeJobUpdate.getJobInstances().get(0).getState(), is(JobState.Scheduled)); JobInstance instance = stage.getJobInstances().get(0); instance.changeState(JobState.Building, new Date()); jobInstanceService.updateStateAndResult(instance); Stage stageLoadedAfterJobUpdate = stageService.stageById(stageId); assertThat(stageLoadedAfterJobUpdate.getJobInstances().get(0).getState(), is(JobState.Building)); } @Test public void shouldContainIdentifierAfterSaved() throws Exception { final Pipeline pipeline = pipelineFixture.createdPipelineWithAllStagesPassed(); JobConfig jobConfig = pipelineFixture.devStage().allBuildPlans().first(); RunOnAllAgents.CounterBasedJobNameGenerator jobNameGenerator = new RunOnAllAgents.CounterBasedJobNameGenerator(CaseInsensitiveString.str(jobConfig.name())); JobInstances instances = instanceFactory.createJobInstance(new CaseInsensitiveString("someStage"), jobConfig, new DefaultSchedulingContext(), new TimeProvider(), jobNameGenerator); final JobInstance newJob = instances.first(); final StageIdentifier stageIdentifier = new StageIdentifier(pipeline.getName(), pipeline.getCounter(), pipeline.getLabel(), pipeline.getFirstStage().getName(), String.valueOf(pipeline.getFirstStage().getCounter())); dbHelper.txTemplate().execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(TransactionStatus status) { jobInstanceService.save(stageIdentifier, pipeline.getFirstStage().getId(), newJob); } }); assertThat(newJob.getIdentifier(), is(new JobIdentifier(pipeline, pipeline.getFirstStage(), newJob))); } @Test public void shouldFindCurrentJobsOrderedByName() throws Exception { StageConfig stageConfig = StageConfigMother.custom("dev", "build", "alpha"); Stage stage = instanceFactory.createStageInstance(stageConfig, new DefaultSchedulingContext("anyone"), "md5-test", new TimeProvider()); for (JobInstance instance : stage.getJobInstances()) { instance.setIdentifier(new JobIdentifier("cruise", "1", "dev", "1", instance.getName())); } jobStatusCache.jobStatusChanged(stage.getJobInstances().first()); jobStatusCache.jobStatusChanged(stage.getJobInstances().last()); JobInstances jobs = jobInstanceService.currentJobsOfStage("cruise", stageConfig); assertThat(jobs.first().getName(), is("alpha")); assertThat(jobs.last().getName(), is("build")); } @Test public void shouldFindAllCopiesOfJobsRunOnAllAgents() throws Exception { StageConfig stageConfig = StageConfigMother.custom("dev", "build"); JobConfig jobConfig = stageConfig.jobConfigByInstanceName("build", true); jobConfig.setRunOnAllAgents(true); String uuid1 = UUID.randomUUID().toString(); String uuid2 = UUID.randomUUID().toString(); DefaultSchedulingContext schedulingContext = new DefaultSchedulingContext("anyone", new Agents(new AgentConfig(uuid1), new AgentConfig(uuid2))); Stage stage = instanceFactory.createStageInstance(stageConfig, schedulingContext, "md5-test", new TimeProvider()); for (JobInstance instance : stage.getJobInstances()) { instance.setIdentifier(new JobIdentifier("cruise", "1", "dev", "1", instance.getName())); } jobStatusCache.jobStatusChanged(stage.getJobInstances().first()); jobStatusCache.jobStatusChanged(stage.getJobInstances().last()); JobInstances jobs = jobInstanceService.currentJobsOfStage("cruise", stageConfig); assertThat(jobs.toArray(), hasItemInArray(hasProperty("name", is(RunOnAllAgents.CounterBasedJobNameGenerator.appendMarker("build", 1))))); assertThat(jobs.toArray(), hasItemInArray(hasProperty("name", is(RunOnAllAgents.CounterBasedJobNameGenerator.appendMarker("build", 2))))); assertThat(jobs.size(), is(2)); } @Test public void shouldFindAllCopiesOfJobsRunMultipleInstance() throws Exception { StageConfig stageConfig = StageConfigMother.custom("dev", "build"); JobConfig jobConfig = stageConfig.jobConfigByInstanceName("build", true); jobConfig.setRunInstanceCount(2); DefaultSchedulingContext schedulingContext = new DefaultSchedulingContext("anyone", new Agents()); Stage stage = instanceFactory.createStageInstance(stageConfig, schedulingContext, "md5-test", new TimeProvider()); for (JobInstance instance : stage.getJobInstances()) { instance.setIdentifier(new JobIdentifier("cruise", "1", "dev", "1", instance.getName())); } jobStatusCache.jobStatusChanged(stage.getJobInstances().first()); jobStatusCache.jobStatusChanged(stage.getJobInstances().last()); JobInstances jobs = jobInstanceService.currentJobsOfStage("cruise", stageConfig); assertThat(jobs.size(), is(2)); assertThat(jobs.toArray(), hasItemInArray(hasProperty("name", is(RunMultipleInstance.CounterBasedJobNameGenerator.appendMarker("build", 1))))); assertThat(jobs.toArray(), hasItemInArray(hasProperty("name", is(RunMultipleInstance.CounterBasedJobNameGenerator.appendMarker("build", 2))))); } @Test public void shouldThrowExceptionIfThereAreNoJobsToBeScheduled() throws Exception { StageConfig stageConfig = StageConfigMother.custom("dev", "build"); JobConfig jobConfig = stageConfig.jobConfigByInstanceName("build", true); jobConfig.setRunOnAllAgents(true); jobConfig.addResource("non-existent"); String uuid1 = UUID.randomUUID().toString(); String uuid2 = UUID.randomUUID().toString(); DefaultSchedulingContext schedulingContext = new DefaultSchedulingContext("anyone", new Agents(new AgentConfig(uuid1), new AgentConfig(uuid2))); try { instanceFactory.createStageInstance(stageConfig, schedulingContext, "md5-test", new TimeProvider()); fail("Expected a CannotScheduleException to be thrown"); } catch (CannotScheduleException e) { //expected } } @Test public void orderedScheduledBuilds_shouldLoadJobPlansWithFetchMaterialsFlagFromStage() { PipelineConfig pipelineConfig = PipelineMother.withSingleStageWithMaterials("go", "dev", withBuildPlans("unit")); pipelineConfig.getFirstStageConfig().setFetchMaterials(false); configHelper.addPipeline("go", "dev"); scheduleHelper.schedule(pipelineConfig, BuildCause.createWithModifications(modifyOneFile(pipelineConfig), ""), DEFAULT_APPROVED_BY); List<JobPlan> jobPlans = jobInstanceService.orderedScheduledBuilds(); assertThat(jobPlans.size(), is(1)); assertThat(jobPlans.get(0).shouldFetchMaterials(), is(false)); } @Test public void orderedScheduledBuilds_shouldLoadJobPlansWithCleanWorkingDirFlagFromStage() { PipelineConfig pipelineConfig = PipelineMother.withSingleStageWithMaterials("go", "dev", withBuildPlans("unit")); pipelineConfig.getFirstStageConfig().setCleanWorkingDir(true); configHelper.addPipeline("go", "dev"); scheduleHelper.schedule(pipelineConfig, BuildCause.createWithModifications(modifyOneFile(pipelineConfig), ""), DEFAULT_APPROVED_BY); List<JobPlan> jobPlans = jobInstanceService.orderedScheduledBuilds(); assertThat(jobPlans.size(), is(1)); assertThat(jobPlans.get(0).shouldCleanWorkingDir(), is(true)); } @Test public void waitingJobPlans_shouldLoadScheduledJobPlansEnvironmentMapping() { PipelineConfig pipelineConfig = PipelineMother.withSingleStageWithMaterials("go", "dev", withBuildPlans("unit")); pipelineConfig.getFirstStageConfig().setCleanWorkingDir(true); configHelper.addPipeline("go", "dev"); configHelper.addEnvironments("newEnv"); configHelper.addPipelineToEnvironment("newEnv", "go"); scheduleHelper.schedule(pipelineConfig, BuildCause.createWithModifications(modifyOneFile(pipelineConfig), ""), DEFAULT_APPROVED_BY); List<JobPlan> jobPlans = jobInstanceService.orderedScheduledBuilds(); List<WaitingJobPlan> waitingJobPlans = jobInstanceService.waitingJobPlans(); assertThat(waitingJobPlans.size(), is(1)); assertThat(waitingJobPlans.get(0).jobPlan(), is(jobPlans.get(0))); assertThat(waitingJobPlans.get(0).envName(), is("newEnv")); } @Test public void shouldLoadAllBuildingJobs() throws SQLException { PipelineConfig goConfig = PipelineMother.withSingleStageWithMaterials("go", "dev", withBuildPlans("unit")); Stage goDev = dbHelper.schedulePipeline(goConfig, new TimeProvider()).getStages().get(0); dbHelper.buildingBuildInstance(goDev); PipelineConfig mingleConfig = PipelineMother.withSingleStageWithMaterials("mingle", "test", withBuildPlans("integration")); Stage mingleTest = dbHelper.schedulePipeline(mingleConfig, new TimeProvider()).getStages().get(0); dbHelper.buildingBuildInstance(mingleTest); dbHelper.newPipelineWithAllStagesPassed(PipelineMother.withSingleStageWithMaterials("twist", "acceptance", withBuildPlans("firefox"))).getStages().get(0);//a completed pipeline assertThat(jobInstanceService.allBuildingJobs().size(), is(2)); assertThat(jobInstanceService.allBuildingJobs(), hasItem(goDev.getFirstJob().getIdentifier())); assertThat(jobInstanceService.allBuildingJobs(), hasItem(mingleTest.getFirstJob().getIdentifier())); } @Test public void shouldFailRequestedJobAndNotifyStageChange() throws SQLException { PipelineConfig goConfig = PipelineMother.withSingleStageWithMaterials("go", "dev", withBuildPlans("unit")); Stage goDev = dbHelper.schedulePipeline(goConfig, new TimeProvider()).getStages().get(0); dbHelper.buildingBuildInstance(goDev); PipelineConfig mingleConfig = PipelineMother.withSingleStageWithMaterials("mingle", "test", withBuildPlans("integration")); Stage mingleTest = dbHelper.schedulePipeline(mingleConfig, new TimeProvider()).getStages().get(0); dbHelper.buildingBuildInstance(mingleTest); JobInstance jobInstance = dbHelper.newPipelineWithFirstStageScheduled(PipelineMother.withSingleStageWithMaterials("twist", "acceptance", withBuildPlans("firefox"))).getStages().get(0).getJobInstances().get(0); final JobInstance[] changedJobPassed = new JobInstance[1]; jobInstanceService.registerJobStateChangeListener(new JobStatusListener() { public void jobStatusChanged(JobInstance job) { changedJobPassed[0] = job; } }); JobInstance jobInstance1 = jobInstanceService.buildByIdWithTransitions(jobInstance.getId()); jobInstanceService.failJob(jobInstance1); assertThat(changedJobPassed[0].isFailed(), is(true)); } @Test public void shouldSet_BelongsToKnownPipeline_FlagOnEachJob_pipelineForWhichIsStillPresentInConfig() { String agentUuid = "special_uuid"; configHelper.addPipeline("existingPipeline", "existingStage"); Long existingStage = stageWithId("existingPipeline", "existingStage"); Long nonExistentStage = stageWithId("existingPipeline", "removedStage"); JobInstance completedJob = completed("existingJob", JobResult.Passed, new Date(1)); completedJob.setAgentUuid(agentUuid); jobInstanceDao.save(existingStage, completedJob); JobInstance rescheduledJob = rescheduled("rescheduled", agentUuid); jobInstanceDao.save(nonExistentStage, rescheduledJob); jobInstanceDao.ignore(rescheduledJob); Long stageFromDeletedPipeline = stageWithId("deletedPipeline", "stage"); JobInstance cancelledJob = cancelled("job"); cancelledJob.setAgentUuid(agentUuid); jobInstanceDao.save(stageFromDeletedPipeline, cancelledJob); //completed List<JobInstance> sortedOnCompleted = listOf(jobInstanceService.completedJobsOnAgent(agentUuid, JobInstanceService.JobHistoryColumns.job, SortOrder.ASC, 1, 10).iterator()); assertThat(sortedOnCompleted.size(), is(3)); assertThat(sortedOnCompleted.get(0).getName(), is("existingJob")); assertThat(sortedOnCompleted.get(0).isPipelineStillConfigured(), is(true)); assertThat(sortedOnCompleted.get(1).getName(), is("job")); assertThat(sortedOnCompleted.get(1).isPipelineStillConfigured(), is(false)); assertThat(sortedOnCompleted.get(2).getName(), is("rescheduled")); assertThat(sortedOnCompleted.get(2).isPipelineStillConfigured(), is(true)); } @Test public void shouldCompletedJobsForGivenAgent() { Long stageB_Id = stageWithId("pipeline-aaa", "stage-bbb"); String agentUuid = "special_uuid"; JobInstance completedJob = completed("job-bbb", JobResult.Passed, new Date(1)); completedJob.setAgentUuid(agentUuid); jobInstanceDao.save(stageB_Id, completedJob); JobInstance rescheduledJob = rescheduled("rescheduled", agentUuid); jobInstanceDao.save(stageB_Id, rescheduledJob); jobInstanceDao.ignore(rescheduledJob); Long stageC_Id = stageWithId("pipeline-bbb", "stage-ccc"); JobInstance cancelledJob = cancelled("job3"); cancelledJob.setAgentUuid(agentUuid); jobInstanceDao.save(stageC_Id, cancelledJob); JobInstance simpleJob = failed("simpleJob"); simpleJob.getTransition(JobState.Completed).setStateChangeTime(new DateTime().plusYears(2).toDate()); simpleJob.setAgentUuid(agentUuid); jobInstanceDao.save(stageC_Id, simpleJob); //completed List<JobInstance> sortedOnCompleted = listOf(jobInstanceService.completedJobsOnAgent(agentUuid, JobInstanceService.JobHistoryColumns.completed, SortOrder.DESC, 1, 10).iterator()); assertThat(sortedOnCompleted.size(), is(4)); assertThat(sortedOnCompleted.get(0).getName(), is("simpleJob")); List<JobInstance> sortedOnCompletedAsc = listOf(jobInstanceService.completedJobsOnAgent(agentUuid, JobInstanceService.JobHistoryColumns.completed, SortOrder.ASC, 1, 10).iterator()); assertThat(sortedOnCompletedAsc.size(), is(4)); assertThat(sortedOnCompletedAsc.get(3).getName(), is("simpleJob")); //pipeline List<JobInstance> sortedOnPipelineName = listOf(jobInstanceService.completedJobsOnAgent(agentUuid, JobInstanceService.JobHistoryColumns.pipeline, SortOrder.ASC, 1, 10).iterator()); assertThat(sortedOnPipelineName.size(), is(4)); assertThat(sortedOnPipelineName.get(0).getIdentifier().getPipelineName(), is("pipeline-aaa")); assertThat(sortedOnPipelineName.get(1).getIdentifier().getPipelineName(), is("pipeline-aaa")); assertThat(sortedOnPipelineName.get(2).getIdentifier().getPipelineName(), is("pipeline-bbb")); List<JobInstance> sortedOnPipelineNameDesc = listOf(jobInstanceService.completedJobsOnAgent(agentUuid, JobInstanceService.JobHistoryColumns.pipeline, SortOrder.DESC, 1, 10).iterator()); assertThat(sortedOnPipelineNameDesc.size(), is(4)); assertThat(sortedOnPipelineNameDesc.get(0).getIdentifier().getPipelineName(), is("pipeline-bbb")); assertThat(sortedOnPipelineNameDesc.get(2).getIdentifier().getPipelineName(), is("pipeline-aaa")); //stage List<JobInstance> sortedOnStageName = listOf(jobInstanceService.completedJobsOnAgent(agentUuid, JobInstanceService.JobHistoryColumns.stage, SortOrder.ASC, 1, 10).iterator()); assertThat(sortedOnStageName.size(), is(4)); assertThat(sortedOnStageName.get(0).getIdentifier().getStageName(), is("stage-bbb")); assertThat(sortedOnStageName.get(2).getIdentifier().getStageName(), is("stage-ccc")); List<JobInstance> sortedOnStageNameDesc = listOf(jobInstanceService.completedJobsOnAgent(agentUuid, JobInstanceService.JobHistoryColumns.stage, SortOrder.DESC, 1, 10).iterator()); assertThat(sortedOnStageNameDesc.size(), is(4)); assertThat(sortedOnStageNameDesc.get(0).getIdentifier().getStageName(), is("stage-ccc")); assertThat(sortedOnStageNameDesc.get(2).getIdentifier().getStageName(), is("stage-bbb")); //result List<JobInstance> sortedOnResult = listOf(jobInstanceService.completedJobsOnAgent(agentUuid, JobInstanceService.JobHistoryColumns.result, SortOrder.ASC, 1, 10).iterator()); assertThat(sortedOnResult.size(), is(4)); assertThat(sortedOnResult.get(0).getResult(), is(JobResult.Cancelled)); assertThat(sortedOnResult.get(1).getResult(), is(JobResult.Failed)); assertThat(sortedOnResult.get(2).getResult(), is(JobResult.Passed)); assertThat(sortedOnResult.get(3).getResult(), is(JobResult.Unknown)); List<JobInstance> sortedOnResultDesc = listOf(jobInstanceService.completedJobsOnAgent(agentUuid, JobInstanceService.JobHistoryColumns.result, SortOrder.DESC, 1, 10).iterator()); assertThat(sortedOnResultDesc.size(), is(4)); assertThat(sortedOnResultDesc.get(3).getResult(), is(JobResult.Cancelled)); assertThat(sortedOnResultDesc.get(2).getResult(), is(JobResult.Failed)); assertThat(sortedOnResultDesc.get(1).getResult(), is(JobResult.Passed)); assertThat(sortedOnResultDesc.get(0).getResult(), is(JobResult.Unknown)); } @Test public void shouldNotNotifyListenersWhenTransactionRollsback() { final boolean[] isListenerCalled = {false}; JobStatusListener jobStatusListener = new JobStatusListener() { @Override public void jobStatusChanged(JobInstance job) { isListenerCalled[0] = true; } }; jobInstanceService.registerJobStateChangeListener(jobStatusListener); StageConfig ftStage = pipelineFixture.ftStage(); Pipeline pipeline = pipelineFixture.createPipelineWithFirstStagePassedAndSecondStageRunning(); Stage stage = pipeline.getStages().byName(CaseInsensitiveString.str(ftStage.name())); final JobInstance instance = stage.getJobInstances().get(0); instance.changeState(JobState.Building, new Date()); try { transactionTemplate.execute(new TransactionCallbackWithoutResult() { protected void doInTransactionWithoutResult(TransactionStatus status) { jobInstanceService.updateStateAndResult(instance); throw new RuntimeException("to rollback txn"); } }); fail("Should have thrown an exception and transaction rolled back. Listeners should not have be called on afterCommit"); } catch (RuntimeException e) { } assertThat(isListenerCalled[0], is(false)); } @Test public void shouldSaveJobDetailsCorrectlyForEveryJobInARunMultipleInstancesJob() { PipelineConfig pipelineConfig = PipelineMother.withSingleStageWithMaterials("go", "dev", withBuildPlans("unit")); JobConfig jobConfig = pipelineConfig.getFirstStageConfig().getJobs().get(0); jobConfig.setRunInstanceCount(2); jobConfig.addResource("blah"); jobConfig.getProperties().add(new ArtifactPropertiesGenerator("prop1", "props.xml", "//somepath")); jobConfig.artifactPlans().add(new ArtifactPlan("src1", "dest1")); configHelper.addPipeline("go", "dev"); scheduleHelper.schedule(pipelineConfig, BuildCause.createWithModifications(modifyOneFile(pipelineConfig), ""), DEFAULT_APPROVED_BY); List<JobPlan> jobPlans = jobInstanceService.orderedScheduledBuilds(); assertThat(jobPlans.size(), is(2)); JobPlan job1 = jobPlans.get(0); assertThat(job1.getResources().size(), is(1)); assertThat(job1.getResources().get(0).getName(), is("blah")); assertThat(job1.getPropertyGenerators().size(), is(1)); assertThat(job1.getPropertyGenerators().get(0).getName(), is("prop1")); assertThat(job1.getArtifactPlans().size(), is(1)); assertThat(job1.getArtifactPlans().get(0).getSrc(), is("src1")); JobPlan job2 = jobPlans.get(1); assertThat(job2.getResources().size(), is(1)); assertThat(job2.getResources().get(0).getName(), is("blah")); assertThat(job2.getPropertyGenerators().size(), is(1)); assertThat(job2.getPropertyGenerators().get(0).getName(), is("prop1")); assertThat(job2.getArtifactPlans().size(), is(1)); assertThat(job2.getArtifactPlans().get(0).getSrc(), is("src1")); assertThat(job1.getResources().get(0).getId(), not(equalTo(job2.getResources().get(0).getId()))); assertThat(job1.getPropertyGenerators().get(0).getId(), not(equalTo(job2.getPropertyGenerators().get(0).getId()))); assertThat(job1.getArtifactPlans().get(0).getId(), not(equalTo(job2.getArtifactPlans().get(0).getId()))); } @Test public void shouldSaveJobDetailsCorrectlyForEveryJobInARunOnAllAgentsJob() { PipelineConfig pipelineConfig = PipelineMother.withSingleStageWithMaterials("go", "dev", withBuildPlans("unit")); JobConfig jobConfig = pipelineConfig.getFirstStageConfig().getJobs().get(0); jobConfig.setRunOnAllAgents(true); jobConfig.addResource("blah"); jobConfig.getProperties().add(new ArtifactPropertiesGenerator("prop1", "props.xml", "//somepath")); jobConfig.artifactPlans().add(new ArtifactPlan("src1", "dest1")); configHelper.addPipeline("go", "dev"); DefaultSchedulingContext schedulingContext = new DefaultSchedulingContext("anyone", new Agents(localAgentWithResources("blah"), localAgentWithResources("blah"))); scheduleHelper.schedule(pipelineConfig, BuildCause.createWithModifications(modifyOneFile(pipelineConfig), ""), DEFAULT_APPROVED_BY, schedulingContext); List<JobPlan> jobPlans = jobInstanceService.orderedScheduledBuilds(); assertThat(jobPlans.size(), is(2)); JobPlan job1 = jobPlans.get(0); assertThat(job1.getResources().size(), is(1)); assertThat(job1.getResources().get(0).getName(), is("blah")); assertThat(job1.getPropertyGenerators().size(), is(1)); assertThat(job1.getPropertyGenerators().get(0).getName(), is("prop1")); assertThat(job1.getArtifactPlans().size(), is(1)); assertThat(job1.getArtifactPlans().get(0).getSrc(), is("src1")); JobPlan job2 = jobPlans.get(1); assertThat(job2.getResources().size(), is(1)); assertThat(job2.getResources().get(0).getName(), is("blah")); assertThat(job2.getPropertyGenerators().size(), is(1)); assertThat(job2.getPropertyGenerators().get(0).getName(), is("prop1")); assertThat(job2.getArtifactPlans().size(), is(1)); assertThat(job2.getArtifactPlans().get(0).getSrc(), is("src1")); assertThat(job1.getResources().get(0).getId(), not(equalTo(job2.getResources().get(0).getId()))); assertThat(job1.getPropertyGenerators().get(0).getId(), not(equalTo(job2.getPropertyGenerators().get(0).getId()))); assertThat(job1.getArtifactPlans().get(0).getId(), not(equalTo(job2.getArtifactPlans().get(0).getId()))); } private Long stageWithId(final String pipelineName, final String stageName) { PipelineConfig pipelineConfig = PipelineMother.withSingleStageWithMaterials(pipelineName, stageName, BuildPlanMother.withBuildPlans("job-random")); Pipeline savedPipeline = instanceFactory.createPipelineInstance(pipelineConfig, modifySomeFiles(pipelineConfig), new DefaultSchedulingContext("cruise"), "md5-test", new TimeProvider()); dbHelper.savePipelineWithStagesAndMaterials(savedPipeline); Stage savedStage = savedPipeline.getFirstStage(); return savedStage.getId(); } }