blob: 975a7f8483095042c86b640f721a92f4896f7234 [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 HIGUCHIe8252bb2014-10-22 09:41:01 -070035import org.onlab.onos.mastership.MastershipServiceAdapter;
Yuta HIGUCHI80912e62014-10-12 00:15:47 -070036import org.onlab.onos.mastership.MastershipTerm;
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -070037import org.onlab.onos.net.Annotations;
38import org.onlab.onos.net.DefaultAnnotations;
39import org.onlab.onos.net.Device;
40import org.onlab.onos.net.DeviceId;
41import org.onlab.onos.net.Port;
42import org.onlab.onos.net.PortNumber;
43import org.onlab.onos.net.SparseAnnotations;
44import org.onlab.onos.net.device.DefaultDeviceDescription;
45import org.onlab.onos.net.device.DefaultPortDescription;
Yuta HIGUCHI093e83e2014-10-10 22:26:11 -070046import org.onlab.onos.net.device.DeviceClockService;
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -070047import org.onlab.onos.net.device.DeviceDescription;
48import org.onlab.onos.net.device.DeviceEvent;
49import org.onlab.onos.net.device.DeviceStore;
50import org.onlab.onos.net.device.DeviceStoreDelegate;
51import org.onlab.onos.net.device.PortDescription;
52import org.onlab.onos.net.provider.ProviderId;
Madan Jampani47c93732014-10-06 20:46:08 -070053import org.onlab.onos.store.cluster.messaging.ClusterCommunicationService;
54import org.onlab.onos.store.cluster.messaging.ClusterMessage;
55import org.onlab.onos.store.cluster.messaging.ClusterMessageHandler;
56import org.onlab.onos.store.cluster.messaging.MessageSubject;
alshabib7911a052014-10-16 17:49:37 -070057import org.onlab.packet.ChassisId;
Madan Jampani53e44e62014-10-07 12:39:51 -070058import org.onlab.packet.IpPrefix;
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -070059
60import com.google.common.collect.Iterables;
61import com.google.common.collect.Sets;
62
63
64// TODO add tests for remote replication
65/**
66 * Test of the gossip based distributed DeviceStore implementation.
67 */
68public class GossipDeviceStoreTest {
69
70 private static final ProviderId PID = new ProviderId("of", "foo");
71 private static final ProviderId PIDA = new ProviderId("of", "bar", true);
72 private static final DeviceId DID1 = deviceId("of:foo");
73 private static final DeviceId DID2 = deviceId("of:bar");
74 private static final String MFR = "whitebox";
75 private static final String HW = "1.1.x";
76 private static final String SW1 = "3.8.1";
77 private static final String SW2 = "3.9.5";
78 private static final String SN = "43311-12345";
alshabib7911a052014-10-16 17:49:37 -070079 private static final ChassisId CID = new ChassisId();
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -070080
81 private static final PortNumber P1 = PortNumber.portNumber(1);
82 private static final PortNumber P2 = PortNumber.portNumber(2);
83 private static final PortNumber P3 = PortNumber.portNumber(3);
84
85 private static final SparseAnnotations A1 = DefaultAnnotations.builder()
86 .set("A1", "a1")
87 .set("B1", "b1")
88 .build();
89 private static final SparseAnnotations A1_2 = DefaultAnnotations.builder()
90 .remove("A1")
91 .set("B3", "b3")
92 .build();
93 private static final SparseAnnotations A2 = DefaultAnnotations.builder()
94 .set("A2", "a2")
95 .set("B2", "b2")
96 .build();
97 private static final SparseAnnotations A2_2 = DefaultAnnotations.builder()
98 .remove("A2")
99 .set("B4", "b4")
100 .build();
101
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700102 // local node
103 private static final NodeId NID1 = new NodeId("local");
104 private static final ControllerNode ONOS1 =
105 new DefaultControllerNode(NID1, IpPrefix.valueOf("127.0.0.1"));
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700106
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700107 // remote node
108 private static final NodeId NID2 = new NodeId("remote");
109 private static final ControllerNode ONOS2 =
110 new DefaultControllerNode(NID2, IpPrefix.valueOf("127.0.0.2"));
111 private static final List<SparseAnnotations> NO_ANNOTATION = Collections.<SparseAnnotations>emptyList();
112
113
114 private TestGossipDeviceStore testGossipDeviceStore;
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700115 private GossipDeviceStore gossipDeviceStore;
116 private DeviceStore deviceStore;
117
118 private DeviceClockManager deviceClockManager;
Yuta HIGUCHI093e83e2014-10-10 22:26:11 -0700119 private DeviceClockService deviceClockService;
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700120 private ClusterCommunicationService clusterCommunicator;
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700121 @BeforeClass
122 public static void setUpBeforeClass() throws Exception {
123 }
124
125 @AfterClass
126 public static void tearDownAfterClass() throws Exception {
127 }
128
129
130 @Before
131 public void setUp() throws Exception {
132 deviceClockManager = new DeviceClockManager();
133 deviceClockManager.activate();
Yuta HIGUCHI093e83e2014-10-10 22:26:11 -0700134 deviceClockService = deviceClockManager;
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700135
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700136 deviceClockManager.setMastershipTerm(DID1, MastershipTerm.of(NID1, 1));
137 deviceClockManager.setMastershipTerm(DID2, MastershipTerm.of(NID1, 2));
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700138
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700139 clusterCommunicator = createNiceMock(ClusterCommunicationService.class);
140 clusterCommunicator.addSubscriber(anyObject(MessageSubject.class),
141 anyObject(ClusterMessageHandler.class));
142 expectLastCall().anyTimes();
143 replay(clusterCommunicator);
Madan Jampani53e44e62014-10-07 12:39:51 -0700144 ClusterService clusterService = new TestClusterService();
Madan Jampani47c93732014-10-06 20:46:08 -0700145
Yuta HIGUCHI093e83e2014-10-10 22:26:11 -0700146 testGossipDeviceStore = new TestGossipDeviceStore(deviceClockService, clusterService, clusterCommunicator);
Yuta HIGUCHIe8252bb2014-10-22 09:41:01 -0700147 testGossipDeviceStore.mastershipService = new TestMastershipService();
148
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700149 gossipDeviceStore = testGossipDeviceStore;
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700150 gossipDeviceStore.activate();
151 deviceStore = gossipDeviceStore;
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700152 verify(clusterCommunicator);
153 reset(clusterCommunicator);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700154 }
155
156 @After
157 public void tearDown() throws Exception {
158 gossipDeviceStore.deactivate();
159 deviceClockManager.deactivate();
160 }
161
Yuta HIGUCHI0d6a5e62014-10-03 15:54:09 -0700162 private void putDevice(DeviceId deviceId, String swVersion,
163 SparseAnnotations... annotations) {
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700164 DeviceDescription description =
165 new DefaultDeviceDescription(deviceId.uri(), SWITCH, MFR,
alshabib7911a052014-10-16 17:49:37 -0700166 HW, swVersion, SN, CID, annotations);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700167 reset(clusterCommunicator);
168 try {
169 expect(clusterCommunicator.broadcast(anyObject(ClusterMessage.class)))
170 .andReturn(true).anyTimes();
171 } catch (IOException e) {
172 fail("Should never reach here");
173 }
174 replay(clusterCommunicator);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700175 deviceStore.createOrUpdateDevice(PID, deviceId, description);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700176 verify(clusterCommunicator);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700177 }
178
Yuta HIGUCHI0d6a5e62014-10-03 15:54:09 -0700179 private void putDeviceAncillary(DeviceId deviceId, String swVersion,
180 SparseAnnotations... annotations) {
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700181 DeviceDescription description =
182 new DefaultDeviceDescription(deviceId.uri(), SWITCH, MFR,
alshabib7911a052014-10-16 17:49:37 -0700183 HW, swVersion, SN, CID, annotations);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700184 deviceStore.createOrUpdateDevice(PIDA, deviceId, description);
185 }
186
187 private static void assertDevice(DeviceId id, String swVersion, Device device) {
188 assertNotNull(device);
189 assertEquals(id, device.id());
190 assertEquals(MFR, device.manufacturer());
191 assertEquals(HW, device.hwVersion());
192 assertEquals(swVersion, device.swVersion());
193 assertEquals(SN, device.serialNumber());
194 }
195
196 /**
197 * Verifies that Annotations created by merging {@code annotations} is
198 * equal to actual Annotations.
199 *
200 * @param actual Annotations to check
201 * @param annotations
202 */
203 private static void assertAnnotationsEquals(Annotations actual, SparseAnnotations... annotations) {
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700204 SparseAnnotations expected = DefaultAnnotations.builder().build();
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700205 for (SparseAnnotations a : annotations) {
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700206 expected = DefaultAnnotations.union(expected, a);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700207 }
208 assertEquals(expected.keys(), actual.keys());
209 for (String key : expected.keys()) {
210 assertEquals(expected.value(key), actual.value(key));
211 }
212 }
213
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700214 private static void assertDeviceDescriptionEquals(DeviceDescription expected,
215 DeviceDescription actual) {
216 if (expected == actual) {
217 return;
218 }
219 assertEquals(expected.deviceURI(), actual.deviceURI());
220 assertEquals(expected.hwVersion(), actual.hwVersion());
221 assertEquals(expected.manufacturer(), actual.manufacturer());
222 assertEquals(expected.serialNumber(), actual.serialNumber());
223 assertEquals(expected.swVersion(), actual.swVersion());
224
225 assertAnnotationsEquals(actual.annotations(), expected.annotations());
226 }
227
228 private static void assertDeviceDescriptionEquals(DeviceDescription expected,
229 List<SparseAnnotations> expectedAnnotations,
230 DeviceDescription actual) {
231 if (expected == actual) {
232 return;
233 }
234 assertEquals(expected.deviceURI(), actual.deviceURI());
235 assertEquals(expected.hwVersion(), actual.hwVersion());
236 assertEquals(expected.manufacturer(), actual.manufacturer());
237 assertEquals(expected.serialNumber(), actual.serialNumber());
238 assertEquals(expected.swVersion(), actual.swVersion());
239
240 assertAnnotationsEquals(actual.annotations(),
241 expectedAnnotations.toArray(new SparseAnnotations[0]));
242 }
243
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700244 @Test
245 public final void testGetDeviceCount() {
246 assertEquals("initialy empty", 0, deviceStore.getDeviceCount());
247
248 putDevice(DID1, SW1);
249 putDevice(DID2, SW2);
250 putDevice(DID1, SW1);
251
252 assertEquals("expect 2 uniq devices", 2, deviceStore.getDeviceCount());
253 }
254
255 @Test
256 public final void testGetDevices() {
257 assertEquals("initialy empty", 0, Iterables.size(deviceStore.getDevices()));
258
259 putDevice(DID1, SW1);
260 putDevice(DID2, SW2);
261 putDevice(DID1, SW1);
262
263 assertEquals("expect 2 uniq devices",
264 2, Iterables.size(deviceStore.getDevices()));
265
266 Map<DeviceId, Device> devices = new HashMap<>();
267 for (Device device : deviceStore.getDevices()) {
268 devices.put(device.id(), device);
269 }
270
271 assertDevice(DID1, SW1, devices.get(DID1));
272 assertDevice(DID2, SW2, devices.get(DID2));
273
274 // add case for new node?
275 }
276
277 @Test
278 public final void testGetDevice() {
279
280 putDevice(DID1, SW1);
281
282 assertDevice(DID1, SW1, deviceStore.getDevice(DID1));
283 assertNull("DID2 shouldn't be there", deviceStore.getDevice(DID2));
284 }
285
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700286 private void assertInternalDeviceEvent(NodeId sender,
287 DeviceId deviceId,
288 ProviderId providerId,
289 DeviceDescription expectedDesc,
290 Capture<ClusterMessage> actualMsg) {
291 assertTrue(actualMsg.hasCaptured());
292 assertEquals(sender, actualMsg.getValue().sender());
293 assertEquals(GossipDeviceStoreMessageSubjects.DEVICE_UPDATE,
294 actualMsg.getValue().subject());
295 InternalDeviceEvent addEvent
296 = testGossipDeviceStore.deserialize(actualMsg.getValue().payload());
297 assertEquals(deviceId, addEvent.deviceId());
298 assertEquals(providerId, addEvent.providerId());
299 assertDeviceDescriptionEquals(expectedDesc, addEvent.deviceDescription().value());
300 }
301
302 private void assertInternalDeviceEvent(NodeId sender,
303 DeviceId deviceId,
304 ProviderId providerId,
305 DeviceDescription expectedDesc,
306 List<SparseAnnotations> expectedAnnotations,
307 Capture<ClusterMessage> actualMsg) {
308 assertTrue(actualMsg.hasCaptured());
309 assertEquals(sender, actualMsg.getValue().sender());
310 assertEquals(GossipDeviceStoreMessageSubjects.DEVICE_UPDATE,
311 actualMsg.getValue().subject());
312 InternalDeviceEvent addEvent
313 = testGossipDeviceStore.deserialize(actualMsg.getValue().payload());
314 assertEquals(deviceId, addEvent.deviceId());
315 assertEquals(providerId, addEvent.providerId());
316 assertDeviceDescriptionEquals(expectedDesc, expectedAnnotations, addEvent.deviceDescription().value());
317 }
318
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700319 @Test
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700320 public final void testCreateOrUpdateDevice() throws IOException {
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700321 DeviceDescription description =
322 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
alshabib7911a052014-10-16 17:49:37 -0700323 HW, SW1, SN, CID);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700324 Capture<ClusterMessage> bcast = new Capture<>();
325
326 resetCommunicatorExpectingSingleBroadcast(bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700327 DeviceEvent event = deviceStore.createOrUpdateDevice(PID, DID1, description);
328 assertEquals(DEVICE_ADDED, event.type());
329 assertDevice(DID1, SW1, event.subject());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700330 verify(clusterCommunicator);
331 assertInternalDeviceEvent(NID1, DID1, PID, description, bcast);
332
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700333
334 DeviceDescription description2 =
335 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
alshabib7911a052014-10-16 17:49:37 -0700336 HW, SW2, SN, CID);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700337 resetCommunicatorExpectingSingleBroadcast(bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700338 DeviceEvent event2 = deviceStore.createOrUpdateDevice(PID, DID1, description2);
339 assertEquals(DEVICE_UPDATED, event2.type());
340 assertDevice(DID1, SW2, event2.subject());
341
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700342 verify(clusterCommunicator);
343 assertInternalDeviceEvent(NID1, DID1, PID, description2, bcast);
344 reset(clusterCommunicator);
345
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700346 assertNull("No change expected", deviceStore.createOrUpdateDevice(PID, DID1, description2));
347 }
348
349 @Test
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700350 public final void testCreateOrUpdateDeviceAncillary() throws IOException {
351 // add
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700352 DeviceDescription description =
353 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
alshabib7911a052014-10-16 17:49:37 -0700354 HW, SW1, SN, CID, A2);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700355 Capture<ClusterMessage> bcast = new Capture<>();
356
357 resetCommunicatorExpectingSingleBroadcast(bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700358 DeviceEvent event = deviceStore.createOrUpdateDevice(PIDA, DID1, description);
359 assertEquals(DEVICE_ADDED, event.type());
360 assertDevice(DID1, SW1, event.subject());
361 assertEquals(PIDA, event.subject().providerId());
362 assertAnnotationsEquals(event.subject().annotations(), A2);
363 assertFalse("Ancillary will not bring device up", deviceStore.isAvailable(DID1));
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700364 verify(clusterCommunicator);
365 assertInternalDeviceEvent(NID1, DID1, PIDA, description, bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700366
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700367 // update from primary
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700368 DeviceDescription description2 =
369 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
alshabib7911a052014-10-16 17:49:37 -0700370 HW, SW2, SN, CID, A1);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700371 resetCommunicatorExpectingSingleBroadcast(bcast);
372
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700373 DeviceEvent event2 = deviceStore.createOrUpdateDevice(PID, DID1, description2);
374 assertEquals(DEVICE_UPDATED, event2.type());
375 assertDevice(DID1, SW2, event2.subject());
376 assertEquals(PID, event2.subject().providerId());
377 assertAnnotationsEquals(event2.subject().annotations(), A1, A2);
378 assertTrue(deviceStore.isAvailable(DID1));
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700379 verify(clusterCommunicator);
380 assertInternalDeviceEvent(NID1, DID1, PID, description2, bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700381
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700382 // no-op update from primary
383 resetCommunicatorExpectingNoBroadcast(bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700384 assertNull("No change expected", deviceStore.createOrUpdateDevice(PID, DID1, description2));
385
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700386 verify(clusterCommunicator);
387 assertFalse("no broadcast expected", bcast.hasCaptured());
388
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700389 // For now, Ancillary is ignored once primary appears
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700390 resetCommunicatorExpectingNoBroadcast(bcast);
391
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700392 assertNull("No change expected", deviceStore.createOrUpdateDevice(PIDA, DID1, description));
393
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700394 verify(clusterCommunicator);
395 assertFalse("no broadcast expected", bcast.hasCaptured());
396
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700397 // But, Ancillary annotations will be in effect
398 DeviceDescription description3 =
399 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
alshabib7911a052014-10-16 17:49:37 -0700400 HW, SW1, SN, CID, A2_2);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700401 resetCommunicatorExpectingSingleBroadcast(bcast);
402
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700403 DeviceEvent event3 = deviceStore.createOrUpdateDevice(PIDA, DID1, description3);
404 assertEquals(DEVICE_UPDATED, event3.type());
405 // basic information will be the one from Primary
406 assertDevice(DID1, SW2, event3.subject());
407 assertEquals(PID, event3.subject().providerId());
408 // but annotation from Ancillary will be merged
409 assertAnnotationsEquals(event3.subject().annotations(), A1, A2, A2_2);
410 assertTrue(deviceStore.isAvailable(DID1));
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700411 verify(clusterCommunicator);
412 // note: only annotation from PIDA is sent over the wire
413 assertInternalDeviceEvent(NID1, DID1, PIDA, description3,
414 asList(union(A2, A2_2)), bcast);
415
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700416 }
417
418
419 @Test
420 public final void testMarkOffline() {
421
422 putDevice(DID1, SW1);
423 assertTrue(deviceStore.isAvailable(DID1));
424
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700425 Capture<ClusterMessage> bcast = new Capture<>();
426
427 resetCommunicatorExpectingSingleBroadcast(bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700428 DeviceEvent event = deviceStore.markOffline(DID1);
429 assertEquals(DEVICE_AVAILABILITY_CHANGED, event.type());
430 assertDevice(DID1, SW1, event.subject());
431 assertFalse(deviceStore.isAvailable(DID1));
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700432 verify(clusterCommunicator);
433 // TODO: verify broadcast message
434 assertTrue(bcast.hasCaptured());
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700435
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700436
437 resetCommunicatorExpectingNoBroadcast(bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700438 DeviceEvent event2 = deviceStore.markOffline(DID1);
439 assertNull("No change, no event", event2);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700440 verify(clusterCommunicator);
441 assertFalse(bcast.hasCaptured());
442 }
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700443
444 @Test
445 public final void testUpdatePorts() {
446 putDevice(DID1, SW1);
447 List<PortDescription> pds = Arrays.<PortDescription>asList(
448 new DefaultPortDescription(P1, true),
449 new DefaultPortDescription(P2, true)
450 );
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700451 Capture<ClusterMessage> bcast = new Capture<>();
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700452
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700453 resetCommunicatorExpectingSingleBroadcast(bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700454 List<DeviceEvent> events = deviceStore.updatePorts(PID, DID1, pds);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700455 verify(clusterCommunicator);
456 // TODO: verify broadcast message
457 assertTrue(bcast.hasCaptured());
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700458
459 Set<PortNumber> expectedPorts = Sets.newHashSet(P1, P2);
460 for (DeviceEvent event : events) {
461 assertEquals(PORT_ADDED, event.type());
462 assertDevice(DID1, SW1, event.subject());
463 assertTrue("PortNumber is one of expected",
464 expectedPorts.remove(event.port().number()));
465 assertTrue("Port is enabled", event.port().isEnabled());
466 }
467 assertTrue("Event for all expectedport appeared", expectedPorts.isEmpty());
468
469
470 List<PortDescription> pds2 = Arrays.<PortDescription>asList(
471 new DefaultPortDescription(P1, false),
472 new DefaultPortDescription(P2, true),
473 new DefaultPortDescription(P3, true)
474 );
475
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700476 resetCommunicatorExpectingSingleBroadcast(bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700477 events = deviceStore.updatePorts(PID, DID1, pds2);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700478 verify(clusterCommunicator);
479 // TODO: verify broadcast message
480 assertTrue(bcast.hasCaptured());
481
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700482 assertFalse("event should be triggered", events.isEmpty());
483 for (DeviceEvent event : events) {
484 PortNumber num = event.port().number();
485 if (P1.equals(num)) {
486 assertEquals(PORT_UPDATED, event.type());
487 assertDevice(DID1, SW1, event.subject());
488 assertFalse("Port is disabled", event.port().isEnabled());
489 } else if (P2.equals(num)) {
490 fail("P2 event not expected.");
491 } else if (P3.equals(num)) {
492 assertEquals(PORT_ADDED, event.type());
493 assertDevice(DID1, SW1, event.subject());
494 assertTrue("Port is enabled", event.port().isEnabled());
495 } else {
496 fail("Unknown port number encountered: " + num);
497 }
498 }
499
500 List<PortDescription> pds3 = Arrays.<PortDescription>asList(
501 new DefaultPortDescription(P1, false),
502 new DefaultPortDescription(P2, true)
503 );
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700504 resetCommunicatorExpectingSingleBroadcast(bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700505 events = deviceStore.updatePorts(PID, DID1, pds3);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700506 verify(clusterCommunicator);
507 // TODO: verify broadcast message
508 assertTrue(bcast.hasCaptured());
509
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700510 assertFalse("event should be triggered", events.isEmpty());
511 for (DeviceEvent event : events) {
512 PortNumber num = event.port().number();
513 if (P1.equals(num)) {
514 fail("P1 event not expected.");
515 } else if (P2.equals(num)) {
516 fail("P2 event not expected.");
517 } else if (P3.equals(num)) {
518 assertEquals(PORT_REMOVED, event.type());
519 assertDevice(DID1, SW1, event.subject());
520 assertTrue("Port was enabled", event.port().isEnabled());
521 } else {
522 fail("Unknown port number encountered: " + num);
523 }
524 }
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700525 }
526
527 @Test
528 public final void testUpdatePortStatus() {
529 putDevice(DID1, SW1);
530 List<PortDescription> pds = Arrays.<PortDescription>asList(
531 new DefaultPortDescription(P1, true)
532 );
533 deviceStore.updatePorts(PID, DID1, pds);
534
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700535 Capture<ClusterMessage> bcast = new Capture<>();
536
537 resetCommunicatorExpectingSingleBroadcast(bcast);
538 final DefaultPortDescription desc = new DefaultPortDescription(P1, false);
539 DeviceEvent event = deviceStore.updatePortStatus(PID, DID1, desc);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700540 assertEquals(PORT_UPDATED, event.type());
541 assertDevice(DID1, SW1, event.subject());
542 assertEquals(P1, event.port().number());
543 assertFalse("Port is disabled", event.port().isEnabled());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700544 verify(clusterCommunicator);
545 assertInternalPortStatusEvent(NID1, DID1, PID, desc, NO_ANNOTATION, bcast);
546 assertTrue(bcast.hasCaptured());
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700547 }
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700548
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700549 @Test
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700550 public final void testUpdatePortStatusAncillary() throws IOException {
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700551 putDeviceAncillary(DID1, SW1);
552 putDevice(DID1, SW1);
553 List<PortDescription> pds = Arrays.<PortDescription>asList(
554 new DefaultPortDescription(P1, true, A1)
555 );
556 deviceStore.updatePorts(PID, DID1, pds);
557
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700558 Capture<ClusterMessage> bcast = new Capture<>();
559
560
561 // update port from primary
562 resetCommunicatorExpectingSingleBroadcast(bcast);
563 final DefaultPortDescription desc1 = new DefaultPortDescription(P1, false, A1_2);
564 DeviceEvent event = deviceStore.updatePortStatus(PID, DID1, desc1);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700565 assertEquals(PORT_UPDATED, event.type());
566 assertDevice(DID1, SW1, event.subject());
567 assertEquals(P1, event.port().number());
568 assertAnnotationsEquals(event.port().annotations(), A1, A1_2);
569 assertFalse("Port is disabled", event.port().isEnabled());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700570 verify(clusterCommunicator);
571 assertInternalPortStatusEvent(NID1, DID1, PID, desc1, asList(A1, A1_2), bcast);
572 assertTrue(bcast.hasCaptured());
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700573
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700574 // update port from ancillary with no attributes
575 resetCommunicatorExpectingNoBroadcast(bcast);
576 final DefaultPortDescription desc2 = new DefaultPortDescription(P1, true);
577 DeviceEvent event2 = deviceStore.updatePortStatus(PIDA, DID1, desc2);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700578 assertNull("Ancillary is ignored if primary exists", event2);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700579 verify(clusterCommunicator);
580 assertFalse(bcast.hasCaptured());
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700581
582 // but, Ancillary annotation update will be notified
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700583 resetCommunicatorExpectingSingleBroadcast(bcast);
584 final DefaultPortDescription desc3 = new DefaultPortDescription(P1, true, A2);
585 DeviceEvent event3 = deviceStore.updatePortStatus(PIDA, DID1, desc3);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700586 assertEquals(PORT_UPDATED, event3.type());
587 assertDevice(DID1, SW1, event3.subject());
588 assertEquals(P1, event3.port().number());
589 assertAnnotationsEquals(event3.port().annotations(), A1, A1_2, A2);
590 assertFalse("Port is disabled", event3.port().isEnabled());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700591 verify(clusterCommunicator);
592 assertInternalPortStatusEvent(NID1, DID1, PIDA, desc3, asList(A2), bcast);
593 assertTrue(bcast.hasCaptured());
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700594
595 // port only reported from Ancillary will be notified as down
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700596 resetCommunicatorExpectingSingleBroadcast(bcast);
597 final DefaultPortDescription desc4 = new DefaultPortDescription(P2, true);
598 DeviceEvent event4 = deviceStore.updatePortStatus(PIDA, DID1, desc4);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700599 assertEquals(PORT_ADDED, event4.type());
600 assertDevice(DID1, SW1, event4.subject());
601 assertEquals(P2, event4.port().number());
602 assertAnnotationsEquals(event4.port().annotations());
603 assertFalse("Port is disabled if not given from primary provider",
604 event4.port().isEnabled());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700605 verify(clusterCommunicator);
606 // TODO: verify broadcast message content
607 assertInternalPortStatusEvent(NID1, DID1, PIDA, desc4, NO_ANNOTATION, bcast);
608 assertTrue(bcast.hasCaptured());
609 }
610
611 private void assertInternalPortStatusEvent(NodeId sender, DeviceId did,
612 ProviderId pid, DefaultPortDescription expectedDesc,
613 List<SparseAnnotations> expectedAnnotations, Capture<ClusterMessage> actualMsg) {
614
615 assertTrue(actualMsg.hasCaptured());
616 assertEquals(sender, actualMsg.getValue().sender());
617 assertEquals(GossipDeviceStoreMessageSubjects.PORT_STATUS_UPDATE,
618 actualMsg.getValue().subject());
619 InternalPortStatusEvent addEvent
620 = testGossipDeviceStore.deserialize(actualMsg.getValue().payload());
621 assertEquals(did, addEvent.deviceId());
622 assertEquals(pid, addEvent.providerId());
623 assertPortDescriptionEquals(expectedDesc, expectedAnnotations,
624 addEvent.portDescription().value());
625
626 }
627
628 private void assertPortDescriptionEquals(
629 PortDescription expectedDesc,
630 List<SparseAnnotations> expectedAnnotations,
631 PortDescription actual) {
632
633 assertEquals(expectedDesc.portNumber(), actual.portNumber());
634 assertEquals(expectedDesc.isEnabled(), actual.isEnabled());
635
636 assertAnnotationsEquals(actual.annotations(),
637 expectedAnnotations.toArray(new SparseAnnotations[0]));
638 }
639
640 private void resetCommunicatorExpectingNoBroadcast(
641 Capture<ClusterMessage> bcast) {
642 bcast.reset();
643 reset(clusterCommunicator);
644 replay(clusterCommunicator);
645 }
646
647 private void resetCommunicatorExpectingSingleBroadcast(
648 Capture<ClusterMessage> bcast) {
649
650 bcast.reset();
651 reset(clusterCommunicator);
652 try {
653 expect(clusterCommunicator.broadcast(capture(bcast))).andReturn(true).once();
654 } catch (IOException e) {
655 fail("Should never reach here");
656 }
657 replay(clusterCommunicator);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700658 }
659
660 @Test
661 public final void testGetPorts() {
662 putDevice(DID1, SW1);
663 putDevice(DID2, SW1);
664 List<PortDescription> pds = Arrays.<PortDescription>asList(
665 new DefaultPortDescription(P1, true),
666 new DefaultPortDescription(P2, true)
667 );
668 deviceStore.updatePorts(PID, DID1, pds);
669
670 Set<PortNumber> expectedPorts = Sets.newHashSet(P1, P2);
671 List<Port> ports = deviceStore.getPorts(DID1);
672 for (Port port : ports) {
673 assertTrue("Port is enabled", port.isEnabled());
674 assertTrue("PortNumber is one of expected",
675 expectedPorts.remove(port.number()));
676 }
677 assertTrue("Event for all expectedport appeared", expectedPorts.isEmpty());
678
679
680 assertTrue("DID2 has no ports", deviceStore.getPorts(DID2).isEmpty());
681 }
682
683 @Test
684 public final void testGetPort() {
685 putDevice(DID1, SW1);
686 putDevice(DID2, SW1);
687 List<PortDescription> pds = Arrays.<PortDescription>asList(
688 new DefaultPortDescription(P1, true),
689 new DefaultPortDescription(P2, false)
690 );
691 deviceStore.updatePorts(PID, DID1, pds);
692
693 Port port1 = deviceStore.getPort(DID1, P1);
694 assertEquals(P1, port1.number());
695 assertTrue("Port is enabled", port1.isEnabled());
696
697 Port port2 = deviceStore.getPort(DID1, P2);
698 assertEquals(P2, port2.number());
699 assertFalse("Port is disabled", port2.isEnabled());
700
701 Port port3 = deviceStore.getPort(DID1, P3);
702 assertNull("P3 not expected", port3);
703 }
704
705 @Test
706 public final void testRemoveDevice() {
Yuta HIGUCHI0d6a5e62014-10-03 15:54:09 -0700707 putDevice(DID1, SW1, A1);
708 List<PortDescription> pds = Arrays.<PortDescription>asList(
709 new DefaultPortDescription(P1, true, A2)
710 );
711 deviceStore.updatePorts(PID, DID1, pds);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700712 putDevice(DID2, SW1);
713
714 assertEquals(2, deviceStore.getDeviceCount());
Yuta HIGUCHI0d6a5e62014-10-03 15:54:09 -0700715 assertEquals(1, deviceStore.getPorts(DID1).size());
716 assertAnnotationsEquals(deviceStore.getDevice(DID1).annotations(), A1);
717 assertAnnotationsEquals(deviceStore.getPort(DID1, P1).annotations(), A2);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700718
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700719 Capture<ClusterMessage> bcast = new Capture<>();
720
721 resetCommunicatorExpectingSingleBroadcast(bcast);
722
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700723 DeviceEvent event = deviceStore.removeDevice(DID1);
724 assertEquals(DEVICE_REMOVED, event.type());
725 assertDevice(DID1, SW1, event.subject());
726
727 assertEquals(1, deviceStore.getDeviceCount());
Yuta HIGUCHI0d6a5e62014-10-03 15:54:09 -0700728 assertEquals(0, deviceStore.getPorts(DID1).size());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700729 verify(clusterCommunicator);
730 // TODO: verify broadcast message
731 assertTrue(bcast.hasCaptured());
Yuta HIGUCHI0d6a5e62014-10-03 15:54:09 -0700732
733 // putBack Device, Port w/o annotation
734 putDevice(DID1, SW1);
735 List<PortDescription> pds2 = Arrays.<PortDescription>asList(
736 new DefaultPortDescription(P1, true)
737 );
738 deviceStore.updatePorts(PID, DID1, pds2);
739
740 // annotations should not survive
741 assertEquals(2, deviceStore.getDeviceCount());
742 assertEquals(1, deviceStore.getPorts(DID1).size());
743 assertAnnotationsEquals(deviceStore.getDevice(DID1).annotations());
744 assertAnnotationsEquals(deviceStore.getPort(DID1, P1).annotations());
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700745 }
746
747 // If Delegates should be called only on remote events,
748 // then Simple* should never call them, thus not test required.
749 // TODO add test for Port events when we have them
750 @Ignore("Ignore until Delegate spec. is clear.")
751 @Test
752 public final void testEvents() throws InterruptedException {
753 final CountDownLatch addLatch = new CountDownLatch(1);
754 DeviceStoreDelegate checkAdd = new DeviceStoreDelegate() {
755 @Override
756 public void notify(DeviceEvent event) {
757 assertEquals(DEVICE_ADDED, event.type());
758 assertDevice(DID1, SW1, event.subject());
759 addLatch.countDown();
760 }
761 };
762 final CountDownLatch updateLatch = new CountDownLatch(1);
763 DeviceStoreDelegate checkUpdate = new DeviceStoreDelegate() {
764 @Override
765 public void notify(DeviceEvent event) {
766 assertEquals(DEVICE_UPDATED, event.type());
767 assertDevice(DID1, SW2, event.subject());
768 updateLatch.countDown();
769 }
770 };
771 final CountDownLatch removeLatch = new CountDownLatch(1);
772 DeviceStoreDelegate checkRemove = new DeviceStoreDelegate() {
773 @Override
774 public void notify(DeviceEvent event) {
775 assertEquals(DEVICE_REMOVED, event.type());
776 assertDevice(DID1, SW2, event.subject());
777 removeLatch.countDown();
778 }
779 };
780
781 DeviceDescription description =
782 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
alshabib7911a052014-10-16 17:49:37 -0700783 HW, SW1, SN, CID);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700784 deviceStore.setDelegate(checkAdd);
785 deviceStore.createOrUpdateDevice(PID, DID1, description);
786 assertTrue("Add event fired", addLatch.await(1, TimeUnit.SECONDS));
787
788
789 DeviceDescription description2 =
790 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
alshabib7911a052014-10-16 17:49:37 -0700791 HW, SW2, SN, CID);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700792 deviceStore.unsetDelegate(checkAdd);
793 deviceStore.setDelegate(checkUpdate);
794 deviceStore.createOrUpdateDevice(PID, DID1, description2);
795 assertTrue("Update event fired", updateLatch.await(1, TimeUnit.SECONDS));
796
797 deviceStore.unsetDelegate(checkUpdate);
798 deviceStore.setDelegate(checkRemove);
799 deviceStore.removeDevice(DID1);
800 assertTrue("Remove event fired", removeLatch.await(1, TimeUnit.SECONDS));
801 }
802
Yuta HIGUCHIe8252bb2014-10-22 09:41:01 -0700803 private final class TestMastershipService extends MastershipServiceAdapter {
804 @Override
805 public NodeId getMasterFor(DeviceId deviceId) {
806 return NID1;
807 }
808 }
809
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700810 private static final class TestGossipDeviceStore extends GossipDeviceStore {
811
Madan Jampani53e44e62014-10-07 12:39:51 -0700812 public TestGossipDeviceStore(
Yuta HIGUCHI093e83e2014-10-10 22:26:11 -0700813 DeviceClockService deviceClockService,
Madan Jampani53e44e62014-10-07 12:39:51 -0700814 ClusterService clusterService,
815 ClusterCommunicationService clusterCommunicator) {
Yuta HIGUCHI093e83e2014-10-10 22:26:11 -0700816 this.deviceClockService = deviceClockService;
Madan Jampani53e44e62014-10-07 12:39:51 -0700817 this.clusterService = clusterService;
Madan Jampani47c93732014-10-06 20:46:08 -0700818 this.clusterCommunicator = clusterCommunicator;
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700819 }
Madan Jampani47c93732014-10-06 20:46:08 -0700820
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700821 public <T> T deserialize(byte[] bytes) {
822 return SERIALIZER.decode(bytes);
823 }
Madan Jampani47c93732014-10-06 20:46:08 -0700824 }
Madan Jampani53e44e62014-10-07 12:39:51 -0700825
826 private static final class TestClusterService implements ClusterService {
827
Madan Jampani53e44e62014-10-07 12:39:51 -0700828 private final Map<NodeId, ControllerNode> nodes = new HashMap<>();
829 private final Map<NodeId, ControllerNode.State> nodeStates = new HashMap<>();
830
831 public TestClusterService() {
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700832 nodes.put(NID1, ONOS1);
833 nodeStates.put(NID1, ACTIVE);
834
835 nodes.put(NID2, ONOS2);
836 nodeStates.put(NID2, ACTIVE);
Madan Jampani53e44e62014-10-07 12:39:51 -0700837 }
838
839 @Override
840 public ControllerNode getLocalNode() {
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700841 return GossipDeviceStoreTest.ONOS1;
Madan Jampani53e44e62014-10-07 12:39:51 -0700842 }
843
844 @Override
845 public Set<ControllerNode> getNodes() {
846 return Sets.newHashSet(nodes.values());
847 }
848
849 @Override
850 public ControllerNode getNode(NodeId nodeId) {
851 return nodes.get(nodeId);
852 }
853
854 @Override
855 public State getState(NodeId nodeId) {
856 return nodeStates.get(nodeId);
857 }
858
859 @Override
860 public void addListener(ClusterEventListener listener) {
861 }
862
863 @Override
864 public void removeListener(ClusterEventListener listener) {
865 }
866 }
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700867}