static String prettyPrintTaskInfo(TaskState taskState, ZoneOffset zoneOffset) {
        if (taskState instanceof TaskPending) {
            return "Will start at " + dateString(taskState.spec().startMs(), zoneOffset);
        } else if (taskState instanceof TaskRunning) {
            TaskRunning runState = (TaskRunning) taskState;
            return "Started " + dateString(runState.startedMs(), zoneOffset) +
                "; will stop after " + durationString(taskState.spec().durationMs());
        } else if (taskState instanceof TaskStopping) {
            TaskStopping stoppingState = (TaskStopping) taskState;
            return "Started " + dateString(stoppingState.startedMs(), zoneOffset);
        } else if (taskState instanceof TaskDone) {
            TaskDone doneState = (TaskDone) taskState;
            String status;
            if (doneState.error() == null || doneState.error().isEmpty()) {
                if (doneState.cancelled()) {
                    status = "CANCELLED";
                } else {
                    status = "FINISHED";
                }
            } else {
                status = "FAILED";
            }
            return String.format("%s at %s after %s", status,
                dateString(doneState.doneMs(), zoneOffset),
                durationString(doneState.doneMs() - doneState.startedMs()));
        } else {
            throw new RuntimeException("Unknown task state type " + taskState.stateType());
        }
    }
@Test
    public void testPrettyPrintTaskInfo() {
        assertEquals("Will start at 2019-01-08T07:05:59.85Z",
            CoordinatorClient.prettyPrintTaskInfo(
                new TaskPending(new NoOpTaskSpec(1546931159850L, 9000)),
                ZoneOffset.UTC));
        assertEquals("Started 2009-07-07T01:45:59.85Z; will stop after 9s",
            CoordinatorClient.prettyPrintTaskInfo(
                new TaskRunning(new NoOpTaskSpec(1146931159850L, 9000),
                    1246931159850L,
                    JsonNodeFactory.instance.objectNode()), ZoneOffset.UTC));
        assertEquals("Started 2009-07-07T01:45:59.85Z",
            CoordinatorClient.prettyPrintTaskInfo(
                new TaskStopping(new NoOpTaskSpec(1146931159850L, 9000),
                    1246931159850L,
                    JsonNodeFactory.instance.objectNode()), ZoneOffset.UTC));
        assertEquals("FINISHED at 2019-01-08T20:59:29.85Z after 10s",
            CoordinatorClient.prettyPrintTaskInfo(
                new TaskDone(new NoOpTaskSpec(0, 1000),
                    1546981159850L,
                    1546981169850L,
                    "",
                    false,
                    JsonNodeFactory.instance.objectNode()), ZoneOffset.UTC));
        assertEquals("CANCELLED at 2019-01-08T20:59:29.85Z after 10s",
            CoordinatorClient.prettyPrintTaskInfo(
                new TaskDone(new NoOpTaskSpec(0, 1000),
                    1546981159850L,
                    1546981169850L,
                    "",
                    true,
                    JsonNodeFactory.instance.objectNode()), ZoneOffset.UTC));
        assertEquals("FAILED at 2019-01-08T20:59:29.85Z after 10s",
            CoordinatorClient.prettyPrintTaskInfo(
                new TaskDone(new NoOpTaskSpec(0, 1000),
                    1546981159850L,
                    1546981169850L,
                    "foobar",
                    true,
                    JsonNodeFactory.instance.objectNode()), ZoneOffset.UTC));
    }