blob: 55fa1f4f7a1c12f5a606bcfe051cdb729179fcd0 [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 HIGUCHI67a527f2014-10-02 22:23:54 -070034import org.onlab.onos.cluster.NodeId;
Yuta HIGUCHI80912e62014-10-12 00:15:47 -070035import org.onlab.onos.mastership.MastershipTerm;
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -070036import 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;
alshabib7911a052014-10-16 17:49:37 -070056import org.onlab.packet.ChassisId;
Madan Jampani53e44e62014-10-07 12:39:51 -070057import org.onlab.packet.IpPrefix;
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -070058
59import com.google.common.collect.Iterables;
60import com.google.common.collect.Sets;
61
62
63// TODO add tests for remote replication
64/**
65 * Test of the gossip based distributed DeviceStore implementation.
66 */
67public class GossipDeviceStoreTest {
68
69 private static final ProviderId PID = new ProviderId("of", "foo");
70 private static final ProviderId PIDA = new ProviderId("of", "bar", true);
71 private static final DeviceId DID1 = deviceId("of:foo");
72 private static final DeviceId DID2 = deviceId("of:bar");
73 private static final String MFR = "whitebox";
74 private static final String HW = "1.1.x";
75 private static final String SW1 = "3.8.1";
76 private static final String SW2 = "3.9.5";
77 private static final String SN = "43311-12345";
alshabib7911a052014-10-16 17:49:37 -070078 private static final ChassisId CID = new ChassisId();
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -070079
80 private static final PortNumber P1 = PortNumber.portNumber(1);
81 private static final PortNumber P2 = PortNumber.portNumber(2);
82 private static final PortNumber P3 = PortNumber.portNumber(3);
83
84 private static final SparseAnnotations A1 = DefaultAnnotations.builder()
85 .set("A1", "a1")
86 .set("B1", "b1")
87 .build();
88 private static final SparseAnnotations A1_2 = DefaultAnnotations.builder()
89 .remove("A1")
90 .set("B3", "b3")
91 .build();
92 private static final SparseAnnotations A2 = DefaultAnnotations.builder()
93 .set("A2", "a2")
94 .set("B2", "b2")
95 .build();
96 private static final SparseAnnotations A2_2 = DefaultAnnotations.builder()
97 .remove("A2")
98 .set("B4", "b4")
99 .build();
100
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700101 // local node
102 private static final NodeId NID1 = new NodeId("local");
103 private static final ControllerNode ONOS1 =
104 new DefaultControllerNode(NID1, IpPrefix.valueOf("127.0.0.1"));
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700105
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700106 // remote node
107 private static final NodeId NID2 = new NodeId("remote");
108 private static final ControllerNode ONOS2 =
109 new DefaultControllerNode(NID2, IpPrefix.valueOf("127.0.0.2"));
110 private static final List<SparseAnnotations> NO_ANNOTATION = Collections.<SparseAnnotations>emptyList();
111
112
113 private TestGossipDeviceStore testGossipDeviceStore;
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700114 private GossipDeviceStore gossipDeviceStore;
115 private DeviceStore deviceStore;
116
117 private DeviceClockManager deviceClockManager;
Yuta HIGUCHI093e83e2014-10-10 22:26:11 -0700118 private DeviceClockService deviceClockService;
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700119 private ClusterCommunicationService clusterCommunicator;
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700120 @BeforeClass
121 public static void setUpBeforeClass() throws Exception {
122 }
123
124 @AfterClass
125 public static void tearDownAfterClass() throws Exception {
126 }
127
128
129 @Before
130 public void setUp() throws Exception {
131 deviceClockManager = new DeviceClockManager();
132 deviceClockManager.activate();
Yuta HIGUCHI093e83e2014-10-10 22:26:11 -0700133 deviceClockService = deviceClockManager;
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700134
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700135 deviceClockManager.setMastershipTerm(DID1, MastershipTerm.of(NID1, 1));
136 deviceClockManager.setMastershipTerm(DID2, MastershipTerm.of(NID1, 2));
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700137
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700138 clusterCommunicator = createNiceMock(ClusterCommunicationService.class);
139 clusterCommunicator.addSubscriber(anyObject(MessageSubject.class),
140 anyObject(ClusterMessageHandler.class));
141 expectLastCall().anyTimes();
142 replay(clusterCommunicator);
Madan Jampani53e44e62014-10-07 12:39:51 -0700143 ClusterService clusterService = new TestClusterService();
Madan Jampani47c93732014-10-06 20:46:08 -0700144
Yuta HIGUCHI093e83e2014-10-10 22:26:11 -0700145 testGossipDeviceStore = new TestGossipDeviceStore(deviceClockService, clusterService, clusterCommunicator);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700146 gossipDeviceStore = testGossipDeviceStore;
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700147 gossipDeviceStore.activate();
148 deviceStore = gossipDeviceStore;
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700149 verify(clusterCommunicator);
150 reset(clusterCommunicator);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700151 }
152
153 @After
154 public void tearDown() throws Exception {
155 gossipDeviceStore.deactivate();
156 deviceClockManager.deactivate();
157 }
158
Yuta HIGUCHI0d6a5e62014-10-03 15:54:09 -0700159 private void putDevice(DeviceId deviceId, String swVersion,
160 SparseAnnotations... annotations) {
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700161 DeviceDescription description =
162 new DefaultDeviceDescription(deviceId.uri(), SWITCH, MFR,
alshabib7911a052014-10-16 17:49:37 -0700163 HW, swVersion, SN, CID, annotations);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700164 reset(clusterCommunicator);
165 try {
166 expect(clusterCommunicator.broadcast(anyObject(ClusterMessage.class)))
167 .andReturn(true).anyTimes();
168 } catch (IOException e) {
169 fail("Should never reach here");
170 }
171 replay(clusterCommunicator);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700172 deviceStore.createOrUpdateDevice(PID, deviceId, description);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700173 verify(clusterCommunicator);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700174 }
175
Yuta HIGUCHI0d6a5e62014-10-03 15:54:09 -0700176 private void putDeviceAncillary(DeviceId deviceId, String swVersion,
177 SparseAnnotations... annotations) {
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700178 DeviceDescription description =
179 new DefaultDeviceDescription(deviceId.uri(), SWITCH, MFR,
alshabib7911a052014-10-16 17:49:37 -0700180 HW, swVersion, SN, CID, annotations);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700181 deviceStore.createOrUpdateDevice(PIDA, deviceId, description);
182 }
183
184 private static void assertDevice(DeviceId id, String swVersion, Device device) {
185 assertNotNull(device);
186 assertEquals(id, device.id());
187 assertEquals(MFR, device.manufacturer());
188 assertEquals(HW, device.hwVersion());
189 assertEquals(swVersion, device.swVersion());
190 assertEquals(SN, device.serialNumber());
191 }
192
193 /**
194 * Verifies that Annotations created by merging {@code annotations} is
195 * equal to actual Annotations.
196 *
197 * @param actual Annotations to check
198 * @param annotations
199 */
200 private static void assertAnnotationsEquals(Annotations actual, SparseAnnotations... annotations) {
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700201 SparseAnnotations expected = DefaultAnnotations.builder().build();
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700202 for (SparseAnnotations a : annotations) {
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700203 expected = DefaultAnnotations.union(expected, a);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700204 }
205 assertEquals(expected.keys(), actual.keys());
206 for (String key : expected.keys()) {
207 assertEquals(expected.value(key), actual.value(key));
208 }
209 }
210
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700211 private static void assertDeviceDescriptionEquals(DeviceDescription expected,
212 DeviceDescription actual) {
213 if (expected == actual) {
214 return;
215 }
216 assertEquals(expected.deviceURI(), actual.deviceURI());
217 assertEquals(expected.hwVersion(), actual.hwVersion());
218 assertEquals(expected.manufacturer(), actual.manufacturer());
219 assertEquals(expected.serialNumber(), actual.serialNumber());
220 assertEquals(expected.swVersion(), actual.swVersion());
221
222 assertAnnotationsEquals(actual.annotations(), expected.annotations());
223 }
224
225 private static void assertDeviceDescriptionEquals(DeviceDescription expected,
226 List<SparseAnnotations> expectedAnnotations,
227 DeviceDescription actual) {
228 if (expected == actual) {
229 return;
230 }
231 assertEquals(expected.deviceURI(), actual.deviceURI());
232 assertEquals(expected.hwVersion(), actual.hwVersion());
233 assertEquals(expected.manufacturer(), actual.manufacturer());
234 assertEquals(expected.serialNumber(), actual.serialNumber());
235 assertEquals(expected.swVersion(), actual.swVersion());
236
237 assertAnnotationsEquals(actual.annotations(),
238 expectedAnnotations.toArray(new SparseAnnotations[0]));
239 }
240
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700241 @Test
242 public final void testGetDeviceCount() {
243 assertEquals("initialy empty", 0, deviceStore.getDeviceCount());
244
245 putDevice(DID1, SW1);
246 putDevice(DID2, SW2);
247 putDevice(DID1, SW1);
248
249 assertEquals("expect 2 uniq devices", 2, deviceStore.getDeviceCount());
250 }
251
252 @Test
253 public final void testGetDevices() {
254 assertEquals("initialy empty", 0, Iterables.size(deviceStore.getDevices()));
255
256 putDevice(DID1, SW1);
257 putDevice(DID2, SW2);
258 putDevice(DID1, SW1);
259
260 assertEquals("expect 2 uniq devices",
261 2, Iterables.size(deviceStore.getDevices()));
262
263 Map<DeviceId, Device> devices = new HashMap<>();
264 for (Device device : deviceStore.getDevices()) {
265 devices.put(device.id(), device);
266 }
267
268 assertDevice(DID1, SW1, devices.get(DID1));
269 assertDevice(DID2, SW2, devices.get(DID2));
270
271 // add case for new node?
272 }
273
274 @Test
275 public final void testGetDevice() {
276
277 putDevice(DID1, SW1);
278
279 assertDevice(DID1, SW1, deviceStore.getDevice(DID1));
280 assertNull("DID2 shouldn't be there", deviceStore.getDevice(DID2));
281 }
282
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700283 private void assertInternalDeviceEvent(NodeId sender,
284 DeviceId deviceId,
285 ProviderId providerId,
286 DeviceDescription expectedDesc,
287 Capture<ClusterMessage> actualMsg) {
288 assertTrue(actualMsg.hasCaptured());
289 assertEquals(sender, actualMsg.getValue().sender());
290 assertEquals(GossipDeviceStoreMessageSubjects.DEVICE_UPDATE,
291 actualMsg.getValue().subject());
292 InternalDeviceEvent addEvent
293 = testGossipDeviceStore.deserialize(actualMsg.getValue().payload());
294 assertEquals(deviceId, addEvent.deviceId());
295 assertEquals(providerId, addEvent.providerId());
296 assertDeviceDescriptionEquals(expectedDesc, addEvent.deviceDescription().value());
297 }
298
299 private void assertInternalDeviceEvent(NodeId sender,
300 DeviceId deviceId,
301 ProviderId providerId,
302 DeviceDescription expectedDesc,
303 List<SparseAnnotations> expectedAnnotations,
304 Capture<ClusterMessage> actualMsg) {
305 assertTrue(actualMsg.hasCaptured());
306 assertEquals(sender, actualMsg.getValue().sender());
307 assertEquals(GossipDeviceStoreMessageSubjects.DEVICE_UPDATE,
308 actualMsg.getValue().subject());
309 InternalDeviceEvent addEvent
310 = testGossipDeviceStore.deserialize(actualMsg.getValue().payload());
311 assertEquals(deviceId, addEvent.deviceId());
312 assertEquals(providerId, addEvent.providerId());
313 assertDeviceDescriptionEquals(expectedDesc, expectedAnnotations, addEvent.deviceDescription().value());
314 }
315
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700316 @Test
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700317 public final void testCreateOrUpdateDevice() throws IOException {
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700318 DeviceDescription description =
319 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
alshabib7911a052014-10-16 17:49:37 -0700320 HW, SW1, SN, CID);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700321 Capture<ClusterMessage> bcast = new Capture<>();
322
323 resetCommunicatorExpectingSingleBroadcast(bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700324 DeviceEvent event = deviceStore.createOrUpdateDevice(PID, DID1, description);
325 assertEquals(DEVICE_ADDED, event.type());
326 assertDevice(DID1, SW1, event.subject());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700327 verify(clusterCommunicator);
328 assertInternalDeviceEvent(NID1, DID1, PID, description, bcast);
329
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700330
331 DeviceDescription description2 =
332 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
alshabib7911a052014-10-16 17:49:37 -0700333 HW, SW2, SN, CID);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700334 resetCommunicatorExpectingSingleBroadcast(bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700335 DeviceEvent event2 = deviceStore.createOrUpdateDevice(PID, DID1, description2);
336 assertEquals(DEVICE_UPDATED, event2.type());
337 assertDevice(DID1, SW2, event2.subject());
338
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700339 verify(clusterCommunicator);
340 assertInternalDeviceEvent(NID1, DID1, PID, description2, bcast);
341 reset(clusterCommunicator);
342
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700343 assertNull("No change expected", deviceStore.createOrUpdateDevice(PID, DID1, description2));
344 }
345
346 @Test
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700347 public final void testCreateOrUpdateDeviceAncillary() throws IOException {
348 // add
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700349 DeviceDescription description =
350 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
alshabib7911a052014-10-16 17:49:37 -0700351 HW, SW1, SN, CID, A2);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700352 Capture<ClusterMessage> bcast = new Capture<>();
353
354 resetCommunicatorExpectingSingleBroadcast(bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700355 DeviceEvent event = deviceStore.createOrUpdateDevice(PIDA, DID1, description);
356 assertEquals(DEVICE_ADDED, event.type());
357 assertDevice(DID1, SW1, event.subject());
358 assertEquals(PIDA, event.subject().providerId());
359 assertAnnotationsEquals(event.subject().annotations(), A2);
360 assertFalse("Ancillary will not bring device up", deviceStore.isAvailable(DID1));
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700361 verify(clusterCommunicator);
362 assertInternalDeviceEvent(NID1, DID1, PIDA, description, bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700363
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700364 // update from primary
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700365 DeviceDescription description2 =
366 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
alshabib7911a052014-10-16 17:49:37 -0700367 HW, SW2, SN, CID, A1);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700368 resetCommunicatorExpectingSingleBroadcast(bcast);
369
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700370 DeviceEvent event2 = deviceStore.createOrUpdateDevice(PID, DID1, description2);
371 assertEquals(DEVICE_UPDATED, event2.type());
372 assertDevice(DID1, SW2, event2.subject());
373 assertEquals(PID, event2.subject().providerId());
374 assertAnnotationsEquals(event2.subject().annotations(), A1, A2);
375 assertTrue(deviceStore.isAvailable(DID1));
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700376 verify(clusterCommunicator);
377 assertInternalDeviceEvent(NID1, DID1, PID, description2, bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700378
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700379 // no-op update from primary
380 resetCommunicatorExpectingNoBroadcast(bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700381 assertNull("No change expected", deviceStore.createOrUpdateDevice(PID, DID1, description2));
382
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700383 verify(clusterCommunicator);
384 assertFalse("no broadcast expected", bcast.hasCaptured());
385
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700386 // For now, Ancillary is ignored once primary appears
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700387 resetCommunicatorExpectingNoBroadcast(bcast);
388
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700389 assertNull("No change expected", deviceStore.createOrUpdateDevice(PIDA, DID1, description));
390
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700391 verify(clusterCommunicator);
392 assertFalse("no broadcast expected", bcast.hasCaptured());
393
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700394 // But, Ancillary annotations will be in effect
395 DeviceDescription description3 =
396 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
alshabib7911a052014-10-16 17:49:37 -0700397 HW, SW1, SN, CID, A2_2);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700398 resetCommunicatorExpectingSingleBroadcast(bcast);
399
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700400 DeviceEvent event3 = deviceStore.createOrUpdateDevice(PIDA, DID1, description3);
401 assertEquals(DEVICE_UPDATED, event3.type());
402 // basic information will be the one from Primary
403 assertDevice(DID1, SW2, event3.subject());
404 assertEquals(PID, event3.subject().providerId());
405 // but annotation from Ancillary will be merged
406 assertAnnotationsEquals(event3.subject().annotations(), A1, A2, A2_2);
407 assertTrue(deviceStore.isAvailable(DID1));
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700408 verify(clusterCommunicator);
409 // note: only annotation from PIDA is sent over the wire
410 assertInternalDeviceEvent(NID1, DID1, PIDA, description3,
411 asList(union(A2, A2_2)), bcast);
412
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700413 }
414
415
416 @Test
417 public final void testMarkOffline() {
418
419 putDevice(DID1, SW1);
420 assertTrue(deviceStore.isAvailable(DID1));
421
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700422 Capture<ClusterMessage> bcast = new Capture<>();
423
424 resetCommunicatorExpectingSingleBroadcast(bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700425 DeviceEvent event = deviceStore.markOffline(DID1);
426 assertEquals(DEVICE_AVAILABILITY_CHANGED, event.type());
427 assertDevice(DID1, SW1, event.subject());
428 assertFalse(deviceStore.isAvailable(DID1));
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700429 verify(clusterCommunicator);
430 // TODO: verify broadcast message
431 assertTrue(bcast.hasCaptured());
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700432
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700433
434 resetCommunicatorExpectingNoBroadcast(bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700435 DeviceEvent event2 = deviceStore.markOffline(DID1);
436 assertNull("No change, no event", event2);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700437 verify(clusterCommunicator);
438 assertFalse(bcast.hasCaptured());
439 }
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700440
441 @Test
442 public final void testUpdatePorts() {
443 putDevice(DID1, SW1);
444 List<PortDescription> pds = Arrays.<PortDescription>asList(
445 new DefaultPortDescription(P1, true),
446 new DefaultPortDescription(P2, true)
447 );
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700448 Capture<ClusterMessage> bcast = new Capture<>();
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700449
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700450 resetCommunicatorExpectingSingleBroadcast(bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700451 List<DeviceEvent> events = deviceStore.updatePorts(PID, DID1, pds);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700452 verify(clusterCommunicator);
453 // TODO: verify broadcast message
454 assertTrue(bcast.hasCaptured());
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700455
456 Set<PortNumber> expectedPorts = Sets.newHashSet(P1, P2);
457 for (DeviceEvent event : events) {
458 assertEquals(PORT_ADDED, event.type());
459 assertDevice(DID1, SW1, event.subject());
460 assertTrue("PortNumber is one of expected",
461 expectedPorts.remove(event.port().number()));
462 assertTrue("Port is enabled", event.port().isEnabled());
463 }
464 assertTrue("Event for all expectedport appeared", expectedPorts.isEmpty());
465
466
467 List<PortDescription> pds2 = Arrays.<PortDescription>asList(
468 new DefaultPortDescription(P1, false),
469 new DefaultPortDescription(P2, true),
470 new DefaultPortDescription(P3, true)
471 );
472
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700473 resetCommunicatorExpectingSingleBroadcast(bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700474 events = deviceStore.updatePorts(PID, DID1, pds2);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700475 verify(clusterCommunicator);
476 // TODO: verify broadcast message
477 assertTrue(bcast.hasCaptured());
478
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700479 assertFalse("event should be triggered", events.isEmpty());
480 for (DeviceEvent event : events) {
481 PortNumber num = event.port().number();
482 if (P1.equals(num)) {
483 assertEquals(PORT_UPDATED, event.type());
484 assertDevice(DID1, SW1, event.subject());
485 assertFalse("Port is disabled", event.port().isEnabled());
486 } else if (P2.equals(num)) {
487 fail("P2 event not expected.");
488 } else if (P3.equals(num)) {
489 assertEquals(PORT_ADDED, event.type());
490 assertDevice(DID1, SW1, event.subject());
491 assertTrue("Port is enabled", event.port().isEnabled());
492 } else {
493 fail("Unknown port number encountered: " + num);
494 }
495 }
496
497 List<PortDescription> pds3 = Arrays.<PortDescription>asList(
498 new DefaultPortDescription(P1, false),
499 new DefaultPortDescription(P2, true)
500 );
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700501 resetCommunicatorExpectingSingleBroadcast(bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700502 events = deviceStore.updatePorts(PID, DID1, pds3);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700503 verify(clusterCommunicator);
504 // TODO: verify broadcast message
505 assertTrue(bcast.hasCaptured());
506
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700507 assertFalse("event should be triggered", events.isEmpty());
508 for (DeviceEvent event : events) {
509 PortNumber num = event.port().number();
510 if (P1.equals(num)) {
511 fail("P1 event not expected.");
512 } else if (P2.equals(num)) {
513 fail("P2 event not expected.");
514 } else if (P3.equals(num)) {
515 assertEquals(PORT_REMOVED, event.type());
516 assertDevice(DID1, SW1, event.subject());
517 assertTrue("Port was enabled", event.port().isEnabled());
518 } else {
519 fail("Unknown port number encountered: " + num);
520 }
521 }
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700522 }
523
524 @Test
525 public final void testUpdatePortStatus() {
526 putDevice(DID1, SW1);
527 List<PortDescription> pds = Arrays.<PortDescription>asList(
528 new DefaultPortDescription(P1, true)
529 );
530 deviceStore.updatePorts(PID, DID1, pds);
531
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700532 Capture<ClusterMessage> bcast = new Capture<>();
533
534 resetCommunicatorExpectingSingleBroadcast(bcast);
535 final DefaultPortDescription desc = new DefaultPortDescription(P1, false);
536 DeviceEvent event = deviceStore.updatePortStatus(PID, DID1, desc);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700537 assertEquals(PORT_UPDATED, event.type());
538 assertDevice(DID1, SW1, event.subject());
539 assertEquals(P1, event.port().number());
540 assertFalse("Port is disabled", event.port().isEnabled());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700541 verify(clusterCommunicator);
542 assertInternalPortStatusEvent(NID1, DID1, PID, desc, NO_ANNOTATION, bcast);
543 assertTrue(bcast.hasCaptured());
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700544 }
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700545
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700546 @Test
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700547 public final void testUpdatePortStatusAncillary() throws IOException {
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700548 putDeviceAncillary(DID1, SW1);
549 putDevice(DID1, SW1);
550 List<PortDescription> pds = Arrays.<PortDescription>asList(
551 new DefaultPortDescription(P1, true, A1)
552 );
553 deviceStore.updatePorts(PID, DID1, pds);
554
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700555 Capture<ClusterMessage> bcast = new Capture<>();
556
557
558 // update port from primary
559 resetCommunicatorExpectingSingleBroadcast(bcast);
560 final DefaultPortDescription desc1 = new DefaultPortDescription(P1, false, A1_2);
561 DeviceEvent event = deviceStore.updatePortStatus(PID, DID1, desc1);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700562 assertEquals(PORT_UPDATED, event.type());
563 assertDevice(DID1, SW1, event.subject());
564 assertEquals(P1, event.port().number());
565 assertAnnotationsEquals(event.port().annotations(), A1, A1_2);
566 assertFalse("Port is disabled", event.port().isEnabled());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700567 verify(clusterCommunicator);
568 assertInternalPortStatusEvent(NID1, DID1, PID, desc1, asList(A1, A1_2), bcast);
569 assertTrue(bcast.hasCaptured());
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700570
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700571 // update port from ancillary with no attributes
572 resetCommunicatorExpectingNoBroadcast(bcast);
573 final DefaultPortDescription desc2 = new DefaultPortDescription(P1, true);
574 DeviceEvent event2 = deviceStore.updatePortStatus(PIDA, DID1, desc2);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700575 assertNull("Ancillary is ignored if primary exists", event2);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700576 verify(clusterCommunicator);
577 assertFalse(bcast.hasCaptured());
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700578
579 // but, Ancillary annotation update will be notified
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700580 resetCommunicatorExpectingSingleBroadcast(bcast);
581 final DefaultPortDescription desc3 = new DefaultPortDescription(P1, true, A2);
582 DeviceEvent event3 = deviceStore.updatePortStatus(PIDA, DID1, desc3);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700583 assertEquals(PORT_UPDATED, event3.type());
584 assertDevice(DID1, SW1, event3.subject());
585 assertEquals(P1, event3.port().number());
586 assertAnnotationsEquals(event3.port().annotations(), A1, A1_2, A2);
587 assertFalse("Port is disabled", event3.port().isEnabled());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700588 verify(clusterCommunicator);
589 assertInternalPortStatusEvent(NID1, DID1, PIDA, desc3, asList(A2), bcast);
590 assertTrue(bcast.hasCaptured());
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700591
592 // port only reported from Ancillary will be notified as down
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700593 resetCommunicatorExpectingSingleBroadcast(bcast);
594 final DefaultPortDescription desc4 = new DefaultPortDescription(P2, true);
595 DeviceEvent event4 = deviceStore.updatePortStatus(PIDA, DID1, desc4);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700596 assertEquals(PORT_ADDED, event4.type());
597 assertDevice(DID1, SW1, event4.subject());
598 assertEquals(P2, event4.port().number());
599 assertAnnotationsEquals(event4.port().annotations());
600 assertFalse("Port is disabled if not given from primary provider",
601 event4.port().isEnabled());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700602 verify(clusterCommunicator);
603 // TODO: verify broadcast message content
604 assertInternalPortStatusEvent(NID1, DID1, PIDA, desc4, NO_ANNOTATION, bcast);
605 assertTrue(bcast.hasCaptured());
606 }
607
608 private void assertInternalPortStatusEvent(NodeId sender, DeviceId did,
609 ProviderId pid, DefaultPortDescription expectedDesc,
610 List<SparseAnnotations> expectedAnnotations, Capture<ClusterMessage> actualMsg) {
611
612 assertTrue(actualMsg.hasCaptured());
613 assertEquals(sender, actualMsg.getValue().sender());
614 assertEquals(GossipDeviceStoreMessageSubjects.PORT_STATUS_UPDATE,
615 actualMsg.getValue().subject());
616 InternalPortStatusEvent addEvent
617 = testGossipDeviceStore.deserialize(actualMsg.getValue().payload());
618 assertEquals(did, addEvent.deviceId());
619 assertEquals(pid, addEvent.providerId());
620 assertPortDescriptionEquals(expectedDesc, expectedAnnotations,
621 addEvent.portDescription().value());
622
623 }
624
625 private void assertPortDescriptionEquals(
626 PortDescription expectedDesc,
627 List<SparseAnnotations> expectedAnnotations,
628 PortDescription actual) {
629
630 assertEquals(expectedDesc.portNumber(), actual.portNumber());
631 assertEquals(expectedDesc.isEnabled(), actual.isEnabled());
632
633 assertAnnotationsEquals(actual.annotations(),
634 expectedAnnotations.toArray(new SparseAnnotations[0]));
635 }
636
637 private void resetCommunicatorExpectingNoBroadcast(
638 Capture<ClusterMessage> bcast) {
639 bcast.reset();
640 reset(clusterCommunicator);
641 replay(clusterCommunicator);
642 }
643
644 private void resetCommunicatorExpectingSingleBroadcast(
645 Capture<ClusterMessage> bcast) {
646
647 bcast.reset();
648 reset(clusterCommunicator);
649 try {
650 expect(clusterCommunicator.broadcast(capture(bcast))).andReturn(true).once();
651 } catch (IOException e) {
652 fail("Should never reach here");
653 }
654 replay(clusterCommunicator);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700655 }
656
657 @Test
658 public final void testGetPorts() {
659 putDevice(DID1, SW1);
660 putDevice(DID2, SW1);
661 List<PortDescription> pds = Arrays.<PortDescription>asList(
662 new DefaultPortDescription(P1, true),
663 new DefaultPortDescription(P2, true)
664 );
665 deviceStore.updatePorts(PID, DID1, pds);
666
667 Set<PortNumber> expectedPorts = Sets.newHashSet(P1, P2);
668 List<Port> ports = deviceStore.getPorts(DID1);
669 for (Port port : ports) {
670 assertTrue("Port is enabled", port.isEnabled());
671 assertTrue("PortNumber is one of expected",
672 expectedPorts.remove(port.number()));
673 }
674 assertTrue("Event for all expectedport appeared", expectedPorts.isEmpty());
675
676
677 assertTrue("DID2 has no ports", deviceStore.getPorts(DID2).isEmpty());
678 }
679
680 @Test
681 public final void testGetPort() {
682 putDevice(DID1, SW1);
683 putDevice(DID2, SW1);
684 List<PortDescription> pds = Arrays.<PortDescription>asList(
685 new DefaultPortDescription(P1, true),
686 new DefaultPortDescription(P2, false)
687 );
688 deviceStore.updatePorts(PID, DID1, pds);
689
690 Port port1 = deviceStore.getPort(DID1, P1);
691 assertEquals(P1, port1.number());
692 assertTrue("Port is enabled", port1.isEnabled());
693
694 Port port2 = deviceStore.getPort(DID1, P2);
695 assertEquals(P2, port2.number());
696 assertFalse("Port is disabled", port2.isEnabled());
697
698 Port port3 = deviceStore.getPort(DID1, P3);
699 assertNull("P3 not expected", port3);
700 }
701
702 @Test
703 public final void testRemoveDevice() {
Yuta HIGUCHI0d6a5e62014-10-03 15:54:09 -0700704 putDevice(DID1, SW1, A1);
705 List<PortDescription> pds = Arrays.<PortDescription>asList(
706 new DefaultPortDescription(P1, true, A2)
707 );
708 deviceStore.updatePorts(PID, DID1, pds);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700709 putDevice(DID2, SW1);
710
711 assertEquals(2, deviceStore.getDeviceCount());
Yuta HIGUCHI0d6a5e62014-10-03 15:54:09 -0700712 assertEquals(1, deviceStore.getPorts(DID1).size());
713 assertAnnotationsEquals(deviceStore.getDevice(DID1).annotations(), A1);
714 assertAnnotationsEquals(deviceStore.getPort(DID1, P1).annotations(), A2);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700715
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700716 Capture<ClusterMessage> bcast = new Capture<>();
717
718 resetCommunicatorExpectingSingleBroadcast(bcast);
719
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700720 DeviceEvent event = deviceStore.removeDevice(DID1);
721 assertEquals(DEVICE_REMOVED, event.type());
722 assertDevice(DID1, SW1, event.subject());
723
724 assertEquals(1, deviceStore.getDeviceCount());
Yuta HIGUCHI0d6a5e62014-10-03 15:54:09 -0700725 assertEquals(0, deviceStore.getPorts(DID1).size());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700726 verify(clusterCommunicator);
727 // TODO: verify broadcast message
728 assertTrue(bcast.hasCaptured());
Yuta HIGUCHI0d6a5e62014-10-03 15:54:09 -0700729
730 // putBack Device, Port w/o annotation
731 putDevice(DID1, SW1);
732 List<PortDescription> pds2 = Arrays.<PortDescription>asList(
733 new DefaultPortDescription(P1, true)
734 );
735 deviceStore.updatePorts(PID, DID1, pds2);
736
737 // annotations should not survive
738 assertEquals(2, deviceStore.getDeviceCount());
739 assertEquals(1, deviceStore.getPorts(DID1).size());
740 assertAnnotationsEquals(deviceStore.getDevice(DID1).annotations());
741 assertAnnotationsEquals(deviceStore.getPort(DID1, P1).annotations());
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700742 }
743
744 // If Delegates should be called only on remote events,
745 // then Simple* should never call them, thus not test required.
746 // TODO add test for Port events when we have them
747 @Ignore("Ignore until Delegate spec. is clear.")
748 @Test
749 public final void testEvents() throws InterruptedException {
750 final CountDownLatch addLatch = new CountDownLatch(1);
751 DeviceStoreDelegate checkAdd = new DeviceStoreDelegate() {
752 @Override
753 public void notify(DeviceEvent event) {
754 assertEquals(DEVICE_ADDED, event.type());
755 assertDevice(DID1, SW1, event.subject());
756 addLatch.countDown();
757 }
758 };
759 final CountDownLatch updateLatch = new CountDownLatch(1);
760 DeviceStoreDelegate checkUpdate = new DeviceStoreDelegate() {
761 @Override
762 public void notify(DeviceEvent event) {
763 assertEquals(DEVICE_UPDATED, event.type());
764 assertDevice(DID1, SW2, event.subject());
765 updateLatch.countDown();
766 }
767 };
768 final CountDownLatch removeLatch = new CountDownLatch(1);
769 DeviceStoreDelegate checkRemove = new DeviceStoreDelegate() {
770 @Override
771 public void notify(DeviceEvent event) {
772 assertEquals(DEVICE_REMOVED, event.type());
773 assertDevice(DID1, SW2, event.subject());
774 removeLatch.countDown();
775 }
776 };
777
778 DeviceDescription description =
779 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
alshabib7911a052014-10-16 17:49:37 -0700780 HW, SW1, SN, CID);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700781 deviceStore.setDelegate(checkAdd);
782 deviceStore.createOrUpdateDevice(PID, DID1, description);
783 assertTrue("Add event fired", addLatch.await(1, TimeUnit.SECONDS));
784
785
786 DeviceDescription description2 =
787 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
alshabib7911a052014-10-16 17:49:37 -0700788 HW, SW2, SN, CID);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700789 deviceStore.unsetDelegate(checkAdd);
790 deviceStore.setDelegate(checkUpdate);
791 deviceStore.createOrUpdateDevice(PID, DID1, description2);
792 assertTrue("Update event fired", updateLatch.await(1, TimeUnit.SECONDS));
793
794 deviceStore.unsetDelegate(checkUpdate);
795 deviceStore.setDelegate(checkRemove);
796 deviceStore.removeDevice(DID1);
797 assertTrue("Remove event fired", removeLatch.await(1, TimeUnit.SECONDS));
798 }
799
800 private static final class TestGossipDeviceStore extends GossipDeviceStore {
801
Madan Jampani53e44e62014-10-07 12:39:51 -0700802 public TestGossipDeviceStore(
Yuta HIGUCHI093e83e2014-10-10 22:26:11 -0700803 DeviceClockService deviceClockService,
Madan Jampani53e44e62014-10-07 12:39:51 -0700804 ClusterService clusterService,
805 ClusterCommunicationService clusterCommunicator) {
Yuta HIGUCHI093e83e2014-10-10 22:26:11 -0700806 this.deviceClockService = deviceClockService;
Madan Jampani53e44e62014-10-07 12:39:51 -0700807 this.clusterService = clusterService;
Madan Jampani47c93732014-10-06 20:46:08 -0700808 this.clusterCommunicator = clusterCommunicator;
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700809 }
Madan Jampani47c93732014-10-06 20:46:08 -0700810
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700811 public <T> T deserialize(byte[] bytes) {
812 return SERIALIZER.decode(bytes);
813 }
Madan Jampani47c93732014-10-06 20:46:08 -0700814 }
Madan Jampani53e44e62014-10-07 12:39:51 -0700815
816 private static final class TestClusterService implements ClusterService {
817
Madan Jampani53e44e62014-10-07 12:39:51 -0700818 private final Map<NodeId, ControllerNode> nodes = new HashMap<>();
819 private final Map<NodeId, ControllerNode.State> nodeStates = new HashMap<>();
820
821 public TestClusterService() {
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700822 nodes.put(NID1, ONOS1);
823 nodeStates.put(NID1, ACTIVE);
824
825 nodes.put(NID2, ONOS2);
826 nodeStates.put(NID2, ACTIVE);
Madan Jampani53e44e62014-10-07 12:39:51 -0700827 }
828
829 @Override
830 public ControllerNode getLocalNode() {
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700831 return GossipDeviceStoreTest.ONOS1;
Madan Jampani53e44e62014-10-07 12:39:51 -0700832 }
833
834 @Override
835 public Set<ControllerNode> getNodes() {
836 return Sets.newHashSet(nodes.values());
837 }
838
839 @Override
840 public ControllerNode getNode(NodeId nodeId) {
841 return nodes.get(nodeId);
842 }
843
844 @Override
845 public State getState(NodeId nodeId) {
846 return nodeStates.get(nodeId);
847 }
848
849 @Override
850 public void addListener(ClusterEventListener listener) {
851 }
852
853 @Override
854 public void removeListener(ClusterEventListener listener) {
855 }
856 }
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700857}