abstract void execute(Admin admin, Namespace ns, PrintStream out) throws Exception;
@Test
    public void testDescribeTransaction() throws Exception {
        String transactionalId = "foo";
        String[] args = new String[] {
            "--bootstrap-server",
            "localhost:9092",
            "describe",
            "--transactional-id",
            transactionalId
        };

        DescribeTransactionsResult describeResult = Mockito.mock(DescribeTransactionsResult.class);

        int coordinatorId = 5;
        long transactionStartTime = time.milliseconds();

        KafkaFuture<TransactionDescription> describeFuture = completedFuture(
            new TransactionDescription(
                coordinatorId,
                TransactionState.ONGOING,
                12345L,
                15,
                10000,
                OptionalLong.of(transactionStartTime),
                singleton(new TopicPartition("bar", 0))
        ));

        Mockito.when(describeResult.description(transactionalId)).thenReturn(describeFuture);
        Mockito.when(admin.describeTransactions(singleton(transactionalId))).thenReturn(describeResult);

        // Add a little time so that we can see a positive transaction duration in the output
        time.sleep(5000);

        execute(args);
        assertNormalExit();

        List<List<String>> table = readOutputAsTable();
        assertEquals(2, table.size());

        List<String> expectedHeaders = TransactionsCommand.DescribeTransactionsCommand.HEADERS;
        assertEquals(expectedHeaders, table.get(0));

        List<String> expectedRow = asList(
            String.valueOf(coordinatorId),
            transactionalId,
            "12345",
            "15",
            "Ongoing",
            "10000",
            String.valueOf(transactionStartTime),
            "5000",
            "bar-0"
        );
        assertEquals(expectedRow, table.get(1));
    }