package org.infinispan.server.hotrod.event; import static org.infinispan.server.hotrod.test.HotRodTestingUtil.assertByteArrayEquals; import static org.testng.AssertJUnit.assertEquals; import static org.testng.AssertJUnit.assertFalse; import static org.testng.AssertJUnit.assertNotNull; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Optional; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.TimeUnit; import org.infinispan.Cache; import org.infinispan.container.versioning.NumericVersion; import org.infinispan.notifications.cachelistener.event.Event; import org.infinispan.server.hotrod.test.TestClientListener; import org.infinispan.server.hotrod.test.TestCustomEvent; import org.infinispan.server.hotrod.test.TestKeyEvent; import org.infinispan.server.hotrod.test.TestKeyWithVersionEvent; import org.infinispan.test.TestException; /** * @author Galder ZamarreƱo */ public class EventLogListener extends TestClientListener { private ArrayBlockingQueue<TestKeyWithVersionEvent> createdEvents = new ArrayBlockingQueue<>(128); private ArrayBlockingQueue<TestKeyWithVersionEvent> modifiedEvents = new ArrayBlockingQueue<>(128); private ArrayBlockingQueue<TestKeyEvent> removedEvents = new ArrayBlockingQueue<>(128); private ArrayBlockingQueue<TestCustomEvent> customEvents = new ArrayBlockingQueue<>(128); @Override public int queueSize(Event.Type eventType) { return queue(eventType).size(); } @Override public Object pollEvent(Event.Type eventType) { try { return queue(eventType).poll(10, TimeUnit.SECONDS); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new TestException(); } } private <T> BlockingQueue<T> queue(Event.Type eventType) { BlockingQueue<?> eventQueue; switch (eventType) { case CACHE_ENTRY_CREATED: eventQueue = createdEvents; break; case CACHE_ENTRY_MODIFIED: eventQueue = modifiedEvents; break; case CACHE_ENTRY_REMOVED: eventQueue = removedEvents; break; default: throw new IllegalStateException("Unexpected event type: " + eventType); } return (BlockingQueue<T>) eventQueue; } @Override public void onCreated(TestKeyWithVersionEvent event) { createdEvents.add(event); } @Override public void onModified(TestKeyWithVersionEvent event) { modifiedEvents.add(event); } @Override public void onRemoved(TestKeyEvent event) { removedEvents.add(event); } @Override public int customQueueSize() { return customEvents.size(); } @Override public TestCustomEvent pollCustom() { try { return customEvents.poll(10, TimeUnit.SECONDS); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new TestException(); } } @Override public void onCustom(TestCustomEvent event) { customEvents.add(event); } @Override public byte[] getId() { return new byte[]{1, 2, 3}; } public void expectNoEvents(Optional<Event.Type> eventType) { if (eventType.isPresent()) { assertEquals(0, queueSize(eventType.get())); } else { assertEquals(0, queueSize(Event.Type.CACHE_ENTRY_CREATED)); assertEquals(0, queueSize(Event.Type.CACHE_ENTRY_MODIFIED)); assertEquals(0, queueSize(Event.Type.CACHE_ENTRY_REMOVED)); assertEquals(0, customQueueSize()); } } public void expectOnlyRemovedEvent(Cache cache, byte[] k) { expectSingleEvent(cache, k, Event.Type.CACHE_ENTRY_REMOVED); expectNoEvents(Optional.of(Event.Type.CACHE_ENTRY_CREATED)); expectNoEvents(Optional.of(Event.Type.CACHE_ENTRY_MODIFIED)); } public void expectOnlyModifiedEvent(Cache cache, byte[] k) { expectSingleEvent(cache, k, Event.Type.CACHE_ENTRY_MODIFIED); expectNoEvents(Optional.of(Event.Type.CACHE_ENTRY_CREATED)); expectNoEvents(Optional.of(Event.Type.CACHE_ENTRY_REMOVED)); } public void expectOnlyCreatedEvent(Cache cache, byte[] k) { expectSingleEvent(cache, k, Event.Type.CACHE_ENTRY_CREATED); expectNoEvents(Optional.of(Event.Type.CACHE_ENTRY_MODIFIED)); expectNoEvents(Optional.of(Event.Type.CACHE_ENTRY_REMOVED)); } public void expectSingleEvent(Cache cache, byte[] k, Event.Type eventType) { expectEvent(cache, k, eventType); assertEquals(0, queueSize(eventType)); } public void expectEvent(Cache cache, byte[] k, Event.Type eventType) { Object event = pollEvent(eventType); assertNotNull(event); if (event instanceof TestKeyWithVersionEvent) { TestKeyWithVersionEvent t = (TestKeyWithVersionEvent) event; assertByteArrayEquals(k, t.key); assertEquals(serverDataVersion(k, cache), t.dataVersion); } else if (event instanceof TestKeyEvent) { assertByteArrayEquals(k, ((TestKeyEvent) event).key); } } public void expectUnorderedEvents(Cache cache, Collection<byte[]> keys, Event.Type eventType) { List<byte[]> assertedKeys = new ArrayList<>(); for (int i = 0; i < keys.size(); i++) { Object event = pollEvent(eventType); assertNotNull(event); int initialSize = assertedKeys.size(); keys.forEach(key -> { if (event instanceof TestKeyWithVersionEvent) { TestKeyWithVersionEvent t = (TestKeyWithVersionEvent) event; boolean keyMatched = checkUnorderedKeyEvent(assertedKeys, key, t.key); if (keyMatched) assertEquals(serverDataVersion(key, cache), t.dataVersion); } else if (event instanceof TestKeyEvent) { checkUnorderedKeyEvent(assertedKeys, key, ((TestKeyEvent) event).key); } }); int finalSize = assertedKeys.size(); assertEquals(initialSize + 1, finalSize); } } private boolean checkUnorderedKeyEvent(List<byte[]> assertedKeys, byte[] key, byte[] eventKey) { if (java.util.Arrays.equals(key, eventKey)) { assertFalse(assertedKeys.contains(key)); assertedKeys.add(key); return true; } else { return false; } } public void expectSingleCustomEvent(Cache cache, byte[] eventData) { TestCustomEvent event = pollCustom(); assertNotNull(event); assertByteArrayEquals(eventData, event.eventData); int remaining = customQueueSize(); assertEquals(0, remaining); } private long serverDataVersion(byte[] k, Cache cache) { return ((NumericVersion) cache.getAdvancedCache().getCacheEntry(k).getMetadata().version()).getVersion(); } }