@Test /** Build okay but program fails to load */ public void inProgressButProgramLoadFailure() throws Exception { final int[] build = new int[1]; story.thenWithHardShutdown( j -> { WorkflowRun run = runBasicPauseOnInput(j, DEFAULT_JOBNAME, build); CpsFlowExecution cpsExec = (CpsFlowExecution)(run.getExecution()); cpsExec.getProgramDataFile().delete(); }); story.then( j->{ WorkflowJob r = j.jenkins.getItemByFullName(DEFAULT_JOBNAME, WorkflowJob.class); WorkflowRun run = r.getBuildByNumber(build[0]); assertCompletedCleanly(run); }); }
@Test public void inProgressNormal() throws Exception { final int[] build = new int[1]; story.then( j -> { WorkflowRun run = runBasicPauseOnInput(j, DEFAULT_JOBNAME, build); }); story.then( j->{ WorkflowJob r = j.jenkins.getItemByFullName(DEFAULT_JOBNAME, WorkflowJob.class); WorkflowRun run = r.getBuildByNumber(build[0]); assertCleanInProgress(run); InputStepExecution exec = getInputStepExecution(run, "pause"); exec.doProceedEmpty(); j.waitForCompletion(run); assertCompletedCleanly(run); Assert.assertEquals(Result.SUCCESS, run.getResult()); }); }
@Test public void inProgressButFlowNodesLost() throws Exception { final int[] build = new int[1]; story.thenWithHardShutdown( j -> { WorkflowRun run = runBasicPauseOnInput(j, DEFAULT_JOBNAME, build); CpsFlowExecution cpsExec = (CpsFlowExecution)(run.getExecution()); FileUtils.deleteDirectory(((CpsFlowExecution)(run.getExecution())).getStorageDir()); }); story.then( j->{ WorkflowJob r = j.jenkins.getItemByFullName(DEFAULT_JOBNAME, WorkflowJob.class); WorkflowRun run = r.getBuildByNumber(build[0]); assertCompletedCleanly(run); }); }
@Issue("JENKINS-50888") // Tried to modify build without lazy load being triggered @Test public void modifyBeforeLazyLoad() { story.then(r -> { // Normal build WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition(new CpsFlowDefinition("echo 'dosomething'", true)); r.buildAndAssertSuccess(p); }); story.then(r -> { // But wait, we try to modify the build without loading the execution WorkflowJob p = r.jenkins.getItemByFullName("p", WorkflowJob.class); WorkflowRun b = p.getBuildByNumber(1); b.setDescription("Bob"); b.save(); // Before the JENKINS-50888 fix this would trigger an IOException }); story.then( r-> { // Verify that the FlowExecutionOwner can trigger lazy-load correctly WorkflowJob p = r.jenkins.getItemByFullName("p", WorkflowJob.class); WorkflowRun b = p.getBuildByNumber(1); Assert.assertEquals("Bob", b.getDescription()); Assert.assertEquals("4", b.getExecution().getCurrentHeads().get(0).getId()); }); } }
@Test /** Build okay but then the start nodes get screwed up */ public void inProgressButStartBlocksLost() throws Exception { final int[] build = new int[1]; story.thenWithHardShutdown( j -> { WorkflowRun run = runBasicPauseOnInput(j, DEFAULT_JOBNAME, build); CpsFlowExecution cpsExec = (CpsFlowExecution)(run.getExecution()); cpsExec.startNodes.push(new FlowStartNode(cpsExec, cpsExec.iotaStr())); run.save(); }); story.then( j->{ WorkflowJob r = j.jenkins.getItemByFullName(DEFAULT_JOBNAME, WorkflowJob.class); WorkflowRun run = r.getBuildByNumber(build[0]); assertCompletedCleanly(run); }); }
rr.then(jenkins -> { WorkflowJob p = jenkins.createProject(WorkflowJob.class); p.setDefinition(new CpsFlowDefinition("synchronousExceptionInBody()",true));
@Test @Ignore public void inProgressMaxPerfDirtyShutdown() throws Exception { final int[] build = new int[1]; final String[] finalNodeId = new String[1]; story.thenWithHardShutdown( j -> { runBasicPauseOnInput(j, DEFAULT_JOBNAME, build, FlowDurabilityHint.PERFORMANCE_OPTIMIZED); // SHOULD still save at end via persist-at-shutdown hooks }); story.then( j->{ WorkflowJob r = j.jenkins.getItemByFullName(DEFAULT_JOBNAME, WorkflowJob.class); WorkflowRun run = r.getBuildByNumber(build[0]); Thread.sleep(1000); j.waitForCompletion(run); assertCompletedCleanly(run); Assert.assertEquals(Result.FAILURE, run.getResult()); finalNodeId[0] = run.getExecution().getCurrentHeads().get(0).getId(); }); story.then(j-> { WorkflowJob r = j.jenkins.getItemByFullName(DEFAULT_JOBNAME, WorkflowJob.class); WorkflowRun run = r.getBuildByNumber(build[0]); assertCompletedCleanly(run); Assert.assertEquals(finalNodeId[0], run.getExecution().getCurrentHeads().get(0).getId()); // JENKINS-50199, verify it doesn't try to resume again }); }
@Test @Ignore public void inProgressMaxPerfCleanShutdown() throws Exception { final int[] build = new int[1]; story.then( j -> { WorkflowRun run = runBasicPauseOnInput(j, DEFAULT_JOBNAME, build, FlowDurabilityHint.PERFORMANCE_OPTIMIZED); // SHOULD still save at end via persist-at-shutdown hooks }); story.then( j->{ WorkflowJob r = j.jenkins.getItemByFullName(DEFAULT_JOBNAME, WorkflowJob.class); WorkflowRun run = r.getBuildByNumber(build[0]); assertCleanInProgress(run); InputStepExecution exec = getInputStepExecution(run, "pause"); exec.doProceedEmpty(); j.waitForCompletion(run); assertCompletedCleanly(run); Assert.assertEquals(Result.SUCCESS, run.getResult()); }); }
/** Perhaps there was a serialization error breaking the FlowGraph persistence for non-durable mode. */ @Test public void completedNoNodesPersisted() throws Exception { final int[] build = new int[1]; final Result[] executionAndBuildResult = new Result[2]; story.thenWithHardShutdown( j -> { WorkflowRun run = runBasicBuild(j, DEFAULT_JOBNAME, build); FileUtils.deleteDirectory(((CpsFlowExecution)(run.getExecution())).getStorageDir()); executionAndBuildResult[0] = ((CpsFlowExecution)(run.getExecution())).getResult(); executionAndBuildResult[1] = run.getResult(); }); story.then(j-> { WorkflowJob r = j.jenkins.getItemByFullName(DEFAULT_JOBNAME, WorkflowJob.class); WorkflowRun run = r.getBuildByNumber(build[0]); assertCompletedCleanly(run); // assertNulledExecution(run); Assert.assertEquals(Result.SUCCESS, run.getResult()); assertResultMatchExecutionAndRun(run, executionAndBuildResult); }); }
@Issue("JENKINS-53709") @Test public void popContextVarsOnBodyCompletion() { rr.then(r -> { DumbSlave s = r.createOnlineSlave(); WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "demo"); p.setDefinition(new CpsFlowDefinition("node('" + s.getNodeName() + "') {\n" + " parallel one: {\n" + " echo '" + s.getNodeName() + "'\n" + " }\n" + "}\n" + "semaphore 'wait'\n", true)); WorkflowRun b = p.scheduleBuild2(0).waitForStart(); SemaphoreStep.waitForStart("wait/1", b); r.jenkins.removeNode(s); }); rr.then(r -> { WorkflowRun b = r.jenkins.getItemByFullName("demo", WorkflowJob.class).getBuildByNumber(1); SemaphoreStep.waitForStart("wait/1", b); SemaphoreStep.success("wait/1", null); while (b.isBuilding()) { // Before the fix for JENKINS-53709, the job hangs forever while attempting to rehydrate the agent. r.assertLogNotContains("Jenkins doesn’t have label", b); Thread.sleep(100); } r.assertBuildStatusSuccess(b); }); }
/** Simulates something happening badly during final shutdown, which may cause build to not appear done. */ @Test public void completedFinalFlowNodeNotPersisted() throws Exception { final int[] build = new int[1]; final Result[] executionAndBuildResult = new Result[2]; story.thenWithHardShutdown( j -> { WorkflowRun run = runBasicBuild(j, DEFAULT_JOBNAME, build); String finalId = run.getExecution().getCurrentHeads().get(0).getId(); // Hack but deletes the file from disk CpsFlowExecution cpsExec = (CpsFlowExecution)(run.getExecution()); File f = new File(cpsExec.getStorageDir(), finalId+".xml"); f.delete(); executionAndBuildResult[0] = ((CpsFlowExecution)(run.getExecution())).getResult(); executionAndBuildResult[1] = run.getResult(); }); story.then(j-> { WorkflowJob r = j.jenkins.getItemByFullName(DEFAULT_JOBNAME, WorkflowJob.class); WorkflowRun run = r.getBuildByNumber(build[0]); assertCompletedCleanly(run); // assertNulledExecution(run); Assert.assertEquals(Result.SUCCESS, run.getResult()); assertResultMatchExecutionAndRun(run, executionAndBuildResult); }); } /** Perhaps there was a serialization error breaking the FlowGraph persistence for non-durable mode. */
@Issue("JENKINS-34637") @Test public void currentExecutions() throws Exception { rr.then(jenkins -> { WorkflowJob p = jenkins.createProject(WorkflowJob.class); p.setDefinition(new CpsFlowDefinition("parallel main: {retainsBody {parallel a: {retainsBody {semaphore 'a'}}, b: {retainsBody {semaphore 'b'}}}}, aside: {semaphore 'c'}", true));
/** Simulates case where done flag was not persisted. */ @Test public void completedButWrongDoneStatus() throws Exception { final int[] build = new int[1]; final Result[] executionAndBuildResult = new Result[2]; story.thenWithHardShutdown( j -> { WorkflowRun run = runBasicBuild(j, DEFAULT_JOBNAME, build); String finalId = run.getExecution().getCurrentHeads().get(0).getId(); // Hack but deletes the FlowNodeStorage from disk CpsFlowExecution cpsExec = (CpsFlowExecution)(run.getExecution()); cpsExec.done = false; cpsExec.saveOwner(); executionAndBuildResult[0] = ((CpsFlowExecution)(run.getExecution())).getResult(); executionAndBuildResult[1] = run.getResult(); }); story.then(j-> { WorkflowJob r = j.jenkins.getItemByFullName(DEFAULT_JOBNAME, WorkflowJob.class); WorkflowRun run = r.getBuildByNumber(build[0]); assertCompletedCleanly(run); Assert.assertEquals(Result.SUCCESS, run.getResult()); assertResultMatchExecutionAndRun(run, executionAndBuildResult); }); }
@Issue("JENKINS-50784") @Test public void lazyLoadExecutionStillReplayable() throws Exception { story.then( r-> { WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); WorkflowJob p2 = r.jenkins.createProject(WorkflowJob.class, "p2"); grant(ReplayAction.REPLAY).everywhere().to("normal")); }); story.then( r-> { WorkflowJob job = r.jenkins.getItemByFullName("p", WorkflowJob.class); WorkflowJob job2 = r.jenkins.getItemByFullName("p2", WorkflowJob.class);