@Test
    void testAsyncFederation() throws InterruptedException, ExecutionException {
        // Setup environment
        AsyncProviderSearcher asyncProviderSearcher = new AsyncProviderSearcher();
        Searcher syncProviderSearcher = new SyncProviderSearcher();
        Chain<Searcher> asyncSource = new Chain<>(new ComponentId("async"), asyncProviderSearcher);
        Chain<Searcher> syncSource = new Chain<>(new ComponentId("sync"), syncProviderSearcher);
        var searchChainResolver = new SearchChainResolver.Builder()
                .addSearchChain(new ComponentId("sync"), new FederationOptions().setUseByDefault(true))
                .addSearchChain(new ComponentId("async"), new FederationOptions().setUseByDefault(true))
                .build();
        Chain<Searcher> main = new Chain<>(new FederationSearcher(searchChainResolver, Map.of()));
        SearchChainRegistry searchChainRegistry = new SearchChainRegistry();
        searchChainRegistry.register(main);
        searchChainRegistry.register(syncSource);
        searchChainRegistry.register(asyncSource);

        Query query = new Query();
        query.setTimeout(5000);
        Result result = new Execution(main, Execution.Context.createContextStub(searchChainRegistry)).search(query);
        assertNotNull(result);

        HitGroup syncGroup = (HitGroup) result.hits().get("source:sync");
        assertNotNull(syncGroup);

        HitGroup asyncGroup = (HitGroup) result.hits().get("source:async");
        assertNotNull(asyncGroup);

        assertEquals(3, syncGroup.size(), "Got all sync data");
        assertEquals("sync:0", syncGroup.get(0).getId().toString());
        assertEquals("sync:1", syncGroup.get(1).getId().toString());
        assertEquals("sync:2",  syncGroup.get(2).getId().toString());

        assertEquals(asyncGroup.incoming(), asyncProviderSearcher.incomingData);
        assertEquals(0, asyncGroup.size(), "Got no async data yet");
        asyncProviderSearcher.simulateOneHitIOComplete(new Hit("async:0"));
        assertEquals(0, asyncGroup.size(), "Got no async data yet, as we haven't completed the incoming buffer and there is no data listener");
        asyncProviderSearcher.simulateOneHitIOComplete(new Hit("async:1"));
        asyncProviderSearcher.simulateAllHitsIOComplete();
        assertEquals(0, asyncGroup.size(), "Got no async data yet, as we haven't pulled it");
        asyncGroup.completeFuture().get();
        assertEquals(2, asyncGroup.size(), "Completed, so we have the data");
        assertEquals("async:0", asyncGroup.get(0).getId().toString());
        assertEquals("async:1", asyncGroup.get(1).getId().toString());
    }
Tests using the async capabilities of the Processing parent framework of searchers.

@author bratseth
container-search/src/test/java/com/yahoo/search/searchchain/test/FutureDataTestCase.java