@Test public void shouldScheduleIfAgentMatchingResources() throws Exception { JobConfig plan = evolveConfig .findBy(new CaseInsensitiveString(STAGE_NAME)) .jobConfigByInstanceName("unit", true); plan.addResource("some-resource"); scheduleHelper.schedule(evolveConfig, modifySomeFiles(evolveConfig), DEFAULT_APPROVED_BY); AgentConfig agentConfig = AgentMother.localAgent(); agentConfig.addResource(new Resource("some-resource")); buildAssignmentService.onTimer(); Work work = buildAssignmentService.assignWorkToAgent(agent(agentConfig)); assertThat(work, is(not((Work) BuildAssignmentService.NO_WORK))); Pipeline pipeline = pipelineDao.mostRecentPipeline(CaseInsensitiveString.str(evolveConfig.name())); JobInstance job = pipeline.findStage(STAGE_NAME).findJob("unit"); JobPlan loadedPlan = jobInstanceDao.loadPlan(job.getId()); assertThat(loadedPlan.getResources(), is((List<Resource>) plan.resources())); assertThat(job.getState(), is(JobState.Assigned)); assertThat(job.getAgentUuid(), is(agentConfig.getUuid())); }
@Test public void shouldNotAssignWorkToDeniedAgent() throws Exception { AgentConfig deniedAgentConfig = AgentMother.localAgent(); deniedAgentConfig.disable(); Work assignedWork = buildAssignmentService.assignWorkToAgent(agent(deniedAgentConfig)); assertThat(assignedWork, instanceOf(DeniedAgentWork.class)); }
@Test public void shouldUpdateNumberOfActiveRemoteAgentsAfterAssigned() { AgentConfig agentConfig = AgentMother.remoteAgent(); configHelper.addAgent(agentConfig); fixture.createPipelineWithFirstStageScheduled(); buildAssignmentService.onTimer(); int before = agentService.numberOfActiveRemoteAgents(); Work work = buildAssignmentService.assignWorkToAgent(agent(agentConfig)); assertThat(work, instanceOf(BuildWork.class)); assertThat(agentService.numberOfActiveRemoteAgents(), is(before + 1)); }
@Test public void shouldReScheduleToCorrectAgent() throws Exception { JobConfig plan = evolveConfig .findBy(new CaseInsensitiveString(STAGE_NAME)) .jobConfigByInstanceName("unit", true); plan.addResource("some-resource"); scheduleHelper.schedule(evolveConfig, modifySomeFiles(evolveConfig), DEFAULT_APPROVED_BY); buildAssignmentService.onTimer(); AgentConfig agentConfig = AgentMother.localAgent(); agentConfig.addResource(new Resource("some-resource")); Work work = buildAssignmentService.assignWorkToAgent(agent(agentConfig)); assertThat(work, is(not((Work) BuildAssignmentService.NO_WORK))); Pipeline pipeline = pipelineDao.mostRecentPipeline(CaseInsensitiveString.str(evolveConfig.name())); JobInstance job = pipeline.findStage(STAGE_NAME).findJob("unit"); JobInstance runningJob = jobInstanceDao.buildByIdWithTransitions(job.getId()); scheduleService.rescheduleJob(runningJob); pipeline = pipelineDao.mostRecentPipeline(CaseInsensitiveString.str(evolveConfig.name())); JobInstance rescheduledJob = pipeline.findStage(STAGE_NAME).findJob("unit"); assertThat(rescheduledJob.getId(), not(runningJob.getId())); buildAssignmentService.onTimer(); Work noResourcesWork = buildAssignmentService.assignWorkToAgent( agent(AgentMother.localAgentWithResources("WITHOUT_RESOURCES"))); assertThat(noResourcesWork, is((Work) BuildAssignmentService.NO_WORK)); buildAssignmentService.onTimer(); Work correctAgentWork = buildAssignmentService.assignWorkToAgent(agent(agentConfig)); assertThat(correctAgentWork, is(not((Work) BuildAssignmentService.NO_WORK))); }
@Test public void shouldRescheduleAbandonedBuild() throws SQLException { AgentIdentifier instance = agent(AgentMother.localAgent()); Pipeline pipeline = instanceFactory.createPipelineInstance( evolveConfig, modifyNoFiles(evolveConfig), new DefaultSchedulingContext(DEFAULT_APPROVED_BY), md5, new TimeProvider()); dbHelper.savePipelineWithStagesAndMaterials(pipeline); buildAssignmentService.onConfigChange(goConfigService.getCurrentConfig()); buildAssignmentService.onTimer(); buildAssignmentService.assignWorkToAgent(instance); long firstAssignedBuildId = buildOf(pipeline).getId(); // somehow agent abandoned its original build... buildAssignmentService.assignWorkToAgent(instance); JobInstance reloaded = jobInstanceDao.buildByIdWithTransitions(firstAssignedBuildId); assertThat(reloaded.getState(), is(JobState.Rescheduled)); assertThat(reloaded.isIgnored(), is(true)); }
@Test public void shouldCancelBuildBelongingToNonExistentPipelineWhenCreatingWork() throws Exception { fixture.createPipelineWithFirstStageScheduled(); Pipeline pipeline = pipelineDao.mostRecentPipeline(fixture.pipelineName); ScheduledPipelineLoader scheduledPipelineLoader = mock(ScheduledPipelineLoader.class); when(scheduledPipelineLoader.pipelineWithPasswordAwareBuildCauseByBuildId( pipeline.getFirstStage().getJobInstances().first().getId())) .thenThrow(new PipelineNotFoundException("thrown by mockPipelineService")); GoConfigService mockGoConfigService = mock(GoConfigService.class); CruiseConfig config = configHelper.currentConfig(); configHelper.removePipeline(fixture.pipelineName, config); when(mockGoConfigService.getCurrentConfig()).thenReturn(config); buildAssignmentService = new BuildAssignmentService( mockGoConfigService, jobInstanceService, scheduleService, agentService, environmentConfigService, timeProvider, transactionTemplate, scheduledPipelineLoader, pipelineService, builderFactory, agentRemoteHandler); buildAssignmentService.onTimer(); AgentConfig agentConfig = AgentMother.localAgent(); agentConfig.addResource(new Resource("some-other-resource")); try { buildAssignmentService.assignWorkToAgent(agent(agentConfig)); fail("should have thrown PipelineNotFoundException"); } catch (PipelineNotFoundException e) { // ok } pipeline = pipelineDao.mostRecentPipeline(fixture.pipelineName); JobInstance job = pipeline.getFirstStage().getJobInstances().first(); assertThat(job.getState(), is(JobState.Completed)); assertThat(job.getResult(), is(JobResult.Cancelled)); Stage stage = stageDao.findStageWithIdentifier(job.getIdentifier().getStageIdentifier()); assertThat(stage.getState(), is(StageState.Cancelled)); assertThat(stage.getResult(), is(StageResult.Cancelled)); }
@Test public void shouldNotScheduleIfAgentDoesNotHaveResources() throws Exception { JobConfig plan = evolveConfig .findBy(new CaseInsensitiveString(STAGE_NAME)) .jobConfigByInstanceName("unit", true); plan.addResource("some-resource"); scheduleHelper.schedule(evolveConfig, modifySomeFiles(evolveConfig), DEFAULT_APPROVED_BY); Work work = buildAssignmentService.assignWorkToAgent(agent(AgentMother.localAgent())); Pipeline pipeline = pipelineDao.mostRecentPipeline(CaseInsensitiveString.str(evolveConfig.name())); JobInstance job = pipeline.findStage(STAGE_NAME).findJob("unit"); assertThat(work, is((Work) BuildAssignmentService.NO_WORK)); assertThat(job.getState(), is(JobState.Scheduled)); assertThat(job.getAgentUuid(), is(nullValue())); }
@Test public void shouldNotAssignCancelledJob() throws Exception { AgentIdentifier instance = agent(AgentMother.localAgent()); Pipeline pipeline = instanceFactory.createPipelineInstance( evolveConfig, modifyNoFiles(evolveConfig), new DefaultSchedulingContext(DEFAULT_APPROVED_BY), md5, new TimeProvider()); dbHelper.savePipelineWithStagesAndMaterials(pipeline); buildAssignmentService.onConfigChange(goConfigService.getCurrentConfig()); JobInstance job = buildOf(pipeline); job.cancel(); jobInstanceDao.updateStateAndResult(job); assertThat( buildAssignmentService.assignWorkToAgent(instance), is((Work) BuildAssignmentService.NO_WORK)); }
@Test public void shouldCreateWorkWithFetchMaterialsFlagFromStageConfig() throws Exception { evolveConfig.getFirstStageConfig().setFetchMaterials(true); Pipeline pipeline1 = instanceFactory.createPipelineInstance( evolveConfig, modifySomeFiles(evolveConfig), new DefaultSchedulingContext(DEFAULT_APPROVED_BY), md5, new TimeProvider()); dbHelper.savePipelineWithStagesAndMaterials(pipeline1); buildAssignmentService.onTimer(); BuildWork work = (BuildWork) buildAssignmentService.assignWorkToAgent(agent(AgentMother.localAgent())); assertThat( "should have set fetchMaterials on assignment", work.getAssignment().getPlan().shouldFetchMaterials(), is(true)); }
@Test public void shouldCancelBuildBelongingToNonExistentPipeline() throws Exception { fixture.createPipelineWithFirstStageScheduled(); buildAssignmentService.onTimer(); configHelper.removePipeline(fixture.pipelineName); AgentConfig agentConfig = AgentMother.localAgent(); agentConfig.addResource(new Resource("some-other-resource")); assertThat( (NoWork) buildAssignmentService.assignWorkToAgent(agent(agentConfig)), Matchers.is(BuildAssignmentService.NO_WORK)); Pipeline pipeline = pipelineDao.mostRecentPipeline(fixture.pipelineName); JobInstance job = pipeline.getFirstStage().getJobInstances().first(); assertThat(job.getState(), is(JobState.Completed)); assertThat(job.getResult(), is(JobResult.Cancelled)); Stage stage = stageDao.findStageWithIdentifier(job.getIdentifier().getStageIdentifier()); assertThat(stage.getState(), is(StageState.Cancelled)); assertThat(stage.getResult(), is(StageResult.Cancelled)); }
@Test public void shouldNotAssignWorkWhenPipelineScheduledWithStaleMaterials() { AgentIdentifier instance = agent(AgentMother.localAgent()); Pipeline pipeline = instanceFactory.createPipelineInstance( evolveConfig, modifyNoFiles(evolveConfig), new DefaultSchedulingContext(DEFAULT_APPROVED_BY), md5, new TimeProvider()); dbHelper.savePipelineWithStagesAndMaterials(pipeline); evolveConfig.setMaterialConfigs(new MaterialConfigs(new HgMaterialConfig("foo", null))); configHelper.removePipeline(CaseInsensitiveString.str(evolveConfig.name())); configHelper.addPipeline(evolveConfig); buildAssignmentService.onConfigChange(goConfigService.getCurrentConfig()); JobInstance job = buildOf(pipeline); jobInstanceDao.updateStateAndResult(job); assertThat( buildAssignmentService.assignWorkToAgent(instance), is((Work) BuildAssignmentService.NO_WORK)); }
@Test public void shouldBeAbleToSerializeAndDeserializeBuildWork() throws Exception { Pipeline pipeline1 = instanceFactory.createPipelineInstance( evolveConfig, modifySomeFiles(evolveConfig), new DefaultSchedulingContext(DEFAULT_APPROVED_BY), md5, new TimeProvider()); dbHelper.savePipelineWithStagesAndMaterials(pipeline1); buildAssignmentService.onTimer(); BuildWork work = (BuildWork) buildAssignmentService.assignWorkToAgent(agent(AgentMother.localAgent())); BuildWork deserialized = (BuildWork) SerializationTester.serializeAndDeserialize(work); assertThat( deserialized.getAssignment().materialRevisions(), is(work.getAssignment().materialRevisions())); assertThat(deserialized.getAssignment(), is(work.getAssignment())); assertThat(deserialized, is(work)); }
/** * (uppest/2/uppest-stage/1) |------------------> upper-peer ------- | * ...................................|............................................... | . | . [ * uppest-stage ............................|...................... {bar.zip * uppest/upper-peer/downer} V . uppest uppest-stage-2 ------> upper ------> downer ------> * downest {foo.zip uppest/upper/downer} (uppest/1/uppest-stage-2/1) uppest-stage-3 ] * * <p>.... :: fetch artifact call ---> :: material dependency */ @Test public void shouldCreateWork_withAncestorFetchArtifactCalls_resolvedToRelevantStage() throws Exception { configHelper.addPipeline("uppest", "uppest-stage"); configHelper.addStageToPipeline("uppest", "uppest-stage-2"); PipelineConfig uppest = configHelper.addStageToPipeline("uppest", "uppest-stage-3"); configHelper.addPipeline("upper", "upper-stage"); DependencyMaterial upper_sMaterial = new DependencyMaterial( new CaseInsensitiveString("uppest"), new CaseInsensitiveString("uppest-stage-2")); PipelineConfig upper = configHelper.setMaterialConfigForPipeline("upper", upper_sMaterial.config()); configHelper.addPipeline("upper-peer", "upper-peer-stage"); DependencyMaterial upperPeer_sMaterial = new DependencyMaterial( new CaseInsensitiveString("uppest"), new CaseInsensitiveString("uppest-stage")); PipelineConfig upperPeer = configHelper.setMaterialConfigForPipeline("upper-peer", upperPeer_sMaterial.config()); configHelper.addPipeline("downer", "downer-stage"); DependencyMaterial downer_sUpperMaterial = new DependencyMaterial( new CaseInsensitiveString("upper"), new CaseInsensitiveString("upper-stage")); configHelper.setMaterialConfigForPipeline("downer", downer_sUpperMaterial.config()); DependencyMaterial downer_sUpperPeerMaterial = new DependencyMaterial( new CaseInsensitiveString("upper-peer"), new CaseInsensitiveString("upper-peer-stage")); PipelineConfig downer = configHelper.addMaterialToPipeline("downer", downer_sUpperPeerMaterial.config()); configHelper.addPipeline("downest", "downest-stage"); DependencyMaterial downest_sMaterial = new DependencyMaterial( new CaseInsensitiveString("downer"), new CaseInsensitiveString("downer-stage")); configHelper.setMaterialConfigForPipeline("downest", downest_sMaterial.config()); Tasks allFetchTasks = new Tasks(); allFetchTasks.add( new FetchTask( new CaseInsensitiveString("uppest/upper/downer"), new CaseInsensitiveString("uppest-stage"), new CaseInsensitiveString("unit"), "foo.zip", "bar")); allFetchTasks.add( new FetchTask( new CaseInsensitiveString("uppest/upper-peer/downer"), new CaseInsensitiveString("uppest-stage"), new CaseInsensitiveString("unit"), "bar.zip", "baz")); configHelper.replaceAllJobsInStage( "downest", "downest-stage", new JobConfig( new CaseInsensitiveString("fetcher"), new Resources("fetcher"), new ArtifactPlans(), allFetchTasks)); PipelineConfig downest = goConfigService .getCurrentConfig() .pipelineConfigByName(new CaseInsensitiveString("downest")); DefaultSchedulingContext defaultSchedulingCtx = new DefaultSchedulingContext(DEFAULT_APPROVED_BY); Pipeline uppestInstanceForUpper = instanceFactory.createPipelineInstance( uppest, modifySomeFiles(uppest), defaultSchedulingCtx, md5, new TimeProvider()); dbHelper.savePipelineWithStagesAndMaterials(uppestInstanceForUpper); dbHelper.passStage(uppestInstanceForUpper.findStage("uppest-stage")); Stage upper_sMaterialStage = dbHelper.scheduleStage( uppestInstanceForUpper, uppest.getStage(new CaseInsensitiveString("uppest-stage-2"))); dbHelper.passStage(upper_sMaterialStage); Pipeline uppestInstanceForUpperPeer = instanceFactory.createPipelineInstance( uppest, modifySomeFiles(uppest), new DefaultSchedulingContext("super-hero"), md5, new TimeProvider()); dbHelper.savePipelineWithStagesAndMaterials(uppestInstanceForUpperPeer); Stage upperPeer_sMaterialStage = uppestInstanceForUpperPeer.findStage("uppest-stage"); dbHelper.passStage(upperPeer_sMaterialStage); Pipeline upperInstance = instanceFactory.createPipelineInstance( upper, buildCauseForDependency(upper_sMaterial, upper_sMaterialStage), defaultSchedulingCtx, md5, new TimeProvider()); dbHelper.savePipelineWithStagesAndMaterials(upperInstance); Stage downer_sUpperMaterialStage = upperInstance.findStage("upper-stage"); dbHelper.passStage(downer_sUpperMaterialStage); Pipeline upperPeerInstance = instanceFactory.createPipelineInstance( upperPeer, buildCauseForDependency(upperPeer_sMaterial, upperPeer_sMaterialStage), defaultSchedulingCtx, md5, new TimeProvider()); dbHelper.savePipelineWithStagesAndMaterials(upperPeerInstance); Stage downer_sUpperPeerMaterialStage = upperPeerInstance.findStage("upper-peer-stage"); dbHelper.passStage(downer_sUpperPeerMaterialStage); MaterialRevisions downer_sMaterialRevisions = new MaterialRevisions( materialRevisionForDownstream(downer_sUpperMaterial, downer_sUpperMaterialStage), materialRevisionForDownstream( downer_sUpperPeerMaterial, downer_sUpperPeerMaterialStage)); Pipeline downerInstance = instanceFactory.createPipelineInstance( downer, BuildCause.createManualForced(downer_sMaterialRevisions, loserUser), defaultSchedulingCtx, md5, new TimeProvider()); dbHelper.savePipelineWithStagesAndMaterials(downerInstance); Stage downest_sMaterialStage = downerInstance.findStage("downer-stage"); dbHelper.passStage(downest_sMaterialStage); Pipeline downestInstance = instanceFactory.createPipelineInstance( downest, buildCauseForDependency(downest_sMaterial, downest_sMaterialStage), defaultSchedulingCtx, md5, new TimeProvider()); dbHelper.savePipelineWithStagesAndMaterials(downestInstance); buildAssignmentService.onTimer(); AgentConfig agentConfig = AgentMother.localAgent(); agentConfig.addResource(new Resource("fetcher")); BuildWork work = (BuildWork) buildAssignmentService.assignWorkToAgent(agent(agentConfig)); List<Builder> builders = work.getAssignment().getBuilders(); FetchArtifactBuilder fooZipFetch = (FetchArtifactBuilder) builders.get(0); assertThat(fooZipFetch.artifactLocator(), is("uppest/1/uppest-stage/latest/unit/foo.zip")); FetchArtifactBuilder barZipFetch = (FetchArtifactBuilder) builders.get(1); assertThat(barZipFetch.artifactLocator(), is("uppest/2/uppest-stage/1/unit/bar.zip")); }