@Test public void testLoadAndSaveWithConflictingChanges() { ConflictResolver conflictResolver = mock(ConflictResolver.class); UUID identifier = UUID.randomUUID(); DomainEventMessage event2 = new GenericDomainEventMessage<String>( identifier, (long) 2, "Mock contents", MetaData.emptyInstance()); DomainEventMessage event3 = new GenericDomainEventMessage<String>( identifier, (long) 3, "Mock contents", MetaData.emptyInstance()); when(mockEventStore.readEvents("test", identifier)) .thenReturn( new SimpleDomainEventStream( new GenericDomainEventMessage<String>( identifier, (long) 1, "Mock contents", MetaData.emptyInstance()), event2, event3)); testSubject.setConflictResolver(conflictResolver); TestAggregate actual = testSubject.load(identifier, 1L); verify(conflictResolver, never()) .resolveConflicts(anyListOf(DomainEventMessage.class), anyListOf(DomainEventMessage.class)); final StubDomainEvent appliedEvent = new StubDomainEvent(); actual.apply(appliedEvent); CurrentUnitOfWork.commit(); verify(conflictResolver) .resolveConflicts(payloadsEqual(appliedEvent), eq(Arrays.asList(event2, event3))); }
public static void main(String[] args) { // let's start with the Command Bus CommandBus commandBus = new SimpleCommandBus(); // the CommandGateway provides a friendlier API to send commands CommandGateway commandGateway = new DefaultCommandGateway(commandBus); // we'll store Events on the FileSystem, in the "events" folder EventStore eventStore = new FileSystemEventStore(new SimpleEventFileResolver(new File("./events"))); // a Simple Event Bus will do EventBus eventBus = new SimpleEventBus(); // we need to configure the repository EventSourcingRepository<ToDoItem> repository = new EventSourcingRepository<>(ToDoItem.class, eventStore); repository.setEventBus(eventBus); // Axon needs to know that our ToDoItem Aggregate can handle commands new AggregateAnnotationCommandHandler<>(ToDoItem.class, repository).subscribe(commandBus); // We register an event listener to see which events are created eventBus.subscribe( new SimpleEventProcessor( "logging", new AnnotationEventListenerAdapter(new ToDoEventHandler()))); // and let's send some Commands on the CommandBus. CommandGenerator.sendCommands(commandGateway); }
@Test public void testLoadEventsWithDecorators() { UUID identifier = UUID.randomUUID(); SpyEventPreprocessor decorator1 = new SpyEventPreprocessor(); SpyEventPreprocessor decorator2 = new SpyEventPreprocessor(); testSubject.setEventStreamDecorators(Arrays.asList(decorator1, decorator2)); when(mockEventStore.readEvents("test", identifier)) .thenReturn( new SimpleDomainEventStream( new GenericDomainEventMessage<String>( identifier, (long) 1, "Mock contents", MetaData.emptyInstance()), new GenericDomainEventMessage<String>( identifier, (long) 2, "Mock contents", MetaData.emptyInstance()), new GenericDomainEventMessage<String>( identifier, (long) 3, "Mock contents", MetaData.emptyInstance()))); TestAggregate aggregate = testSubject.load(identifier); // loading them in... InOrder inOrder = Mockito.inOrder(decorator1.lastSpy, decorator2.lastSpy); inOrder.verify(decorator2.lastSpy).next(); inOrder.verify(decorator1.lastSpy).next(); inOrder.verify(decorator2.lastSpy).next(); inOrder.verify(decorator1.lastSpy).next(); inOrder.verify(decorator2.lastSpy).next(); inOrder.verify(decorator1.lastSpy).next(); aggregate.apply(new StubDomainEvent()); aggregate.apply(new StubDomainEvent()); }
@Bean Repository<TimesheetAR> timesheetARRepository( EventBus eventBus, SnapshotEventStore eventStore, SnapshotterTrigger snapshotterTrigger) { EventSourcingRepository<TimesheetAR> repository = new EventSourcingRepository<TimesheetAR>(timesheetAggregateFactory(), eventStore); repository.setEventBus(eventBus); repository.setSnapshotterTrigger(snapshotterTrigger); return repository; }
@Before public void setUp() { mockEventStore = mock(SnapshotEventStore.class); mockEventBus = mock(EventBus.class); testSubject = new EventSourcingRepository<TestAggregate>(new SubtAggregateFactory()); testSubject.setEventBus(mockEventBus); testSubject.setEventStore(mockEventStore); unitOfWork = DefaultUnitOfWork.startAndGet(); }
@Before public void setUp() { repository = new EventSourcingRepository<StubAggregate>(StubAggregate.class); mockEventBus = mock(EventBus.class); mockEventStore = new StubEventStore(); repository.setEventBus(mockEventBus); repository.setEventStore(mockEventStore); aggregateIdentifier = "testAggregateIdentifier"; }
@Bean public EventSourcingRepository<SalesChannel> salesChannelRepository() { FileSystemEventStore eventStore = new FileSystemEventStore(new SimpleEventFileResolver(new File("data/eventstore"))); EventSourcingRepository<SalesChannel> repository = new EventSourcingRepository<SalesChannel>(SalesChannel.class, eventStore); repository.setEventBus(eventBus()); return repository; }
@Test public void testLoadAndSaveAggregate() { UUID identifier = UUID.randomUUID(); DomainEventMessage event1 = new GenericDomainEventMessage<String>( identifier, (long) 1, "Mock contents", MetaData.emptyInstance()); DomainEventMessage event2 = new GenericDomainEventMessage<String>( identifier, (long) 2, "Mock contents", MetaData.emptyInstance()); when(mockEventStore.readEvents("test", identifier)) .thenReturn(new SimpleDomainEventStream(event1, event2)); TestAggregate aggregate = testSubject.load(identifier, null); assertEquals(0, aggregate.getUncommittedEventCount()); assertEquals(2, aggregate.getHandledEvents().size()); assertSame(event1, aggregate.getHandledEvents().get(0)); assertSame(event2, aggregate.getHandledEvents().get(1)); // now the aggregate is loaded (and hopefully correctly locked) StubDomainEvent event3 = new StubDomainEvent(); aggregate.apply(event3); CurrentUnitOfWork.commit(); verify(mockEventBus).publish(isA(DomainEventMessage.class)); verify(mockEventBus, never()).publish(event1); verify(mockEventBus, never()).publish(event2); verify(mockEventStore, times(1)).appendEvents(eq("test"), isA(DomainEventStream.class)); assertEquals(0, aggregate.getUncommittedEventCount()); }
@Test public void testLoadWithConflictingChanges_NoConflictResolverSet() { UUID identifier = UUID.randomUUID(); DomainEventMessage event2 = new GenericDomainEventMessage<String>( identifier, (long) 2, "Mock contents", MetaData.emptyInstance()); DomainEventMessage event3 = new GenericDomainEventMessage<String>( identifier, (long) 3, "Mock contents", MetaData.emptyInstance()); when(mockEventStore.readEvents("test", identifier)) .thenReturn( new SimpleDomainEventStream( new GenericDomainEventMessage<String>( identifier, (long) 1, "Mock contents", MetaData.emptyInstance()), event2, event3)); try { testSubject.load(identifier, 1L); fail("Expected ConflictingAggregateVersionException"); } catch (ConflictingAggregateVersionException e) { assertEquals(identifier, e.getAggregateIdentifier()); assertEquals(1L, e.getExpectedVersion()); assertEquals(3L, e.getActualVersion()); } }
@Test public void testLoad_FirstEventIsSnapshot() { UUID identifier = UUID.randomUUID(); TestAggregate aggregate = new TestAggregate(identifier); when(mockEventStore.readEvents("test", identifier)) .thenReturn( new SimpleDomainEventStream( new GenericDomainEventMessage<AggregateSnapshot<TestAggregate>>( identifier, 10, new AggregateSnapshot<TestAggregate>(aggregate)))); assertSame(aggregate, testSubject.load(identifier)); }
@Test public void testCommandHandlerLoadsSameAggregateTwice() { DefaultUnitOfWork.startAndGet(); StubAggregate stubAggregate = new StubAggregate(aggregateIdentifier); stubAggregate.doSomething(); repository.add(stubAggregate); CurrentUnitOfWork.commit(); DefaultUnitOfWork.startAndGet(); repository.load(aggregateIdentifier).doSomething(); repository.load(aggregateIdentifier).doSomething(); CurrentUnitOfWork.commit(); DomainEventStream es = mockEventStore.readEvents("", aggregateIdentifier); assertTrue(es.hasNext()); assertEquals((Object) 0L, es.next().getSequenceNumber()); assertTrue(es.hasNext()); assertEquals((Object) 1L, es.next().getSequenceNumber()); assertTrue(es.hasNext()); assertEquals((Object) 2L, es.next().getSequenceNumber()); assertFalse(es.hasNext()); }
@Test public void testSaveEventsWithDecorators() { SpyEventPreprocessor decorator1 = new SpyEventPreprocessor(); SpyEventPreprocessor decorator2 = new SpyEventPreprocessor(); testSubject.setEventStreamDecorators(Arrays.asList(decorator1, decorator2)); testSubject.setEventStore( new EventStore() { @Override public void appendEvents(String type, DomainEventStream events) { while (events.hasNext()) { events.next(); } } @Override public DomainEventStream readEvents(String type, Object identifier) { return mockEventStore.readEvents(type, identifier); } }); UUID identifier = UUID.randomUUID(); when(mockEventStore.readEvents("test", identifier)) .thenReturn( new SimpleDomainEventStream( new GenericDomainEventMessage<String>( identifier, (long) 3, "Mock contents", MetaData.emptyInstance()))); TestAggregate aggregate = testSubject.load(identifier); aggregate.apply(new StubDomainEvent()); aggregate.apply(new StubDomainEvent()); CurrentUnitOfWork.commit(); InOrder inOrder = Mockito.inOrder(decorator1.lastSpy, decorator2.lastSpy); inOrder.verify(decorator1.lastSpy).next(); inOrder.verify(decorator2.lastSpy).next(); inOrder.verify(decorator1.lastSpy).next(); inOrder.verify(decorator2.lastSpy).next(); }