### Question:
Step { public String getName() { String name = getClass().getName(); int idx = name.lastIndexOf('.'); if (idx >= 0) { name = name.substring(idx + 1); } name = name.endsWith("Step") ? name.substring(0, name.length() - 4) : name; String detail = getDetail(); return detail != null ? name + "(" + detail + ")" : name; } protected  Step(); protected  Step(Step next); static Step chain(Step... stepGroups); String getName(); @Override String toString(); abstract NextAction apply(Packet packet); Step getNext();  }### Answer:
@Test public void testSuspendAndThrow() throws InterruptedException { final Step stepline = createStepline(Arrays.asList(Step1.class, Step2.class, Step3.class)); Packet p = new Packet(); Map<Class<? extends BaseStep>, Command> commandMap = new HashMap<>(); commandMap.put( Step2.class, new Command(RELEASE_SEMAPHORE, ACQUIRE_SEMAPHORE, SUSPEND_AND_THROW)); p.put(NA, commandMap); Semaphore releaseSemaphore = new Semaphore(0); Semaphore acquireSemaphore = new Semaphore(0); p.put(Step2.class.getName() + RELEASE_SEMAPHORE_SUFFIX, releaseSemaphore); p.put(Step2.class.getName() + ACQUIRE_SEMAPHORE_SUFFIX, acquireSemaphore); Semaphore signal = new Semaphore(0); List<Throwable> throwables = new ArrayList<>(); engine .createFiber() .start( stepline, p, new CompletionCallback() { @Override public void onCompletion(Packet packet) { signal.release(); } @Override public void onThrowable(Packet packet, Throwable throwable) { throwables.add(throwable); signal.release(); } }); releaseSemaphore.acquire(); acquireSemaphore.release(); @SuppressWarnings({"unchecked", "rawtypes"}) List<Step> called = (List) p.get(MARK); boolean result = signal.tryAcquire(1, TimeUnit.SECONDS); assertFalse(result); assertEquals(2, called.size()); assertTrue(called.get(0) instanceof Step1); assertTrue(called.get(1) instanceof Step2); }
@Test public void testCancel() throws InterruptedException { final Step stepline = createStepline(Arrays.asList(Step1.class, Step2.class, Step3.class)); Packet p = new Packet(); Map<Class<? extends BaseStep>, Command> commandMap = new HashMap<>(); commandMap.put(Step2.class, new Command(RELEASE_SEMAPHORE, ACQUIRE_SEMAPHORE, INVOKE_NEXT)); p.put(NA, commandMap); Semaphore releaseSemaphore = new Semaphore(0); Semaphore acquireSemaphore = new Semaphore(0); p.put(Step2.class.getName() + RELEASE_SEMAPHORE_SUFFIX, releaseSemaphore); p.put(Step2.class.getName() + ACQUIRE_SEMAPHORE_SUFFIX, acquireSemaphore); Semaphore signal = new Semaphore(0); List<Throwable> throwables = new ArrayList<>(); Fiber f = engine.createFiber(); f.start( stepline, p, new CompletionCallback() { @Override public void onCompletion(Packet packet) { signal.release(); } @Override public void onThrowable(Packet packet, Throwable throwable) { throwables.add(throwable); signal.release(); } }); releaseSemaphore.acquire(); f.cancel(false); acquireSemaphore.release(); @SuppressWarnings({"unchecked", "rawtypes"}) final List<Step> called = (List) p.get(MARK); boolean result = signal.tryAcquire(1, TimeUnit.SECONDS); assertFalse(result); assertTrue(f.isCancelled()); assertFalse(f.isDone()); assertEquals(2, called.size()); assertTrue(called.get(0) instanceof Step1); assertTrue(called.get(1) instanceof Step2); assertTrue(throwables.isEmpty()); }