/***************************************************************** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. ****************************************************************/ package org.apache.cayenne.event; import org.apache.cayenne.test.parallel.ParallelTestContainer; import org.junit.After; import org.junit.Before; import org.junit.Test; import java.util.EventListener; import java.util.EventObject; import static org.junit.Assert.*; public class DefaultEventManagerTest implements EventListener { // used for counting received events on the class public static int numberOfReceivedEventsForClass; // used for counting received events per listener instance public int numberOfReceivedEvents; // the event manager used for testing private EventManager eventManager; @Before public void setUp() { eventManager = new DefaultEventManager(); numberOfReceivedEvents = 0; numberOfReceivedEventsForClass = 0; } @After public void tearDown() { ((DefaultEventManager)eventManager).shutdown(); } @Test public void testSubjectListenerWouldRegisterListener() { MockListener listener = new MockListener(eventManager); eventManager.addListener( listener, "processEvent", EventObject.class, MockListener.mockSubject); // test concurrent modification of the queue ... on event listener would attempt // adding another listener // add more than one listener to see that dispatch can proceed after one of the // listeners recats to event eventManager.addListener( new MockListener(eventManager), "processEvent", EventObject.class, MockListener.mockSubject); eventManager.postEvent(new EventObject(this), MockListener.mockSubject); } @Test public void testObjectListenerWouldRegisterListener() { MockListener listener = new MockListener(eventManager, this); eventManager.addListener( listener, "processEvent", EventObject.class, MockListener.mockSubject, this); // test concurrent modification of the queue ... on event listener would attempt // adding another listener // add more than one listener to see that dispatch can proceed after one of the // listeners recats to event eventManager.addListener( new MockListener(eventManager, this), "processEvent", EventObject.class, MockListener.mockSubject, this); eventManager.postEvent(new EventObject(this), MockListener.mockSubject); } @Test public void testNullListener() { try { EventSubject subject = EventSubject.getSubject(this.getClass(), "hansi"); eventManager.addListener(null, null, null, subject); fail(); } catch (IllegalArgumentException ia) { // expected } } @Test public void testNullNotification() { // null notification try { eventManager.addListener(this, "testNullObserver", CayenneEvent.class, null); fail(); } catch (IllegalArgumentException e) { // expected } // invalid event class try { EventSubject subject = EventSubject.getSubject(this.getClass(), ""); eventManager.addListener(this, "testNullObserver", null, subject); fail(); } catch (IllegalArgumentException e) { // expected } // empty string notification try { EventSubject subject = EventSubject.getSubject(this.getClass(), ""); eventManager.addListener( this, "testNullObserver", CayenneEvent.class, subject); fail(); } catch (IllegalArgumentException e) { // expected } } @Test public void testNonexistingMethod() { try { EventSubject subject = EventSubject.getSubject(this.getClass(), "hansi"); eventManager.addListener( this, "thisMethodDoesNotExist", CayenneEvent.class, subject); fail(); } catch (RuntimeException e) { // expected } } @Test public void testInvalidArgumentTypes() { try { EventSubject subject = EventSubject.getSubject(this.getClass(), "hansi"); eventManager.addListener( this, "seeTheWrongMethod", CayenneEvent.class, subject); fail(); } catch (RuntimeException e) { // expected } } @Test public void testNonretainedListener() { EventSubject subject = EventSubject.getSubject(this.getClass(), "XXX"); eventManager.addListener( new DefaultEventManagerTest(), "seeNotification", CayenneEvent.class, subject); // (hopefully) make the listener go away System.gc(); System.gc(); eventManager.postEvent(new CayenneEvent(this), subject); assertEquals(0, numberOfReceivedEventsForClass); } @Test public void testValidSubclassOfRegisteredEventClass() throws Exception { EventSubject subject = EventSubject.getSubject(this.getClass(), "XXX"); eventManager.addListener(this, "seeNotification", CayenneEvent.class, subject); eventManager.postEvent(new MyCayenneEvent(this), subject); assertReceivedEvents(1, this); } @Test public void testWrongRegisteredEventClass() throws Exception { EventSubject subject = EventSubject.getSubject(this.getClass(), "XXX"); // we register a method that takes a CayenneEvent or subclass thereof.. eventManager.addListener(this, "seeNotification", CayenneEvent.class, subject); // ..but post a subclass of EventObject that is not compatible with CayenneEvent eventManager.postEvent(new EventObject(this), subject); assertReceivedEvents(0, this); } @Test public void testSuccessfulNotificationDefaultSender() throws Exception { DefaultEventManagerTest listener1 = this; DefaultEventManagerTest listener2 = new DefaultEventManagerTest(); EventSubject subject = EventSubject.getSubject(this.getClass(), "XXX"); eventManager.addListener( listener1, "seeNotification", CayenneEvent.class, subject); eventManager.addListener( listener2, "seeNotification", CayenneEvent.class, subject); eventManager.postEvent(new CayenneEvent(this), subject); assertReceivedEvents(1, listener1); assertReceivedEvents(1, listener2); assertReceivedEventsForClass(2); } @Test public void testSuccessfulNotificationIndividualSender() throws Exception { EventSubject subject = EventSubject.getSubject(this.getClass(), "XXX"); eventManager.addListener( this, "seeNotification", CayenneEvent.class, subject, this); eventManager.postEvent(new CayenneEvent(this), subject); assertReceivedEvents(1, this); assertReceivedEventsForClass(1); } @Test public void testSuccessfulNotificationIndividualSenderTwice() throws Exception { EventSubject subject = EventSubject.getSubject(this.getClass(), "XXX"); eventManager.addListener(this, "seeNotification", CayenneEvent.class, subject); eventManager.addListener( this, "seeNotification", CayenneEvent.class, subject, this); eventManager.postEvent(new CayenneEvent(this), subject); assertReceivedEvents(2, this); assertReceivedEventsForClass(2); } @Test public void testSuccessfulNotificationBothDefaultAndIndividualSender() throws Exception { DefaultEventManagerTest listener1 = this; DefaultEventManagerTest listener2 = new DefaultEventManagerTest(); EventSubject subject = EventSubject.getSubject(this.getClass(), "XXX"); eventManager.addListener( listener1, "seeNotification", CayenneEvent.class, subject, listener1); eventManager.addListener( listener2, "seeNotification", CayenneEvent.class, subject); eventManager.postEvent(new CayenneEvent(this), subject); assertReceivedEvents(1, listener1); assertReceivedEvents(1, listener2); assertReceivedEventsForClass(2); } @Test public void testRemoveOnEmptyList() { EventSubject subject = EventSubject.getSubject(this.getClass(), "XXX"); assertFalse(eventManager.removeListener(this, subject)); } @Test public void testRemoveOnNullSubject() { assertFalse(eventManager.removeListener(this, null)); } @Test public void testRemoveFromDefaultQueue() { EventSubject subject = EventSubject.getSubject(this.getClass(), "XXX"); eventManager.addListener(this, "seeNotification", CayenneEvent.class, subject); assertTrue(eventManager.removeListener(this, subject)); assertFalse(eventManager.removeListener(this)); } @Test public void testRemoveSpecificQueue() { EventSubject subject = EventSubject.getSubject(this.getClass(), "XXX"); eventManager.addListener( this, "seeNotification", CayenneEvent.class, subject, this); assertTrue(eventManager.removeListener(this, subject)); assertFalse(eventManager.removeListener(this)); } @Test public void testRemoveSpecificSender() { EventSubject subject = EventSubject.getSubject(this.getClass(), "XXX"); eventManager.addListener( this, "seeNotification", CayenneEvent.class, subject, this); assertTrue(eventManager.removeListener(this, subject, this)); assertFalse(eventManager.removeListener(this)); } @Test public void testRemoveNullSender() { EventSubject subject = EventSubject.getSubject(this.getClass(), "XXX"); eventManager.addListener( this, "seeNotification", CayenneEvent.class, subject, this); assertTrue(eventManager.removeListener(this, subject, null)); assertFalse(eventManager.removeListener(this)); } @Test public void testRemoveNonexistingSender() { EventSubject subject = EventSubject.getSubject(this.getClass(), "XXX"); eventManager.addListener( this, "seeNotification", CayenneEvent.class, subject, this); assertFalse(eventManager.removeListener(this, subject, "foo")); assertTrue(eventManager.removeListener(this)); } @Test public void testRemoveAll() { EventSubject subject1 = EventSubject.getSubject(this.getClass(), "XXX1"); EventSubject subject2 = EventSubject.getSubject(this.getClass(), "XXX2"); EventSubject subject3 = EventSubject.getSubject(this.getClass(), "XXX3"); eventManager.addListener(this, "seeNotification", CayenneEvent.class, subject1); eventManager.addListener(this, "seeNotification", CayenneEvent.class, subject2); eventManager.addListener( this, "seeNotification", CayenneEvent.class, subject3, this); assertTrue(eventManager.removeListener(this)); assertFalse(eventManager.removeListener(this)); assertFalse(eventManager.removeListener(this, subject1)); assertFalse(eventManager.removeListener(this, subject2)); assertFalse(eventManager.removeListener(this, subject3)); } @Test public void testSubjectGarbageCollection() { EventSubject subject = EventSubject.getSubject(this.getClass(), "XXX"); eventManager.addListener(this, "seeNotification", CayenneEvent.class, subject); // let go of the subject & (hopefully) release queue subject = null; System.gc(); System.gc(); assertFalse(eventManager.removeListener(this)); } // notification method public void seeNotification(CayenneEvent event) { numberOfReceivedEvents++; numberOfReceivedEventsForClass++; } // allows just enough time for the event threads to run private static void assertReceivedEvents( final int expected, final DefaultEventManagerTest listener) throws Exception { ParallelTestContainer helper = new ParallelTestContainer() { @Override protected void assertResult() throws Exception { assertEquals(expected, listener.numberOfReceivedEvents); } }; helper.runTest(5000); } // allows just enough time for the event threads to run private static void assertReceivedEventsForClass(final int expected) throws Exception { ParallelTestContainer helper = new ParallelTestContainer() { @Override protected void assertResult() throws Exception { assertEquals(expected, numberOfReceivedEventsForClass); } }; helper.runTest(5000); } } // dummy class to test for incompatible events class MyCayenneEvent extends CayenneEvent { public MyCayenneEvent(EventListener l) { super(l); } }