Source:
public void testMergeSegmentsDuringReplay() throws Exception { initProcessor(TrackingEventProcessorConfiguration.forParallelProcessing(2)); tokenStore.initializeTokenSegments(testSubject.getName(), 2); List<EventMessage<?>> handledEvents = new CopyOnWriteArrayList<>(); List<EventMessage<?>> events = new ArrayList<>(); for (int i = 0; i < 10; i++) { events.add(createEvent(UUID.randomUUID().toString(), 0)); } when(mockHandler.handle(any())).thenAnswer(i -> { TrackedEventMessage<?> message = i.getArgument(0); if(!ReplayToken.isReplay(message)) { System.out.println(Thread.currentThread().getName() + " " + message.trackingToken()); } return handledEvents.add(message); }); eventBus.publish(events); testSubject.start(); while (testSubject.processingStatus().size() < 2 || !testSubject.processingStatus().values().stream().allMatch(EventTrackerStatus::isCaughtUp)) { Thread.sleep(10); } testSubject.shutDown(); testSubject.resetTokens(); testSubject.releaseSegment(1); testSubject.start(); waitForActiveThreads(1); CompletableFuture<Boolean> mergeResult = testSubject.mergeSegment(0); publishEvents(20); System.out.println("Number of events handled at merge: " + handledEvents.size()); assertTrue("Expected split to succeed", mergeResult.join()); assertArrayEquals(new int[]{0}, tokenStore.fetchSegments(testSubject.getName())); waitForSegmentStart(0); assertWithin(10, TimeUnit.SECONDS, () -> assertEquals(40, handledEvents.size())); Thread.sleep(100); assertEquals(40, handledEvents.size()); }

Target:
public void testMergeSegmentsDuringReplay() throws Exception { initProcessor(TrackingEventProcessorConfiguration.forParallelProcessing(2)); tokenStore.initializeTokenSegments(testSubject.getName(), 2); List<EventMessage<?>> handledEvents = new CopyOnWriteArrayList<>(); List<EventMessage<?>> replayedEvents = new CopyOnWriteArrayList<>(); when(mockHandler.handle(any())).thenAnswer(i -> { TrackedEventMessage<?> message = i.getArgument(0); if (ReplayToken.isReplay(message)) { System.out.println("[replay]" + Thread.currentThread().getName() + " " + message.trackingToken()); replayedEvents.add(message); } else { System.out.println(Thread.currentThread().getName() + " " + message.trackingToken()); handledEvents.add(message); } return null; }); for (int i = 0; i < 10; i++) { eventBus.publish(createEvent(UUID.randomUUID().toString(), 0)); } testSubject.start(); while (testSubject.processingStatus().size() < 2 || !testSubject.processingStatus().values().stream().allMatch(EventTrackerStatus::isCaughtUp)) { Thread.sleep(10); } testSubject.shutDown(); testSubject.resetTokens(); testSubject.releaseSegment(1); testSubject.start(); waitForActiveThreads(1); Thread.yield(); CompletableFuture<Boolean> mergeResult = testSubject.mergeSegment(0); publishEvents(20); System.out.println("Number of events handled at merge: " + handledEvents.size()); assertTrue("Expected merge to succeed", mergeResult.join()); assertArrayEquals(new int[]{0}, tokenStore.fetchSegments(testSubject.getName())); waitForSegmentStart(0); assertWithin(10, TimeUnit.SECONDS, () -> assertEquals(30, handledEvents.size())); Thread.sleep(100); assertEquals(30, handledEvents.size()); assertEquals(replayedEvents.stream().map(EventMessage::getIdentifier).distinct().count(), replayedEvents.size()); }