blob: 0e842ec3ad3880841195a79f7778893b5076d220 [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;
Yuta HIGUCHI093e83e2014-10-10 22:26:11 -070011
Madan Jampani47c93732014-10-06 20:46:08 -070012import java.io.IOException;
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -070013import java.util.Arrays;
Yuta HIGUCHI47c40882014-10-10 18:44:37 -070014import java.util.Collections;
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -070015import java.util.HashMap;
16import java.util.List;
17import java.util.Map;
18import java.util.Set;
19import java.util.concurrent.CountDownLatch;
20import java.util.concurrent.TimeUnit;
21
Yuta HIGUCHI47c40882014-10-10 18:44:37 -070022import org.easymock.Capture;
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -070023import org.junit.After;
24import org.junit.AfterClass;
25import org.junit.Before;
26import org.junit.BeforeClass;
27import org.junit.Ignore;
28import org.junit.Test;
Madan Jampani53e44e62014-10-07 12:39:51 -070029import org.onlab.onos.cluster.ClusterEventListener;
30import org.onlab.onos.cluster.ClusterService;
31import org.onlab.onos.cluster.ControllerNode;
32import org.onlab.onos.cluster.ControllerNode.State;
33import org.onlab.onos.cluster.DefaultControllerNode;
Yuta HIGUCHIfa891c92014-10-09 15:21:40 -070034import org.onlab.onos.cluster.MastershipTerm;
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -070035import org.onlab.onos.cluster.NodeId;
36import org.onlab.onos.net.Annotations;
37import org.onlab.onos.net.DefaultAnnotations;
38import org.onlab.onos.net.Device;
39import org.onlab.onos.net.DeviceId;
40import org.onlab.onos.net.Port;
41import org.onlab.onos.net.PortNumber;
42import org.onlab.onos.net.SparseAnnotations;
43import org.onlab.onos.net.device.DefaultDeviceDescription;
44import org.onlab.onos.net.device.DefaultPortDescription;
Yuta HIGUCHI093e83e2014-10-10 22:26:11 -070045import org.onlab.onos.net.device.DeviceClockService;
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -070046import org.onlab.onos.net.device.DeviceDescription;
47import org.onlab.onos.net.device.DeviceEvent;
48import org.onlab.onos.net.device.DeviceStore;
49import org.onlab.onos.net.device.DeviceStoreDelegate;
50import org.onlab.onos.net.device.PortDescription;
51import org.onlab.onos.net.provider.ProviderId;
Madan Jampani47c93732014-10-06 20:46:08 -070052import org.onlab.onos.store.cluster.messaging.ClusterCommunicationService;
53import org.onlab.onos.store.cluster.messaging.ClusterMessage;
54import org.onlab.onos.store.cluster.messaging.ClusterMessageHandler;
55import org.onlab.onos.store.cluster.messaging.MessageSubject;
Madan Jampani53e44e62014-10-07 12:39:51 -070056import org.onlab.packet.IpPrefix;
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -070057
58import com.google.common.collect.Iterables;
59import com.google.common.collect.Sets;
60
61
62// TODO add tests for remote replication
63/**
64 * Test of the gossip based distributed DeviceStore implementation.
65 */
66public class GossipDeviceStoreTest {
67
68 private static final ProviderId PID = new ProviderId("of", "foo");
69 private static final ProviderId PIDA = new ProviderId("of", "bar", true);
70 private static final DeviceId DID1 = deviceId("of:foo");
71 private static final DeviceId DID2 = deviceId("of:bar");
72 private static final String MFR = "whitebox";
73 private static final String HW = "1.1.x";
74 private static final String SW1 = "3.8.1";
75 private static final String SW2 = "3.9.5";
76 private static final String SN = "43311-12345";
77
78 private static final PortNumber P1 = PortNumber.portNumber(1);
79 private static final PortNumber P2 = PortNumber.portNumber(2);
80 private static final PortNumber P3 = PortNumber.portNumber(3);
81
82 private static final SparseAnnotations A1 = DefaultAnnotations.builder()
83 .set("A1", "a1")
84 .set("B1", "b1")
85 .build();
86 private static final SparseAnnotations A1_2 = DefaultAnnotations.builder()
87 .remove("A1")
88 .set("B3", "b3")
89 .build();
90 private static final SparseAnnotations A2 = DefaultAnnotations.builder()
91 .set("A2", "a2")
92 .set("B2", "b2")
93 .build();
94 private static final SparseAnnotations A2_2 = DefaultAnnotations.builder()
95 .remove("A2")
96 .set("B4", "b4")
97 .build();
98
Yuta HIGUCHI47c40882014-10-10 18:44:37 -070099 // local node
100 private static final NodeId NID1 = new NodeId("local");
101 private static final ControllerNode ONOS1 =
102 new DefaultControllerNode(NID1, IpPrefix.valueOf("127.0.0.1"));
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700103
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700104 // remote node
105 private static final NodeId NID2 = new NodeId("remote");
106 private static final ControllerNode ONOS2 =
107 new DefaultControllerNode(NID2, IpPrefix.valueOf("127.0.0.2"));
108 private static final List<SparseAnnotations> NO_ANNOTATION = Collections.<SparseAnnotations>emptyList();
109
110
111 private TestGossipDeviceStore testGossipDeviceStore;
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700112 private GossipDeviceStore gossipDeviceStore;
113 private DeviceStore deviceStore;
114
115 private DeviceClockManager deviceClockManager;
Yuta HIGUCHI093e83e2014-10-10 22:26:11 -0700116 private DeviceClockService deviceClockService;
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700117 private ClusterCommunicationService clusterCommunicator;
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700118 @BeforeClass
119 public static void setUpBeforeClass() throws Exception {
120 }
121
122 @AfterClass
123 public static void tearDownAfterClass() throws Exception {
124 }
125
126
127 @Before
128 public void setUp() throws Exception {
129 deviceClockManager = new DeviceClockManager();
130 deviceClockManager.activate();
Yuta HIGUCHI093e83e2014-10-10 22:26:11 -0700131 deviceClockService = deviceClockManager;
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700132
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700133 deviceClockManager.setMastershipTerm(DID1, MastershipTerm.of(NID1, 1));
134 deviceClockManager.setMastershipTerm(DID2, MastershipTerm.of(NID1, 2));
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700135
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700136 clusterCommunicator = createNiceMock(ClusterCommunicationService.class);
137 clusterCommunicator.addSubscriber(anyObject(MessageSubject.class),
138 anyObject(ClusterMessageHandler.class));
139 expectLastCall().anyTimes();
140 replay(clusterCommunicator);
Madan Jampani53e44e62014-10-07 12:39:51 -0700141 ClusterService clusterService = new TestClusterService();
Madan Jampani47c93732014-10-06 20:46:08 -0700142
Yuta HIGUCHI093e83e2014-10-10 22:26:11 -0700143 testGossipDeviceStore = new TestGossipDeviceStore(deviceClockService, clusterService, clusterCommunicator);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700144 gossipDeviceStore = testGossipDeviceStore;
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700145 gossipDeviceStore.activate();
146 deviceStore = gossipDeviceStore;
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700147 verify(clusterCommunicator);
148 reset(clusterCommunicator);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700149 }
150
151 @After
152 public void tearDown() throws Exception {
153 gossipDeviceStore.deactivate();
154 deviceClockManager.deactivate();
155 }
156
Yuta HIGUCHI0d6a5e62014-10-03 15:54:09 -0700157 private void putDevice(DeviceId deviceId, String swVersion,
158 SparseAnnotations... annotations) {
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700159 DeviceDescription description =
160 new DefaultDeviceDescription(deviceId.uri(), SWITCH, MFR,
Yuta HIGUCHI0d6a5e62014-10-03 15:54:09 -0700161 HW, swVersion, SN, annotations);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700162 reset(clusterCommunicator);
163 try {
164 expect(clusterCommunicator.broadcast(anyObject(ClusterMessage.class)))
165 .andReturn(true).anyTimes();
166 } catch (IOException e) {
167 fail("Should never reach here");
168 }
169 replay(clusterCommunicator);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700170 deviceStore.createOrUpdateDevice(PID, deviceId, description);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700171 verify(clusterCommunicator);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700172 }
173
Yuta HIGUCHI0d6a5e62014-10-03 15:54:09 -0700174 private void putDeviceAncillary(DeviceId deviceId, String swVersion,
175 SparseAnnotations... annotations) {
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700176 DeviceDescription description =
177 new DefaultDeviceDescription(deviceId.uri(), SWITCH, MFR,
Yuta HIGUCHI0d6a5e62014-10-03 15:54:09 -0700178 HW, swVersion, SN, annotations);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700179 deviceStore.createOrUpdateDevice(PIDA, deviceId, description);
180 }
181
182 private static void assertDevice(DeviceId id, String swVersion, Device device) {
183 assertNotNull(device);
184 assertEquals(id, device.id());
185 assertEquals(MFR, device.manufacturer());
186 assertEquals(HW, device.hwVersion());
187 assertEquals(swVersion, device.swVersion());
188 assertEquals(SN, device.serialNumber());
189 }
190
191 /**
192 * Verifies that Annotations created by merging {@code annotations} is
193 * equal to actual Annotations.
194 *
195 * @param actual Annotations to check
196 * @param annotations
197 */
198 private static void assertAnnotationsEquals(Annotations actual, SparseAnnotations... annotations) {
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700199 SparseAnnotations expected = DefaultAnnotations.builder().build();
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700200 for (SparseAnnotations a : annotations) {
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700201 expected = DefaultAnnotations.union(expected, a);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700202 }
203 assertEquals(expected.keys(), actual.keys());
204 for (String key : expected.keys()) {
205 assertEquals(expected.value(key), actual.value(key));
206 }
207 }
208
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700209 private static void assertDeviceDescriptionEquals(DeviceDescription expected,
210 DeviceDescription actual) {
211 if (expected == actual) {
212 return;
213 }
214 assertEquals(expected.deviceURI(), actual.deviceURI());
215 assertEquals(expected.hwVersion(), actual.hwVersion());
216 assertEquals(expected.manufacturer(), actual.manufacturer());
217 assertEquals(expected.serialNumber(), actual.serialNumber());
218 assertEquals(expected.swVersion(), actual.swVersion());
219
220 assertAnnotationsEquals(actual.annotations(), expected.annotations());
221 }
222
223 private static void assertDeviceDescriptionEquals(DeviceDescription expected,
224 List<SparseAnnotations> expectedAnnotations,
225 DeviceDescription actual) {
226 if (expected == actual) {
227 return;
228 }
229 assertEquals(expected.deviceURI(), actual.deviceURI());
230 assertEquals(expected.hwVersion(), actual.hwVersion());
231 assertEquals(expected.manufacturer(), actual.manufacturer());
232 assertEquals(expected.serialNumber(), actual.serialNumber());
233 assertEquals(expected.swVersion(), actual.swVersion());
234
235 assertAnnotationsEquals(actual.annotations(),
236 expectedAnnotations.toArray(new SparseAnnotations[0]));
237 }
238
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700239 @Test
240 public final void testGetDeviceCount() {
241 assertEquals("initialy empty", 0, deviceStore.getDeviceCount());
242
243 putDevice(DID1, SW1);
244 putDevice(DID2, SW2);
245 putDevice(DID1, SW1);
246
247 assertEquals("expect 2 uniq devices", 2, deviceStore.getDeviceCount());
248 }
249
250 @Test
251 public final void testGetDevices() {
252 assertEquals("initialy empty", 0, Iterables.size(deviceStore.getDevices()));
253
254 putDevice(DID1, SW1);
255 putDevice(DID2, SW2);
256 putDevice(DID1, SW1);
257
258 assertEquals("expect 2 uniq devices",
259 2, Iterables.size(deviceStore.getDevices()));
260
261 Map<DeviceId, Device> devices = new HashMap<>();
262 for (Device device : deviceStore.getDevices()) {
263 devices.put(device.id(), device);
264 }
265
266 assertDevice(DID1, SW1, devices.get(DID1));
267 assertDevice(DID2, SW2, devices.get(DID2));
268
269 // add case for new node?
270 }
271
272 @Test
273 public final void testGetDevice() {
274
275 putDevice(DID1, SW1);
276
277 assertDevice(DID1, SW1, deviceStore.getDevice(DID1));
278 assertNull("DID2 shouldn't be there", deviceStore.getDevice(DID2));
279 }
280
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700281 private void assertInternalDeviceEvent(NodeId sender,
282 DeviceId deviceId,
283 ProviderId providerId,
284 DeviceDescription expectedDesc,
285 Capture<ClusterMessage> actualMsg) {
286 assertTrue(actualMsg.hasCaptured());
287 assertEquals(sender, actualMsg.getValue().sender());
288 assertEquals(GossipDeviceStoreMessageSubjects.DEVICE_UPDATE,
289 actualMsg.getValue().subject());
290 InternalDeviceEvent addEvent
291 = testGossipDeviceStore.deserialize(actualMsg.getValue().payload());
292 assertEquals(deviceId, addEvent.deviceId());
293 assertEquals(providerId, addEvent.providerId());
294 assertDeviceDescriptionEquals(expectedDesc, addEvent.deviceDescription().value());
295 }
296
297 private void assertInternalDeviceEvent(NodeId sender,
298 DeviceId deviceId,
299 ProviderId providerId,
300 DeviceDescription expectedDesc,
301 List<SparseAnnotations> expectedAnnotations,
302 Capture<ClusterMessage> actualMsg) {
303 assertTrue(actualMsg.hasCaptured());
304 assertEquals(sender, actualMsg.getValue().sender());
305 assertEquals(GossipDeviceStoreMessageSubjects.DEVICE_UPDATE,
306 actualMsg.getValue().subject());
307 InternalDeviceEvent addEvent
308 = testGossipDeviceStore.deserialize(actualMsg.getValue().payload());
309 assertEquals(deviceId, addEvent.deviceId());
310 assertEquals(providerId, addEvent.providerId());
311 assertDeviceDescriptionEquals(expectedDesc, expectedAnnotations, addEvent.deviceDescription().value());
312 }
313
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700314 @Test
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700315 public final void testCreateOrUpdateDevice() throws IOException {
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700316 DeviceDescription description =
317 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
318 HW, SW1, SN);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700319 Capture<ClusterMessage> bcast = new Capture<>();
320
321 resetCommunicatorExpectingSingleBroadcast(bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700322 DeviceEvent event = deviceStore.createOrUpdateDevice(PID, DID1, description);
323 assertEquals(DEVICE_ADDED, event.type());
324 assertDevice(DID1, SW1, event.subject());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700325 verify(clusterCommunicator);
326 assertInternalDeviceEvent(NID1, DID1, PID, description, bcast);
327
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700328
329 DeviceDescription description2 =
330 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
331 HW, SW2, SN);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700332 resetCommunicatorExpectingSingleBroadcast(bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700333 DeviceEvent event2 = deviceStore.createOrUpdateDevice(PID, DID1, description2);
334 assertEquals(DEVICE_UPDATED, event2.type());
335 assertDevice(DID1, SW2, event2.subject());
336
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700337 verify(clusterCommunicator);
338 assertInternalDeviceEvent(NID1, DID1, PID, description2, bcast);
339 reset(clusterCommunicator);
340
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700341 assertNull("No change expected", deviceStore.createOrUpdateDevice(PID, DID1, description2));
342 }
343
344 @Test
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700345 public final void testCreateOrUpdateDeviceAncillary() throws IOException {
346 // add
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700347 DeviceDescription description =
348 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
349 HW, SW1, SN, A2);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700350 Capture<ClusterMessage> bcast = new Capture<>();
351
352 resetCommunicatorExpectingSingleBroadcast(bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700353 DeviceEvent event = deviceStore.createOrUpdateDevice(PIDA, DID1, description);
354 assertEquals(DEVICE_ADDED, event.type());
355 assertDevice(DID1, SW1, event.subject());
356 assertEquals(PIDA, event.subject().providerId());
357 assertAnnotationsEquals(event.subject().annotations(), A2);
358 assertFalse("Ancillary will not bring device up", deviceStore.isAvailable(DID1));
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700359 verify(clusterCommunicator);
360 assertInternalDeviceEvent(NID1, DID1, PIDA, description, bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700361
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700362 // update from primary
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700363 DeviceDescription description2 =
364 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
365 HW, SW2, SN, A1);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700366 resetCommunicatorExpectingSingleBroadcast(bcast);
367
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700368 DeviceEvent event2 = deviceStore.createOrUpdateDevice(PID, DID1, description2);
369 assertEquals(DEVICE_UPDATED, event2.type());
370 assertDevice(DID1, SW2, event2.subject());
371 assertEquals(PID, event2.subject().providerId());
372 assertAnnotationsEquals(event2.subject().annotations(), A1, A2);
373 assertTrue(deviceStore.isAvailable(DID1));
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700374 verify(clusterCommunicator);
375 assertInternalDeviceEvent(NID1, DID1, PID, description2, bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700376
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700377 // no-op update from primary
378 resetCommunicatorExpectingNoBroadcast(bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700379 assertNull("No change expected", deviceStore.createOrUpdateDevice(PID, DID1, description2));
380
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700381 verify(clusterCommunicator);
382 assertFalse("no broadcast expected", bcast.hasCaptured());
383
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700384 // For now, Ancillary is ignored once primary appears
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700385 resetCommunicatorExpectingNoBroadcast(bcast);
386
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700387 assertNull("No change expected", deviceStore.createOrUpdateDevice(PIDA, DID1, description));
388
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700389 verify(clusterCommunicator);
390 assertFalse("no broadcast expected", bcast.hasCaptured());
391
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700392 // But, Ancillary annotations will be in effect
393 DeviceDescription description3 =
394 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
395 HW, SW1, SN, A2_2);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700396 resetCommunicatorExpectingSingleBroadcast(bcast);
397
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700398 DeviceEvent event3 = deviceStore.createOrUpdateDevice(PIDA, DID1, description3);
399 assertEquals(DEVICE_UPDATED, event3.type());
400 // basic information will be the one from Primary
401 assertDevice(DID1, SW2, event3.subject());
402 assertEquals(PID, event3.subject().providerId());
403 // but annotation from Ancillary will be merged
404 assertAnnotationsEquals(event3.subject().annotations(), A1, A2, A2_2);
405 assertTrue(deviceStore.isAvailable(DID1));
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700406 verify(clusterCommunicator);
407 // note: only annotation from PIDA is sent over the wire
408 assertInternalDeviceEvent(NID1, DID1, PIDA, description3,
409 asList(union(A2, A2_2)), bcast);
410
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700411 }
412
413
414 @Test
415 public final void testMarkOffline() {
416
417 putDevice(DID1, SW1);
418 assertTrue(deviceStore.isAvailable(DID1));
419
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700420 Capture<ClusterMessage> bcast = new Capture<>();
421
422 resetCommunicatorExpectingSingleBroadcast(bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700423 DeviceEvent event = deviceStore.markOffline(DID1);
424 assertEquals(DEVICE_AVAILABILITY_CHANGED, event.type());
425 assertDevice(DID1, SW1, event.subject());
426 assertFalse(deviceStore.isAvailable(DID1));
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700427 verify(clusterCommunicator);
428 // TODO: verify broadcast message
429 assertTrue(bcast.hasCaptured());
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700430
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700431
432 resetCommunicatorExpectingNoBroadcast(bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700433 DeviceEvent event2 = deviceStore.markOffline(DID1);
434 assertNull("No change, no event", event2);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700435 verify(clusterCommunicator);
436 assertFalse(bcast.hasCaptured());
437 }
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700438
439 @Test
440 public final void testUpdatePorts() {
441 putDevice(DID1, SW1);
442 List<PortDescription> pds = Arrays.<PortDescription>asList(
443 new DefaultPortDescription(P1, true),
444 new DefaultPortDescription(P2, true)
445 );
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700446 Capture<ClusterMessage> bcast = new Capture<>();
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700447
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700448 resetCommunicatorExpectingSingleBroadcast(bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700449 List<DeviceEvent> events = deviceStore.updatePorts(PID, DID1, pds);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700450 verify(clusterCommunicator);
451 // TODO: verify broadcast message
452 assertTrue(bcast.hasCaptured());
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700453
454 Set<PortNumber> expectedPorts = Sets.newHashSet(P1, P2);
455 for (DeviceEvent event : events) {
456 assertEquals(PORT_ADDED, event.type());
457 assertDevice(DID1, SW1, event.subject());
458 assertTrue("PortNumber is one of expected",
459 expectedPorts.remove(event.port().number()));
460 assertTrue("Port is enabled", event.port().isEnabled());
461 }
462 assertTrue("Event for all expectedport appeared", expectedPorts.isEmpty());
463
464
465 List<PortDescription> pds2 = Arrays.<PortDescription>asList(
466 new DefaultPortDescription(P1, false),
467 new DefaultPortDescription(P2, true),
468 new DefaultPortDescription(P3, true)
469 );
470
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700471 resetCommunicatorExpectingSingleBroadcast(bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700472 events = deviceStore.updatePorts(PID, DID1, pds2);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700473 verify(clusterCommunicator);
474 // TODO: verify broadcast message
475 assertTrue(bcast.hasCaptured());
476
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700477 assertFalse("event should be triggered", events.isEmpty());
478 for (DeviceEvent event : events) {
479 PortNumber num = event.port().number();
480 if (P1.equals(num)) {
481 assertEquals(PORT_UPDATED, event.type());
482 assertDevice(DID1, SW1, event.subject());
483 assertFalse("Port is disabled", event.port().isEnabled());
484 } else if (P2.equals(num)) {
485 fail("P2 event not expected.");
486 } else if (P3.equals(num)) {
487 assertEquals(PORT_ADDED, event.type());
488 assertDevice(DID1, SW1, event.subject());
489 assertTrue("Port is enabled", event.port().isEnabled());
490 } else {
491 fail("Unknown port number encountered: " + num);
492 }
493 }
494
495 List<PortDescription> pds3 = Arrays.<PortDescription>asList(
496 new DefaultPortDescription(P1, false),
497 new DefaultPortDescription(P2, true)
498 );
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700499 resetCommunicatorExpectingSingleBroadcast(bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700500 events = deviceStore.updatePorts(PID, DID1, pds3);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700501 verify(clusterCommunicator);
502 // TODO: verify broadcast message
503 assertTrue(bcast.hasCaptured());
504
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700505 assertFalse("event should be triggered", events.isEmpty());
506 for (DeviceEvent event : events) {
507 PortNumber num = event.port().number();
508 if (P1.equals(num)) {
509 fail("P1 event not expected.");
510 } else if (P2.equals(num)) {
511 fail("P2 event not expected.");
512 } else if (P3.equals(num)) {
513 assertEquals(PORT_REMOVED, event.type());
514 assertDevice(DID1, SW1, event.subject());
515 assertTrue("Port was enabled", event.port().isEnabled());
516 } else {
517 fail("Unknown port number encountered: " + num);
518 }
519 }
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700520 }
521
522 @Test
523 public final void testUpdatePortStatus() {
524 putDevice(DID1, SW1);
525 List<PortDescription> pds = Arrays.<PortDescription>asList(
526 new DefaultPortDescription(P1, true)
527 );
528 deviceStore.updatePorts(PID, DID1, pds);
529
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700530 Capture<ClusterMessage> bcast = new Capture<>();
531
532 resetCommunicatorExpectingSingleBroadcast(bcast);
533 final DefaultPortDescription desc = new DefaultPortDescription(P1, false);
534 DeviceEvent event = deviceStore.updatePortStatus(PID, DID1, desc);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700535 assertEquals(PORT_UPDATED, event.type());
536 assertDevice(DID1, SW1, event.subject());
537 assertEquals(P1, event.port().number());
538 assertFalse("Port is disabled", event.port().isEnabled());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700539 verify(clusterCommunicator);
540 assertInternalPortStatusEvent(NID1, DID1, PID, desc, NO_ANNOTATION, bcast);
541 assertTrue(bcast.hasCaptured());
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700542 }
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700543
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700544 @Test
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700545 public final void testUpdatePortStatusAncillary() throws IOException {
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700546 putDeviceAncillary(DID1, SW1);
547 putDevice(DID1, SW1);
548 List<PortDescription> pds = Arrays.<PortDescription>asList(
549 new DefaultPortDescription(P1, true, A1)
550 );
551 deviceStore.updatePorts(PID, DID1, pds);
552
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700553 Capture<ClusterMessage> bcast = new Capture<>();
554
555
556 // update port from primary
557 resetCommunicatorExpectingSingleBroadcast(bcast);
558 final DefaultPortDescription desc1 = new DefaultPortDescription(P1, false, A1_2);
559 DeviceEvent event = deviceStore.updatePortStatus(PID, DID1, desc1);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700560 assertEquals(PORT_UPDATED, event.type());
561 assertDevice(DID1, SW1, event.subject());
562 assertEquals(P1, event.port().number());
563 assertAnnotationsEquals(event.port().annotations(), A1, A1_2);
564 assertFalse("Port is disabled", event.port().isEnabled());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700565 verify(clusterCommunicator);
566 assertInternalPortStatusEvent(NID1, DID1, PID, desc1, asList(A1, A1_2), bcast);
567 assertTrue(bcast.hasCaptured());
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700568
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700569 // update port from ancillary with no attributes
570 resetCommunicatorExpectingNoBroadcast(bcast);
571 final DefaultPortDescription desc2 = new DefaultPortDescription(P1, true);
572 DeviceEvent event2 = deviceStore.updatePortStatus(PIDA, DID1, desc2);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700573 assertNull("Ancillary is ignored if primary exists", event2);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700574 verify(clusterCommunicator);
575 assertFalse(bcast.hasCaptured());
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700576
577 // but, Ancillary annotation update will be notified
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700578 resetCommunicatorExpectingSingleBroadcast(bcast);
579 final DefaultPortDescription desc3 = new DefaultPortDescription(P1, true, A2);
580 DeviceEvent event3 = deviceStore.updatePortStatus(PIDA, DID1, desc3);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700581 assertEquals(PORT_UPDATED, event3.type());
582 assertDevice(DID1, SW1, event3.subject());
583 assertEquals(P1, event3.port().number());
584 assertAnnotationsEquals(event3.port().annotations(), A1, A1_2, A2);
585 assertFalse("Port is disabled", event3.port().isEnabled());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700586 verify(clusterCommunicator);
587 assertInternalPortStatusEvent(NID1, DID1, PIDA, desc3, asList(A2), bcast);
588 assertTrue(bcast.hasCaptured());
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700589
590 // port only reported from Ancillary will be notified as down
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700591 resetCommunicatorExpectingSingleBroadcast(bcast);
592 final DefaultPortDescription desc4 = new DefaultPortDescription(P2, true);
593 DeviceEvent event4 = deviceStore.updatePortStatus(PIDA, DID1, desc4);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700594 assertEquals(PORT_ADDED, event4.type());
595 assertDevice(DID1, SW1, event4.subject());
596 assertEquals(P2, event4.port().number());
597 assertAnnotationsEquals(event4.port().annotations());
598 assertFalse("Port is disabled if not given from primary provider",
599 event4.port().isEnabled());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700600 verify(clusterCommunicator);
601 // TODO: verify broadcast message content
602 assertInternalPortStatusEvent(NID1, DID1, PIDA, desc4, NO_ANNOTATION, bcast);
603 assertTrue(bcast.hasCaptured());
604 }
605
606 private void assertInternalPortStatusEvent(NodeId sender, DeviceId did,
607 ProviderId pid, DefaultPortDescription expectedDesc,
608 List<SparseAnnotations> expectedAnnotations, Capture<ClusterMessage> actualMsg) {
609
610 assertTrue(actualMsg.hasCaptured());
611 assertEquals(sender, actualMsg.getValue().sender());
612 assertEquals(GossipDeviceStoreMessageSubjects.PORT_STATUS_UPDATE,
613 actualMsg.getValue().subject());
614 InternalPortStatusEvent addEvent
615 = testGossipDeviceStore.deserialize(actualMsg.getValue().payload());
616 assertEquals(did, addEvent.deviceId());
617 assertEquals(pid, addEvent.providerId());
618 assertPortDescriptionEquals(expectedDesc, expectedAnnotations,
619 addEvent.portDescription().value());
620
621 }
622
623 private void assertPortDescriptionEquals(
624 PortDescription expectedDesc,
625 List<SparseAnnotations> expectedAnnotations,
626 PortDescription actual) {
627
628 assertEquals(expectedDesc.portNumber(), actual.portNumber());
629 assertEquals(expectedDesc.isEnabled(), actual.isEnabled());
630
631 assertAnnotationsEquals(actual.annotations(),
632 expectedAnnotations.toArray(new SparseAnnotations[0]));
633 }
634
635 private void resetCommunicatorExpectingNoBroadcast(
636 Capture<ClusterMessage> bcast) {
637 bcast.reset();
638 reset(clusterCommunicator);
639 replay(clusterCommunicator);
640 }
641
642 private void resetCommunicatorExpectingSingleBroadcast(
643 Capture<ClusterMessage> bcast) {
644
645 bcast.reset();
646 reset(clusterCommunicator);
647 try {
648 expect(clusterCommunicator.broadcast(capture(bcast))).andReturn(true).once();
649 } catch (IOException e) {
650 fail("Should never reach here");
651 }
652 replay(clusterCommunicator);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700653 }
654
655 @Test
656 public final void testGetPorts() {
657 putDevice(DID1, SW1);
658 putDevice(DID2, SW1);
659 List<PortDescription> pds = Arrays.<PortDescription>asList(
660 new DefaultPortDescription(P1, true),
661 new DefaultPortDescription(P2, true)
662 );
663 deviceStore.updatePorts(PID, DID1, pds);
664
665 Set<PortNumber> expectedPorts = Sets.newHashSet(P1, P2);
666 List<Port> ports = deviceStore.getPorts(DID1);
667 for (Port port : ports) {
668 assertTrue("Port is enabled", port.isEnabled());
669 assertTrue("PortNumber is one of expected",
670 expectedPorts.remove(port.number()));
671 }
672 assertTrue("Event for all expectedport appeared", expectedPorts.isEmpty());
673
674
675 assertTrue("DID2 has no ports", deviceStore.getPorts(DID2).isEmpty());
676 }
677
678 @Test
679 public final void testGetPort() {
680 putDevice(DID1, SW1);
681 putDevice(DID2, SW1);
682 List<PortDescription> pds = Arrays.<PortDescription>asList(
683 new DefaultPortDescription(P1, true),
684 new DefaultPortDescription(P2, false)
685 );
686 deviceStore.updatePorts(PID, DID1, pds);
687
688 Port port1 = deviceStore.getPort(DID1, P1);
689 assertEquals(P1, port1.number());
690 assertTrue("Port is enabled", port1.isEnabled());
691
692 Port port2 = deviceStore.getPort(DID1, P2);
693 assertEquals(P2, port2.number());
694 assertFalse("Port is disabled", port2.isEnabled());
695
696 Port port3 = deviceStore.getPort(DID1, P3);
697 assertNull("P3 not expected", port3);
698 }
699
700 @Test
701 public final void testRemoveDevice() {
Yuta HIGUCHI0d6a5e62014-10-03 15:54:09 -0700702 putDevice(DID1, SW1, A1);
703 List<PortDescription> pds = Arrays.<PortDescription>asList(
704 new DefaultPortDescription(P1, true, A2)
705 );
706 deviceStore.updatePorts(PID, DID1, pds);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700707 putDevice(DID2, SW1);
708
709 assertEquals(2, deviceStore.getDeviceCount());
Yuta HIGUCHI0d6a5e62014-10-03 15:54:09 -0700710 assertEquals(1, deviceStore.getPorts(DID1).size());
711 assertAnnotationsEquals(deviceStore.getDevice(DID1).annotations(), A1);
712 assertAnnotationsEquals(deviceStore.getPort(DID1, P1).annotations(), A2);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700713
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700714 Capture<ClusterMessage> bcast = new Capture<>();
715
716 resetCommunicatorExpectingSingleBroadcast(bcast);
717
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700718 DeviceEvent event = deviceStore.removeDevice(DID1);
719 assertEquals(DEVICE_REMOVED, event.type());
720 assertDevice(DID1, SW1, event.subject());
721
722 assertEquals(1, deviceStore.getDeviceCount());
Yuta HIGUCHI0d6a5e62014-10-03 15:54:09 -0700723 assertEquals(0, deviceStore.getPorts(DID1).size());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700724 verify(clusterCommunicator);
725 // TODO: verify broadcast message
726 assertTrue(bcast.hasCaptured());
Yuta HIGUCHI0d6a5e62014-10-03 15:54:09 -0700727
728 // putBack Device, Port w/o annotation
729 putDevice(DID1, SW1);
730 List<PortDescription> pds2 = Arrays.<PortDescription>asList(
731 new DefaultPortDescription(P1, true)
732 );
733 deviceStore.updatePorts(PID, DID1, pds2);
734
735 // annotations should not survive
736 assertEquals(2, deviceStore.getDeviceCount());
737 assertEquals(1, deviceStore.getPorts(DID1).size());
738 assertAnnotationsEquals(deviceStore.getDevice(DID1).annotations());
739 assertAnnotationsEquals(deviceStore.getPort(DID1, P1).annotations());
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700740 }
741
742 // If Delegates should be called only on remote events,
743 // then Simple* should never call them, thus not test required.
744 // TODO add test for Port events when we have them
745 @Ignore("Ignore until Delegate spec. is clear.")
746 @Test
747 public final void testEvents() throws InterruptedException {
748 final CountDownLatch addLatch = new CountDownLatch(1);
749 DeviceStoreDelegate checkAdd = new DeviceStoreDelegate() {
750 @Override
751 public void notify(DeviceEvent event) {
752 assertEquals(DEVICE_ADDED, event.type());
753 assertDevice(DID1, SW1, event.subject());
754 addLatch.countDown();
755 }
756 };
757 final CountDownLatch updateLatch = new CountDownLatch(1);
758 DeviceStoreDelegate checkUpdate = new DeviceStoreDelegate() {
759 @Override
760 public void notify(DeviceEvent event) {
761 assertEquals(DEVICE_UPDATED, event.type());
762 assertDevice(DID1, SW2, event.subject());
763 updateLatch.countDown();
764 }
765 };
766 final CountDownLatch removeLatch = new CountDownLatch(1);
767 DeviceStoreDelegate checkRemove = new DeviceStoreDelegate() {
768 @Override
769 public void notify(DeviceEvent event) {
770 assertEquals(DEVICE_REMOVED, event.type());
771 assertDevice(DID1, SW2, event.subject());
772 removeLatch.countDown();
773 }
774 };
775
776 DeviceDescription description =
777 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
778 HW, SW1, SN);
779 deviceStore.setDelegate(checkAdd);
780 deviceStore.createOrUpdateDevice(PID, DID1, description);
781 assertTrue("Add event fired", addLatch.await(1, TimeUnit.SECONDS));
782
783
784 DeviceDescription description2 =
785 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
786 HW, SW2, SN);
787 deviceStore.unsetDelegate(checkAdd);
788 deviceStore.setDelegate(checkUpdate);
789 deviceStore.createOrUpdateDevice(PID, DID1, description2);
790 assertTrue("Update event fired", updateLatch.await(1, TimeUnit.SECONDS));
791
792 deviceStore.unsetDelegate(checkUpdate);
793 deviceStore.setDelegate(checkRemove);
794 deviceStore.removeDevice(DID1);
795 assertTrue("Remove event fired", removeLatch.await(1, TimeUnit.SECONDS));
796 }
797
798 private static final class TestGossipDeviceStore extends GossipDeviceStore {
799
Madan Jampani53e44e62014-10-07 12:39:51 -0700800 public TestGossipDeviceStore(
Yuta HIGUCHI093e83e2014-10-10 22:26:11 -0700801 DeviceClockService deviceClockService,
Madan Jampani53e44e62014-10-07 12:39:51 -0700802 ClusterService clusterService,
803 ClusterCommunicationService clusterCommunicator) {
Yuta HIGUCHI093e83e2014-10-10 22:26:11 -0700804 this.deviceClockService = deviceClockService;
Madan Jampani53e44e62014-10-07 12:39:51 -0700805 this.clusterService = clusterService;
Madan Jampani47c93732014-10-06 20:46:08 -0700806 this.clusterCommunicator = clusterCommunicator;
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700807 }
Madan Jampani47c93732014-10-06 20:46:08 -0700808
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700809 public <T> T deserialize(byte[] bytes) {
810 return SERIALIZER.decode(bytes);
811 }
Madan Jampani47c93732014-10-06 20:46:08 -0700812 }
Madan Jampani53e44e62014-10-07 12:39:51 -0700813
814 private static final class TestClusterService implements ClusterService {
815
Madan Jampani53e44e62014-10-07 12:39:51 -0700816 private final Map<NodeId, ControllerNode> nodes = new HashMap<>();
817 private final Map<NodeId, ControllerNode.State> nodeStates = new HashMap<>();
818
819 public TestClusterService() {
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700820 nodes.put(NID1, ONOS1);
821 nodeStates.put(NID1, ACTIVE);
822
823 nodes.put(NID2, ONOS2);
824 nodeStates.put(NID2, ACTIVE);
Madan Jampani53e44e62014-10-07 12:39:51 -0700825 }
826
827 @Override
828 public ControllerNode getLocalNode() {
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700829 return GossipDeviceStoreTest.ONOS1;
Madan Jampani53e44e62014-10-07 12:39:51 -0700830 }
831
832 @Override
833 public Set<ControllerNode> getNodes() {
834 return Sets.newHashSet(nodes.values());
835 }
836
837 @Override
838 public ControllerNode getNode(NodeId nodeId) {
839 return nodes.get(nodeId);
840 }
841
842 @Override
843 public State getState(NodeId nodeId) {
844 return nodeStates.get(nodeId);
845 }
846
847 @Override
848 public void addListener(ClusterEventListener listener) {
849 }
850
851 @Override
852 public void removeListener(ClusterEventListener listener) {
853 }
854 }
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700855}