blob: 3c83169737bc2c86d2ad09465ed1fab35b678f90 [file] [log] [blame]
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -07001package org.onlab.onos.store.device.impl;
2
Yuta HIGUCHI47c40882014-10-10 18:44:37 -07003import static org.easymock.EasyMock.*;
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -07004import static org.junit.Assert.*;
5import static org.onlab.onos.net.Device.Type.SWITCH;
6import static org.onlab.onos.net.DeviceId.deviceId;
7import static org.onlab.onos.net.device.DeviceEvent.Type.*;
Yuta HIGUCHI47c40882014-10-10 18:44:37 -07008import static org.onlab.onos.cluster.ControllerNode.State.*;
9import static org.onlab.onos.net.DefaultAnnotations.union;
10import static java.util.Arrays.asList;
Madan Jampani47c93732014-10-06 20:46:08 -070011import java.io.IOException;
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -070012import java.util.Arrays;
Yuta HIGUCHI47c40882014-10-10 18:44:37 -070013import java.util.Collections;
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -070014import java.util.HashMap;
15import java.util.List;
16import java.util.Map;
17import java.util.Set;
18import java.util.concurrent.CountDownLatch;
19import java.util.concurrent.TimeUnit;
20
Yuta HIGUCHI47c40882014-10-10 18:44:37 -070021import org.easymock.Capture;
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -070022import org.junit.After;
23import org.junit.AfterClass;
24import org.junit.Before;
25import org.junit.BeforeClass;
26import org.junit.Ignore;
27import org.junit.Test;
Madan Jampani53e44e62014-10-07 12:39:51 -070028import org.onlab.onos.cluster.ClusterEventListener;
29import org.onlab.onos.cluster.ClusterService;
30import org.onlab.onos.cluster.ControllerNode;
31import org.onlab.onos.cluster.ControllerNode.State;
32import org.onlab.onos.cluster.DefaultControllerNode;
Yuta HIGUCHIfa891c92014-10-09 15:21:40 -070033import org.onlab.onos.cluster.MastershipTerm;
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -070034import org.onlab.onos.cluster.NodeId;
35import org.onlab.onos.net.Annotations;
36import org.onlab.onos.net.DefaultAnnotations;
37import org.onlab.onos.net.Device;
38import org.onlab.onos.net.DeviceId;
39import org.onlab.onos.net.Port;
40import org.onlab.onos.net.PortNumber;
41import org.onlab.onos.net.SparseAnnotations;
42import org.onlab.onos.net.device.DefaultDeviceDescription;
43import org.onlab.onos.net.device.DefaultPortDescription;
44import org.onlab.onos.net.device.DeviceDescription;
45import org.onlab.onos.net.device.DeviceEvent;
46import org.onlab.onos.net.device.DeviceStore;
47import org.onlab.onos.net.device.DeviceStoreDelegate;
48import org.onlab.onos.net.device.PortDescription;
49import org.onlab.onos.net.provider.ProviderId;
Yuta HIGUCHId40483d2014-10-09 15:20:30 -070050import org.onlab.onos.store.ClockService;
Madan Jampani47c93732014-10-06 20:46:08 -070051import org.onlab.onos.store.cluster.messaging.ClusterCommunicationService;
52import org.onlab.onos.store.cluster.messaging.ClusterMessage;
53import org.onlab.onos.store.cluster.messaging.ClusterMessageHandler;
54import org.onlab.onos.store.cluster.messaging.MessageSubject;
Madan Jampani53e44e62014-10-07 12:39:51 -070055import org.onlab.packet.IpPrefix;
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -070056
57import com.google.common.collect.Iterables;
58import com.google.common.collect.Sets;
59
60
61// TODO add tests for remote replication
62/**
63 * Test of the gossip based distributed DeviceStore implementation.
64 */
65public class GossipDeviceStoreTest {
66
67 private static final ProviderId PID = new ProviderId("of", "foo");
68 private static final ProviderId PIDA = new ProviderId("of", "bar", true);
69 private static final DeviceId DID1 = deviceId("of:foo");
70 private static final DeviceId DID2 = deviceId("of:bar");
71 private static final String MFR = "whitebox";
72 private static final String HW = "1.1.x";
73 private static final String SW1 = "3.8.1";
74 private static final String SW2 = "3.9.5";
75 private static final String SN = "43311-12345";
76
77 private static final PortNumber P1 = PortNumber.portNumber(1);
78 private static final PortNumber P2 = PortNumber.portNumber(2);
79 private static final PortNumber P3 = PortNumber.portNumber(3);
80
81 private static final SparseAnnotations A1 = DefaultAnnotations.builder()
82 .set("A1", "a1")
83 .set("B1", "b1")
84 .build();
85 private static final SparseAnnotations A1_2 = DefaultAnnotations.builder()
86 .remove("A1")
87 .set("B3", "b3")
88 .build();
89 private static final SparseAnnotations A2 = DefaultAnnotations.builder()
90 .set("A2", "a2")
91 .set("B2", "b2")
92 .build();
93 private static final SparseAnnotations A2_2 = DefaultAnnotations.builder()
94 .remove("A2")
95 .set("B4", "b4")
96 .build();
97
Yuta HIGUCHI47c40882014-10-10 18:44:37 -070098 // 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"));
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700102
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700103 // 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();
108
109
110 private TestGossipDeviceStore testGossipDeviceStore;
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700111 private GossipDeviceStore gossipDeviceStore;
112 private DeviceStore deviceStore;
113
114 private DeviceClockManager deviceClockManager;
Yuta HIGUCHId40483d2014-10-09 15:20:30 -0700115 private ClockService clockService;
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700116 private ClusterCommunicationService clusterCommunicator;
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700117 @BeforeClass
118 public static void setUpBeforeClass() throws Exception {
119 }
120
121 @AfterClass
122 public static void tearDownAfterClass() throws Exception {
123 }
124
125
126 @Before
127 public void setUp() throws Exception {
128 deviceClockManager = new DeviceClockManager();
129 deviceClockManager.activate();
130 clockService = deviceClockManager;
131
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700132 deviceClockManager.setMastershipTerm(DID1, MastershipTerm.of(NID1, 1));
133 deviceClockManager.setMastershipTerm(DID2, MastershipTerm.of(NID1, 2));
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700134
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700135 clusterCommunicator = createNiceMock(ClusterCommunicationService.class);
136 clusterCommunicator.addSubscriber(anyObject(MessageSubject.class),
137 anyObject(ClusterMessageHandler.class));
138 expectLastCall().anyTimes();
139 replay(clusterCommunicator);
Madan Jampani53e44e62014-10-07 12:39:51 -0700140 ClusterService clusterService = new TestClusterService();
Madan Jampani47c93732014-10-06 20:46:08 -0700141
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700142 testGossipDeviceStore = new TestGossipDeviceStore(clockService, clusterService, clusterCommunicator);
143 gossipDeviceStore = testGossipDeviceStore;
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700144 gossipDeviceStore.activate();
145 deviceStore = gossipDeviceStore;
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700146 verify(clusterCommunicator);
147 reset(clusterCommunicator);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700148 }
149
150 @After
151 public void tearDown() throws Exception {
152 gossipDeviceStore.deactivate();
153 deviceClockManager.deactivate();
154 }
155
Yuta HIGUCHI0d6a5e62014-10-03 15:54:09 -0700156 private void putDevice(DeviceId deviceId, String swVersion,
157 SparseAnnotations... annotations) {
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700158 DeviceDescription description =
159 new DefaultDeviceDescription(deviceId.uri(), SWITCH, MFR,
Yuta HIGUCHI0d6a5e62014-10-03 15:54:09 -0700160 HW, swVersion, SN, annotations);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700161 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);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700169 deviceStore.createOrUpdateDevice(PID, deviceId, description);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700170 verify(clusterCommunicator);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700171 }
172
Yuta HIGUCHI0d6a5e62014-10-03 15:54:09 -0700173 private void putDeviceAncillary(DeviceId deviceId, String swVersion,
174 SparseAnnotations... annotations) {
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700175 DeviceDescription description =
176 new DefaultDeviceDescription(deviceId.uri(), SWITCH, MFR,
Yuta HIGUCHI0d6a5e62014-10-03 15:54:09 -0700177 HW, swVersion, SN, annotations);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700178 deviceStore.createOrUpdateDevice(PIDA, deviceId, description);
179 }
180
181 private static void assertDevice(DeviceId id, String swVersion, Device device) {
182 assertNotNull(device);
183 assertEquals(id, device.id());
184 assertEquals(MFR, device.manufacturer());
185 assertEquals(HW, device.hwVersion());
186 assertEquals(swVersion, device.swVersion());
187 assertEquals(SN, device.serialNumber());
188 }
189
190 /**
191 * Verifies that Annotations created by merging {@code annotations} is
192 * equal to actual Annotations.
193 *
194 * @param actual Annotations to check
195 * @param annotations
196 */
197 private static void assertAnnotationsEquals(Annotations actual, SparseAnnotations... annotations) {
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700198 SparseAnnotations expected = DefaultAnnotations.builder().build();
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700199 for (SparseAnnotations a : annotations) {
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700200 expected = DefaultAnnotations.union(expected, a);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700201 }
202 assertEquals(expected.keys(), actual.keys());
203 for (String key : expected.keys()) {
204 assertEquals(expected.value(key), actual.value(key));
205 }
206 }
207
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700208 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
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700238 @Test
239 public final void testGetDeviceCount() {
240 assertEquals("initialy empty", 0, deviceStore.getDeviceCount());
241
242 putDevice(DID1, SW1);
243 putDevice(DID2, SW2);
244 putDevice(DID1, SW1);
245
246 assertEquals("expect 2 uniq devices", 2, deviceStore.getDeviceCount());
247 }
248
249 @Test
250 public final void testGetDevices() {
251 assertEquals("initialy empty", 0, Iterables.size(deviceStore.getDevices()));
252
253 putDevice(DID1, SW1);
254 putDevice(DID2, SW2);
255 putDevice(DID1, SW1);
256
257 assertEquals("expect 2 uniq devices",
258 2, Iterables.size(deviceStore.getDevices()));
259
260 Map<DeviceId, Device> devices = new HashMap<>();
261 for (Device device : deviceStore.getDevices()) {
262 devices.put(device.id(), device);
263 }
264
265 assertDevice(DID1, SW1, devices.get(DID1));
266 assertDevice(DID2, SW2, devices.get(DID2));
267
268 // add case for new node?
269 }
270
271 @Test
272 public final void testGetDevice() {
273
274 putDevice(DID1, SW1);
275
276 assertDevice(DID1, SW1, deviceStore.getDevice(DID1));
277 assertNull("DID2 shouldn't be there", deviceStore.getDevice(DID2));
278 }
279
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700280 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
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700313 @Test
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700314 public final void testCreateOrUpdateDevice() throws IOException {
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700315 DeviceDescription description =
316 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
317 HW, SW1, SN);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700318 Capture<ClusterMessage> bcast = new Capture<>();
319
320 resetCommunicatorExpectingSingleBroadcast(bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700321 DeviceEvent event = deviceStore.createOrUpdateDevice(PID, DID1, description);
322 assertEquals(DEVICE_ADDED, event.type());
323 assertDevice(DID1, SW1, event.subject());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700324 verify(clusterCommunicator);
325 assertInternalDeviceEvent(NID1, DID1, PID, description, bcast);
326
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700327
328 DeviceDescription description2 =
329 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
330 HW, SW2, SN);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700331 resetCommunicatorExpectingSingleBroadcast(bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700332 DeviceEvent event2 = deviceStore.createOrUpdateDevice(PID, DID1, description2);
333 assertEquals(DEVICE_UPDATED, event2.type());
334 assertDevice(DID1, SW2, event2.subject());
335
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700336 verify(clusterCommunicator);
337 assertInternalDeviceEvent(NID1, DID1, PID, description2, bcast);
338 reset(clusterCommunicator);
339
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700340 assertNull("No change expected", deviceStore.createOrUpdateDevice(PID, DID1, description2));
341 }
342
343 @Test
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700344 public final void testCreateOrUpdateDeviceAncillary() throws IOException {
345 // add
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700346 DeviceDescription description =
347 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
348 HW, SW1, SN, A2);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700349 Capture<ClusterMessage> bcast = new Capture<>();
350
351 resetCommunicatorExpectingSingleBroadcast(bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700352 DeviceEvent event = deviceStore.createOrUpdateDevice(PIDA, DID1, description);
353 assertEquals(DEVICE_ADDED, event.type());
354 assertDevice(DID1, SW1, event.subject());
355 assertEquals(PIDA, event.subject().providerId());
356 assertAnnotationsEquals(event.subject().annotations(), A2);
357 assertFalse("Ancillary will not bring device up", deviceStore.isAvailable(DID1));
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700358 verify(clusterCommunicator);
359 assertInternalDeviceEvent(NID1, DID1, PIDA, description, bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700360
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700361 // update from primary
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700362 DeviceDescription description2 =
363 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
364 HW, SW2, SN, A1);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700365 resetCommunicatorExpectingSingleBroadcast(bcast);
366
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700367 DeviceEvent event2 = deviceStore.createOrUpdateDevice(PID, DID1, description2);
368 assertEquals(DEVICE_UPDATED, event2.type());
369 assertDevice(DID1, SW2, event2.subject());
370 assertEquals(PID, event2.subject().providerId());
371 assertAnnotationsEquals(event2.subject().annotations(), A1, A2);
372 assertTrue(deviceStore.isAvailable(DID1));
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700373 verify(clusterCommunicator);
374 assertInternalDeviceEvent(NID1, DID1, PID, description2, bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700375
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700376 // no-op update from primary
377 resetCommunicatorExpectingNoBroadcast(bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700378 assertNull("No change expected", deviceStore.createOrUpdateDevice(PID, DID1, description2));
379
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700380 verify(clusterCommunicator);
381 assertFalse("no broadcast expected", bcast.hasCaptured());
382
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700383 // For now, Ancillary is ignored once primary appears
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700384 resetCommunicatorExpectingNoBroadcast(bcast);
385
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700386 assertNull("No change expected", deviceStore.createOrUpdateDevice(PIDA, DID1, description));
387
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700388 verify(clusterCommunicator);
389 assertFalse("no broadcast expected", bcast.hasCaptured());
390
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700391 // But, Ancillary annotations will be in effect
392 DeviceDescription description3 =
393 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
394 HW, SW1, SN, A2_2);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700395 resetCommunicatorExpectingSingleBroadcast(bcast);
396
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700397 DeviceEvent event3 = deviceStore.createOrUpdateDevice(PIDA, DID1, description3);
398 assertEquals(DEVICE_UPDATED, event3.type());
399 // basic information will be the one from Primary
400 assertDevice(DID1, SW2, event3.subject());
401 assertEquals(PID, event3.subject().providerId());
402 // but annotation from Ancillary will be merged
403 assertAnnotationsEquals(event3.subject().annotations(), A1, A2, A2_2);
404 assertTrue(deviceStore.isAvailable(DID1));
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700405 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
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700410 }
411
412
413 @Test
414 public final void testMarkOffline() {
415
416 putDevice(DID1, SW1);
417 assertTrue(deviceStore.isAvailable(DID1));
418
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700419 Capture<ClusterMessage> bcast = new Capture<>();
420
421 resetCommunicatorExpectingSingleBroadcast(bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700422 DeviceEvent event = deviceStore.markOffline(DID1);
423 assertEquals(DEVICE_AVAILABILITY_CHANGED, event.type());
424 assertDevice(DID1, SW1, event.subject());
425 assertFalse(deviceStore.isAvailable(DID1));
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700426 verify(clusterCommunicator);
427 // TODO: verify broadcast message
428 assertTrue(bcast.hasCaptured());
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700429
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700430
431 resetCommunicatorExpectingNoBroadcast(bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700432 DeviceEvent event2 = deviceStore.markOffline(DID1);
433 assertNull("No change, no event", event2);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700434 verify(clusterCommunicator);
435 assertFalse(bcast.hasCaptured());
436 }
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700437
438 @Test
439 public final void testUpdatePorts() {
440 putDevice(DID1, SW1);
441 List<PortDescription> pds = Arrays.<PortDescription>asList(
442 new DefaultPortDescription(P1, true),
443 new DefaultPortDescription(P2, true)
444 );
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700445 Capture<ClusterMessage> bcast = new Capture<>();
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700446
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700447 resetCommunicatorExpectingSingleBroadcast(bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700448 List<DeviceEvent> events = deviceStore.updatePorts(PID, DID1, pds);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700449 verify(clusterCommunicator);
450 // TODO: verify broadcast message
451 assertTrue(bcast.hasCaptured());
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700452
453 Set<PortNumber> expectedPorts = Sets.newHashSet(P1, P2);
454 for (DeviceEvent event : events) {
455 assertEquals(PORT_ADDED, event.type());
456 assertDevice(DID1, SW1, event.subject());
457 assertTrue("PortNumber is one of expected",
458 expectedPorts.remove(event.port().number()));
459 assertTrue("Port is enabled", event.port().isEnabled());
460 }
461 assertTrue("Event for all expectedport appeared", expectedPorts.isEmpty());
462
463
464 List<PortDescription> pds2 = Arrays.<PortDescription>asList(
465 new DefaultPortDescription(P1, false),
466 new DefaultPortDescription(P2, true),
467 new DefaultPortDescription(P3, true)
468 );
469
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700470 resetCommunicatorExpectingSingleBroadcast(bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700471 events = deviceStore.updatePorts(PID, DID1, pds2);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700472 verify(clusterCommunicator);
473 // TODO: verify broadcast message
474 assertTrue(bcast.hasCaptured());
475
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700476 assertFalse("event should be triggered", events.isEmpty());
477 for (DeviceEvent event : events) {
478 PortNumber num = event.port().number();
479 if (P1.equals(num)) {
480 assertEquals(PORT_UPDATED, event.type());
481 assertDevice(DID1, SW1, event.subject());
482 assertFalse("Port is disabled", event.port().isEnabled());
483 } else if (P2.equals(num)) {
484 fail("P2 event not expected.");
485 } else if (P3.equals(num)) {
486 assertEquals(PORT_ADDED, event.type());
487 assertDevice(DID1, SW1, event.subject());
488 assertTrue("Port is enabled", event.port().isEnabled());
489 } else {
490 fail("Unknown port number encountered: " + num);
491 }
492 }
493
494 List<PortDescription> pds3 = Arrays.<PortDescription>asList(
495 new DefaultPortDescription(P1, false),
496 new DefaultPortDescription(P2, true)
497 );
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700498 resetCommunicatorExpectingSingleBroadcast(bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700499 events = deviceStore.updatePorts(PID, DID1, pds3);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700500 verify(clusterCommunicator);
501 // TODO: verify broadcast message
502 assertTrue(bcast.hasCaptured());
503
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700504 assertFalse("event should be triggered", events.isEmpty());
505 for (DeviceEvent event : events) {
506 PortNumber num = event.port().number();
507 if (P1.equals(num)) {
508 fail("P1 event not expected.");
509 } else if (P2.equals(num)) {
510 fail("P2 event not expected.");
511 } else if (P3.equals(num)) {
512 assertEquals(PORT_REMOVED, event.type());
513 assertDevice(DID1, SW1, event.subject());
514 assertTrue("Port was enabled", event.port().isEnabled());
515 } else {
516 fail("Unknown port number encountered: " + num);
517 }
518 }
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700519 }
520
521 @Test
522 public final void testUpdatePortStatus() {
523 putDevice(DID1, SW1);
524 List<PortDescription> pds = Arrays.<PortDescription>asList(
525 new DefaultPortDescription(P1, true)
526 );
527 deviceStore.updatePorts(PID, DID1, pds);
528
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700529 Capture<ClusterMessage> bcast = new Capture<>();
530
531 resetCommunicatorExpectingSingleBroadcast(bcast);
532 final DefaultPortDescription desc = new DefaultPortDescription(P1, false);
533 DeviceEvent event = deviceStore.updatePortStatus(PID, DID1, desc);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700534 assertEquals(PORT_UPDATED, event.type());
535 assertDevice(DID1, SW1, event.subject());
536 assertEquals(P1, event.port().number());
537 assertFalse("Port is disabled", event.port().isEnabled());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700538 verify(clusterCommunicator);
539 assertInternalPortStatusEvent(NID1, DID1, PID, desc, NO_ANNOTATION, bcast);
540 assertTrue(bcast.hasCaptured());
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700541 }
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700542
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700543 @Test
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700544 public final void testUpdatePortStatusAncillary() throws IOException {
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700545 putDeviceAncillary(DID1, SW1);
546 putDevice(DID1, SW1);
547 List<PortDescription> pds = Arrays.<PortDescription>asList(
548 new DefaultPortDescription(P1, true, A1)
549 );
550 deviceStore.updatePorts(PID, DID1, pds);
551
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700552 Capture<ClusterMessage> bcast = new Capture<>();
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);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700559 assertEquals(PORT_UPDATED, event.type());
560 assertDevice(DID1, SW1, event.subject());
561 assertEquals(P1, event.port().number());
562 assertAnnotationsEquals(event.port().annotations(), A1, A1_2);
563 assertFalse("Port is disabled", event.port().isEnabled());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700564 verify(clusterCommunicator);
565 assertInternalPortStatusEvent(NID1, DID1, PID, desc1, asList(A1, A1_2), bcast);
566 assertTrue(bcast.hasCaptured());
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700567
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700568 // 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);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700572 assertNull("Ancillary is ignored if primary exists", event2);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700573 verify(clusterCommunicator);
574 assertFalse(bcast.hasCaptured());
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700575
576 // but, Ancillary annotation update will be notified
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700577 resetCommunicatorExpectingSingleBroadcast(bcast);
578 final DefaultPortDescription desc3 = new DefaultPortDescription(P1, true, A2);
579 DeviceEvent event3 = deviceStore.updatePortStatus(PIDA, DID1, desc3);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700580 assertEquals(PORT_UPDATED, event3.type());
581 assertDevice(DID1, SW1, event3.subject());
582 assertEquals(P1, event3.port().number());
583 assertAnnotationsEquals(event3.port().annotations(), A1, A1_2, A2);
584 assertFalse("Port is disabled", event3.port().isEnabled());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700585 verify(clusterCommunicator);
586 assertInternalPortStatusEvent(NID1, DID1, PIDA, desc3, asList(A2), bcast);
587 assertTrue(bcast.hasCaptured());
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700588
589 // port only reported from Ancillary will be notified as down
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700590 resetCommunicatorExpectingSingleBroadcast(bcast);
591 final DefaultPortDescription desc4 = new DefaultPortDescription(P2, true);
592 DeviceEvent event4 = deviceStore.updatePortStatus(PIDA, DID1, desc4);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700593 assertEquals(PORT_ADDED, event4.type());
594 assertDevice(DID1, SW1, event4.subject());
595 assertEquals(P2, event4.port().number());
596 assertAnnotationsEquals(event4.port().annotations());
597 assertFalse("Port is disabled if not given from primary provider",
598 event4.port().isEnabled());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700599 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);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700652 }
653
654 @Test
655 public final void testGetPorts() {
656 putDevice(DID1, SW1);
657 putDevice(DID2, SW1);
658 List<PortDescription> pds = Arrays.<PortDescription>asList(
659 new DefaultPortDescription(P1, true),
660 new DefaultPortDescription(P2, true)
661 );
662 deviceStore.updatePorts(PID, DID1, pds);
663
664 Set<PortNumber> expectedPorts = Sets.newHashSet(P1, P2);
665 List<Port> ports = deviceStore.getPorts(DID1);
666 for (Port port : ports) {
667 assertTrue("Port is enabled", port.isEnabled());
668 assertTrue("PortNumber is one of expected",
669 expectedPorts.remove(port.number()));
670 }
671 assertTrue("Event for all expectedport appeared", expectedPorts.isEmpty());
672
673
674 assertTrue("DID2 has no ports", deviceStore.getPorts(DID2).isEmpty());
675 }
676
677 @Test
678 public final void testGetPort() {
679 putDevice(DID1, SW1);
680 putDevice(DID2, SW1);
681 List<PortDescription> pds = Arrays.<PortDescription>asList(
682 new DefaultPortDescription(P1, true),
683 new DefaultPortDescription(P2, false)
684 );
685 deviceStore.updatePorts(PID, DID1, pds);
686
687 Port port1 = deviceStore.getPort(DID1, P1);
688 assertEquals(P1, port1.number());
689 assertTrue("Port is enabled", port1.isEnabled());
690
691 Port port2 = deviceStore.getPort(DID1, P2);
692 assertEquals(P2, port2.number());
693 assertFalse("Port is disabled", port2.isEnabled());
694
695 Port port3 = deviceStore.getPort(DID1, P3);
696 assertNull("P3 not expected", port3);
697 }
698
699 @Test
700 public final void testRemoveDevice() {
Yuta HIGUCHI0d6a5e62014-10-03 15:54:09 -0700701 putDevice(DID1, SW1, A1);
702 List<PortDescription> pds = Arrays.<PortDescription>asList(
703 new DefaultPortDescription(P1, true, A2)
704 );
705 deviceStore.updatePorts(PID, DID1, pds);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700706 putDevice(DID2, SW1);
707
708 assertEquals(2, deviceStore.getDeviceCount());
Yuta HIGUCHI0d6a5e62014-10-03 15:54:09 -0700709 assertEquals(1, deviceStore.getPorts(DID1).size());
710 assertAnnotationsEquals(deviceStore.getDevice(DID1).annotations(), A1);
711 assertAnnotationsEquals(deviceStore.getPort(DID1, P1).annotations(), A2);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700712
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700713 Capture<ClusterMessage> bcast = new Capture<>();
714
715 resetCommunicatorExpectingSingleBroadcast(bcast);
716
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700717 DeviceEvent event = deviceStore.removeDevice(DID1);
718 assertEquals(DEVICE_REMOVED, event.type());
719 assertDevice(DID1, SW1, event.subject());
720
721 assertEquals(1, deviceStore.getDeviceCount());
Yuta HIGUCHI0d6a5e62014-10-03 15:54:09 -0700722 assertEquals(0, deviceStore.getPorts(DID1).size());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700723 verify(clusterCommunicator);
724 // TODO: verify broadcast message
725 assertTrue(bcast.hasCaptured());
Yuta HIGUCHI0d6a5e62014-10-03 15:54:09 -0700726
727 // putBack Device, Port w/o annotation
728 putDevice(DID1, SW1);
729 List<PortDescription> pds2 = Arrays.<PortDescription>asList(
730 new DefaultPortDescription(P1, true)
731 );
732 deviceStore.updatePorts(PID, DID1, pds2);
733
734 // annotations should not survive
735 assertEquals(2, deviceStore.getDeviceCount());
736 assertEquals(1, deviceStore.getPorts(DID1).size());
737 assertAnnotationsEquals(deviceStore.getDevice(DID1).annotations());
738 assertAnnotationsEquals(deviceStore.getPort(DID1, P1).annotations());
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700739 }
740
741 // If Delegates should be called only on remote events,
742 // then Simple* should never call them, thus not test required.
743 // TODO add test for Port events when we have them
744 @Ignore("Ignore until Delegate spec. is clear.")
745 @Test
746 public final void testEvents() throws InterruptedException {
747 final CountDownLatch addLatch = new CountDownLatch(1);
748 DeviceStoreDelegate checkAdd = new DeviceStoreDelegate() {
749 @Override
750 public void notify(DeviceEvent event) {
751 assertEquals(DEVICE_ADDED, event.type());
752 assertDevice(DID1, SW1, event.subject());
753 addLatch.countDown();
754 }
755 };
756 final CountDownLatch updateLatch = new CountDownLatch(1);
757 DeviceStoreDelegate checkUpdate = new DeviceStoreDelegate() {
758 @Override
759 public void notify(DeviceEvent event) {
760 assertEquals(DEVICE_UPDATED, event.type());
761 assertDevice(DID1, SW2, event.subject());
762 updateLatch.countDown();
763 }
764 };
765 final CountDownLatch removeLatch = new CountDownLatch(1);
766 DeviceStoreDelegate checkRemove = new DeviceStoreDelegate() {
767 @Override
768 public void notify(DeviceEvent event) {
769 assertEquals(DEVICE_REMOVED, event.type());
770 assertDevice(DID1, SW2, event.subject());
771 removeLatch.countDown();
772 }
773 };
774
775 DeviceDescription description =
776 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
777 HW, SW1, SN);
778 deviceStore.setDelegate(checkAdd);
779 deviceStore.createOrUpdateDevice(PID, DID1, description);
780 assertTrue("Add event fired", addLatch.await(1, TimeUnit.SECONDS));
781
782
783 DeviceDescription description2 =
784 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
785 HW, SW2, SN);
786 deviceStore.unsetDelegate(checkAdd);
787 deviceStore.setDelegate(checkUpdate);
788 deviceStore.createOrUpdateDevice(PID, DID1, description2);
789 assertTrue("Update event fired", updateLatch.await(1, TimeUnit.SECONDS));
790
791 deviceStore.unsetDelegate(checkUpdate);
792 deviceStore.setDelegate(checkRemove);
793 deviceStore.removeDevice(DID1);
794 assertTrue("Remove event fired", removeLatch.await(1, TimeUnit.SECONDS));
795 }
796
797 private static final class TestGossipDeviceStore extends GossipDeviceStore {
798
Madan Jampani53e44e62014-10-07 12:39:51 -0700799 public TestGossipDeviceStore(
Yuta HIGUCHId40483d2014-10-09 15:20:30 -0700800 ClockService clockService,
Madan Jampani53e44e62014-10-07 12:39:51 -0700801 ClusterService clusterService,
802 ClusterCommunicationService clusterCommunicator) {
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700803 this.clockService = clockService;
Madan Jampani53e44e62014-10-07 12:39:51 -0700804 this.clusterService = clusterService;
Madan Jampani47c93732014-10-06 20:46:08 -0700805 this.clusterCommunicator = clusterCommunicator;
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700806 }
Madan Jampani47c93732014-10-06 20:46:08 -0700807
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700808 public <T> T deserialize(byte[] bytes) {
809 return SERIALIZER.decode(bytes);
810 }
Madan Jampani47c93732014-10-06 20:46:08 -0700811 }
Madan Jampani53e44e62014-10-07 12:39:51 -0700812
813 private static final class TestClusterService implements ClusterService {
814
Madan Jampani53e44e62014-10-07 12:39:51 -0700815 private final Map<NodeId, ControllerNode> nodes = new HashMap<>();
816 private final Map<NodeId, ControllerNode.State> nodeStates = new HashMap<>();
817
818 public TestClusterService() {
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700819 nodes.put(NID1, ONOS1);
820 nodeStates.put(NID1, ACTIVE);
821
822 nodes.put(NID2, ONOS2);
823 nodeStates.put(NID2, ACTIVE);
Madan Jampani53e44e62014-10-07 12:39:51 -0700824 }
825
826 @Override
827 public ControllerNode getLocalNode() {
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700828 return GossipDeviceStoreTest.ONOS1;
Madan Jampani53e44e62014-10-07 12:39:51 -0700829 }
830
831 @Override
832 public Set<ControllerNode> getNodes() {
833 return Sets.newHashSet(nodes.values());
834 }
835
836 @Override
837 public ControllerNode getNode(NodeId nodeId) {
838 return nodes.get(nodeId);
839 }
840
841 @Override
842 public State getState(NodeId nodeId) {
843 return nodeStates.get(nodeId);
844 }
845
846 @Override
847 public void addListener(ClusterEventListener listener) {
848 }
849
850 @Override
851 public void removeListener(ClusterEventListener listener) {
852 }
853 }
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700854}