### Question:
AsyncOpsLogger implements OpsLogger<T> { @Override public void logThrowable(T message, Throwable cause, Object... details) { try { DiagnosticContext diagnosticContext = new DiagnosticContext(diagnosticContextSupplier); LogicalLogRecord<T> record = new LogicalLogRecord<>(clock.instant(), diagnosticContext, message, Optional.of(cause), details); transferQueue.put(Optional.of(record)); } catch (Throwable t) { errorHandler.accept(t); } } AsyncOpsLogger(Clock clock, DiagnosticContextSupplier diagnosticContextSupplier, Destination<T> destination, Consumer<Throwable> errorHandler, LinkedTransferQueue<Optional<LogicalLogRecord<T>>> transferQueue, AsyncExecutor executor); private  AsyncOpsLogger(Clock clock, DiagnosticContextSupplier diagnosticContextSupplier, Destination<T> destination, Consumer<Throwable> errorHandler, LinkedTransferQueue<Optional<LogicalLogRecord<T>>> transferQueue, Future<?> processingThread, boolean closeable); @Override void log(T message, Object... details); @Override void logThrowable(T message, Throwable cause, Object... details); @Override AsyncOpsLogger<T> with(DiagnosticContextSupplier override); @Override void close(); Clock getClock(); Destination<T> getDestination(); DiagnosticContextSupplier getDiagnosticContextSupplier(); Consumer<Throwable> getErrorHandler(); LinkedTransferQueue<Optional<LogicalLogRecord<T>>> getTransferQueue();  }### Answer:
@Test public void logThrowable_shouldAddALogicalLogRecordToTheQueue_givenALogMessageInstanceAndAThrowable() throws Exception { Map<String, String> expectedCorrelationIds = generateCorrelationIds(); when(diagnosticContextSupplier.getMessageContext()).thenReturn(expectedCorrelationIds); Throwable expectedCause = new RuntimeException(); doNothing().when(transferQueue).put(captor.capture()); logger.logThrowable(TestMessages.Bar, expectedCause, 64, "Hello, World"); verify(transferQueue).put(captor.capture()); LogicalLogRecord<TestMessages> record = captor.getValue().get(); assertEquals(fixedClock.instant(), record.getTimestamp()); assertEquals(expectedCorrelationIds, record.getDiagnosticContext().getContext()); assertEquals(TestMessages.Bar, record.getMessage()); assertNotNull(record.getCause()); assertTrue(record.getCause().isPresent()); assertSame(expectedCause, record.getCause().get()); assertArrayEquals(new Object[] {64, "Hello, World"}, record.getDetails()); }
@Test public void logThrowable_shouldExposeAnExceptionToTheHandler_givenAProblemCreatingTheLogRecordAndAThrowable() throws Exception { logger.logThrowable(null, new RuntimeException()); verify(exceptionConsumer).accept(Mockito.isA(NullPointerException.class)); }
@Test public void logThrowable_shouldExposeAnExceptionToTheHandler_givenAProblemObtainingCorrelationIdsAndAThrowable() throws Exception { Error expectedThrowable = new Error(); when(diagnosticContextSupplier.getMessageContext()).thenThrow(expectedThrowable); logger.logThrowable(TestMessages.Foo, new RuntimeException()); verify(exceptionConsumer).accept(Mockito.same(expectedThrowable)); }
@Test public void logThrowable_shouldExposeAnExceptionToTheHandler_givenAProblemAddingAMessageToTheQueueAndAThrowable() throws Exception { RuntimeException expectedThrowable = new RuntimeException("blah"); doThrow(expectedThrowable).when(transferQueue).put(any()); logger.logThrowable(TestMessages.Foo, new Exception()); verify(exceptionConsumer).accept(Mockito.same(expectedThrowable)); }