/*
* Jajuk
* Copyright (C) The Jajuk Team
* http://jajuk.info
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
package org.jajuk.events;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import org.jajuk.JajukTestCase;
import org.jajuk.ThreadTestHelper;
/**
* .
*/
public class TestObserverRegistry extends JajukTestCase {
/** The Constant NUMBER_OF_THREADS. */
private static final int NUMBER_OF_THREADS = 15; // 15 is the limit on
// concurrent events
/** The Constant NUMBER_OF_TESTS. */
private static final int NUMBER_OF_TESTS = 1000;
private AtomicInteger called = new AtomicInteger(0);
/**
* Test method for.
*
* {@link org.jajuk.events.ObserverRegistry#notifySync(org.jajuk.events.JajukEvent)}
* .
*/
public void testNotifySync() {
ObserverRegistry registry = new ObserverRegistry();
registry.notifySync(new JajukEvent(JajukEvents.PLAYER_PLAY));
}
/**
* Test method for.
*
* {@link org.jajuk.events.ObserverRegistry#register(org.jajuk.events.JajukEvents, org.jajuk.events.Observer)}
* .
*/
public void testRegister() {
ObserverRegistry registry = new ObserverRegistry();
registry.register(JajukEvents.PLAYER_PLAY, new LocalObserver(called));
}
/**
* Test method for.
*
* {@link org.jajuk.events.ObserverRegistry#unregister(org.jajuk.events.JajukEvents, org.jajuk.events.Observer)}
* .
*/
public void testUnregister() {
ObserverRegistry registry = new ObserverRegistry();
registry.unregister(JajukEvents.PLAYER_PLAY, new LocalObserver(called));
}
/**
* Test below zero.
*
*/
public void testBelowZero() {
ObserverRegistry registry = new ObserverRegistry();
Observer observer = new LocalObserver(called);
// first register
registry.register(JajukEvents.FILE_FINISHED, observer);
assertEquals(0, called.get());
// then notifySync
registry.notifySync(new JajukEvent(JajukEvents.FILE_FINISHED));
assertEquals(1, called.get());
// then unregister again
registry.unregister(JajukEvents.FILE_FINISHED, observer);
}
/**
* Test exception.
*
*/
public void testException() {
ObserverRegistry registry = new ObserverRegistry();
Observer observer = new LocalObserver(true, called);
// first register
registry.register(JajukEvents.FILE_FINISHED, observer);
assertEquals(0, called.get());
// then notifySync, this will not return an error even if an exception
// occurred
registry.notifySync(new JajukEvent(JajukEvents.FILE_FINISHED));
assertEquals(1, called.get());
// then unregister again
registry.unregister(JajukEvents.FILE_FINISHED, observer);
}
/**
* Test multiple threads.
*
*
* @throws Exception the exception
*/
public void testMultipleThreads() throws Exception {
final ObserverRegistry registry = new ObserverRegistry();
Observer observer = new LocalObserver(called);
// first register
registry.register(JajukEvents.FILE_FINISHED, observer);
assertEquals(0, called.get());
ThreadTestHelper helper = new ThreadTestHelper(NUMBER_OF_THREADS, NUMBER_OF_TESTS);
helper.executeTest(new ThreadTestHelper.TestRunnable() {
@Override
public void doEnd(int threadnum) throws Exception {
// nothing to do
}
@Override
public void run(int threadnum, int iter) {
// then notifySync
registry.notifySync(new JajukEvent(JajukEvents.FILE_FINISHED));
}
});
assertEquals(NUMBER_OF_THREADS * NUMBER_OF_TESTS, called.get());
// then unregister again
registry.unregister(JajukEvents.FILE_FINISHED, observer);
}
/**
* Test multiple threads wait.
*
*
* @throws Exception the exception
*/
public void testMultipleThreadsWait() throws Exception {
final ObserverRegistry registry = new ObserverRegistry();
// set 100ms wait time to reach event queue size on normal speed machines
Observer observer = new LocalObserver(100, called);
// first register
registry.register(JajukEvents.FILE_FINISHED, observer);
assertEquals(0, called.get());
// more threads so that we reach the limit of 15 concurrent events
// a bit fewer tests as they will need some time
ThreadTestHelper helper = new ThreadTestHelper(NUMBER_OF_THREADS * 2, NUMBER_OF_TESTS / 20);
helper.executeTest(new ThreadTestHelper.TestRunnable() {
@Override
public void doEnd(int threadnum) throws Exception {
// nothing to do
}
@Override
public void run(int threadnum, int iter) {
// then notifySync
registry.notifySync(new JajukEvent(JajukEvents.FILE_FINISHED));
}
});
// can not test this as we have overflows here!
// assertEquals(NUMBER_OF_THREADS * NUMBER_OF_TESTS, called.get());
// then unregister again
registry.unregister(JajukEvents.FILE_FINISHED, observer);
}
/**
* Test multiple threads multiple observers.
*
*
* @throws Exception the exception
*/
public void testMultipleThreadsMultipleObservers() throws Exception {
final ObserverRegistry registry = new ObserverRegistry();
Observer observer1 = new LocalObserver(called);
Observer observer2 = new LocalObserver(called);
// first register
registry.register(JajukEvents.FILE_FINISHED, observer1);
registry.register(JajukEvents.FILE_FINISHED, observer2);
assertEquals(0, called.get());
ThreadTestHelper helper = new ThreadTestHelper(NUMBER_OF_THREADS, NUMBER_OF_TESTS);
helper.executeTest(new ThreadTestHelper.TestRunnable() {
@Override
public void doEnd(int threadnum) throws Exception {
// nothing to do
}
@Override
public void run(int threadnum, int iter) {
// then notifySync
registry.notifySync(new JajukEvent(JajukEvents.FILE_FINISHED));
}
});
// now we were called twice as many times because of two observers...
assertEquals(2 * NUMBER_OF_THREADS * NUMBER_OF_TESTS, called.get());
// then unregister again
registry.unregister(JajukEvents.FILE_FINISHED, observer2);
registry.unregister(JajukEvents.FILE_FINISHED, observer1);
}
/**
* Test high priority observer.
*
*
* @throws Exception the exception
*/
public void testHighPriorityObserver() throws Exception {
final ObserverRegistry registry = new ObserverRegistry();
LocalObserver observer1 = new LocalObserver(called);
Observer observer2 = new LocalHighPriorityObserver(observer1, called);
// first register
registry.register(JajukEvents.FILE_FINISHED, observer1);
registry.register(JajukEvents.FILE_FINISHED, observer2);
assertEquals(0, called.get());
ThreadTestHelper helper = new ThreadTestHelper(NUMBER_OF_THREADS, NUMBER_OF_TESTS);
helper.executeTest(new ThreadTestHelper.TestRunnable() {
@Override
public void doEnd(int threadnum) throws Exception {
// nothing to do
}
@Override
public void run(int threadnum, int iter) {
// then notifySync
registry.notifySync(new JajukEvent(JajukEvents.FILE_FINISHED));
}
});
// now we were called twice as many times because of two observers...
assertEquals(2 * NUMBER_OF_THREADS * NUMBER_OF_TESTS, called.get());
// then unregister again
registry.unregister(JajukEvents.FILE_FINISHED, observer2);
registry.unregister(JajukEvents.FILE_FINISHED, observer1);
}
/**
* .
*/
static class LocalObserver implements Observer {
boolean invoked = false;
int wait = 0;
boolean exception = false;
AtomicInteger called;
/**
* Instantiates a new local observer.
*
* @param called
*/
public LocalObserver(AtomicInteger called) {
super();
this.called = called;
}
/**
* Instantiates a new local observer.
*
* @param wait
* @param called
*/
public LocalObserver(int wait, AtomicInteger called) {
super();
this.wait = wait;
this.called = called;
}
/**
* Instantiates a new local observer.
*
* @param exception
* @param called
*/
public LocalObserver(boolean exception, AtomicInteger called) {
super();
this.exception = exception;
this.called = called;
}
/*
* (non-Javadoc)
*
* @see org.jajuk.events.Observer#getRegistrationKeys()
*/
@Override
public Set<JajukEvents> getRegistrationKeys() {
// only used in ObservationManager, not used in this testcase
Set<JajukEvents> set = new HashSet<JajukEvents>();
set.add(JajukEvents.ALBUM_CHANGED);
set.add(JajukEvents.PLAY_ERROR);
return set;
}
/*
* (non-Javadoc)
*
* @see org.jajuk.events.Observer#update(org.jajuk.events.JajukEvent)
*/
@Override
public void update(JajukEvent event) {
called.incrementAndGet();
if (exception) {
throw new RuntimeException("Exception requested in update...");
}
if (wait > 0) {
try {
Thread.sleep(wait);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
/**
* .
*/
private class LocalHighPriorityObserver extends LocalObserver implements HighPriorityObserver {
LocalObserver lowprioobserver; // to check if other was not yet called
/**
* Instantiates a new local high priority observer.
*
* @param lowprioobserver
* @param called
*/
public LocalHighPriorityObserver(LocalObserver lowprioobserver, AtomicInteger called) {
super(called);
this.lowprioobserver = lowprioobserver;
}
/*
* (non-Javadoc)
*
* @see
* org.jajuk.events.TestObserverRegistry.LocalObserver#update(org.jajuk.
* events.JajukEvent)
*/
@Override
public void update(JajukEvent event) {
if (lowprioobserver.invoked) {
throw new RuntimeException("LocalObserver was called before HighPriorityObserver!");
}
super.update(event);
}
}
}