TaskStateMachine { public synchronized TransitionResult updateState(final Optional<ScheduleStatus> status) { requireNonNull(status); Preconditions.checkState(sideEffects.isEmpty()); TaskState taskState = status.transform(STATUS_TO_TASK_STATE).or(DELETED); if (stateMachine.getState() == taskState) { return new TransitionResult(NOOP, ImmutableSet.of()); } boolean success = stateMachine.transition(taskState); ImmutableSet<SideEffect> transitionEffects = ImmutableSet.copyOf(sideEffects); sideEffects.clear(); if (success) { return new TransitionResult(SUCCESS, transitionEffects); } return new TransitionResult( transitionEffects.isEmpty() ? ILLEGAL : ILLEGAL_WITH_SIDE_EFFECTS, transitionEffects); } TaskStateMachine(String name);   TaskStateMachine(IScheduledTask task); private  TaskStateMachine(final String name, final Optional<IScheduledTask> task); synchronized TransitionResult updateState(final Optional<ScheduleStatus> status); @Override String toString();  }
@Test public void testPostTerminalTransitionDenied() { for (ScheduleStatus endState : Tasks.TERMINAL_STATES) { stateMachine = makeStateMachine(makeTask(false)); Set<SideEffect.Action> finalActions = Sets.newHashSet(Action.SAVE_STATE); switch (endState) { case FAILED: finalActions.add(Action.INCREMENT_FAILURES); break; case FINISHED: break; case KILLED: case LOST: finalActions.add(Action.RESCHEDULE); break; case KILLING: finalActions.add(Action.KILL); break; default: fail("Unknown state " + endState); break; } expectUpdateStateOnTransitionTo(PENDING, ASSIGNED, STARTING, RUNNING); legalTransition(TaskState.valueOf(endState.name()), finalActions); for (ScheduleStatus badTransition : Tasks.TERMINAL_STATES) { if (endState.equals(badTransition)) { assertEquals(NOOP, stateMachine.updateState(Optional.of(badTransition)).getResult()); } else { illegalTransition(TaskState.valueOf(badTransition.name())); } } } }
@Test public void testAllTransitions() { for (TaskState from : TaskState.values()) { for (TaskState to : TaskState.values()) { for (Boolean taskPresent : ImmutableList.of(Boolean.TRUE, Boolean.FALSE)) { TestCase testCase = new TestCase(taskPresent, from, to); TransitionResult expectation = EXPECTATIONS.get(testCase); if (expectation == null) { if (taskPresent && from.equals(to) || !taskPresent && to.equals(DELETED)) { expectation = new TransitionResult(NOOP, ImmutableSet.of()); } else { expectation = new TransitionResult(ILLEGAL, ImmutableSet.of()); } } TaskStateMachine machine; if (taskPresent) { boolean expectException = from.equals(DELETED); try { machine = new TaskStateMachine( IScheduledTask.build(makeTask(false).setStatus(from.getStatus().get()))); if (expectException) { fail(); } } catch (IllegalStateException e) { if (expectException) { continue; } else { throw e; } } } else { machine = new TaskStateMachine("name"); } assertEquals( "Unexpected behavior for " + testCase, expectation, machine.updateState(to.getStatus())); } } } }