blob: c3e51b209aff5fa13a588a1cde6f804abf84d7c3 [file] [log] [blame]
/**
*
* Copyright 2005 the original author or authors.
*
* Licensed 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.gbean.kernel.standard;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;
import junit.framework.TestCase;
import org.gbean.kernel.KernelErrorsError;
import org.gbean.kernel.KernelMonitor;
import org.gbean.kernel.NullServiceMonitor;
import org.gbean.kernel.ServiceEvent;
import org.gbean.kernel.ServiceMonitor;
import org.gbean.kernel.ServiceName;
import org.gbean.kernel.StaticServiceFactory;
import org.gbean.kernel.StringServiceName;
/**
* Tests ServiceMonitorBroadcaster.
*
* @author Dain Sundstrom
* @version $Id$
* @since 1.0
*/
public class ServiceMonitorBroadcasterTest extends TestCase {
private static final StandardKernel KERNEL = new StandardKernel("test");
private static final StaticServiceFactory SERVICE_FACTORY = new StaticServiceFactory(new Object());
private static final ClassLoader SYSTEM_CLASS_LOADER = ClassLoader.getSystemClassLoader();
private static final int SERVICE_REGISTERED = 1 << 0;
private static final int SERVICE_STARTING = 1 << 1;
private static final int SERVICE_WAITING_TO_START = 1 << 2;
private static final int SERVICE_START_ERROR = 1 << 3;
private static final int SERVICE_RUNNING = 1 << 4;
private static final int SERVICE_STOPPING = 1 << 5;
private static final int SERVICE_WAITING_TO_STOP = 1 << 6;
private static final int SERVICE_STOP_ERROR = 1 << 7;
private static final int SERVICE_STOPPED = 1 << 8;
private static final int SERVICE_UNREGISTERED = 1 << 9;
private static final int[] NOTIFICATION_TYPES = new int[]{
SERVICE_REGISTERED,
SERVICE_STARTING,
SERVICE_WAITING_TO_START,
SERVICE_START_ERROR,
SERVICE_RUNNING,
SERVICE_STOPPING,
SERVICE_WAITING_TO_STOP,
SERVICE_STOP_ERROR,
SERVICE_STOPPED,
SERVICE_UNREGISTERED,
};
private static final int SERVICE_COUNT = 4;
private static final ServiceName[] serviceName = new ServiceName[SERVICE_COUNT];
private static final ServiceEvent[] serviceEvent = new ServiceEvent[SERVICE_COUNT];
private final Set[] expectedMonitors = new Set[SERVICE_COUNT];
private final Set[] unexpectedMonitors = new Set[SERVICE_COUNT];
private final MockKernelMonitor kernelMonitor = new MockKernelMonitor();
private final ServiceMonitorBroadcaster serviceMonitorBroadcaster = new ServiceMonitorBroadcaster(kernelMonitor);
private MockServiceMonitor[] globalMonitors;
private MockServiceMonitor[][] serviceMonitors;
private MockServiceMonitor evenMonitor;
private MockServiceMonitor oddMonitor;
private Throwable throwable;
private Throwable kernelThrowable;
/**
* Fires all events on every service and verifies.
*/
public void testFireEvent() {
fireAllEvents();
}
/**
* Test that if a monitor is added more then once it only recieves the event once.
* Strategy:
* <ul><li>
* Add a monitor several times
* </li><li>
* Fire all events and verify
* </li></ul>
*/
public void testMultipleAdd() {
serviceMonitorBroadcaster.addServiceMonitor(globalMonitors[0], null);
serviceMonitorBroadcaster.addServiceMonitor(globalMonitors[0], null);
serviceMonitorBroadcaster.addServiceMonitor(globalMonitors[0], null);
serviceMonitorBroadcaster.addServiceMonitor(serviceMonitors[1][0], serviceName[1]);
serviceMonitorBroadcaster.addServiceMonitor(serviceMonitors[1][0], serviceName[1]);
serviceMonitorBroadcaster.addServiceMonitor(serviceMonitors[1][0], serviceName[1]);
fireAllEvents();
}
/**
* Test that events are not fired to a monitor that has been removed.
* Strategy:
* </li><li>
* Fire all events and verify
* </li><li>
* Removes some monitors
* </li><li>
* Fire all events and verify
* </li></ul>
*/
public void testRemove() {
fireAllEvents();
serviceMonitorBroadcaster.removeServiceMonitor(globalMonitors[0]);
for (int i = 0; i < expectedMonitors.length; i++) {
Set expectedMonitor = expectedMonitors[i];
expectedMonitor.remove(globalMonitors[0]);
}
for (int i = 0; i < unexpectedMonitors.length; i++) {
Set expectedMonitor = unexpectedMonitors[i];
expectedMonitor.add(globalMonitors[0]);
}
serviceMonitorBroadcaster.removeServiceMonitor(serviceMonitors[1][0]);
expectedMonitors[1].remove(serviceMonitors[1][0]);
unexpectedMonitors[1].add(serviceMonitors[1][0]);
fireAllEvents();
}
/**
* Tests that no exceptions are thrown if an attempt is made to remove a monitor not registered.
*/
public void testRemoveUnassociated() {
serviceMonitorBroadcaster.removeServiceMonitor(new NullServiceMonitor());
}
/**
* Test that when a service monitor throws a RuntimeException the kernel monitor is notified.
* Strategy:
* </li><li>
* Set all monitors to throw a RuntimeException
* </li><li>
* Fire all events and verify
* </li></ul>
*/
public void testNotificationRuntimeException() {
throwable = new RuntimeException("notification exception");
fireAllEvents();
}
/**
* Test that when a service monitor throws an Error the kernel monitor is notified.
* Strategy:
* </li><li>
* Set all monitors to throw an Error
* </li><li>
* Fire all events and verify
* </li></ul>
*/
public void testNotificationError() {
throwable = new Error("notification error");
fireAllEvents();
}
/**
* Tests that when a kernel monitor throws a RuntimeException that it is ignored.
* </li><li>
* Set all service monitors to throw a RuntimeException
* </li><li>
* Set kernel monitor to throw a RuntimeException
* </li><li>
* Fire all events and verify
* </li></ul>
*/
public void testKernelMonitorException() {
throwable = new RuntimeException("notification exception");
kernelThrowable = new RuntimeException("kernel exception");
fireAllEvents();
}
/**
* Tests that when a kernel monitor throws an Error that it is propagated back to call in a KernelErrorsError.
* </li><li>
* Set all service monitors to throw a RuntimeException
* </li><li>
* Set kernel monitor to throw an Error
* </li><li>
* Fire all events and verify
* </li></ul>
*/
public void testKernelMonitorError() {
throwable = new RuntimeException("notification exception");
kernelThrowable = new Error("kernel error");
fireAllEvents();
}
private void fireAllEvents() {
for (int serviceId = 0; serviceId < serviceEvent.length; serviceId++) {
for (int j = 0; j < NOTIFICATION_TYPES.length; j++) {
int notificationType = NOTIFICATION_TYPES[j];
initMonitors(serviceId, throwable);
fireEvent(serviceId, notificationType);
assertNotificationCorrect(serviceId, notificationType);
}
}
}
private void initMonitors(int serviceId, Throwable throwable) {
if (throwable != null) {
kernelMonitor.init(expectedMonitors[serviceId], serviceEvent[serviceId], throwable, kernelThrowable);
} else {
kernelMonitor.init(Collections.EMPTY_SET, null, null, null);
}
for (Iterator iterator = expectedMonitors[serviceId].iterator(); iterator.hasNext();) {
((MockServiceMonitor) iterator.next()).init(serviceEvent[serviceId], throwable);
}
for (Iterator iterator = unexpectedMonitors[serviceId].iterator(); iterator.hasNext();) {
((MockServiceMonitor) iterator.next()).init(null, throwable);
}
}
private void fireEvent(int serviceId, int notificationType) {
try {
if (notificationType == SERVICE_REGISTERED) {
serviceMonitorBroadcaster.serviceRegistered(serviceEvent[serviceId]);
} else if (notificationType == SERVICE_STARTING) {
serviceMonitorBroadcaster.serviceStarting(serviceEvent[serviceId]);
} else if (notificationType == SERVICE_WAITING_TO_START) {
serviceMonitorBroadcaster.serviceWaitingToStart(serviceEvent[serviceId]);
} else if (notificationType == SERVICE_START_ERROR) {
serviceMonitorBroadcaster.serviceStartError(serviceEvent[serviceId]);
} else if (notificationType == SERVICE_RUNNING) {
serviceMonitorBroadcaster.serviceRunning(serviceEvent[serviceId]);
} else if (notificationType == SERVICE_STOPPING) {
serviceMonitorBroadcaster.serviceStopping(serviceEvent[serviceId]);
} else if (notificationType == SERVICE_WAITING_TO_STOP) {
serviceMonitorBroadcaster.serviceWaitingToStop(serviceEvent[serviceId]);
} else if (notificationType == SERVICE_STOP_ERROR) {
serviceMonitorBroadcaster.serviceStopError(serviceEvent[serviceId]);
} else if (notificationType == SERVICE_STOPPED) {
serviceMonitorBroadcaster.serviceStopped(serviceEvent[serviceId]);
} else if (notificationType == SERVICE_UNREGISTERED) {
serviceMonitorBroadcaster.serviceUnregistered(serviceEvent[serviceId]);
} else {
fail("Unknown notification type " + notificationType);
}
} catch (KernelErrorsError e) {
assertEquals(e.getErrors().size(), expectedMonitors[serviceId].size());
for (Iterator iterator = e.getErrors().iterator(); iterator.hasNext();) {
assertEquals(kernelThrowable, iterator.next());
}
}
}
private void assertNotificationCorrect(int serviceId, int notificationType) {
for (Iterator iterator = expectedMonitors[serviceId].iterator(); iterator.hasNext();) {
MockServiceMonitor mockServiceMonitor = (MockServiceMonitor) iterator.next();
assertEquals(notificationType, mockServiceMonitor.getCalled());
}
for (Iterator iterator = unexpectedMonitors[serviceId].iterator(); iterator.hasNext();) {
MockServiceMonitor mockServiceMonitor = (MockServiceMonitor) iterator.next();
assertEquals(0, mockServiceMonitor.getCalled());
}
assertTrue("Unfired service errors " + kernelMonitor.getExpectedServiceMonitors(), kernelMonitor.getExpectedServiceMonitors().isEmpty());
}
protected void setUp() throws Exception {
super.setUp();
// serviceNames
for (int i = 0; i < serviceName.length; i++) {
serviceName[i] = new StringServiceName("service-" + i);
}
// serviceEvents
for (int i = 0; i < serviceEvent.length; i++) {
serviceEvent[i] = createEvent(serviceName[i]);
}
// all monitors
Set allMonitors = new LinkedHashSet();
// global
globalMonitors = createMonitors(2, "global");
allMonitors.addAll(Arrays.asList(globalMonitors));
for (int i = 0; i < globalMonitors.length; i++) {
MockServiceMonitor gloalMonitor = globalMonitors[i];
serviceMonitorBroadcaster.addServiceMonitor(gloalMonitor, null);
}
// service specific
serviceMonitors = new MockServiceMonitor[SERVICE_COUNT][];
for (int i = 0; i < serviceMonitors.length; i++) {
serviceMonitors[i] = createMonitors(i, "service" + i);
allMonitors.addAll(Arrays.asList(serviceMonitors[i]));
for (int j = 0; j < serviceMonitors[i].length; j++) {
MockServiceMonitor serviceMonitor = serviceMonitors[i][j];
serviceMonitorBroadcaster.addServiceMonitor(serviceMonitor, serviceName[i]);
}
}
// even numbered services
evenMonitor = new MockServiceMonitor("even");
allMonitors.add(evenMonitor);
for (int i = 0; i < serviceName.length; i++) {
if (i % 2 == 0) {
serviceMonitorBroadcaster.addServiceMonitor(evenMonitor, serviceName[i]);
}
}
// odd numbered services
oddMonitor = new MockServiceMonitor("odd");
allMonitors.add(oddMonitor);
for (int i = 0; i < serviceName.length; i++) {
if (i % 2 != 0) {
serviceMonitorBroadcaster.addServiceMonitor(oddMonitor, serviceName[i]);
}
}
// expected monitors
for (int i = 0; i < expectedMonitors.length; i++) {
expectedMonitors[i] = new LinkedHashSet();
expectedMonitors[i].addAll(Arrays.asList(globalMonitors));
expectedMonitors[i].addAll(Arrays.asList(serviceMonitors[i]));
if (i % 2 == 0) {
expectedMonitors[i].add(evenMonitor);
} else {
expectedMonitors[i].add(oddMonitor);
}
}
// unexpected monitors
for (int i = 0; i < unexpectedMonitors.length; i++) {
unexpectedMonitors[i] = new LinkedHashSet(allMonitors);
unexpectedMonitors[i].removeAll(expectedMonitors[i]);
}
}
private MockServiceMonitor[] createMonitors(int count, String name) {
MockServiceMonitor[] gloalMonitors = new MockServiceMonitor[count];
for (int i = 0; i < gloalMonitors.length; i++) {
gloalMonitors[i] = new MockServiceMonitor(name + "-" + i);
}
return gloalMonitors;
}
private static ServiceEvent createEvent(ServiceName serviceName) {
return new ServiceEvent(0,
KERNEL,
serviceName,
SERVICE_FACTORY,
SYSTEM_CLASS_LOADER,
null,
null,
null);
}
private static class MockServiceMonitor implements ServiceMonitor {
private final String name;
private int called;
private ServiceEvent expectedEvent;
private Throwable throwable;
private MockServiceMonitor(String name) {
this.name = name;
}
public String toString() {
return name;
}
private void init(ServiceEvent expectedEvent, Throwable throwable) {
this.expectedEvent = expectedEvent;
this.throwable = throwable;
called = 0;
}
public int getCalled() {
return called;
}
public void serviceRegistered(ServiceEvent serviceEvent) {
assertTrue("alread called", (called & SERVICE_REGISTERED) == 0);
called |= SERVICE_REGISTERED;
assertNotNull("call not expected", expectedEvent);
assertSame("wrong event object", expectedEvent, serviceEvent);
throwIfNecessary();
}
public void serviceStarting(ServiceEvent serviceEvent) {
assertTrue("alread called", (called & SERVICE_STARTING) == 0);
called |= SERVICE_STARTING;
assertNotNull("call not expected", expectedEvent);
assertSame("wrong event object", expectedEvent, serviceEvent);
throwIfNecessary();
}
public void serviceWaitingToStart(ServiceEvent serviceEvent) {
assertTrue("alread called", (called & SERVICE_WAITING_TO_START) == 0);
called |= SERVICE_WAITING_TO_START;
assertNotNull("call not expected", expectedEvent);
assertSame("wrong event object", expectedEvent, serviceEvent);
throwIfNecessary();
}
public void serviceStartError(ServiceEvent serviceEvent) {
assertTrue("alread called", (called & SERVICE_START_ERROR) == 0);
called |= SERVICE_START_ERROR;
assertNotNull("call not expected", expectedEvent);
assertSame("wrong event object", expectedEvent, serviceEvent);
throwIfNecessary();
}
public void serviceRunning(ServiceEvent serviceEvent) {
assertTrue("alread called", (called & SERVICE_RUNNING) == 0);
called |= SERVICE_RUNNING;
assertNotNull("call not expected", expectedEvent);
assertSame("wrong event object", expectedEvent, serviceEvent);
throwIfNecessary();
}
public void serviceStopping(ServiceEvent serviceEvent) {
assertTrue("alread called", (called & SERVICE_STOPPING) == 0);
called |= SERVICE_STOPPING;
assertNotNull("call not expected", expectedEvent);
assertSame("wrong event object", expectedEvent, serviceEvent);
throwIfNecessary();
}
public void serviceWaitingToStop(ServiceEvent serviceEvent) {
assertTrue("alread called", (called & SERVICE_WAITING_TO_STOP) == 0);
called |= SERVICE_WAITING_TO_STOP;
assertNotNull("call not expected", expectedEvent);
assertSame("wrong event object", expectedEvent, serviceEvent);
throwIfNecessary();
}
public void serviceStopError(ServiceEvent serviceEvent) {
assertTrue("alread called", (called & SERVICE_STOP_ERROR) == 0);
called |= SERVICE_STOP_ERROR;
assertNotNull("call not expected", expectedEvent);
assertSame("wrong event object", expectedEvent, serviceEvent);
throwIfNecessary();
}
public void serviceStopped(ServiceEvent serviceEvent) {
assertTrue("alread called", (called & SERVICE_STOPPED) == 0);
called |= SERVICE_STOPPED;
assertNotNull("call not expected", expectedEvent);
assertSame("wrong event object", expectedEvent, serviceEvent);
throwIfNecessary();
}
public void serviceUnregistered(ServiceEvent serviceEvent) {
assertTrue("alread called", (called & SERVICE_UNREGISTERED) == 0);
called |= SERVICE_UNREGISTERED;
assertNotNull("call not expected", expectedEvent);
assertSame("wrong event object", expectedEvent, serviceEvent);
throwIfNecessary();
}
private void throwIfNecessary() {
if (throwable instanceof RuntimeException) {
throw (RuntimeException) throwable;
} else if (throwable instanceof Error) {
throw (Error) throwable;
} else {
assertNull(throwable);
}
}
}
private static class MockKernelMonitor implements KernelMonitor {
private Set expectedServiceMonitors;
private ServiceEvent expectedEvent;
private Throwable expectedThrowable;
private Throwable kernelThrowable;
private void init(Set expectedServiceMonitors, ServiceEvent expectedEvent, Throwable expectedThrowable, Throwable kernelThrowable) {
this.expectedServiceMonitors = new LinkedHashSet(expectedServiceMonitors);
this.expectedEvent = expectedEvent;
this.expectedThrowable = expectedThrowable;
this.kernelThrowable = kernelThrowable;
}
public Set getExpectedServiceMonitors() {
return expectedServiceMonitors;
}
public void serviceNotificationError(ServiceMonitor serviceMonitor, ServiceEvent serviceEvent, Throwable throwable) {
assertNotNull(expectedEvent);
assertTrue(expectedServiceMonitors.contains(serviceMonitor));
expectedServiceMonitors.remove(serviceMonitor);
assertSame(expectedEvent, serviceEvent);
assertSame(expectedThrowable, throwable);
throwIfNecessary();
}
private void throwIfNecessary() {
if (kernelThrowable instanceof RuntimeException) {
throw (RuntimeException) kernelThrowable;
} else if (kernelThrowable instanceof Error) {
throw (Error) kernelThrowable;
} else {
assertNull(kernelThrowable);
}
}
}
}