tom

Added unit tests for the event abstractions.

Added Element as the notion of common ancestry between Device and Host.
......@@ -51,8 +51,13 @@ public class AbstractListenerManager<E extends Event, L extends EventListener<E>
}
}
@Override
public void reportProblem(E event, Throwable error) {
/**
* Reports a problem encountered while processing an event.
*
* @param event event being processed
* @param error error encountered while processing
*/
protected void reportProblem(E event, Throwable error) {
log.warn("Exception encountered while processing event " + event, error);
}
......
......@@ -12,7 +12,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
/**
* Base implementation of event sink broker.
*/
public class AbstractEventSinkBroker implements EventSinkBroker {
public class DefaultEventSinkBroker implements EventSinkBroker {
private final Map<Class<? extends Event>, EventSink<? extends Event>> sinks =
new ConcurrentHashMap<>();
......@@ -36,6 +36,7 @@ public class AbstractEventSinkBroker implements EventSinkBroker {
@Override
@SuppressWarnings("unchecked")
public <E extends Event> EventSink<E> getSink(Class<E> eventClass) {
// TODO: add implicit registration of descendant classes
return (EventSink<E>) sinks.get(eventClass);
}
......
......@@ -12,12 +12,4 @@ public interface EventSink<E extends Event> {
*/
void process(E event);
/**
* Reports a problem encountered while processing an event.
*
* @param event event being processed
* @param error error encountered while processing
*/
void reportProblem(E event, Throwable error);
}
......
package org.onlab.onos.net;
import org.onlab.onos.net.provider.Provided;
/**
* Representation of a network infrastructure device.
*/
public interface Device extends Provided {
public interface Device extends Element {
/**
* Coarse classification of the type of the infrastructure device.
......
package org.onlab.onos.net;
import java.net.URI;
import java.util.Objects;
import static com.google.common.base.Objects.toStringHelper;
/**
* Immutable representation of a device identity.
*/
public class DeviceId {
private final URI uri;
public DeviceId(URI uri) {
this.uri = uri;
}
public class DeviceId extends ElementId {
/**
* Returns the backing URI.
* Creates a device id using the supplied URI.
*
* @return backing device URI
* @param uri backing device URI
*/
public URI uri() {
return uri;
}
@Override
public int hashCode() {
return Objects.hash(uri);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
final DeviceId other = (DeviceId) obj;
return Objects.equals(this.uri, other.uri);
}
@Override
public String toString() {
return toStringHelper(this).add("uri", uri).toString();
public DeviceId(URI uri) {
super(uri);
}
}
......
package org.onlab.onos.net;
import org.onlab.onos.net.provider.Provided;
/**
* Base abstraction of a network element, i.e. an infrastructure device or an end-station host.
*/
public interface Element extends Provided {
/**
* Returns the network element identifier.
*
* @return element identifier
*/
ElementId id();
}
package org.onlab.onos.net;
import java.net.URI;
import java.util.Objects;
import static com.google.common.base.Objects.toStringHelper;
/**
* Immutable representation of a network element identity.
*/
public class ElementId {
private final URI uri;
/**
* Creates an element identifier using the supplied URI.
*
* @param uri backing URI
*/
public ElementId(URI uri) {
this.uri = uri;
}
/**
* Returns the backing URI.
*
* @return backing URI
*/
public URI uri() {
return uri;
}
@Override
public int hashCode() {
return Objects.hash(uri);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
final ElementId other = (ElementId) obj;
return Objects.equals(this.uri, other.uri);
}
@Override
public String toString() {
return toStringHelper(this).add("uri", uri).toString();
}
}
package org.onlab.onos.net;
import org.onlab.onos.net.provider.Provided;
/**
* Abstraction of an end-station host on the network, essentially a NIC.
*/
public interface Host extends Provided {
public interface Host extends Element {
// MAC, IP(s), optional VLAN ID
// Location (current, recent locations?
/**
* Returns the most recent host location where the host attaches to the
* network edge.
*
* @return host location
*/
HostLocation location();
// list of recent locations?
}
......
package org.onlab.onos.net;
/**
* Representation of a network edge location where an end-station host is
* connected.
*/
public interface HostLocation extends ConnectPoint {
/**
* Returns the timestamp when the location was established, given in
* milliseconds since start of epoch.
*
* @return timestamp in milliseconds since start of epoch
*/
long timestamp();
}
package org.onlab.onos.net;
/**
* Abstraction of a network port.
*/
public interface Port {
// Notion of port state: enabled, disabled, blocked
/**
* Returns the port number.
*
* @return port number
*/
PortNumber number();
/**
* Returns the identifier of the network element to which this port belongs.
*
* @return parent network element
*/
Element parent();
// set of port attributes
}
......@@ -3,6 +3,10 @@ package org.onlab.onos.net.device;
import org.onlab.onos.net.Device;
import org.onlab.onos.net.DeviceId;
import org.onlab.onos.net.MastershipRole;
import org.onlab.onos.net.Port;
import org.onlab.onos.net.PortNumber;
import java.util.List;
/**
* Service for interacting with the inventory of infrastructure devices.
......@@ -34,7 +38,21 @@ public interface DeviceService {
Device getDevice(DeviceId deviceId);
// List<Port> getPorts(DeviceId deviceId);
/**
* Returns the list of ports associated with the device.
*
* @param deviceId device identifier
* @return list of ports
*/
List<Port> getPorts(DeviceId deviceId);
/**
* Returns the port with the specified number and hosted by the given device.
* @param deviceId device identifier
* @param portNumber port number
* @return device port
*/
Port getPort(DeviceId deviceId, PortNumber portNumber);
/**
* Adds the specified device listener.
......@@ -49,4 +67,5 @@ public interface DeviceService {
* @param listener device listener
*/
void removeListener(DeviceListener listener);
}
......
package org.onlab.onos.event;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.onlab.onos.event.TestEvent.Type.FOO;
/**
* Tests of the base event abstraction.
*/
public class AbstractEventTest {
@Test
public void withTime() {
TestEvent event = new TestEvent(FOO, "foo", 123L);
assertEquals("incorrect type", FOO, event.type());
assertEquals("incorrect subject", "foo", event.subject());
assertEquals("incorrect time", 123L, event.time());
}
@Test
public void withoutTime() {
long before = System.currentTimeMillis();
TestEvent event = new TestEvent(FOO, "foo");
long after = System.currentTimeMillis();
assertEquals("incorrect type", FOO, event.type());
assertEquals("incorrect subject", "foo", event.subject());
assertTrue("incorrect time", before <= event.time() && event.time() <= after);
}
}
package org.onlab.onos.event;
import org.junit.Test;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
/**
* Tests of the base listener manager.
*/
public class AbstractListenerManagerTest {
@Test
public void basics() {
TestListener listener = new TestListener();
TestListener secondListener = new TestListener();
TestListenerManager manager = new TestListenerManager();
manager.addListener(listener);
manager.addListener(secondListener);
TestEvent event = new TestEvent(TestEvent.Type.BAR, "bar");
manager.process(event);
assertTrue("event not processed", listener.events.contains(event));
assertTrue("event not processed", secondListener.events.contains(event));
manager.removeListener(listener);
TestEvent another = new TestEvent(TestEvent.Type.FOO, "foo");
manager.process(another);
assertFalse("event processed", listener.events.contains(another));
assertTrue("event not processed", secondListener.events.contains(event));
}
@Test
public void badListener() {
TestListener listener = new BrokenListener();
TestListener secondListener = new TestListener();
TestListenerManager manager = new TestListenerManager();
manager.addListener(listener);
manager.addListener(secondListener);
TestEvent event = new TestEvent(TestEvent.Type.BAR, "bar");
manager.process(event);
assertFalse("event processed", listener.events.contains(event));
assertFalse("error not reported", manager.errors.isEmpty());
assertTrue("event not processed", secondListener.events.contains(event));
}
}
package org.onlab.onos.event;
/**
* Test event listener fixture.
*/
public class BrokenListener extends TestListener {
public void event(TestEvent event) {
throw new IllegalStateException("boom");
}
}
package org.onlab.onos.event;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Tests of the default event sink broker.
*/
public class DefaultEventSinkBrokerTest {
private DefaultEventSinkBroker broker;
private static class FooEvent extends TestEvent {
public FooEvent(String subject) { super(Type.FOO, subject); }
}
private static class BarEvent extends TestEvent {
public BarEvent(String subject) { super(Type.BAR, subject); }
}
private static class FooSink implements EventSink<FooEvent> {
@Override public void process(FooEvent event) {}
}
private static class BarSink implements EventSink<BarEvent> {
@Override public void process(BarEvent event) {}
}
@Before
public void setUp() {
broker = new DefaultEventSinkBroker();
}
@Test
public void basics() {
FooSink fooSink = new FooSink();
BarSink barSink = new BarSink();
broker.addSink(FooEvent.class, fooSink);
broker.addSink(BarEvent.class, barSink);
assertEquals("incorrect sink count", 2, broker.getSinks().size());
assertEquals("incorrect sink", fooSink, broker.getSink(FooEvent.class));
assertEquals("incorrect sink", barSink, broker.getSink(BarEvent.class));
broker.removeSink(FooEvent.class);
assertNull("incorrect sink", broker.getSink(FooEvent.class));
assertEquals("incorrect sink", barSink, broker.getSink(BarEvent.class));
}
}
package org.onlab.onos.event;
/**
* Test event fixture.
*/
public class TestEvent extends AbstractEvent<TestEvent.Type, String> {
public enum Type { FOO, BAR };
public TestEvent(Type type, String subject) {
super(type, subject);
}
public TestEvent(Type type, String subject, long timestamp) {
super(type, subject, timestamp);
}
}
package org.onlab.onos.event;
import java.util.ArrayList;
import java.util.List;
/**
* Test event listener fixture.
*/
public class TestListener implements EventListener<TestEvent> {
public final List<TestEvent> events = new ArrayList<>();
@Override
public void event(TestEvent event) {
events.add(event);
}
}
package org.onlab.onos.event;
import java.util.ArrayList;
import java.util.List;
/**
* Test event listener manager fixture.
*/
public class TestListenerManager
extends AbstractListenerManager<TestEvent, TestListener> {
public final List<Throwable> errors = new ArrayList<>();
@Override
protected void reportProblem(TestEvent event, Throwable error) {
super.reportProblem(event, error);
errors.add(error);
}
}
......@@ -19,7 +19,7 @@ import org.slf4j.LoggerFactory;
import java.util.List;
/**
* Provides basic implementation of the device SB & NB APIs.
* Provides basic implementation of the device SB &amp; NB APIs.
*/
@Component(immediate = true)
@Service
......