Yuta HIGUCHI

Adding some tests for GossipDeviceStore + bugfix

Change-Id: Ic0d55fa499b1d66131f059b4a47cd105c55a6e63
...@@ -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
......
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,
......