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