package com.getsentry.raven.connection; import mockit.*; import com.getsentry.raven.Raven; import com.getsentry.raven.environment.RavenEnvironment; import com.getsentry.raven.event.Event; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeUnit; public class AsyncConnectionTest { @Tested private AsyncConnection asyncConnection = null; @Injectable private Connection mockConnection = null; @Injectable private ExecutorService mockExecutorService = null; @Injectable("false") private boolean mockGracefulShutdown = false; @Injectable private long mockTimeout = 10000L; @SuppressWarnings("unused") @Mocked("addShutdownHook") private Runtime mockRuntime = null; @BeforeMethod public void setUp() throws Exception { new NonStrictExpectations() {{ mockExecutorService.awaitTermination(anyLong, (TimeUnit) any); result = true; }}; } @Test public void verifyShutdownHookIsAddedWhenGraceful() throws Exception { // Ensure that the shutdown hooks for the unused @Tested instance are removed asyncConnection.close(); new AsyncConnection(mockConnection, mockExecutorService, true, mockTimeout); new Verifications() {{ mockRuntime.addShutdownHook((Thread) any); }}; } @Test public void verifyShutdownHookNotAddedWhenNotGraceful() throws Exception { // Ensure that the shutdown hooks for the unused @Tested instance are removed asyncConnection.close(); new AsyncConnection(mockConnection, mockExecutorService, false, mockTimeout); new Verifications() {{ mockRuntime.addShutdownHook((Thread) any); times = 0; }}; } @Test public void verifyShutdownHookSetManagedByRavenAndCloseConnection( @SuppressWarnings("unused") @Mocked({"startManagingThread", "stopManagingThread"}) Raven mockRaven) throws Exception { // Ensure that the shutdown hooks for the unused @Tested instance are removed asyncConnection.close(); new NonStrictExpectations() {{ mockRuntime.addShutdownHook((Thread) any); result = new Delegate<Void>() { @SuppressWarnings("unused") public void addShutdownHook(Thread hook) { hook.run(); } }; }}; new AsyncConnection(mockConnection, mockExecutorService, true, mockTimeout); new VerificationsInOrder() {{ RavenEnvironment.startManagingThread(); mockConnection.close(); RavenEnvironment.stopManagingThread(); }}; } @Test public void ensureFailingShutdownHookStopsBeingManaged( @SuppressWarnings("unused") @Mocked({"startManagingThread", "stopManagingThread"}) Raven mockRaven) throws Exception { // Ensure that the shutdown hooks for the unused @Tested instance are removed asyncConnection.close(); new NonStrictExpectations() {{ mockRuntime.addShutdownHook((Thread) any); result = new Delegate<Void>() { @SuppressWarnings("unused") public void addShutdownHook(Thread hook) { hook.run(); } }; mockConnection.close(); result = new RuntimeException("Close operation failed"); }}; new AsyncConnection(mockConnection, mockExecutorService, true, mockTimeout); new Verifications() {{ RavenEnvironment.stopManagingThread(); }}; } @Test public void testCloseOperation() throws Exception { asyncConnection.close(); new Verifications() {{ mockConnection.close(); mockExecutorService.awaitTermination(anyLong, (TimeUnit) any); }}; } @Test public void testSendEventQueued(@Injectable final Event mockEvent) throws Exception { asyncConnection.send(mockEvent); new Verifications() {{ mockExecutorService.execute((Runnable) any); }}; // Ensure that the shutdown hooks for the used @Tested instance are removed asyncConnection.close(); } @Test public void testQueuedEventExecuted(@Injectable final Event mockEvent) throws Exception { new NonStrictExpectations() {{ mockExecutorService.execute((Runnable) any); result = new Delegate<Void>() { @SuppressWarnings("unused") public void execute(Runnable command) { command.run(); } }; }}; asyncConnection.send(mockEvent); new Verifications() {{ mockConnection.send(mockEvent); }}; // Ensure that the shutdown hooks for the used @Tested instance are removed asyncConnection.close(); } }