@Override
    public List<Extension> getAdditionalExtensions() {
        if (clusterConfig.numControllers() != 1) {
            throw new IllegalArgumentException("For ZK clusters, please specify exactly 1 controller.");
        }
        ClusterInstance clusterShim = new ZkClusterInstance(clusterConfig, clusterReference);
        return Arrays.asList(
            (BeforeTestExecutionCallback) context -> {
                // We have to wait to actually create the underlying cluster until after our @BeforeEach methods
                // have run. This allows tests to set up external dependencies like ZK, MiniKDC, etc.
                // However, since we cannot create this instance until we are inside the test invocation, we have
                // to use a container class (AtomicReference) to provide this cluster object to the test itself
                clusterReference.set(new ClusterConfigurableIntegrationHarness(clusterConfig));
                if (clusterConfig.isAutoStart()) {
                    clusterShim.start();
                }
            },
            (AfterTestExecutionCallback) context -> clusterShim.stop(),
            new ClusterInstanceParameterResolver(clusterShim)
        );
    }
Wraps a {@link IntegrationTestHarness} inside lifecycle methods for a test invocation. Each instance of this
class is provided with a configuration for the cluster.

This context also provides parameter resolvers for:

<ul>
    <li>ClusterConfig (the same instance passed to the constructor)</li>
    <li>ClusterInstance (includes methods to expose underlying SocketServer-s)</li>
</ul>
core/src/test/java/kafka/test/junit/ZkClusterInvocationContext.java