@Override public void completed(final Status status) { final List<FlowCallback> callbackList; synchronized (sync) { updateState(); callbackList = callbacksToCall; // Get the reference before leaving the synchronized } if (jobState == Status.SUCCEEDED && notifiedCallbackAlready.compareAndSet(false, true)) { callCallbacks(callbackList, Status.SUCCEEDED); } else if (jobState == Status.FAILED && notifiedCallbackAlready.compareAndSet(false, true)) { for (ExecutableFlow flow : flows) { exceptions.putAll(flow.getExceptions()); } callCallbacks(callbackList, Status.FAILED); } else { for (FlowCallback flowCallback : callbackList) { flowCallback.progressMade(); } } }
@Test public void testFailureJob2() throws Exception { final AtomicLong numJobsComplete = new AtomicLong(0); /** ** Setup mockFlow1 *** */ final Capture<FlowCallback> flow1Callback = new Capture<FlowCallback>(); mockFlow1.execute(EasyMock.eq(props), EasyMock.capture(flow1Callback)); EasyMock.expectLastCall() .andAnswer( new IAnswer<Void>() { @Override public Void answer() throws Throwable { Assert.assertEquals(Status.RUNNING, flow.getStatus()); Assert.assertEquals(1, numJobsComplete.incrementAndGet()); flow1Callback.getValue().completed(Status.SUCCEEDED); return null; } }) .once(); EasyMock.expect(mockFlow1.getStatus()).andReturn(Status.SUCCEEDED).times(2); EasyMock.expect(mockFlow1.getExceptions()).andReturn(emptyExceptions).times(1); /** ** Setup mockFlow2 *** */ final Capture<FlowCallback> flow2Callback = new Capture<FlowCallback>(); mockFlow2.execute(EasyMock.eq(props), EasyMock.capture(flow2Callback)); EasyMock.expectLastCall() .andAnswer( new IAnswer<Void>() { @Override public Void answer() throws Throwable { Assert.assertEquals(Status.RUNNING, flow.getStatus()); Assert.assertEquals(2, numJobsComplete.incrementAndGet()); flow2Callback.getValue().completed(Status.FAILED); return null; } }) .once(); EasyMock.expect(mockFlow2.getStatus()) .andAnswer( new IAnswer<Status>() { private volatile AtomicInteger count = new AtomicInteger(0); @Override public Status answer() throws Throwable { switch (count.getAndIncrement()) { case 0: return Status.READY; case 1: return Status.FAILED; default: Assert.fail("mockFlow2.getStatus() should only be called 2 times."); } return null; } }) .times(2); final RuntimeException e1 = new RuntimeException(); final RuntimeException e2 = new RuntimeException(); final Map<String, Throwable> e1s = new HashMap<String, Throwable>(); e1s.put("e1", e1); e1s.put("e2", e2); EasyMock.expect(mockFlow2.getExceptions()).andReturn(e1s).times(1); EasyMock.expect(props.equalsProps(props)).andReturn(true).once(); EasyMock.replay(mockFlow1, mockFlow2, props); /** ** Start the test *** */ AtomicBoolean callbackRan = new AtomicBoolean(false); flow.execute( props, new OneCallFlowCallback(callbackRan) { @Override public void theCallback(Status status) { Assert.assertEquals(Status.FAILED, status); } }); Assert.assertTrue("Callback wasn't run.", callbackRan.get()); Assert.assertEquals(Status.FAILED, flow.getStatus()); Assert.assertEquals(e1s, flow.getExceptions()); callbackRan = new AtomicBoolean(false); flow.execute( props, new OneCallFlowCallback(callbackRan) { @Override protected void theCallback(Status status) { Assert.assertEquals(Status.FAILED, status); Assert.assertEquals(2, numJobsComplete.get()); } }); Assert.assertTrue("Callback wasn't run.", callbackRan.get()); Assert.assertEquals(Status.FAILED, flow.getStatus()); Assert.assertEquals(e1s, flow.getExceptions()); Assert.assertTrue("Expected to be able to reset the flow", flow.reset()); Assert.assertEquals(Status.READY, flow.getStatus()); Assert.assertEquals(emptyExceptions, flow.getExceptions()); }
@Test public void testFailureJob1() throws Exception { final AtomicLong numJobsComplete = new AtomicLong(0); /** ** Setup mockFlow1 *** */ final Capture<FlowCallback> flow1Callback = new Capture<FlowCallback>(); mockFlow1.execute(EasyMock.eq(props), EasyMock.capture(flow1Callback)); EasyMock.expectLastCall() .andAnswer( new IAnswer<Void>() { @Override public Void answer() throws Throwable { Assert.assertEquals(Status.RUNNING, flow.getStatus()); Assert.assertEquals(1, numJobsComplete.incrementAndGet()); flow1Callback.getValue().completed(Status.FAILED); return null; } }) .once(); EasyMock.expect(mockFlow1.getStatus()).andReturn(Status.FAILED).times(1); EasyMock.expect(mockFlow1.getExceptions()).andReturn(theExceptions).times(1); EasyMock.expect(props.equalsProps(props)).andReturn(true).once(); /** ** Setup mockFlow2 *** */ EasyMock.expect(mockFlow2.getExceptions()).andReturn(emptyExceptions).times(1); EasyMock.replay(mockFlow1, mockFlow2, props); /** ** Start the test *** */ AtomicBoolean callbackRan = new AtomicBoolean(false); flow.execute( props, new OneCallFlowCallback(callbackRan) { @Override public void theCallback(Status status) { Assert.assertEquals(Status.FAILED, status); } }); Assert.assertTrue("Callback wasn't run.", callbackRan.get()); Assert.assertEquals(Status.FAILED, flow.getStatus()); Assert.assertEquals(theExceptions, flow.getExceptions()); callbackRan = new AtomicBoolean(false); flow.execute( props, new OneCallFlowCallback(callbackRan) { @Override protected void theCallback(Status status) { Assert.assertEquals(Status.FAILED, status); } }); Assert.assertTrue("Callback wasn't run.", callbackRan.get()); Assert.assertEquals(Status.FAILED, flow.getStatus()); Assert.assertEquals(theExceptions, flow.getExceptions()); Assert.assertTrue("Expected to be able to reset the flow", flow.reset()); Assert.assertEquals(Status.READY, flow.getStatus()); Assert.assertEquals(emptyExceptions, flow.getExceptions()); }