public <T> void execute(final AsyncTask<T> task) {
    try {
      // some small tasks such as validation can be performed here.
      task.onPreCall();
    } catch (Exception e) {
      task.onError(e);
      return;
    }

    service.submit(new FutureTask<>(task) {
      @Override
      protected void done() {
        super.done();
        try {
          /*
           * called in context of background thread. There is other variant possible where result is
           * posted back and sits in the queue of caller thread which then picks it up for
           * processing. An example of such a system is Android OS, where the UI elements can only
           * be updated using UI thread. So result must be posted back in UI thread.
           */
          task.onPostCall(get());
        } catch (InterruptedException e) {
          // should not occur
        } catch (ExecutionException e) {
          task.onError(e.getCause());
        }
      }
    });
  }
@Test
  void testPerfectExecution() throws Exception {
    final var result = new Object();
    when(task.call()).thenReturn(result);
    service.execute(task);

    verify(task, timeout(2000)).onPostCall(eq(result));

    final var inOrder = inOrder(task);
    inOrder.verify(task, times(1)).onPreCall();
    inOrder.verify(task, times(1)).call();
    inOrder.verify(task, times(1)).onPostCall(eq(result));

    verifyNoMoreInteractions(task);
  }