@Test(timeout = 10000) public void testCommandsAgainstInexistentAggregatesOnlyRetriedOnce() throws Throwable { inMemoryEventStore.storedEvents.clear(); testSubject = new DisruptorCommandBus<StubAggregate>( new GenericAggregateFactory<StubAggregate>(StubAggregate.class), inMemoryEventStore, eventBus, new MetaDataCommandTargetResolver(TARGET_AGGREGATE_PROPERTY)); stubHandler.setRepository(testSubject); StubHandler spy = spy(stubHandler); testSubject.subscribe(StubCommand.class, spy); List<CommandMessage<StubCommand>> dispatchedCommands = new ArrayList<CommandMessage<StubCommand>>(); for (int i = 0; i < 10; i++) { CommandMessage<StubCommand> subsequentCommand = new GenericCommandMessage<StubCommand>( new StubCommand(aggregateIdentifier), singletonMap(TARGET_AGGREGATE_PROPERTY, (Object) aggregateIdentifier)); testSubject.dispatch(subsequentCommand); dispatchedCommands.add(subsequentCommand); } testSubject.stop(); assertTrue(inMemoryEventStore.storedEvents.isEmpty()); for (CommandMessage<StubCommand> command : dispatchedCommands) { // subsequent commands could be retried more that once, as the aggregate they work in is // blacklisted verify(spy, atLeast(2)).handle(same(command), isA(UnitOfWork.class)); } }
@Test public void testCommandProcessedAndEventsStored() throws InterruptedException { testSubject = new DisruptorCommandBus<StubAggregate>( new GenericAggregateFactory<StubAggregate>(StubAggregate.class), inMemoryEventStore, eventBus, new MetaDataCommandTargetResolver(TARGET_AGGREGATE_PROPERTY)); testSubject.subscribe(StubCommand.class, stubHandler); stubHandler.setRepository(testSubject); for (int i = 0; i < COMMAND_COUNT; i++) { CommandMessage<StubCommand> command = new GenericCommandMessage<StubCommand>( new StubCommand(aggregateIdentifier), singletonMap(TARGET_AGGREGATE_PROPERTY, (Object) aggregateIdentifier)); testSubject.dispatch(command); } inMemoryEventStore.countDownLatch.await(5, TimeUnit.SECONDS); eventBus.publisherCountDown.await(1, TimeUnit.SECONDS); assertEquals( "Seems that some events are not published", 0, eventBus.publisherCountDown.getCount()); assertEquals( "Seems that some events are not stored", 0, inMemoryEventStore.countDownLatch.getCount()); }
@Test public void testCreateAggregate() { inMemoryEventStore.storedEvents.clear(); testSubject = new DisruptorCommandBus<StubAggregate>( new GenericAggregateFactory<StubAggregate>(StubAggregate.class), inMemoryEventStore, eventBus, new MetaDataCommandTargetResolver(TARGET_AGGREGATE_PROPERTY), new DisruptorConfiguration() .setClaimStrategy(new SingleThreadedClaimStrategy(8)) .setWaitStrategy(new SleepingWaitStrategy())); testSubject.subscribe(StubCommand.class, stubHandler); testSubject.subscribe(CreateCommand.class, stubHandler); testSubject.subscribe(ErrorCommand.class, stubHandler); stubHandler.setRepository(testSubject); testSubject.dispatch( new GenericCommandMessage<Object>( new CreateCommand(aggregateIdentifier), singletonMap(TARGET_AGGREGATE_PROPERTY, (Object) aggregateIdentifier))); testSubject.stop(); DomainEventMessage lastEvent = inMemoryEventStore.storedEvents.get(aggregateIdentifier); assertEquals(0, lastEvent.getSequenceNumber()); assertEquals(aggregateIdentifier, lastEvent.getAggregateIdentifier()); }
@SuppressWarnings("unchecked") @Test public void testCallbackInvokedBeforeUnitOfWorkCleanup() throws Throwable { CommandHandlerInterceptor mockInterceptor = mock(CommandHandlerInterceptor.class); ExecutorService customExecutor = Executors.newCachedThreadPool(); testSubject = new DisruptorCommandBus<StubAggregate>( new GenericAggregateFactory<StubAggregate>(StubAggregate.class), inMemoryEventStore, eventBus, new MetaDataCommandTargetResolver(TARGET_AGGREGATE_PROPERTY), new DisruptorConfiguration() .setInvokerInterceptors(Arrays.asList(mockInterceptor)) .setClaimStrategy(new SingleThreadedClaimStrategy(8)) .setWaitStrategy(new SleepingWaitStrategy()) .setExecutor(customExecutor)); testSubject.subscribe(StubCommand.class, stubHandler); stubHandler.setRepository(testSubject); final UnitOfWorkListener mockUnitOfWorkListener = mock(UnitOfWorkListener.class); when(mockUnitOfWorkListener.onEventRegistered(any(EventMessage.class))) .thenAnswer( new Answer<Object>() { @Override public Object answer(InvocationOnMock invocation) throws Throwable { return invocation.getArguments()[0]; } }); when(mockInterceptor.handle( any(CommandMessage.class), any(UnitOfWork.class), any(InterceptorChain.class))) .thenAnswer( new Answer<Object>() { @Override public Object answer(InvocationOnMock invocation) throws Throwable { ((UnitOfWork) invocation.getArguments()[1]) .registerListener(mockUnitOfWorkListener); return ((InterceptorChain) invocation.getArguments()[2]).proceed(); } }); CommandMessage<StubCommand> command = new GenericCommandMessage<StubCommand>( new StubCommand(aggregateIdentifier), singletonMap(TARGET_AGGREGATE_PROPERTY, (Object) aggregateIdentifier)); CommandCallback mockCallback = mock(CommandCallback.class); testSubject.dispatch(command, mockCallback); testSubject.stop(); assertFalse(customExecutor.awaitTermination(250, TimeUnit.MILLISECONDS)); customExecutor.shutdown(); assertTrue(customExecutor.awaitTermination(5, TimeUnit.SECONDS)); InOrder inOrder = inOrder(mockInterceptor, mockUnitOfWorkListener, mockCallback); inOrder .verify(mockInterceptor) .handle(any(CommandMessage.class), any(UnitOfWork.class), any(InterceptorChain.class)); inOrder.verify(mockUnitOfWorkListener).onPrepareCommit(any(Set.class), any(List.class)); inOrder.verify(mockUnitOfWorkListener).afterCommit(); inOrder.verify(mockUnitOfWorkListener).onCleanup(); verify(mockCallback).onSuccess(any()); }
@Test(expected = IllegalStateException.class) public void testCommandRejectedAfterShutdown() throws InterruptedException { testSubject = new DisruptorCommandBus<StubAggregate>( new GenericAggregateFactory<StubAggregate>(StubAggregate.class), inMemoryEventStore, eventBus, new MetaDataCommandTargetResolver(TARGET_AGGREGATE_PROPERTY)); testSubject.subscribe(StubCommand.class, stubHandler); stubHandler.setRepository(testSubject); testSubject.stop(); testSubject.dispatch(new GenericCommandMessage<Object>(new Object())); }
@After public void tearDown() { testSubject.stop(); }
private CommandCallback dispatchCommands( CommandHandlerInterceptor mockInterceptor, ExecutorService customExecutor, GenericCommandMessage<ErrorCommand> errorCommand) throws Throwable { inMemoryEventStore.storedEvents.clear(); testSubject = new DisruptorCommandBus<StubAggregate>( new GenericAggregateFactory<StubAggregate>(StubAggregate.class), inMemoryEventStore, eventBus, new MetaDataCommandTargetResolver(TARGET_AGGREGATE_PROPERTY), new DisruptorConfiguration() .setInvokerInterceptors(Arrays.asList(mockInterceptor)) .setClaimStrategy(new MultiThreadedClaimStrategy(8)) .setWaitStrategy(new SleepingWaitStrategy()) .setExecutor(customExecutor) .setRollbackConfiguration(new RollbackOnAllExceptionsConfiguration())); testSubject.subscribe(StubCommand.class, stubHandler); testSubject.subscribe(CreateCommand.class, stubHandler); testSubject.subscribe(ErrorCommand.class, stubHandler); stubHandler.setRepository(testSubject); final UnitOfWorkListener mockUnitOfWorkListener = mock(UnitOfWorkListener.class); when(mockUnitOfWorkListener.onEventRegistered(any(EventMessage.class))) .thenAnswer( new Answer<Object>() { @Override public Object answer(InvocationOnMock invocation) throws Throwable { return invocation.getArguments()[0]; } }); when(mockInterceptor.handle( any(CommandMessage.class), any(UnitOfWork.class), any(InterceptorChain.class))) .thenAnswer( new Answer<Object>() { @Override public Object answer(InvocationOnMock invocation) throws Throwable { ((UnitOfWork) invocation.getArguments()[1]) .registerListener(mockUnitOfWorkListener); return ((InterceptorChain) invocation.getArguments()[2]).proceed(); } }); testSubject.dispatch( new GenericCommandMessage<CreateCommand>( new CreateCommand(aggregateIdentifier), singletonMap(TARGET_AGGREGATE_PROPERTY, aggregateIdentifier))); CommandCallback mockCallback = mock(CommandCallback.class); for (int t = 0; t < 1000; t++) { CommandMessage command; if (t % 100 == 10) { command = errorCommand; } else { command = new GenericCommandMessage<StubCommand>( new StubCommand(aggregateIdentifier), singletonMap(TARGET_AGGREGATE_PROPERTY, (Object) aggregateIdentifier)); } testSubject.dispatch(command, mockCallback); } testSubject.stop(); return mockCallback; }