public void testStartAlreadyRunning() throws Exception { final int containerId = 1; TestContainerFactory factory = new TestContainerFactory(); @Cleanup StreamSegmentContainerRegistry registry = new StreamSegmentContainerRegistry(factory, executorService());
/** * Tests the getContainer method for registered and unregistered containers. */ @Test public void testGetContainer() throws Exception { final int containerCount = 1000; TestContainerFactory factory = new TestContainerFactory(); @Cleanup StreamSegmentContainerRegistry registry = new StreamSegmentContainerRegistry(factory, executorService()); HashSet<Integer> expectedContainerIds = new HashSet<>(); List<CompletableFuture<ContainerHandle>> handleFutures = new ArrayList<>(); for (int containerId = 0; containerId < containerCount; containerId++) { handleFutures.add(registry.startContainer(containerId, TIMEOUT)); expectedContainerIds.add(containerId); } List<ContainerHandle> handles = Futures.allOfWithResults(handleFutures).join(); HashSet<Integer> actualHandleIds = new HashSet<>(); for (ContainerHandle handle : handles) { actualHandleIds.add(handle.getContainerId()); SegmentContainer container = registry.getContainer(handle.getContainerId()); Assert.assertTrue("Wrong container Java type.", container instanceof TestContainer); Assert.assertEquals("Unexpected container Id.", handle.getContainerId(), container.getId()); container.close(); } AssertExtensions.assertContainsSameElements("Unexpected container ids registered.", expectedContainerIds, actualHandleIds); AssertExtensions.assertThrows( "getContainer did not throw when passed an invalid container id.", () -> registry.getContainer(containerCount + 1), ex -> ex instanceof ContainerNotFoundException); }
/** * Tests the ability to detect a container failure and unregister the container in case the container fails on startup. */ @Test public void testContainerFailureOnStartup() throws Exception { final int containerId = 123; // We insert a ReusableLatch that will allow us to manually delay the TestContainer's shutdown/closing process // so that we have enough time to verify that calling getContainer() on a currently shutting down container will // throw the appropriate exception. ReusableLatch closeReleaseSignal = new ReusableLatch(); TestContainerFactory factory = new TestContainerFactory(new IntentionalException(), closeReleaseSignal); @Cleanup StreamSegmentContainerRegistry registry = new StreamSegmentContainerRegistry(factory, executorService()); AssertExtensions.assertThrows( "Unexpected exception thrown upon failed container startup.", registry.startContainer(containerId, TIMEOUT)::join, ex -> ex instanceof IntentionalException || (ex instanceof IllegalStateException && ex.getCause() instanceof IntentionalException)); AssertExtensions.assertThrows( "Container is registered even if it failed to start (and is currently shut down).", () -> registry.getContainer(containerId), ex -> ex instanceof ContainerNotFoundException); // Unblock container closing, which will, in turn, unblock its de-registration. closeReleaseSignal.release(); AssertExtensions.assertThrows( "Container is registered even if it failed to start (and has been unregistered).", () -> registry.getContainer(containerId), ex -> ex instanceof ContainerNotFoundException); }
/** * Tests the ability to detect a container failure and unregister the container in case the container fails while running. */ @Test public void testContainerFailureWhileRunning() throws Exception { final int containerId = 123; TestContainerFactory factory = new TestContainerFactory(); @Cleanup StreamSegmentContainerRegistry registry = new StreamSegmentContainerRegistry(factory, executorService()); ContainerHandle handle = registry.startContainer(containerId, TIMEOUT).join(); // Register a Listener for the Container.Stop event. Make this a Future since these callbacks are invoked async // so they may finish executing after stop() finished. CompletableFuture<Integer> stopListenerCallback = new CompletableFuture<>(); handle.setContainerStoppedListener(stopListenerCallback::complete); TestContainer container = (TestContainer) registry.getContainer(handle.getContainerId()); // Fail the container and wait for it to properly terminate. container.fail(new IntentionalException()); ServiceListeners.awaitShutdown(container, false); Assert.assertEquals("Unexpected value passed to Handle.stopListenerCallback or callback was not invoked.", containerId, (int) stopListenerCallback.join()); AssertExtensions.assertThrows( "Container is still registered after failure.", () -> registry.getContainer(containerId), ex -> ex instanceof ContainerNotFoundException); }
/** * Tests the ability to stop the container via the stopContainer() method. */ @Test public void testStopContainer() throws Exception { final int containerId = 123; TestContainerFactory factory = new TestContainerFactory(); @Cleanup StreamSegmentContainerRegistry registry = new StreamSegmentContainerRegistry(factory, executorService()); ContainerHandle handle = registry.startContainer(containerId, TIMEOUT).join(); // Register a Listener for the Container.Stop event. Make this a Future since these callbacks are invoked async // so they may finish executing after stop() finished. CompletableFuture<Integer> stopListenerCallback = new CompletableFuture<>(); handle.setContainerStoppedListener(stopListenerCallback::complete); TestContainer container = (TestContainer) registry.getContainer(handle.getContainerId()); Assert.assertFalse("Container is closed before being shut down.", container.isClosed()); registry.stopContainer(handle, TIMEOUT).join(); Assert.assertEquals("Unexpected value passed to Handle.stopListenerCallback or callback was not invoked.", containerId, (int) stopListenerCallback.join()); Assert.assertTrue("Container is not closed after being shut down.", container.isClosed()); AssertExtensions.assertThrows( "Container is still registered after being shut down.", () -> registry.getContainer(handle.getContainerId()), ex -> ex instanceof ContainerNotFoundException); }