Adding some tests for GossipDeviceStore + bugfix
Change-Id: Ic0d55fa499b1d66131f059b4a47cd105c55a6e63
Showing
6 changed files
with
388 additions
and
62 deletions
... | @@ -62,6 +62,11 @@ | ... | @@ -62,6 +62,11 @@ |
62 | <groupId>org.apache.commons</groupId> | 62 | <groupId>org.apache.commons</groupId> |
63 | <artifactId>commons-lang3</artifactId> | 63 | <artifactId>commons-lang3</artifactId> |
64 | </dependency> | 64 | </dependency> |
65 | + <dependency> | ||
66 | + <groupId>org.easymock</groupId> | ||
67 | + <artifactId>easymock</artifactId> | ||
68 | + <scope>test</scope> | ||
69 | + </dependency> | ||
65 | </dependencies> | 70 | </dependencies> |
66 | 71 | ||
67 | <build> | 72 | <build> | ... | ... |
... | @@ -58,7 +58,7 @@ class DeviceDescriptions { | ... | @@ -58,7 +58,7 @@ class DeviceDescriptions { |
58 | * | 58 | * |
59 | * @param newDesc new DeviceDescription | 59 | * @param newDesc new DeviceDescription |
60 | */ | 60 | */ |
61 | - public synchronized void putDeviceDesc(Timestamped<DeviceDescription> newDesc) { | 61 | + public void putDeviceDesc(Timestamped<DeviceDescription> newDesc) { |
62 | Timestamped<DeviceDescription> oldOne = deviceDesc; | 62 | Timestamped<DeviceDescription> oldOne = deviceDesc; |
63 | Timestamped<DeviceDescription> newOne = newDesc; | 63 | Timestamped<DeviceDescription> newOne = newDesc; |
64 | if (oldOne != null) { | 64 | if (oldOne != null) { |
... | @@ -76,7 +76,7 @@ class DeviceDescriptions { | ... | @@ -76,7 +76,7 @@ class DeviceDescriptions { |
76 | * | 76 | * |
77 | * @param newDesc new PortDescription | 77 | * @param newDesc new PortDescription |
78 | */ | 78 | */ |
79 | - public synchronized void putPortDesc(Timestamped<PortDescription> newDesc) { | 79 | + public void putPortDesc(Timestamped<PortDescription> newDesc) { |
80 | Timestamped<PortDescription> oldOne = portDescs.get(newDesc.value().portNumber()); | 80 | Timestamped<PortDescription> oldOne = portDescs.get(newDesc.value().portNumber()); |
81 | Timestamped<PortDescription> newOne = newDesc; | 81 | Timestamped<PortDescription> newOne = newDesc; |
82 | if (oldOne != null) { | 82 | if (oldOne != null) { | ... | ... |
1 | package org.onlab.onos.store.device.impl; | 1 | package org.onlab.onos.store.device.impl; |
2 | 2 | ||
3 | +import com.google.common.base.Function; | ||
3 | import com.google.common.collect.FluentIterable; | 4 | import com.google.common.collect.FluentIterable; |
4 | import com.google.common.collect.ImmutableList; | 5 | import com.google.common.collect.ImmutableList; |
5 | import com.google.common.collect.Maps; | 6 | import com.google.common.collect.Maps; |
... | @@ -118,7 +119,7 @@ public class GossipDeviceStore | ... | @@ -118,7 +119,7 @@ public class GossipDeviceStore |
118 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 119 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
119 | protected ClusterService clusterService; | 120 | protected ClusterService clusterService; |
120 | 121 | ||
121 | - private static final KryoSerializer SERIALIZER = new KryoSerializer() { | 122 | + protected static final KryoSerializer SERIALIZER = new KryoSerializer() { |
122 | @Override | 123 | @Override |
123 | protected void setupKryoPool() { | 124 | protected void setupKryoPool() { |
124 | serializerPool = KryoPool.newBuilder() | 125 | serializerPool = KryoPool.newBuilder() |
... | @@ -206,14 +207,19 @@ public class GossipDeviceStore | ... | @@ -206,14 +207,19 @@ public class GossipDeviceStore |
206 | public synchronized DeviceEvent createOrUpdateDevice(ProviderId providerId, | 207 | public synchronized DeviceEvent createOrUpdateDevice(ProviderId providerId, |
207 | DeviceId deviceId, | 208 | DeviceId deviceId, |
208 | DeviceDescription deviceDescription) { | 209 | DeviceDescription deviceDescription) { |
209 | - Timestamp newTimestamp = clockService.getTimestamp(deviceId); | 210 | + final Timestamp newTimestamp = clockService.getTimestamp(deviceId); |
210 | final Timestamped<DeviceDescription> deltaDesc = new Timestamped<>(deviceDescription, newTimestamp); | 211 | final Timestamped<DeviceDescription> deltaDesc = new Timestamped<>(deviceDescription, newTimestamp); |
211 | - DeviceEvent event = createOrUpdateDeviceInternal(providerId, deviceId, deltaDesc); | 212 | + final DeviceEvent event; |
213 | + final Timestamped<DeviceDescription> mergedDesc; | ||
214 | + synchronized (getDeviceDescriptions(deviceId)) { | ||
215 | + event = createOrUpdateDeviceInternal(providerId, deviceId, deltaDesc); | ||
216 | + mergedDesc = getDeviceDescriptions(deviceId).get(providerId).getDeviceDesc(); | ||
217 | + } | ||
212 | if (event != null) { | 218 | if (event != null) { |
213 | log.info("Notifying peers of a device update topology event for providerId: {} and deviceId: {}", | 219 | log.info("Notifying peers of a device update topology event for providerId: {} and deviceId: {}", |
214 | providerId, deviceId); | 220 | providerId, deviceId); |
215 | try { | 221 | try { |
216 | - notifyPeers(new InternalDeviceEvent(providerId, deviceId, deltaDesc)); | 222 | + notifyPeers(new InternalDeviceEvent(providerId, deviceId, mergedDesc)); |
217 | } catch (IOException e) { | 223 | } catch (IOException e) { |
218 | log.error("Failed to notify peers of a device update topology event for providerId: " | 224 | log.error("Failed to notify peers of a device update topology event for providerId: " |
219 | + providerId + " and deviceId: " + deviceId, e); | 225 | + providerId + " and deviceId: " + deviceId, e); |
... | @@ -317,8 +323,8 @@ public class GossipDeviceStore | ... | @@ -317,8 +323,8 @@ public class GossipDeviceStore |
317 | 323 | ||
318 | @Override | 324 | @Override |
319 | public DeviceEvent markOffline(DeviceId deviceId) { | 325 | public DeviceEvent markOffline(DeviceId deviceId) { |
320 | - Timestamp timestamp = clockService.getTimestamp(deviceId); | 326 | + final Timestamp timestamp = clockService.getTimestamp(deviceId); |
321 | - DeviceEvent event = markOfflineInternal(deviceId, timestamp); | 327 | + final DeviceEvent event = markOfflineInternal(deviceId, timestamp); |
322 | if (event != null) { | 328 | if (event != null) { |
323 | log.info("Notifying peers of a device offline topology event for deviceId: {}", | 329 | log.info("Notifying peers of a device offline topology event for deviceId: {}", |
324 | deviceId); | 330 | deviceId); |
... | @@ -390,17 +396,33 @@ public class GossipDeviceStore | ... | @@ -390,17 +396,33 @@ public class GossipDeviceStore |
390 | public synchronized List<DeviceEvent> updatePorts(ProviderId providerId, | 396 | public synchronized List<DeviceEvent> updatePorts(ProviderId providerId, |
391 | DeviceId deviceId, | 397 | DeviceId deviceId, |
392 | List<PortDescription> portDescriptions) { | 398 | List<PortDescription> portDescriptions) { |
393 | - Timestamp newTimestamp = clockService.getTimestamp(deviceId); | ||
394 | 399 | ||
395 | - Timestamped<List<PortDescription>> timestampedPortDescriptions = | 400 | + final Timestamp newTimestamp = clockService.getTimestamp(deviceId); |
396 | - new Timestamped<>(portDescriptions, newTimestamp); | 401 | + |
397 | - | 402 | + final Timestamped<List<PortDescription>> timestampedInput |
398 | - List<DeviceEvent> events = updatePortsInternal(providerId, deviceId, timestampedPortDescriptions); | 403 | + = new Timestamped<>(portDescriptions, newTimestamp); |
404 | + final List<DeviceEvent> events; | ||
405 | + final Timestamped<List<PortDescription>> merged; | ||
406 | + | ||
407 | + synchronized (getDeviceDescriptions(deviceId)) { | ||
408 | + events = updatePortsInternal(providerId, deviceId, timestampedInput); | ||
409 | + final DeviceDescriptions descs = getDeviceDescriptions(deviceId).get(providerId); | ||
410 | + List<PortDescription> mergedList = | ||
411 | + FluentIterable.from(portDescriptions) | ||
412 | + .transform(new Function<PortDescription, PortDescription>() { | ||
413 | + @Override | ||
414 | + public PortDescription apply(PortDescription input) { | ||
415 | + // lookup merged port description | ||
416 | + return descs.getPortDesc(input.portNumber()).value(); | ||
417 | + } | ||
418 | + }).toList(); | ||
419 | + merged = new Timestamped<List<PortDescription>>(mergedList, newTimestamp); | ||
420 | + } | ||
399 | if (!events.isEmpty()) { | 421 | if (!events.isEmpty()) { |
400 | log.info("Notifying peers of a port update topology event for providerId: {} and deviceId: {}", | 422 | log.info("Notifying peers of a port update topology event for providerId: {} and deviceId: {}", |
401 | providerId, deviceId); | 423 | providerId, deviceId); |
402 | try { | 424 | try { |
403 | - notifyPeers(new InternalPortEvent(providerId, deviceId, timestampedPortDescriptions)); | 425 | + notifyPeers(new InternalPortEvent(providerId, deviceId, merged)); |
404 | } catch (IOException e) { | 426 | } catch (IOException e) { |
405 | log.error("Failed to notify peers of a port update topology event or providerId: " | 427 | log.error("Failed to notify peers of a port update topology event or providerId: " |
406 | + providerId + " and deviceId: " + deviceId, e); | 428 | + providerId + " and deviceId: " + deviceId, e); |
... | @@ -527,16 +549,25 @@ public class GossipDeviceStore | ... | @@ -527,16 +549,25 @@ public class GossipDeviceStore |
527 | } | 549 | } |
528 | 550 | ||
529 | @Override | 551 | @Override |
530 | - public synchronized DeviceEvent updatePortStatus(ProviderId providerId, DeviceId deviceId, | 552 | + public synchronized DeviceEvent updatePortStatus(ProviderId providerId, |
531 | - PortDescription portDescription) { | 553 | + DeviceId deviceId, |
532 | - Timestamp newTimestamp = clockService.getTimestamp(deviceId); | 554 | + PortDescription portDescription) { |
533 | - final Timestamped<PortDescription> deltaDesc = new Timestamped<>(portDescription, newTimestamp); | 555 | + |
534 | - DeviceEvent event = updatePortStatusInternal(providerId, deviceId, deltaDesc); | 556 | + final Timestamp newTimestamp = clockService.getTimestamp(deviceId); |
557 | + final Timestamped<PortDescription> deltaDesc | ||
558 | + = new Timestamped<>(portDescription, newTimestamp); | ||
559 | + final DeviceEvent event; | ||
560 | + final Timestamped<PortDescription> mergedDesc; | ||
561 | + synchronized (getDeviceDescriptions(deviceId)) { | ||
562 | + event = updatePortStatusInternal(providerId, deviceId, deltaDesc); | ||
563 | + mergedDesc = getDeviceDescriptions(deviceId).get(providerId) | ||
564 | + .getPortDesc(portDescription.portNumber()); | ||
565 | + } | ||
535 | if (event != null) { | 566 | if (event != null) { |
536 | log.info("Notifying peers of a port status update topology event for providerId: {} and deviceId: {}", | 567 | log.info("Notifying peers of a port status update topology event for providerId: {} and deviceId: {}", |
537 | providerId, deviceId); | 568 | providerId, deviceId); |
538 | try { | 569 | try { |
539 | - notifyPeers(new InternalPortStatusEvent(providerId, deviceId, deltaDesc)); | 570 | + notifyPeers(new InternalPortStatusEvent(providerId, deviceId, mergedDesc)); |
540 | } catch (IOException e) { | 571 | } catch (IOException e) { |
541 | log.error("Failed to notify peers of a port status update topology event or providerId: " | 572 | log.error("Failed to notify peers of a port status update topology event or providerId: " |
542 | + providerId + " and deviceId: " + deviceId, e); | 573 | + providerId + " and deviceId: " + deviceId, e); |
... | @@ -684,7 +715,7 @@ public class GossipDeviceStore | ... | @@ -684,7 +715,7 @@ public class GossipDeviceStore |
684 | * @return Device instance | 715 | * @return Device instance |
685 | */ | 716 | */ |
686 | private Device composeDevice(DeviceId deviceId, | 717 | private Device composeDevice(DeviceId deviceId, |
687 | - ConcurrentMap<ProviderId, DeviceDescriptions> providerDescs) { | 718 | + Map<ProviderId, DeviceDescriptions> providerDescs) { |
688 | 719 | ||
689 | checkArgument(!providerDescs.isEmpty(), "No Device descriptions supplied"); | 720 | checkArgument(!providerDescs.isEmpty(), "No Device descriptions supplied"); |
690 | 721 | ... | ... |
1 | package org.onlab.onos.store.device.impl; | 1 | package org.onlab.onos.store.device.impl; |
2 | 2 | ||
3 | +import static org.easymock.EasyMock.*; | ||
3 | import static org.junit.Assert.*; | 4 | import static org.junit.Assert.*; |
4 | import static org.onlab.onos.net.Device.Type.SWITCH; | 5 | import static org.onlab.onos.net.Device.Type.SWITCH; |
5 | import static org.onlab.onos.net.DeviceId.deviceId; | 6 | import static org.onlab.onos.net.DeviceId.deviceId; |
6 | import static org.onlab.onos.net.device.DeviceEvent.Type.*; | 7 | import static org.onlab.onos.net.device.DeviceEvent.Type.*; |
7 | - | 8 | +import static org.onlab.onos.cluster.ControllerNode.State.*; |
9 | +import static org.onlab.onos.net.DefaultAnnotations.union; | ||
10 | +import static java.util.Arrays.asList; | ||
8 | import java.io.IOException; | 11 | import java.io.IOException; |
9 | import java.util.Arrays; | 12 | import java.util.Arrays; |
13 | +import java.util.Collections; | ||
10 | import java.util.HashMap; | 14 | import java.util.HashMap; |
11 | import java.util.List; | 15 | import java.util.List; |
12 | import java.util.Map; | 16 | import java.util.Map; |
... | @@ -14,6 +18,7 @@ import java.util.Set; | ... | @@ -14,6 +18,7 @@ import java.util.Set; |
14 | import java.util.concurrent.CountDownLatch; | 18 | import java.util.concurrent.CountDownLatch; |
15 | import java.util.concurrent.TimeUnit; | 19 | import java.util.concurrent.TimeUnit; |
16 | 20 | ||
21 | +import org.easymock.Capture; | ||
17 | import org.junit.After; | 22 | import org.junit.After; |
18 | import org.junit.AfterClass; | 23 | import org.junit.AfterClass; |
19 | import org.junit.Before; | 24 | import org.junit.Before; |
... | @@ -90,14 +95,25 @@ public class GossipDeviceStoreTest { | ... | @@ -90,14 +95,25 @@ public class GossipDeviceStoreTest { |
90 | .set("B4", "b4") | 95 | .set("B4", "b4") |
91 | .build(); | 96 | .build(); |
92 | 97 | ||
93 | - private static final NodeId MYSELF = new NodeId("myself"); | 98 | + // local node |
99 | + private static final NodeId NID1 = new NodeId("local"); | ||
100 | + private static final ControllerNode ONOS1 = | ||
101 | + new DefaultControllerNode(NID1, IpPrefix.valueOf("127.0.0.1")); | ||
102 | + | ||
103 | + // remote node | ||
104 | + private static final NodeId NID2 = new NodeId("remote"); | ||
105 | + private static final ControllerNode ONOS2 = | ||
106 | + new DefaultControllerNode(NID2, IpPrefix.valueOf("127.0.0.2")); | ||
107 | + private static final List<SparseAnnotations> NO_ANNOTATION = Collections.<SparseAnnotations>emptyList(); | ||
94 | 108 | ||
109 | + | ||
110 | + private TestGossipDeviceStore testGossipDeviceStore; | ||
95 | private GossipDeviceStore gossipDeviceStore; | 111 | private GossipDeviceStore gossipDeviceStore; |
96 | private DeviceStore deviceStore; | 112 | private DeviceStore deviceStore; |
97 | 113 | ||
98 | private DeviceClockManager deviceClockManager; | 114 | private DeviceClockManager deviceClockManager; |
99 | private ClockService clockService; | 115 | private ClockService clockService; |
100 | - | 116 | + private ClusterCommunicationService clusterCommunicator; |
101 | @BeforeClass | 117 | @BeforeClass |
102 | public static void setUpBeforeClass() throws Exception { | 118 | public static void setUpBeforeClass() throws Exception { |
103 | } | 119 | } |
... | @@ -113,15 +129,22 @@ public class GossipDeviceStoreTest { | ... | @@ -113,15 +129,22 @@ public class GossipDeviceStoreTest { |
113 | deviceClockManager.activate(); | 129 | deviceClockManager.activate(); |
114 | clockService = deviceClockManager; | 130 | clockService = deviceClockManager; |
115 | 131 | ||
116 | - deviceClockManager.setMastershipTerm(DID1, MastershipTerm.of(MYSELF, 1)); | 132 | + deviceClockManager.setMastershipTerm(DID1, MastershipTerm.of(NID1, 1)); |
117 | - deviceClockManager.setMastershipTerm(DID2, MastershipTerm.of(MYSELF, 2)); | 133 | + deviceClockManager.setMastershipTerm(DID2, MastershipTerm.of(NID1, 2)); |
118 | 134 | ||
119 | - ClusterCommunicationService clusterCommunicator = new TestClusterCommunicationService(); | 135 | + clusterCommunicator = createNiceMock(ClusterCommunicationService.class); |
136 | + clusterCommunicator.addSubscriber(anyObject(MessageSubject.class), | ||
137 | + anyObject(ClusterMessageHandler.class)); | ||
138 | + expectLastCall().anyTimes(); | ||
139 | + replay(clusterCommunicator); | ||
120 | ClusterService clusterService = new TestClusterService(); | 140 | ClusterService clusterService = new TestClusterService(); |
121 | 141 | ||
122 | - gossipDeviceStore = new TestGossipDeviceStore(clockService, clusterService, clusterCommunicator); | 142 | + testGossipDeviceStore = new TestGossipDeviceStore(clockService, clusterService, clusterCommunicator); |
143 | + gossipDeviceStore = testGossipDeviceStore; | ||
123 | gossipDeviceStore.activate(); | 144 | gossipDeviceStore.activate(); |
124 | deviceStore = gossipDeviceStore; | 145 | deviceStore = gossipDeviceStore; |
146 | + verify(clusterCommunicator); | ||
147 | + reset(clusterCommunicator); | ||
125 | } | 148 | } |
126 | 149 | ||
127 | @After | 150 | @After |
... | @@ -135,7 +158,16 @@ public class GossipDeviceStoreTest { | ... | @@ -135,7 +158,16 @@ public class GossipDeviceStoreTest { |
135 | DeviceDescription description = | 158 | DeviceDescription description = |
136 | new DefaultDeviceDescription(deviceId.uri(), SWITCH, MFR, | 159 | new DefaultDeviceDescription(deviceId.uri(), SWITCH, MFR, |
137 | HW, swVersion, SN, annotations); | 160 | HW, swVersion, SN, annotations); |
161 | + reset(clusterCommunicator); | ||
162 | + try { | ||
163 | + expect(clusterCommunicator.broadcast(anyObject(ClusterMessage.class))) | ||
164 | + .andReturn(true).anyTimes(); | ||
165 | + } catch (IOException e) { | ||
166 | + fail("Should never reach here"); | ||
167 | + } | ||
168 | + replay(clusterCommunicator); | ||
138 | deviceStore.createOrUpdateDevice(PID, deviceId, description); | 169 | deviceStore.createOrUpdateDevice(PID, deviceId, description); |
170 | + verify(clusterCommunicator); | ||
139 | } | 171 | } |
140 | 172 | ||
141 | private void putDeviceAncillary(DeviceId deviceId, String swVersion, | 173 | private void putDeviceAncillary(DeviceId deviceId, String swVersion, |
... | @@ -163,9 +195,9 @@ public class GossipDeviceStoreTest { | ... | @@ -163,9 +195,9 @@ public class GossipDeviceStoreTest { |
163 | * @param annotations | 195 | * @param annotations |
164 | */ | 196 | */ |
165 | private static void assertAnnotationsEquals(Annotations actual, SparseAnnotations... annotations) { | 197 | private static void assertAnnotationsEquals(Annotations actual, SparseAnnotations... annotations) { |
166 | - DefaultAnnotations expected = DefaultAnnotations.builder().build(); | 198 | + SparseAnnotations expected = DefaultAnnotations.builder().build(); |
167 | for (SparseAnnotations a : annotations) { | 199 | for (SparseAnnotations a : annotations) { |
168 | - expected = DefaultAnnotations.merge(expected, a); | 200 | + expected = DefaultAnnotations.union(expected, a); |
169 | } | 201 | } |
170 | assertEquals(expected.keys(), actual.keys()); | 202 | assertEquals(expected.keys(), actual.keys()); |
171 | for (String key : expected.keys()) { | 203 | for (String key : expected.keys()) { |
... | @@ -173,6 +205,36 @@ public class GossipDeviceStoreTest { | ... | @@ -173,6 +205,36 @@ public class GossipDeviceStoreTest { |
173 | } | 205 | } |
174 | } | 206 | } |
175 | 207 | ||
208 | + private static void assertDeviceDescriptionEquals(DeviceDescription expected, | ||
209 | + DeviceDescription actual) { | ||
210 | + if (expected == actual) { | ||
211 | + return; | ||
212 | + } | ||
213 | + assertEquals(expected.deviceURI(), actual.deviceURI()); | ||
214 | + assertEquals(expected.hwVersion(), actual.hwVersion()); | ||
215 | + assertEquals(expected.manufacturer(), actual.manufacturer()); | ||
216 | + assertEquals(expected.serialNumber(), actual.serialNumber()); | ||
217 | + assertEquals(expected.swVersion(), actual.swVersion()); | ||
218 | + | ||
219 | + assertAnnotationsEquals(actual.annotations(), expected.annotations()); | ||
220 | + } | ||
221 | + | ||
222 | + private static void assertDeviceDescriptionEquals(DeviceDescription expected, | ||
223 | + List<SparseAnnotations> expectedAnnotations, | ||
224 | + DeviceDescription actual) { | ||
225 | + if (expected == actual) { | ||
226 | + return; | ||
227 | + } | ||
228 | + assertEquals(expected.deviceURI(), actual.deviceURI()); | ||
229 | + assertEquals(expected.hwVersion(), actual.hwVersion()); | ||
230 | + assertEquals(expected.manufacturer(), actual.manufacturer()); | ||
231 | + assertEquals(expected.serialNumber(), actual.serialNumber()); | ||
232 | + assertEquals(expected.swVersion(), actual.swVersion()); | ||
233 | + | ||
234 | + assertAnnotationsEquals(actual.annotations(), | ||
235 | + expectedAnnotations.toArray(new SparseAnnotations[0])); | ||
236 | + } | ||
237 | + | ||
176 | @Test | 238 | @Test |
177 | public final void testGetDeviceCount() { | 239 | public final void testGetDeviceCount() { |
178 | assertEquals("initialy empty", 0, deviceStore.getDeviceCount()); | 240 | assertEquals("initialy empty", 0, deviceStore.getDeviceCount()); |
... | @@ -215,56 +277,123 @@ public class GossipDeviceStoreTest { | ... | @@ -215,56 +277,123 @@ public class GossipDeviceStoreTest { |
215 | assertNull("DID2 shouldn't be there", deviceStore.getDevice(DID2)); | 277 | assertNull("DID2 shouldn't be there", deviceStore.getDevice(DID2)); |
216 | } | 278 | } |
217 | 279 | ||
280 | + private void assertInternalDeviceEvent(NodeId sender, | ||
281 | + DeviceId deviceId, | ||
282 | + ProviderId providerId, | ||
283 | + DeviceDescription expectedDesc, | ||
284 | + Capture<ClusterMessage> actualMsg) { | ||
285 | + assertTrue(actualMsg.hasCaptured()); | ||
286 | + assertEquals(sender, actualMsg.getValue().sender()); | ||
287 | + assertEquals(GossipDeviceStoreMessageSubjects.DEVICE_UPDATE, | ||
288 | + actualMsg.getValue().subject()); | ||
289 | + InternalDeviceEvent addEvent | ||
290 | + = testGossipDeviceStore.deserialize(actualMsg.getValue().payload()); | ||
291 | + assertEquals(deviceId, addEvent.deviceId()); | ||
292 | + assertEquals(providerId, addEvent.providerId()); | ||
293 | + assertDeviceDescriptionEquals(expectedDesc, addEvent.deviceDescription().value()); | ||
294 | + } | ||
295 | + | ||
296 | + private void assertInternalDeviceEvent(NodeId sender, | ||
297 | + DeviceId deviceId, | ||
298 | + ProviderId providerId, | ||
299 | + DeviceDescription expectedDesc, | ||
300 | + List<SparseAnnotations> expectedAnnotations, | ||
301 | + Capture<ClusterMessage> actualMsg) { | ||
302 | + assertTrue(actualMsg.hasCaptured()); | ||
303 | + assertEquals(sender, actualMsg.getValue().sender()); | ||
304 | + assertEquals(GossipDeviceStoreMessageSubjects.DEVICE_UPDATE, | ||
305 | + actualMsg.getValue().subject()); | ||
306 | + InternalDeviceEvent addEvent | ||
307 | + = testGossipDeviceStore.deserialize(actualMsg.getValue().payload()); | ||
308 | + assertEquals(deviceId, addEvent.deviceId()); | ||
309 | + assertEquals(providerId, addEvent.providerId()); | ||
310 | + assertDeviceDescriptionEquals(expectedDesc, expectedAnnotations, addEvent.deviceDescription().value()); | ||
311 | + } | ||
312 | + | ||
218 | @Test | 313 | @Test |
219 | - public final void testCreateOrUpdateDevice() { | 314 | + public final void testCreateOrUpdateDevice() throws IOException { |
220 | DeviceDescription description = | 315 | DeviceDescription description = |
221 | new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR, | 316 | new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR, |
222 | HW, SW1, SN); | 317 | HW, SW1, SN); |
318 | + Capture<ClusterMessage> bcast = new Capture<>(); | ||
319 | + | ||
320 | + resetCommunicatorExpectingSingleBroadcast(bcast); | ||
223 | DeviceEvent event = deviceStore.createOrUpdateDevice(PID, DID1, description); | 321 | DeviceEvent event = deviceStore.createOrUpdateDevice(PID, DID1, description); |
224 | assertEquals(DEVICE_ADDED, event.type()); | 322 | assertEquals(DEVICE_ADDED, event.type()); |
225 | assertDevice(DID1, SW1, event.subject()); | 323 | assertDevice(DID1, SW1, event.subject()); |
324 | + verify(clusterCommunicator); | ||
325 | + assertInternalDeviceEvent(NID1, DID1, PID, description, bcast); | ||
326 | + | ||
226 | 327 | ||
227 | DeviceDescription description2 = | 328 | DeviceDescription description2 = |
228 | new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR, | 329 | new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR, |
229 | HW, SW2, SN); | 330 | HW, SW2, SN); |
331 | + resetCommunicatorExpectingSingleBroadcast(bcast); | ||
230 | DeviceEvent event2 = deviceStore.createOrUpdateDevice(PID, DID1, description2); | 332 | DeviceEvent event2 = deviceStore.createOrUpdateDevice(PID, DID1, description2); |
231 | assertEquals(DEVICE_UPDATED, event2.type()); | 333 | assertEquals(DEVICE_UPDATED, event2.type()); |
232 | assertDevice(DID1, SW2, event2.subject()); | 334 | assertDevice(DID1, SW2, event2.subject()); |
233 | 335 | ||
336 | + verify(clusterCommunicator); | ||
337 | + assertInternalDeviceEvent(NID1, DID1, PID, description2, bcast); | ||
338 | + reset(clusterCommunicator); | ||
339 | + | ||
234 | assertNull("No change expected", deviceStore.createOrUpdateDevice(PID, DID1, description2)); | 340 | assertNull("No change expected", deviceStore.createOrUpdateDevice(PID, DID1, description2)); |
235 | } | 341 | } |
236 | 342 | ||
237 | @Test | 343 | @Test |
238 | - public final void testCreateOrUpdateDeviceAncillary() { | 344 | + public final void testCreateOrUpdateDeviceAncillary() throws IOException { |
345 | + // add | ||
239 | DeviceDescription description = | 346 | DeviceDescription description = |
240 | new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR, | 347 | new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR, |
241 | HW, SW1, SN, A2); | 348 | HW, SW1, SN, A2); |
349 | + Capture<ClusterMessage> bcast = new Capture<>(); | ||
350 | + | ||
351 | + resetCommunicatorExpectingSingleBroadcast(bcast); | ||
242 | DeviceEvent event = deviceStore.createOrUpdateDevice(PIDA, DID1, description); | 352 | DeviceEvent event = deviceStore.createOrUpdateDevice(PIDA, DID1, description); |
243 | assertEquals(DEVICE_ADDED, event.type()); | 353 | assertEquals(DEVICE_ADDED, event.type()); |
244 | assertDevice(DID1, SW1, event.subject()); | 354 | assertDevice(DID1, SW1, event.subject()); |
245 | assertEquals(PIDA, event.subject().providerId()); | 355 | assertEquals(PIDA, event.subject().providerId()); |
246 | assertAnnotationsEquals(event.subject().annotations(), A2); | 356 | assertAnnotationsEquals(event.subject().annotations(), A2); |
247 | assertFalse("Ancillary will not bring device up", deviceStore.isAvailable(DID1)); | 357 | assertFalse("Ancillary will not bring device up", deviceStore.isAvailable(DID1)); |
358 | + verify(clusterCommunicator); | ||
359 | + assertInternalDeviceEvent(NID1, DID1, PIDA, description, bcast); | ||
248 | 360 | ||
361 | + // update from primary | ||
249 | DeviceDescription description2 = | 362 | DeviceDescription description2 = |
250 | new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR, | 363 | new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR, |
251 | HW, SW2, SN, A1); | 364 | HW, SW2, SN, A1); |
365 | + resetCommunicatorExpectingSingleBroadcast(bcast); | ||
366 | + | ||
252 | DeviceEvent event2 = deviceStore.createOrUpdateDevice(PID, DID1, description2); | 367 | DeviceEvent event2 = deviceStore.createOrUpdateDevice(PID, DID1, description2); |
253 | assertEquals(DEVICE_UPDATED, event2.type()); | 368 | assertEquals(DEVICE_UPDATED, event2.type()); |
254 | assertDevice(DID1, SW2, event2.subject()); | 369 | assertDevice(DID1, SW2, event2.subject()); |
255 | assertEquals(PID, event2.subject().providerId()); | 370 | assertEquals(PID, event2.subject().providerId()); |
256 | assertAnnotationsEquals(event2.subject().annotations(), A1, A2); | 371 | assertAnnotationsEquals(event2.subject().annotations(), A1, A2); |
257 | assertTrue(deviceStore.isAvailable(DID1)); | 372 | assertTrue(deviceStore.isAvailable(DID1)); |
373 | + verify(clusterCommunicator); | ||
374 | + assertInternalDeviceEvent(NID1, DID1, PID, description2, bcast); | ||
258 | 375 | ||
376 | + // no-op update from primary | ||
377 | + resetCommunicatorExpectingNoBroadcast(bcast); | ||
259 | assertNull("No change expected", deviceStore.createOrUpdateDevice(PID, DID1, description2)); | 378 | assertNull("No change expected", deviceStore.createOrUpdateDevice(PID, DID1, description2)); |
260 | 379 | ||
380 | + verify(clusterCommunicator); | ||
381 | + assertFalse("no broadcast expected", bcast.hasCaptured()); | ||
382 | + | ||
261 | // For now, Ancillary is ignored once primary appears | 383 | // For now, Ancillary is ignored once primary appears |
384 | + resetCommunicatorExpectingNoBroadcast(bcast); | ||
385 | + | ||
262 | assertNull("No change expected", deviceStore.createOrUpdateDevice(PIDA, DID1, description)); | 386 | assertNull("No change expected", deviceStore.createOrUpdateDevice(PIDA, DID1, description)); |
263 | 387 | ||
388 | + verify(clusterCommunicator); | ||
389 | + assertFalse("no broadcast expected", bcast.hasCaptured()); | ||
390 | + | ||
264 | // But, Ancillary annotations will be in effect | 391 | // But, Ancillary annotations will be in effect |
265 | DeviceDescription description3 = | 392 | DeviceDescription description3 = |
266 | new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR, | 393 | new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR, |
267 | HW, SW1, SN, A2_2); | 394 | HW, SW1, SN, A2_2); |
395 | + resetCommunicatorExpectingSingleBroadcast(bcast); | ||
396 | + | ||
268 | DeviceEvent event3 = deviceStore.createOrUpdateDevice(PIDA, DID1, description3); | 397 | DeviceEvent event3 = deviceStore.createOrUpdateDevice(PIDA, DID1, description3); |
269 | assertEquals(DEVICE_UPDATED, event3.type()); | 398 | assertEquals(DEVICE_UPDATED, event3.type()); |
270 | // basic information will be the one from Primary | 399 | // basic information will be the one from Primary |
... | @@ -273,6 +402,11 @@ public class GossipDeviceStoreTest { | ... | @@ -273,6 +402,11 @@ public class GossipDeviceStoreTest { |
273 | // but annotation from Ancillary will be merged | 402 | // but annotation from Ancillary will be merged |
274 | assertAnnotationsEquals(event3.subject().annotations(), A1, A2, A2_2); | 403 | assertAnnotationsEquals(event3.subject().annotations(), A1, A2, A2_2); |
275 | assertTrue(deviceStore.isAvailable(DID1)); | 404 | assertTrue(deviceStore.isAvailable(DID1)); |
405 | + verify(clusterCommunicator); | ||
406 | + // note: only annotation from PIDA is sent over the wire | ||
407 | + assertInternalDeviceEvent(NID1, DID1, PIDA, description3, | ||
408 | + asList(union(A2, A2_2)), bcast); | ||
409 | + | ||
276 | } | 410 | } |
277 | 411 | ||
278 | 412 | ||
... | @@ -282,14 +416,24 @@ public class GossipDeviceStoreTest { | ... | @@ -282,14 +416,24 @@ public class GossipDeviceStoreTest { |
282 | putDevice(DID1, SW1); | 416 | putDevice(DID1, SW1); |
283 | assertTrue(deviceStore.isAvailable(DID1)); | 417 | assertTrue(deviceStore.isAvailable(DID1)); |
284 | 418 | ||
419 | + Capture<ClusterMessage> bcast = new Capture<>(); | ||
420 | + | ||
421 | + resetCommunicatorExpectingSingleBroadcast(bcast); | ||
285 | DeviceEvent event = deviceStore.markOffline(DID1); | 422 | DeviceEvent event = deviceStore.markOffline(DID1); |
286 | assertEquals(DEVICE_AVAILABILITY_CHANGED, event.type()); | 423 | assertEquals(DEVICE_AVAILABILITY_CHANGED, event.type()); |
287 | assertDevice(DID1, SW1, event.subject()); | 424 | assertDevice(DID1, SW1, event.subject()); |
288 | assertFalse(deviceStore.isAvailable(DID1)); | 425 | assertFalse(deviceStore.isAvailable(DID1)); |
426 | + verify(clusterCommunicator); | ||
427 | + // TODO: verify broadcast message | ||
428 | + assertTrue(bcast.hasCaptured()); | ||
429 | + | ||
289 | 430 | ||
431 | + resetCommunicatorExpectingNoBroadcast(bcast); | ||
290 | DeviceEvent event2 = deviceStore.markOffline(DID1); | 432 | DeviceEvent event2 = deviceStore.markOffline(DID1); |
291 | assertNull("No change, no event", event2); | 433 | assertNull("No change, no event", event2); |
292 | -} | 434 | + verify(clusterCommunicator); |
435 | + assertFalse(bcast.hasCaptured()); | ||
436 | + } | ||
293 | 437 | ||
294 | @Test | 438 | @Test |
295 | public final void testUpdatePorts() { | 439 | public final void testUpdatePorts() { |
... | @@ -298,8 +442,13 @@ public class GossipDeviceStoreTest { | ... | @@ -298,8 +442,13 @@ public class GossipDeviceStoreTest { |
298 | new DefaultPortDescription(P1, true), | 442 | new DefaultPortDescription(P1, true), |
299 | new DefaultPortDescription(P2, true) | 443 | new DefaultPortDescription(P2, true) |
300 | ); | 444 | ); |
445 | + Capture<ClusterMessage> bcast = new Capture<>(); | ||
301 | 446 | ||
447 | + resetCommunicatorExpectingSingleBroadcast(bcast); | ||
302 | List<DeviceEvent> events = deviceStore.updatePorts(PID, DID1, pds); | 448 | List<DeviceEvent> events = deviceStore.updatePorts(PID, DID1, pds); |
449 | + verify(clusterCommunicator); | ||
450 | + // TODO: verify broadcast message | ||
451 | + assertTrue(bcast.hasCaptured()); | ||
303 | 452 | ||
304 | Set<PortNumber> expectedPorts = Sets.newHashSet(P1, P2); | 453 | Set<PortNumber> expectedPorts = Sets.newHashSet(P1, P2); |
305 | for (DeviceEvent event : events) { | 454 | for (DeviceEvent event : events) { |
... | @@ -318,7 +467,12 @@ public class GossipDeviceStoreTest { | ... | @@ -318,7 +467,12 @@ public class GossipDeviceStoreTest { |
318 | new DefaultPortDescription(P3, true) | 467 | new DefaultPortDescription(P3, true) |
319 | ); | 468 | ); |
320 | 469 | ||
470 | + resetCommunicatorExpectingSingleBroadcast(bcast); | ||
321 | events = deviceStore.updatePorts(PID, DID1, pds2); | 471 | events = deviceStore.updatePorts(PID, DID1, pds2); |
472 | + verify(clusterCommunicator); | ||
473 | + // TODO: verify broadcast message | ||
474 | + assertTrue(bcast.hasCaptured()); | ||
475 | + | ||
322 | assertFalse("event should be triggered", events.isEmpty()); | 476 | assertFalse("event should be triggered", events.isEmpty()); |
323 | for (DeviceEvent event : events) { | 477 | for (DeviceEvent event : events) { |
324 | PortNumber num = event.port().number(); | 478 | PortNumber num = event.port().number(); |
... | @@ -341,7 +495,12 @@ public class GossipDeviceStoreTest { | ... | @@ -341,7 +495,12 @@ public class GossipDeviceStoreTest { |
341 | new DefaultPortDescription(P1, false), | 495 | new DefaultPortDescription(P1, false), |
342 | new DefaultPortDescription(P2, true) | 496 | new DefaultPortDescription(P2, true) |
343 | ); | 497 | ); |
498 | + resetCommunicatorExpectingSingleBroadcast(bcast); | ||
344 | events = deviceStore.updatePorts(PID, DID1, pds3); | 499 | events = deviceStore.updatePorts(PID, DID1, pds3); |
500 | + verify(clusterCommunicator); | ||
501 | + // TODO: verify broadcast message | ||
502 | + assertTrue(bcast.hasCaptured()); | ||
503 | + | ||
345 | assertFalse("event should be triggered", events.isEmpty()); | 504 | assertFalse("event should be triggered", events.isEmpty()); |
346 | for (DeviceEvent event : events) { | 505 | for (DeviceEvent event : events) { |
347 | PortNumber num = event.port().number(); | 506 | PortNumber num = event.port().number(); |
... | @@ -357,7 +516,6 @@ public class GossipDeviceStoreTest { | ... | @@ -357,7 +516,6 @@ public class GossipDeviceStoreTest { |
357 | fail("Unknown port number encountered: " + num); | 516 | fail("Unknown port number encountered: " + num); |
358 | } | 517 | } |
359 | } | 518 | } |
360 | - | ||
361 | } | 519 | } |
362 | 520 | ||
363 | @Test | 521 | @Test |
... | @@ -368,16 +526,22 @@ public class GossipDeviceStoreTest { | ... | @@ -368,16 +526,22 @@ public class GossipDeviceStoreTest { |
368 | ); | 526 | ); |
369 | deviceStore.updatePorts(PID, DID1, pds); | 527 | deviceStore.updatePorts(PID, DID1, pds); |
370 | 528 | ||
371 | - DeviceEvent event = deviceStore.updatePortStatus(PID, DID1, | 529 | + Capture<ClusterMessage> bcast = new Capture<>(); |
372 | - new DefaultPortDescription(P1, false)); | 530 | + |
531 | + resetCommunicatorExpectingSingleBroadcast(bcast); | ||
532 | + final DefaultPortDescription desc = new DefaultPortDescription(P1, false); | ||
533 | + DeviceEvent event = deviceStore.updatePortStatus(PID, DID1, desc); | ||
373 | assertEquals(PORT_UPDATED, event.type()); | 534 | assertEquals(PORT_UPDATED, event.type()); |
374 | assertDevice(DID1, SW1, event.subject()); | 535 | assertDevice(DID1, SW1, event.subject()); |
375 | assertEquals(P1, event.port().number()); | 536 | assertEquals(P1, event.port().number()); |
376 | assertFalse("Port is disabled", event.port().isEnabled()); | 537 | assertFalse("Port is disabled", event.port().isEnabled()); |
377 | - | 538 | + verify(clusterCommunicator); |
539 | + assertInternalPortStatusEvent(NID1, DID1, PID, desc, NO_ANNOTATION, bcast); | ||
540 | + assertTrue(bcast.hasCaptured()); | ||
378 | } | 541 | } |
542 | + | ||
379 | @Test | 543 | @Test |
380 | - public final void testUpdatePortStatusAncillary() { | 544 | + public final void testUpdatePortStatusAncillary() throws IOException { |
381 | putDeviceAncillary(DID1, SW1); | 545 | putDeviceAncillary(DID1, SW1); |
382 | putDevice(DID1, SW1); | 546 | putDevice(DID1, SW1); |
383 | List<PortDescription> pds = Arrays.<PortDescription>asList( | 547 | List<PortDescription> pds = Arrays.<PortDescription>asList( |
... | @@ -385,36 +549,106 @@ public class GossipDeviceStoreTest { | ... | @@ -385,36 +549,106 @@ public class GossipDeviceStoreTest { |
385 | ); | 549 | ); |
386 | deviceStore.updatePorts(PID, DID1, pds); | 550 | deviceStore.updatePorts(PID, DID1, pds); |
387 | 551 | ||
388 | - DeviceEvent event = deviceStore.updatePortStatus(PID, DID1, | 552 | + Capture<ClusterMessage> bcast = new Capture<>(); |
389 | - new DefaultPortDescription(P1, false, A1_2)); | 553 | + |
554 | + | ||
555 | + // update port from primary | ||
556 | + resetCommunicatorExpectingSingleBroadcast(bcast); | ||
557 | + final DefaultPortDescription desc1 = new DefaultPortDescription(P1, false, A1_2); | ||
558 | + DeviceEvent event = deviceStore.updatePortStatus(PID, DID1, desc1); | ||
390 | assertEquals(PORT_UPDATED, event.type()); | 559 | assertEquals(PORT_UPDATED, event.type()); |
391 | assertDevice(DID1, SW1, event.subject()); | 560 | assertDevice(DID1, SW1, event.subject()); |
392 | assertEquals(P1, event.port().number()); | 561 | assertEquals(P1, event.port().number()); |
393 | assertAnnotationsEquals(event.port().annotations(), A1, A1_2); | 562 | assertAnnotationsEquals(event.port().annotations(), A1, A1_2); |
394 | assertFalse("Port is disabled", event.port().isEnabled()); | 563 | assertFalse("Port is disabled", event.port().isEnabled()); |
395 | - | 564 | + verify(clusterCommunicator); |
396 | - DeviceEvent event2 = deviceStore.updatePortStatus(PIDA, DID1, | 565 | + assertInternalPortStatusEvent(NID1, DID1, PID, desc1, asList(A1, A1_2), bcast); |
397 | - new DefaultPortDescription(P1, true)); | 566 | + assertTrue(bcast.hasCaptured()); |
567 | + | ||
568 | + // update port from ancillary with no attributes | ||
569 | + resetCommunicatorExpectingNoBroadcast(bcast); | ||
570 | + final DefaultPortDescription desc2 = new DefaultPortDescription(P1, true); | ||
571 | + DeviceEvent event2 = deviceStore.updatePortStatus(PIDA, DID1, desc2); | ||
398 | assertNull("Ancillary is ignored if primary exists", event2); | 572 | assertNull("Ancillary is ignored if primary exists", event2); |
573 | + verify(clusterCommunicator); | ||
574 | + assertFalse(bcast.hasCaptured()); | ||
399 | 575 | ||
400 | // but, Ancillary annotation update will be notified | 576 | // but, Ancillary annotation update will be notified |
401 | - DeviceEvent event3 = deviceStore.updatePortStatus(PIDA, DID1, | 577 | + resetCommunicatorExpectingSingleBroadcast(bcast); |
402 | - new DefaultPortDescription(P1, true, A2)); | 578 | + final DefaultPortDescription desc3 = new DefaultPortDescription(P1, true, A2); |
579 | + DeviceEvent event3 = deviceStore.updatePortStatus(PIDA, DID1, desc3); | ||
403 | assertEquals(PORT_UPDATED, event3.type()); | 580 | assertEquals(PORT_UPDATED, event3.type()); |
404 | assertDevice(DID1, SW1, event3.subject()); | 581 | assertDevice(DID1, SW1, event3.subject()); |
405 | assertEquals(P1, event3.port().number()); | 582 | assertEquals(P1, event3.port().number()); |
406 | assertAnnotationsEquals(event3.port().annotations(), A1, A1_2, A2); | 583 | assertAnnotationsEquals(event3.port().annotations(), A1, A1_2, A2); |
407 | assertFalse("Port is disabled", event3.port().isEnabled()); | 584 | assertFalse("Port is disabled", event3.port().isEnabled()); |
585 | + verify(clusterCommunicator); | ||
586 | + assertInternalPortStatusEvent(NID1, DID1, PIDA, desc3, asList(A2), bcast); | ||
587 | + assertTrue(bcast.hasCaptured()); | ||
408 | 588 | ||
409 | // port only reported from Ancillary will be notified as down | 589 | // port only reported from Ancillary will be notified as down |
410 | - DeviceEvent event4 = deviceStore.updatePortStatus(PIDA, DID1, | 590 | + resetCommunicatorExpectingSingleBroadcast(bcast); |
411 | - new DefaultPortDescription(P2, true)); | 591 | + final DefaultPortDescription desc4 = new DefaultPortDescription(P2, true); |
592 | + DeviceEvent event4 = deviceStore.updatePortStatus(PIDA, DID1, desc4); | ||
412 | assertEquals(PORT_ADDED, event4.type()); | 593 | assertEquals(PORT_ADDED, event4.type()); |
413 | assertDevice(DID1, SW1, event4.subject()); | 594 | assertDevice(DID1, SW1, event4.subject()); |
414 | assertEquals(P2, event4.port().number()); | 595 | assertEquals(P2, event4.port().number()); |
415 | assertAnnotationsEquals(event4.port().annotations()); | 596 | assertAnnotationsEquals(event4.port().annotations()); |
416 | assertFalse("Port is disabled if not given from primary provider", | 597 | assertFalse("Port is disabled if not given from primary provider", |
417 | event4.port().isEnabled()); | 598 | event4.port().isEnabled()); |
599 | + verify(clusterCommunicator); | ||
600 | + // TODO: verify broadcast message content | ||
601 | + assertInternalPortStatusEvent(NID1, DID1, PIDA, desc4, NO_ANNOTATION, bcast); | ||
602 | + assertTrue(bcast.hasCaptured()); | ||
603 | + } | ||
604 | + | ||
605 | + private void assertInternalPortStatusEvent(NodeId sender, DeviceId did, | ||
606 | + ProviderId pid, DefaultPortDescription expectedDesc, | ||
607 | + List<SparseAnnotations> expectedAnnotations, Capture<ClusterMessage> actualMsg) { | ||
608 | + | ||
609 | + assertTrue(actualMsg.hasCaptured()); | ||
610 | + assertEquals(sender, actualMsg.getValue().sender()); | ||
611 | + assertEquals(GossipDeviceStoreMessageSubjects.PORT_STATUS_UPDATE, | ||
612 | + actualMsg.getValue().subject()); | ||
613 | + InternalPortStatusEvent addEvent | ||
614 | + = testGossipDeviceStore.deserialize(actualMsg.getValue().payload()); | ||
615 | + assertEquals(did, addEvent.deviceId()); | ||
616 | + assertEquals(pid, addEvent.providerId()); | ||
617 | + assertPortDescriptionEquals(expectedDesc, expectedAnnotations, | ||
618 | + addEvent.portDescription().value()); | ||
619 | + | ||
620 | + } | ||
621 | + | ||
622 | + private void assertPortDescriptionEquals( | ||
623 | + PortDescription expectedDesc, | ||
624 | + List<SparseAnnotations> expectedAnnotations, | ||
625 | + PortDescription actual) { | ||
626 | + | ||
627 | + assertEquals(expectedDesc.portNumber(), actual.portNumber()); | ||
628 | + assertEquals(expectedDesc.isEnabled(), actual.isEnabled()); | ||
629 | + | ||
630 | + assertAnnotationsEquals(actual.annotations(), | ||
631 | + expectedAnnotations.toArray(new SparseAnnotations[0])); | ||
632 | + } | ||
633 | + | ||
634 | + private void resetCommunicatorExpectingNoBroadcast( | ||
635 | + Capture<ClusterMessage> bcast) { | ||
636 | + bcast.reset(); | ||
637 | + reset(clusterCommunicator); | ||
638 | + replay(clusterCommunicator); | ||
639 | + } | ||
640 | + | ||
641 | + private void resetCommunicatorExpectingSingleBroadcast( | ||
642 | + Capture<ClusterMessage> bcast) { | ||
643 | + | ||
644 | + bcast.reset(); | ||
645 | + reset(clusterCommunicator); | ||
646 | + try { | ||
647 | + expect(clusterCommunicator.broadcast(capture(bcast))).andReturn(true).once(); | ||
648 | + } catch (IOException e) { | ||
649 | + fail("Should never reach here"); | ||
650 | + } | ||
651 | + replay(clusterCommunicator); | ||
418 | } | 652 | } |
419 | 653 | ||
420 | @Test | 654 | @Test |
... | @@ -476,12 +710,19 @@ public class GossipDeviceStoreTest { | ... | @@ -476,12 +710,19 @@ public class GossipDeviceStoreTest { |
476 | assertAnnotationsEquals(deviceStore.getDevice(DID1).annotations(), A1); | 710 | assertAnnotationsEquals(deviceStore.getDevice(DID1).annotations(), A1); |
477 | assertAnnotationsEquals(deviceStore.getPort(DID1, P1).annotations(), A2); | 711 | assertAnnotationsEquals(deviceStore.getPort(DID1, P1).annotations(), A2); |
478 | 712 | ||
713 | + Capture<ClusterMessage> bcast = new Capture<>(); | ||
714 | + | ||
715 | + resetCommunicatorExpectingSingleBroadcast(bcast); | ||
716 | + | ||
479 | DeviceEvent event = deviceStore.removeDevice(DID1); | 717 | DeviceEvent event = deviceStore.removeDevice(DID1); |
480 | assertEquals(DEVICE_REMOVED, event.type()); | 718 | assertEquals(DEVICE_REMOVED, event.type()); |
481 | assertDevice(DID1, SW1, event.subject()); | 719 | assertDevice(DID1, SW1, event.subject()); |
482 | 720 | ||
483 | assertEquals(1, deviceStore.getDeviceCount()); | 721 | assertEquals(1, deviceStore.getDeviceCount()); |
484 | assertEquals(0, deviceStore.getPorts(DID1).size()); | 722 | assertEquals(0, deviceStore.getPorts(DID1).size()); |
723 | + verify(clusterCommunicator); | ||
724 | + // TODO: verify broadcast message | ||
725 | + assertTrue(bcast.hasCaptured()); | ||
485 | 726 | ||
486 | // putBack Device, Port w/o annotation | 727 | // putBack Device, Port w/o annotation |
487 | putDevice(DID1, SW1); | 728 | putDevice(DID1, SW1); |
... | @@ -563,34 +804,28 @@ public class GossipDeviceStoreTest { | ... | @@ -563,34 +804,28 @@ public class GossipDeviceStoreTest { |
563 | this.clusterService = clusterService; | 804 | this.clusterService = clusterService; |
564 | this.clusterCommunicator = clusterCommunicator; | 805 | this.clusterCommunicator = clusterCommunicator; |
565 | } | 806 | } |
566 | - } | ||
567 | 807 | ||
568 | - private static final class TestClusterCommunicationService implements ClusterCommunicationService { | 808 | + public <T> T deserialize(byte[] bytes) { |
569 | - @Override | 809 | + return SERIALIZER.decode(bytes); |
570 | - public boolean broadcast(ClusterMessage message) throws IOException { return true; } | 810 | + } |
571 | - @Override | ||
572 | - public boolean unicast(ClusterMessage message, NodeId nodeId) throws IOException { return true; } | ||
573 | - @Override | ||
574 | - public boolean multicast(ClusterMessage message, Set<NodeId> nodeIds) throws IOException { return true; } | ||
575 | - @Override | ||
576 | - public void addSubscriber(MessageSubject subject, ClusterMessageHandler subscriber) {} | ||
577 | } | 811 | } |
578 | 812 | ||
579 | private static final class TestClusterService implements ClusterService { | 813 | private static final class TestClusterService implements ClusterService { |
580 | 814 | ||
581 | - private static final ControllerNode ONOS1 = | ||
582 | - new DefaultControllerNode(new NodeId("N1"), IpPrefix.valueOf("127.0.0.1")); | ||
583 | private final Map<NodeId, ControllerNode> nodes = new HashMap<>(); | 815 | private final Map<NodeId, ControllerNode> nodes = new HashMap<>(); |
584 | private final Map<NodeId, ControllerNode.State> nodeStates = new HashMap<>(); | 816 | private final Map<NodeId, ControllerNode.State> nodeStates = new HashMap<>(); |
585 | 817 | ||
586 | public TestClusterService() { | 818 | public TestClusterService() { |
587 | - nodes.put(new NodeId("N1"), ONOS1); | 819 | + nodes.put(NID1, ONOS1); |
588 | - nodeStates.put(new NodeId("N1"), ControllerNode.State.ACTIVE); | 820 | + nodeStates.put(NID1, ACTIVE); |
821 | + | ||
822 | + nodes.put(NID2, ONOS2); | ||
823 | + nodeStates.put(NID2, ACTIVE); | ||
589 | } | 824 | } |
590 | 825 | ||
591 | @Override | 826 | @Override |
592 | public ControllerNode getLocalNode() { | 827 | public ControllerNode getLocalNode() { |
593 | - return ONOS1; | 828 | + return GossipDeviceStoreTest.ONOS1; |
594 | } | 829 | } |
595 | 830 | ||
596 | @Override | 831 | @Override | ... | ... |
core/store/serializers/src/main/java/org/onlab/onos/store/serializers/ImmutableListSerializer.java
0 → 100644
1 | +package org.onlab.onos.store.serializers; | ||
2 | + | ||
3 | +import org.onlab.util.KryoPool.FamilySerializer; | ||
4 | + | ||
5 | +import com.esotericsoftware.kryo.Kryo; | ||
6 | +import com.esotericsoftware.kryo.io.Input; | ||
7 | +import com.esotericsoftware.kryo.io.Output; | ||
8 | +import com.google.common.collect.ImmutableList; | ||
9 | +import com.google.common.collect.ImmutableList.Builder; | ||
10 | + | ||
11 | +/** | ||
12 | + * Creates {@link ImmutableList} serializer instance. | ||
13 | + */ | ||
14 | +public class ImmutableListSerializer extends FamilySerializer<ImmutableList<?>> { | ||
15 | + | ||
16 | + /** | ||
17 | + * Creates {@link ImmutableList} serializer instance. | ||
18 | + */ | ||
19 | + public ImmutableListSerializer() { | ||
20 | + // non-null, immutable | ||
21 | + super(false, true); | ||
22 | + } | ||
23 | + @Override | ||
24 | + public void write(Kryo kryo, Output output, ImmutableList<?> object) { | ||
25 | + output.writeInt(object.size()); | ||
26 | + for (Object e : object) { | ||
27 | + kryo.writeClassAndObject(output, e); | ||
28 | + } | ||
29 | + } | ||
30 | + | ||
31 | + @Override | ||
32 | + public ImmutableList<?> read(Kryo kryo, Input input, | ||
33 | + Class<ImmutableList<?>> type) { | ||
34 | + final int size = input.readInt(); | ||
35 | + Builder<Object> builder = ImmutableList.builder(); | ||
36 | + for (int i = 0; i < size; ++i) { | ||
37 | + builder.add(kryo.readClassAndObject(input)); | ||
38 | + } | ||
39 | + return builder.build(); | ||
40 | + } | ||
41 | + | ||
42 | + @Override | ||
43 | + public void registerFamilies(Kryo kryo) { | ||
44 | + kryo.register(ImmutableList.of(1).getClass(), this); | ||
45 | + kryo.register(ImmutableList.of(1, 2).getClass(), this); | ||
46 | + // TODO register required ImmutableList variants | ||
47 | + } | ||
48 | + | ||
49 | +} |
... | @@ -31,6 +31,9 @@ import org.onlab.packet.IpAddress; | ... | @@ -31,6 +31,9 @@ import org.onlab.packet.IpAddress; |
31 | import org.onlab.packet.IpPrefix; | 31 | import org.onlab.packet.IpPrefix; |
32 | import org.onlab.util.KryoPool; | 32 | import org.onlab.util.KryoPool; |
33 | 33 | ||
34 | +import com.google.common.collect.ImmutableList; | ||
35 | +import com.google.common.collect.ImmutableMap; | ||
36 | + | ||
34 | public final class KryoPoolUtil { | 37 | public final class KryoPoolUtil { |
35 | 38 | ||
36 | /** | 39 | /** |
... | @@ -47,12 +50,15 @@ public final class KryoPoolUtil { | ... | @@ -47,12 +50,15 @@ public final class KryoPoolUtil { |
47 | */ | 50 | */ |
48 | public static final KryoPool API = KryoPool.newBuilder() | 51 | public static final KryoPool API = KryoPool.newBuilder() |
49 | .register(MISC) | 52 | .register(MISC) |
53 | + .register(ImmutableMap.class, new ImmutableMapSerializer()) | ||
54 | + .register(ImmutableList.class, new ImmutableListSerializer()) | ||
50 | .register( | 55 | .register( |
51 | // | 56 | // |
52 | ArrayList.class, | 57 | ArrayList.class, |
53 | Arrays.asList().getClass(), | 58 | Arrays.asList().getClass(), |
54 | HashMap.class, | 59 | HashMap.class, |
55 | // | 60 | // |
61 | + // | ||
56 | ControllerNode.State.class, | 62 | ControllerNode.State.class, |
57 | Device.Type.class, | 63 | Device.Type.class, |
58 | DefaultAnnotations.class, | 64 | DefaultAnnotations.class, | ... | ... |
-
Please register or login to post a comment