Yuta HIGUCHI

basic test for ReplicaInfoManager

Change-Id: I604b8b24b9ac0896e6dd2a0650092af76f37968d
...@@ -52,6 +52,12 @@ ...@@ -52,6 +52,12 @@
52 <artifactId>easymock</artifactId> 52 <artifactId>easymock</artifactId>
53 <scope>test</scope> 53 <scope>test</scope>
54 </dependency> 54 </dependency>
55 + <dependency>
56 + <groupId>org.onlab.onos</groupId>
57 + <artifactId>onos-api</artifactId>
58 + <classifier>tests</classifier>
59 + <scope>test</scope>
60 + </dependency>
55 </dependencies> 61 </dependencies>
56 62
57 </project> 63 </project>
......
...@@ -3,7 +3,7 @@ package org.onlab.onos.store.flow; ...@@ -3,7 +3,7 @@ package org.onlab.onos.store.flow;
3 import org.onlab.onos.net.DeviceId; 3 import org.onlab.onos.net.DeviceId;
4 4
5 /** 5 /**
6 - * Service to return where the Replica should be placed. 6 + * Service to return where the replica should be placed.
7 */ 7 */
8 public interface ReplicaInfoService { 8 public interface ReplicaInfoService {
9 9
...@@ -15,4 +15,19 @@ public interface ReplicaInfoService { ...@@ -15,4 +15,19 @@ public interface ReplicaInfoService {
15 * @return placement information 15 * @return placement information
16 */ 16 */
17 ReplicaInfo getReplicaInfoFor(DeviceId deviceId); 17 ReplicaInfo getReplicaInfoFor(DeviceId deviceId);
18 +
19 + /**
20 + * Adds the specified replica placement info change listener.
21 + *
22 + * @param listener the replica placement info change listener
23 + */
24 + void addListener(ReplicaInfoEventListener listener);
25 +
26 + /**
27 + * Removes the specified replica placement info change listener.
28 + *
29 + * @param listener the replica placement info change listener
30 + */
31 + void removeListener(ReplicaInfoEventListener listener);
32 +
18 } 33 }
......
1 package org.onlab.onos.store.flow.impl; 1 package org.onlab.onos.store.flow.impl;
2 2
3 +import static com.google.common.base.Preconditions.checkNotNull;
3 import static org.slf4j.LoggerFactory.getLogger; 4 import static org.slf4j.LoggerFactory.getLogger;
4 import static org.onlab.onos.store.flow.ReplicaInfoEvent.Type.MASTER_CHANGED; 5 import static org.onlab.onos.store.flow.ReplicaInfoEvent.Type.MASTER_CHANGED;
5 6
...@@ -66,6 +67,16 @@ public class ReplicaInfoManager implements ReplicaInfoService { ...@@ -66,6 +67,16 @@ public class ReplicaInfoManager implements ReplicaInfoService {
66 Collections.<NodeId>emptyList()); 67 Collections.<NodeId>emptyList());
67 } 68 }
68 69
70 + @Override
71 + public void addListener(ReplicaInfoEventListener listener) {
72 + listenerRegistry.addListener(checkNotNull(listener));
73 + }
74 +
75 + @Override
76 + public void removeListener(ReplicaInfoEventListener listener) {
77 + listenerRegistry.removeListener(checkNotNull(listener));
78 + }
79 +
69 final class InternalMastershipListener implements MastershipListener { 80 final class InternalMastershipListener implements MastershipListener {
70 81
71 @Override 82 @Override
......
1 +package org.onlab.onos.store.flow.impl;
2 +
3 +import static com.google.common.base.Preconditions.checkState;
4 +import static org.junit.Assert.*;
5 +
6 +import java.util.Collections;
7 +import java.util.Map;
8 +import java.util.concurrent.CountDownLatch;
9 +import java.util.concurrent.TimeUnit;
10 +
11 +import org.junit.After;
12 +import org.junit.Before;
13 +import org.junit.Test;
14 +import org.onlab.onos.cluster.NodeId;
15 +import org.onlab.onos.event.AbstractListenerRegistry;
16 +import org.onlab.onos.event.DefaultEventSinkRegistry;
17 +import org.onlab.onos.event.Event;
18 +import org.onlab.onos.event.EventDeliveryService;
19 +import org.onlab.onos.event.EventSink;
20 +import org.onlab.onos.mastership.MastershipEvent;
21 +import org.onlab.onos.mastership.MastershipEvent.Type;
22 +import org.onlab.onos.mastership.MastershipListener;
23 +import org.onlab.onos.mastership.MastershipService;
24 +import org.onlab.onos.mastership.MastershipServiceAdapter;
25 +import org.onlab.onos.net.DeviceId;
26 +import org.onlab.onos.store.flow.ReplicaInfo;
27 +import org.onlab.onos.store.flow.ReplicaInfoEvent;
28 +import org.onlab.onos.store.flow.ReplicaInfoEventListener;
29 +import org.onlab.onos.store.flow.ReplicaInfoService;
30 +
31 +import com.google.common.base.Optional;
32 +import com.google.common.collect.Maps;
33 +
34 +public class ReplicaInfoManagerTest {
35 +
36 +
37 + private static final DeviceId DID1 = DeviceId.deviceId("of:1");
38 + private static final DeviceId DID2 = DeviceId.deviceId("of:2");
39 + private static final NodeId NID1 = new NodeId("foo");
40 +
41 + private ReplicaInfoManager mgr;
42 + private ReplicaInfoService service;
43 +
44 + private AbstractListenerRegistry<MastershipEvent, MastershipListener>
45 + mastershipListenerRegistry;
46 + private TestEventDispatcher eventDispatcher;
47 +
48 +
49 + @Before
50 + public void setUp() throws Exception {
51 + mastershipListenerRegistry = new AbstractListenerRegistry<>();
52 +
53 + mgr = new ReplicaInfoManager();
54 + service = mgr;
55 +
56 + eventDispatcher = new TestEventDispatcher();
57 + mgr.eventDispatcher = eventDispatcher;
58 + mgr.mastershipService = new TestMastershipService();
59 +
60 + // register dummy mastership event source
61 + mgr.eventDispatcher.addSink(MastershipEvent.class, mastershipListenerRegistry);
62 +
63 + mgr.activate();
64 + }
65 +
66 + @After
67 + public void tearDown() throws Exception {
68 + mgr.deactivate();
69 + }
70 +
71 + @Test
72 + public void testGetReplicaInfoFor() {
73 + ReplicaInfo info1 = service.getReplicaInfoFor(DID1);
74 + assertEquals(Optional.of(NID1), info1.master());
75 + // backups are always empty for now
76 + assertEquals(Collections.emptyList(), info1.backups());
77 +
78 + ReplicaInfo info2 = service.getReplicaInfoFor(DID2);
79 + assertEquals("There's no master", Optional.absent(), info2.master());
80 + // backups are always empty for now
81 + assertEquals(Collections.emptyList(), info2.backups());
82 + }
83 +
84 + @Test
85 + public void testReplicaInfoEvent() throws InterruptedException {
86 + final CountDownLatch latch = new CountDownLatch(1);
87 + service.addListener(new MasterNodeCheck(latch, DID1, NID1));
88 +
89 + // fake MastershipEvent
90 + eventDispatcher.post(new MastershipEvent(Type.MASTER_CHANGED, DID1, NID1));
91 +
92 + assertTrue(latch.await(1, TimeUnit.SECONDS));
93 + }
94 +
95 +
96 + private final class MasterNodeCheck implements ReplicaInfoEventListener {
97 + private final CountDownLatch latch;
98 + private Optional<NodeId> expectedMaster;
99 + private DeviceId expectedDevice;
100 +
101 +
102 + MasterNodeCheck(CountDownLatch latch, DeviceId did,
103 + NodeId nid) {
104 + this.latch = latch;
105 + this.expectedMaster = Optional.fromNullable(nid);
106 + this.expectedDevice = did;
107 + }
108 +
109 + @Override
110 + public void event(ReplicaInfoEvent event) {
111 + assertEquals(expectedDevice, event.subject());
112 + assertEquals(expectedMaster, event.replicaInfo().master());
113 + // backups are always empty for now
114 + assertEquals(Collections.emptyList(), event.replicaInfo().backups());
115 + latch.countDown();
116 + }
117 + }
118 +
119 +
120 + private final class TestMastershipService
121 + extends MastershipServiceAdapter
122 + implements MastershipService {
123 +
124 + private Map<DeviceId, NodeId> masters;
125 +
126 + TestMastershipService() {
127 + masters = Maps.newHashMap();
128 + masters.put(DID1, NID1);
129 + // DID2 has no master
130 + }
131 +
132 + @Override
133 + public NodeId getMasterFor(DeviceId deviceId) {
134 + return masters.get(deviceId);
135 + }
136 +
137 + @Override
138 + public void addListener(MastershipListener listener) {
139 + mastershipListenerRegistry.addListener(listener);
140 + }
141 +
142 + @Override
143 + public void removeListener(MastershipListener listener) {
144 + mastershipListenerRegistry.removeListener(listener);
145 + }
146 + }
147 +
148 +
149 + // code clone
150 + /**
151 + * Implements event delivery system that delivers events synchronously, or
152 + * in-line with the post method invocation.
153 + */
154 + private static class TestEventDispatcher extends DefaultEventSinkRegistry
155 + implements EventDeliveryService {
156 +
157 + @SuppressWarnings({ "rawtypes", "unchecked" })
158 + @Override
159 + public void post(Event event) {
160 + EventSink sink = getSink(event.getClass());
161 + checkState(sink != null, "No sink for event %s", event);
162 + sink.process(event);
163 + }
164 + }
165 +}