blob: 7054bd34a5733287109d238b2c10f48dbda1e715 [file] [log] [blame]
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07001/*
2 * Copyright 2014 Open Networking Laboratory
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Brian O'Connorabafb502014-12-02 22:26:20 -080016package org.onosproject.store.device.impl;
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -070017
Jonathan Hart7d656f42015-01-27 14:07:23 -080018import com.google.common.collect.Iterables;
19import com.google.common.collect.Sets;
Madan Jampani2af244a2015-02-22 13:12:01 -080020
Yuta HIGUCHI47c40882014-10-10 18:44:37 -070021import org.easymock.Capture;
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -070022import org.junit.After;
23import org.junit.AfterClass;
24import org.junit.Before;
25import org.junit.BeforeClass;
26import org.junit.Ignore;
27import org.junit.Test;
Jonathan Hart7d656f42015-01-27 14:07:23 -080028import org.onlab.packet.ChassisId;
29import org.onlab.packet.IpAddress;
Brian O'Connorabafb502014-12-02 22:26:20 -080030import org.onosproject.cluster.ClusterService;
31import org.onosproject.cluster.ControllerNode;
32import org.onosproject.cluster.DefaultControllerNode;
33import org.onosproject.cluster.NodeId;
34import org.onosproject.mastership.MastershipServiceAdapter;
35import org.onosproject.mastership.MastershipTerm;
36import org.onosproject.net.Annotations;
37import org.onosproject.net.DefaultAnnotations;
38import org.onosproject.net.Device;
39import org.onosproject.net.DeviceId;
40import org.onosproject.net.Port;
41import org.onosproject.net.PortNumber;
42import org.onosproject.net.SparseAnnotations;
43import org.onosproject.net.device.DefaultDeviceDescription;
44import org.onosproject.net.device.DefaultPortDescription;
45import org.onosproject.net.device.DeviceClockService;
46import org.onosproject.net.device.DeviceDescription;
47import org.onosproject.net.device.DeviceEvent;
48import org.onosproject.net.device.DeviceStore;
49import org.onosproject.net.device.DeviceStoreDelegate;
50import org.onosproject.net.device.PortDescription;
51import org.onosproject.net.provider.ProviderId;
52import org.onosproject.store.cluster.StaticClusterService;
53import org.onosproject.store.cluster.messaging.ClusterCommunicationService;
54import org.onosproject.store.cluster.messaging.ClusterMessage;
55import org.onosproject.store.cluster.messaging.ClusterMessageHandler;
56import org.onosproject.store.cluster.messaging.MessageSubject;
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -070057
Jonathan Hart7d656f42015-01-27 14:07:23 -080058import java.io.IOException;
59import java.util.Arrays;
60import java.util.Collections;
61import java.util.HashMap;
62import java.util.List;
63import java.util.Map;
64import java.util.Set;
65import java.util.concurrent.CountDownLatch;
Madan Jampani2af244a2015-02-22 13:12:01 -080066import java.util.concurrent.ExecutorService;
Jonathan Hart7d656f42015-01-27 14:07:23 -080067import java.util.concurrent.TimeUnit;
68
69import static java.util.Arrays.asList;
70import static org.easymock.EasyMock.*;
71import static org.junit.Assert.*;
72import static org.onosproject.cluster.ControllerNode.State.ACTIVE;
73import static org.onosproject.net.DefaultAnnotations.union;
74import static org.onosproject.net.Device.Type.SWITCH;
75import static org.onosproject.net.DeviceId.deviceId;
76import static org.onosproject.net.device.DeviceEvent.Type.*;
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -070077
78
79// TODO add tests for remote replication
80/**
81 * Test of the gossip based distributed DeviceStore implementation.
82 */
83public class GossipDeviceStoreTest {
84
85 private static final ProviderId PID = new ProviderId("of", "foo");
86 private static final ProviderId PIDA = new ProviderId("of", "bar", true);
87 private static final DeviceId DID1 = deviceId("of:foo");
88 private static final DeviceId DID2 = deviceId("of:bar");
89 private static final String MFR = "whitebox";
90 private static final String HW = "1.1.x";
91 private static final String SW1 = "3.8.1";
92 private static final String SW2 = "3.9.5";
93 private static final String SN = "43311-12345";
alshabib7911a052014-10-16 17:49:37 -070094 private static final ChassisId CID = new ChassisId();
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -070095
96 private static final PortNumber P1 = PortNumber.portNumber(1);
97 private static final PortNumber P2 = PortNumber.portNumber(2);
98 private static final PortNumber P3 = PortNumber.portNumber(3);
99
100 private static final SparseAnnotations A1 = DefaultAnnotations.builder()
101 .set("A1", "a1")
102 .set("B1", "b1")
103 .build();
104 private static final SparseAnnotations A1_2 = DefaultAnnotations.builder()
105 .remove("A1")
106 .set("B3", "b3")
107 .build();
108 private static final SparseAnnotations A2 = DefaultAnnotations.builder()
109 .set("A2", "a2")
110 .set("B2", "b2")
111 .build();
112 private static final SparseAnnotations A2_2 = DefaultAnnotations.builder()
113 .remove("A2")
114 .set("B4", "b4")
115 .build();
116
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700117 // local node
118 private static final NodeId NID1 = new NodeId("local");
119 private static final ControllerNode ONOS1 =
Pavlin Radoslavov444b5192014-10-28 10:45:19 -0700120 new DefaultControllerNode(NID1, IpAddress.valueOf("127.0.0.1"));
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700121
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700122 // remote node
123 private static final NodeId NID2 = new NodeId("remote");
124 private static final ControllerNode ONOS2 =
Pavlin Radoslavov444b5192014-10-28 10:45:19 -0700125 new DefaultControllerNode(NID2, IpAddress.valueOf("127.0.0.2"));
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700126 private static final List<SparseAnnotations> NO_ANNOTATION = Collections.<SparseAnnotations>emptyList();
127
128
129 private TestGossipDeviceStore testGossipDeviceStore;
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700130 private GossipDeviceStore gossipDeviceStore;
131 private DeviceStore deviceStore;
132
133 private DeviceClockManager deviceClockManager;
Yuta HIGUCHI093e83e2014-10-10 22:26:11 -0700134 private DeviceClockService deviceClockService;
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700135 private ClusterCommunicationService clusterCommunicator;
Yuta HIGUCHI3e5d11a2014-11-04 14:16:44 -0800136
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700137 @BeforeClass
138 public static void setUpBeforeClass() throws Exception {
139 }
140
141 @AfterClass
142 public static void tearDownAfterClass() throws Exception {
143 }
144
145
146 @Before
147 public void setUp() throws Exception {
148 deviceClockManager = new DeviceClockManager();
149 deviceClockManager.activate();
Yuta HIGUCHI093e83e2014-10-10 22:26:11 -0700150 deviceClockService = deviceClockManager;
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700151
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700152 deviceClockManager.setMastershipTerm(DID1, MastershipTerm.of(NID1, 1));
153 deviceClockManager.setMastershipTerm(DID2, MastershipTerm.of(NID1, 2));
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700154
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700155 clusterCommunicator = createNiceMock(ClusterCommunicationService.class);
156 clusterCommunicator.addSubscriber(anyObject(MessageSubject.class),
Madan Jampani2af244a2015-02-22 13:12:01 -0800157 anyObject(ClusterMessageHandler.class), anyObject(ExecutorService.class));
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700158 expectLastCall().anyTimes();
159 replay(clusterCommunicator);
Madan Jampani53e44e62014-10-07 12:39:51 -0700160 ClusterService clusterService = new TestClusterService();
Madan Jampani47c93732014-10-06 20:46:08 -0700161
Yuta HIGUCHI093e83e2014-10-10 22:26:11 -0700162 testGossipDeviceStore = new TestGossipDeviceStore(deviceClockService, clusterService, clusterCommunicator);
Yuta HIGUCHIe8252bb2014-10-22 09:41:01 -0700163 testGossipDeviceStore.mastershipService = new TestMastershipService();
164
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700165 gossipDeviceStore = testGossipDeviceStore;
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700166 gossipDeviceStore.activate();
167 deviceStore = gossipDeviceStore;
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700168 verify(clusterCommunicator);
169 reset(clusterCommunicator);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700170 }
171
172 @After
173 public void tearDown() throws Exception {
174 gossipDeviceStore.deactivate();
175 deviceClockManager.deactivate();
176 }
177
Yuta HIGUCHI0d6a5e62014-10-03 15:54:09 -0700178 private void putDevice(DeviceId deviceId, String swVersion,
179 SparseAnnotations... annotations) {
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700180 DeviceDescription description =
181 new DefaultDeviceDescription(deviceId.uri(), SWITCH, MFR,
alshabib7911a052014-10-16 17:49:37 -0700182 HW, swVersion, SN, CID, annotations);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700183 reset(clusterCommunicator);
Jonathan Hart7d656f42015-01-27 14:07:23 -0800184 expect(clusterCommunicator.broadcast(anyObject(ClusterMessage.class)))
185 .andReturn(true).anyTimes();
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700186 replay(clusterCommunicator);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700187 deviceStore.createOrUpdateDevice(PID, deviceId, description);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700188 verify(clusterCommunicator);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700189 }
190
Yuta HIGUCHI0d6a5e62014-10-03 15:54:09 -0700191 private void putDeviceAncillary(DeviceId deviceId, String swVersion,
192 SparseAnnotations... annotations) {
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700193 DeviceDescription description =
194 new DefaultDeviceDescription(deviceId.uri(), SWITCH, MFR,
alshabib7911a052014-10-16 17:49:37 -0700195 HW, swVersion, SN, CID, annotations);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700196 deviceStore.createOrUpdateDevice(PIDA, deviceId, description);
197 }
198
199 private static void assertDevice(DeviceId id, String swVersion, Device device) {
200 assertNotNull(device);
201 assertEquals(id, device.id());
202 assertEquals(MFR, device.manufacturer());
203 assertEquals(HW, device.hwVersion());
204 assertEquals(swVersion, device.swVersion());
205 assertEquals(SN, device.serialNumber());
206 }
207
208 /**
209 * Verifies that Annotations created by merging {@code annotations} is
210 * equal to actual Annotations.
211 *
212 * @param actual Annotations to check
213 * @param annotations
214 */
215 private static void assertAnnotationsEquals(Annotations actual, SparseAnnotations... annotations) {
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700216 SparseAnnotations expected = DefaultAnnotations.builder().build();
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700217 for (SparseAnnotations a : annotations) {
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700218 expected = DefaultAnnotations.union(expected, a);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700219 }
220 assertEquals(expected.keys(), actual.keys());
221 for (String key : expected.keys()) {
222 assertEquals(expected.value(key), actual.value(key));
223 }
224 }
225
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700226 private static void assertDeviceDescriptionEquals(DeviceDescription expected,
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(), expected.annotations());
238 }
239
240 private static void assertDeviceDescriptionEquals(DeviceDescription expected,
241 List<SparseAnnotations> expectedAnnotations,
242 DeviceDescription actual) {
243 if (expected == actual) {
244 return;
245 }
246 assertEquals(expected.deviceURI(), actual.deviceURI());
247 assertEquals(expected.hwVersion(), actual.hwVersion());
248 assertEquals(expected.manufacturer(), actual.manufacturer());
249 assertEquals(expected.serialNumber(), actual.serialNumber());
250 assertEquals(expected.swVersion(), actual.swVersion());
251
252 assertAnnotationsEquals(actual.annotations(),
253 expectedAnnotations.toArray(new SparseAnnotations[0]));
254 }
255
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700256 @Test
257 public final void testGetDeviceCount() {
258 assertEquals("initialy empty", 0, deviceStore.getDeviceCount());
259
260 putDevice(DID1, SW1);
261 putDevice(DID2, SW2);
262 putDevice(DID1, SW1);
263
264 assertEquals("expect 2 uniq devices", 2, deviceStore.getDeviceCount());
265 }
266
267 @Test
268 public final void testGetDevices() {
269 assertEquals("initialy empty", 0, Iterables.size(deviceStore.getDevices()));
270
271 putDevice(DID1, SW1);
272 putDevice(DID2, SW2);
273 putDevice(DID1, SW1);
274
275 assertEquals("expect 2 uniq devices",
276 2, Iterables.size(deviceStore.getDevices()));
277
278 Map<DeviceId, Device> devices = new HashMap<>();
279 for (Device device : deviceStore.getDevices()) {
280 devices.put(device.id(), device);
281 }
282
283 assertDevice(DID1, SW1, devices.get(DID1));
284 assertDevice(DID2, SW2, devices.get(DID2));
285
286 // add case for new node?
287 }
288
289 @Test
290 public final void testGetDevice() {
291
292 putDevice(DID1, SW1);
293
294 assertDevice(DID1, SW1, deviceStore.getDevice(DID1));
295 assertNull("DID2 shouldn't be there", deviceStore.getDevice(DID2));
296 }
297
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700298 private void assertInternalDeviceEvent(NodeId sender,
299 DeviceId deviceId,
300 ProviderId providerId,
301 DeviceDescription expectedDesc,
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, addEvent.deviceDescription().value());
312 }
313
314 private void assertInternalDeviceEvent(NodeId sender,
315 DeviceId deviceId,
316 ProviderId providerId,
317 DeviceDescription expectedDesc,
318 List<SparseAnnotations> expectedAnnotations,
319 Capture<ClusterMessage> actualMsg) {
320 assertTrue(actualMsg.hasCaptured());
321 assertEquals(sender, actualMsg.getValue().sender());
322 assertEquals(GossipDeviceStoreMessageSubjects.DEVICE_UPDATE,
323 actualMsg.getValue().subject());
324 InternalDeviceEvent addEvent
325 = testGossipDeviceStore.deserialize(actualMsg.getValue().payload());
326 assertEquals(deviceId, addEvent.deviceId());
327 assertEquals(providerId, addEvent.providerId());
328 assertDeviceDescriptionEquals(expectedDesc, expectedAnnotations, addEvent.deviceDescription().value());
329 }
330
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700331 @Test
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700332 public final void testCreateOrUpdateDevice() throws IOException {
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700333 DeviceDescription description =
334 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
alshabib7911a052014-10-16 17:49:37 -0700335 HW, SW1, SN, CID);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700336 Capture<ClusterMessage> bcast = new Capture<>();
337
338 resetCommunicatorExpectingSingleBroadcast(bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700339 DeviceEvent event = deviceStore.createOrUpdateDevice(PID, DID1, description);
340 assertEquals(DEVICE_ADDED, event.type());
341 assertDevice(DID1, SW1, event.subject());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700342 verify(clusterCommunicator);
343 assertInternalDeviceEvent(NID1, DID1, PID, description, bcast);
344
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700345
346 DeviceDescription description2 =
347 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
alshabib7911a052014-10-16 17:49:37 -0700348 HW, SW2, SN, CID);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700349 resetCommunicatorExpectingSingleBroadcast(bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700350 DeviceEvent event2 = deviceStore.createOrUpdateDevice(PID, DID1, description2);
351 assertEquals(DEVICE_UPDATED, event2.type());
352 assertDevice(DID1, SW2, event2.subject());
353
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700354 verify(clusterCommunicator);
355 assertInternalDeviceEvent(NID1, DID1, PID, description2, bcast);
356 reset(clusterCommunicator);
357
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700358 assertNull("No change expected", deviceStore.createOrUpdateDevice(PID, DID1, description2));
359 }
360
361 @Test
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700362 public final void testCreateOrUpdateDeviceAncillary() throws IOException {
363 // add
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700364 DeviceDescription description =
365 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
alshabib7911a052014-10-16 17:49:37 -0700366 HW, SW1, SN, CID, A2);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700367 Capture<ClusterMessage> bcast = new Capture<>();
368
369 resetCommunicatorExpectingSingleBroadcast(bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700370 DeviceEvent event = deviceStore.createOrUpdateDevice(PIDA, DID1, description);
371 assertEquals(DEVICE_ADDED, event.type());
372 assertDevice(DID1, SW1, event.subject());
373 assertEquals(PIDA, event.subject().providerId());
374 assertAnnotationsEquals(event.subject().annotations(), A2);
375 assertFalse("Ancillary will not bring device up", deviceStore.isAvailable(DID1));
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700376 verify(clusterCommunicator);
377 assertInternalDeviceEvent(NID1, DID1, PIDA, description, bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700378
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700379 // update from primary
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700380 DeviceDescription description2 =
381 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
alshabib7911a052014-10-16 17:49:37 -0700382 HW, SW2, SN, CID, A1);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700383 resetCommunicatorExpectingSingleBroadcast(bcast);
384
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700385 DeviceEvent event2 = deviceStore.createOrUpdateDevice(PID, DID1, description2);
386 assertEquals(DEVICE_UPDATED, event2.type());
387 assertDevice(DID1, SW2, event2.subject());
388 assertEquals(PID, event2.subject().providerId());
389 assertAnnotationsEquals(event2.subject().annotations(), A1, A2);
390 assertTrue(deviceStore.isAvailable(DID1));
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700391 verify(clusterCommunicator);
392 assertInternalDeviceEvent(NID1, DID1, PID, description2, bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700393
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700394 // no-op update from primary
395 resetCommunicatorExpectingNoBroadcast(bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700396 assertNull("No change expected", deviceStore.createOrUpdateDevice(PID, DID1, description2));
397
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700398 verify(clusterCommunicator);
399 assertFalse("no broadcast expected", bcast.hasCaptured());
400
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700401 // For now, Ancillary is ignored once primary appears
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700402 resetCommunicatorExpectingNoBroadcast(bcast);
403
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700404 assertNull("No change expected", deviceStore.createOrUpdateDevice(PIDA, DID1, description));
405
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700406 verify(clusterCommunicator);
407 assertFalse("no broadcast expected", bcast.hasCaptured());
408
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700409 // But, Ancillary annotations will be in effect
410 DeviceDescription description3 =
411 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
alshabib7911a052014-10-16 17:49:37 -0700412 HW, SW1, SN, CID, A2_2);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700413 resetCommunicatorExpectingSingleBroadcast(bcast);
414
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700415 DeviceEvent event3 = deviceStore.createOrUpdateDevice(PIDA, DID1, description3);
416 assertEquals(DEVICE_UPDATED, event3.type());
417 // basic information will be the one from Primary
418 assertDevice(DID1, SW2, event3.subject());
419 assertEquals(PID, event3.subject().providerId());
420 // but annotation from Ancillary will be merged
421 assertAnnotationsEquals(event3.subject().annotations(), A1, A2, A2_2);
422 assertTrue(deviceStore.isAvailable(DID1));
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700423 verify(clusterCommunicator);
424 // note: only annotation from PIDA is sent over the wire
425 assertInternalDeviceEvent(NID1, DID1, PIDA, description3,
426 asList(union(A2, A2_2)), bcast);
427
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700428 }
429
430
431 @Test
432 public final void testMarkOffline() {
433
434 putDevice(DID1, SW1);
435 assertTrue(deviceStore.isAvailable(DID1));
436
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700437 Capture<ClusterMessage> bcast = new Capture<>();
438
439 resetCommunicatorExpectingSingleBroadcast(bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700440 DeviceEvent event = deviceStore.markOffline(DID1);
441 assertEquals(DEVICE_AVAILABILITY_CHANGED, event.type());
442 assertDevice(DID1, SW1, event.subject());
443 assertFalse(deviceStore.isAvailable(DID1));
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700444 verify(clusterCommunicator);
445 // TODO: verify broadcast message
446 assertTrue(bcast.hasCaptured());
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700447
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700448
449 resetCommunicatorExpectingNoBroadcast(bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700450 DeviceEvent event2 = deviceStore.markOffline(DID1);
451 assertNull("No change, no event", event2);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700452 verify(clusterCommunicator);
453 assertFalse(bcast.hasCaptured());
454 }
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700455
456 @Test
457 public final void testUpdatePorts() {
458 putDevice(DID1, SW1);
459 List<PortDescription> pds = Arrays.<PortDescription>asList(
460 new DefaultPortDescription(P1, true),
461 new DefaultPortDescription(P2, true)
462 );
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700463 Capture<ClusterMessage> bcast = new Capture<>();
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700464
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700465 resetCommunicatorExpectingSingleBroadcast(bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700466 List<DeviceEvent> events = deviceStore.updatePorts(PID, DID1, pds);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700467 verify(clusterCommunicator);
468 // TODO: verify broadcast message
469 assertTrue(bcast.hasCaptured());
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700470
471 Set<PortNumber> expectedPorts = Sets.newHashSet(P1, P2);
472 for (DeviceEvent event : events) {
473 assertEquals(PORT_ADDED, event.type());
474 assertDevice(DID1, SW1, event.subject());
475 assertTrue("PortNumber is one of expected",
476 expectedPorts.remove(event.port().number()));
477 assertTrue("Port is enabled", event.port().isEnabled());
478 }
479 assertTrue("Event for all expectedport appeared", expectedPorts.isEmpty());
480
481
482 List<PortDescription> pds2 = Arrays.<PortDescription>asList(
483 new DefaultPortDescription(P1, false),
484 new DefaultPortDescription(P2, true),
485 new DefaultPortDescription(P3, true)
486 );
487
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700488 resetCommunicatorExpectingSingleBroadcast(bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700489 events = deviceStore.updatePorts(PID, DID1, pds2);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700490 verify(clusterCommunicator);
491 // TODO: verify broadcast message
492 assertTrue(bcast.hasCaptured());
493
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700494 assertFalse("event should be triggered", events.isEmpty());
495 for (DeviceEvent event : events) {
496 PortNumber num = event.port().number();
497 if (P1.equals(num)) {
498 assertEquals(PORT_UPDATED, event.type());
499 assertDevice(DID1, SW1, event.subject());
500 assertFalse("Port is disabled", event.port().isEnabled());
501 } else if (P2.equals(num)) {
502 fail("P2 event not expected.");
503 } else if (P3.equals(num)) {
504 assertEquals(PORT_ADDED, event.type());
505 assertDevice(DID1, SW1, event.subject());
506 assertTrue("Port is enabled", event.port().isEnabled());
507 } else {
508 fail("Unknown port number encountered: " + num);
509 }
510 }
511
512 List<PortDescription> pds3 = Arrays.<PortDescription>asList(
513 new DefaultPortDescription(P1, false),
514 new DefaultPortDescription(P2, true)
515 );
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700516 resetCommunicatorExpectingSingleBroadcast(bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700517 events = deviceStore.updatePorts(PID, DID1, pds3);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700518 verify(clusterCommunicator);
519 // TODO: verify broadcast message
520 assertTrue(bcast.hasCaptured());
521
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700522 assertFalse("event should be triggered", events.isEmpty());
523 for (DeviceEvent event : events) {
524 PortNumber num = event.port().number();
525 if (P1.equals(num)) {
526 fail("P1 event not expected.");
527 } else if (P2.equals(num)) {
528 fail("P2 event not expected.");
529 } else if (P3.equals(num)) {
530 assertEquals(PORT_REMOVED, event.type());
531 assertDevice(DID1, SW1, event.subject());
532 assertTrue("Port was enabled", event.port().isEnabled());
533 } else {
534 fail("Unknown port number encountered: " + num);
535 }
536 }
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700537 }
538
539 @Test
540 public final void testUpdatePortStatus() {
541 putDevice(DID1, SW1);
542 List<PortDescription> pds = Arrays.<PortDescription>asList(
543 new DefaultPortDescription(P1, true)
544 );
545 deviceStore.updatePorts(PID, DID1, pds);
546
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700547 Capture<ClusterMessage> bcast = new Capture<>();
548
549 resetCommunicatorExpectingSingleBroadcast(bcast);
550 final DefaultPortDescription desc = new DefaultPortDescription(P1, false);
551 DeviceEvent event = deviceStore.updatePortStatus(PID, DID1, desc);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700552 assertEquals(PORT_UPDATED, event.type());
553 assertDevice(DID1, SW1, event.subject());
554 assertEquals(P1, event.port().number());
555 assertFalse("Port is disabled", event.port().isEnabled());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700556 verify(clusterCommunicator);
557 assertInternalPortStatusEvent(NID1, DID1, PID, desc, NO_ANNOTATION, bcast);
558 assertTrue(bcast.hasCaptured());
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700559 }
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700560
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700561 @Test
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700562 public final void testUpdatePortStatusAncillary() throws IOException {
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700563 putDeviceAncillary(DID1, SW1);
564 putDevice(DID1, SW1);
565 List<PortDescription> pds = Arrays.<PortDescription>asList(
566 new DefaultPortDescription(P1, true, A1)
567 );
568 deviceStore.updatePorts(PID, DID1, pds);
569
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700570 Capture<ClusterMessage> bcast = new Capture<>();
571
572
573 // update port from primary
574 resetCommunicatorExpectingSingleBroadcast(bcast);
575 final DefaultPortDescription desc1 = new DefaultPortDescription(P1, false, A1_2);
576 DeviceEvent event = deviceStore.updatePortStatus(PID, DID1, desc1);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700577 assertEquals(PORT_UPDATED, event.type());
578 assertDevice(DID1, SW1, event.subject());
579 assertEquals(P1, event.port().number());
580 assertAnnotationsEquals(event.port().annotations(), A1, A1_2);
581 assertFalse("Port is disabled", event.port().isEnabled());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700582 verify(clusterCommunicator);
583 assertInternalPortStatusEvent(NID1, DID1, PID, desc1, asList(A1, A1_2), bcast);
584 assertTrue(bcast.hasCaptured());
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700585
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700586 // update port from ancillary with no attributes
587 resetCommunicatorExpectingNoBroadcast(bcast);
588 final DefaultPortDescription desc2 = new DefaultPortDescription(P1, true);
589 DeviceEvent event2 = deviceStore.updatePortStatus(PIDA, DID1, desc2);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700590 assertNull("Ancillary is ignored if primary exists", event2);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700591 verify(clusterCommunicator);
592 assertFalse(bcast.hasCaptured());
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700593
594 // but, Ancillary annotation update will be notified
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700595 resetCommunicatorExpectingSingleBroadcast(bcast);
596 final DefaultPortDescription desc3 = new DefaultPortDescription(P1, true, A2);
597 DeviceEvent event3 = deviceStore.updatePortStatus(PIDA, DID1, desc3);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700598 assertEquals(PORT_UPDATED, event3.type());
599 assertDevice(DID1, SW1, event3.subject());
600 assertEquals(P1, event3.port().number());
601 assertAnnotationsEquals(event3.port().annotations(), A1, A1_2, A2);
602 assertFalse("Port is disabled", event3.port().isEnabled());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700603 verify(clusterCommunicator);
604 assertInternalPortStatusEvent(NID1, DID1, PIDA, desc3, asList(A2), bcast);
605 assertTrue(bcast.hasCaptured());
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700606
607 // port only reported from Ancillary will be notified as down
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700608 resetCommunicatorExpectingSingleBroadcast(bcast);
609 final DefaultPortDescription desc4 = new DefaultPortDescription(P2, true);
610 DeviceEvent event4 = deviceStore.updatePortStatus(PIDA, DID1, desc4);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700611 assertEquals(PORT_ADDED, event4.type());
612 assertDevice(DID1, SW1, event4.subject());
613 assertEquals(P2, event4.port().number());
614 assertAnnotationsEquals(event4.port().annotations());
615 assertFalse("Port is disabled if not given from primary provider",
616 event4.port().isEnabled());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700617 verify(clusterCommunicator);
618 // TODO: verify broadcast message content
619 assertInternalPortStatusEvent(NID1, DID1, PIDA, desc4, NO_ANNOTATION, bcast);
620 assertTrue(bcast.hasCaptured());
621 }
622
623 private void assertInternalPortStatusEvent(NodeId sender, DeviceId did,
624 ProviderId pid, DefaultPortDescription expectedDesc,
625 List<SparseAnnotations> expectedAnnotations, Capture<ClusterMessage> actualMsg) {
626
627 assertTrue(actualMsg.hasCaptured());
628 assertEquals(sender, actualMsg.getValue().sender());
629 assertEquals(GossipDeviceStoreMessageSubjects.PORT_STATUS_UPDATE,
630 actualMsg.getValue().subject());
631 InternalPortStatusEvent addEvent
632 = testGossipDeviceStore.deserialize(actualMsg.getValue().payload());
633 assertEquals(did, addEvent.deviceId());
634 assertEquals(pid, addEvent.providerId());
635 assertPortDescriptionEquals(expectedDesc, expectedAnnotations,
636 addEvent.portDescription().value());
637
638 }
639
640 private void assertPortDescriptionEquals(
641 PortDescription expectedDesc,
642 List<SparseAnnotations> expectedAnnotations,
643 PortDescription actual) {
644
645 assertEquals(expectedDesc.portNumber(), actual.portNumber());
646 assertEquals(expectedDesc.isEnabled(), actual.isEnabled());
647
648 assertAnnotationsEquals(actual.annotations(),
649 expectedAnnotations.toArray(new SparseAnnotations[0]));
650 }
651
652 private void resetCommunicatorExpectingNoBroadcast(
653 Capture<ClusterMessage> bcast) {
654 bcast.reset();
655 reset(clusterCommunicator);
656 replay(clusterCommunicator);
657 }
658
659 private void resetCommunicatorExpectingSingleBroadcast(
660 Capture<ClusterMessage> bcast) {
661
662 bcast.reset();
663 reset(clusterCommunicator);
Jonathan Hart7d656f42015-01-27 14:07:23 -0800664 expect(clusterCommunicator.broadcast(capture(bcast))).andReturn(true).once();
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700665 replay(clusterCommunicator);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700666 }
667
668 @Test
669 public final void testGetPorts() {
670 putDevice(DID1, SW1);
671 putDevice(DID2, SW1);
672 List<PortDescription> pds = Arrays.<PortDescription>asList(
673 new DefaultPortDescription(P1, true),
674 new DefaultPortDescription(P2, true)
675 );
676 deviceStore.updatePorts(PID, DID1, pds);
677
678 Set<PortNumber> expectedPorts = Sets.newHashSet(P1, P2);
679 List<Port> ports = deviceStore.getPorts(DID1);
680 for (Port port : ports) {
681 assertTrue("Port is enabled", port.isEnabled());
682 assertTrue("PortNumber is one of expected",
683 expectedPorts.remove(port.number()));
684 }
685 assertTrue("Event for all expectedport appeared", expectedPorts.isEmpty());
686
687
688 assertTrue("DID2 has no ports", deviceStore.getPorts(DID2).isEmpty());
689 }
690
691 @Test
692 public final void testGetPort() {
693 putDevice(DID1, SW1);
694 putDevice(DID2, SW1);
695 List<PortDescription> pds = Arrays.<PortDescription>asList(
696 new DefaultPortDescription(P1, true),
697 new DefaultPortDescription(P2, false)
698 );
699 deviceStore.updatePorts(PID, DID1, pds);
700
701 Port port1 = deviceStore.getPort(DID1, P1);
702 assertEquals(P1, port1.number());
703 assertTrue("Port is enabled", port1.isEnabled());
704
705 Port port2 = deviceStore.getPort(DID1, P2);
706 assertEquals(P2, port2.number());
707 assertFalse("Port is disabled", port2.isEnabled());
708
709 Port port3 = deviceStore.getPort(DID1, P3);
710 assertNull("P3 not expected", port3);
711 }
712
713 @Test
714 public final void testRemoveDevice() {
Yuta HIGUCHI0d6a5e62014-10-03 15:54:09 -0700715 putDevice(DID1, SW1, A1);
716 List<PortDescription> pds = Arrays.<PortDescription>asList(
717 new DefaultPortDescription(P1, true, A2)
718 );
719 deviceStore.updatePorts(PID, DID1, pds);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700720 putDevice(DID2, SW1);
721
722 assertEquals(2, deviceStore.getDeviceCount());
Yuta HIGUCHI0d6a5e62014-10-03 15:54:09 -0700723 assertEquals(1, deviceStore.getPorts(DID1).size());
724 assertAnnotationsEquals(deviceStore.getDevice(DID1).annotations(), A1);
725 assertAnnotationsEquals(deviceStore.getPort(DID1, P1).annotations(), A2);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700726
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700727 Capture<ClusterMessage> bcast = new Capture<>();
728
729 resetCommunicatorExpectingSingleBroadcast(bcast);
730
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700731 DeviceEvent event = deviceStore.removeDevice(DID1);
732 assertEquals(DEVICE_REMOVED, event.type());
733 assertDevice(DID1, SW1, event.subject());
734
735 assertEquals(1, deviceStore.getDeviceCount());
Yuta HIGUCHI0d6a5e62014-10-03 15:54:09 -0700736 assertEquals(0, deviceStore.getPorts(DID1).size());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700737 verify(clusterCommunicator);
738 // TODO: verify broadcast message
739 assertTrue(bcast.hasCaptured());
Yuta HIGUCHI0d6a5e62014-10-03 15:54:09 -0700740
741 // putBack Device, Port w/o annotation
742 putDevice(DID1, SW1);
743 List<PortDescription> pds2 = Arrays.<PortDescription>asList(
744 new DefaultPortDescription(P1, true)
745 );
746 deviceStore.updatePorts(PID, DID1, pds2);
747
748 // annotations should not survive
749 assertEquals(2, deviceStore.getDeviceCount());
750 assertEquals(1, deviceStore.getPorts(DID1).size());
751 assertAnnotationsEquals(deviceStore.getDevice(DID1).annotations());
752 assertAnnotationsEquals(deviceStore.getPort(DID1, P1).annotations());
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700753 }
754
755 // If Delegates should be called only on remote events,
756 // then Simple* should never call them, thus not test required.
757 // TODO add test for Port events when we have them
758 @Ignore("Ignore until Delegate spec. is clear.")
759 @Test
760 public final void testEvents() throws InterruptedException {
761 final CountDownLatch addLatch = new CountDownLatch(1);
762 DeviceStoreDelegate checkAdd = new DeviceStoreDelegate() {
763 @Override
764 public void notify(DeviceEvent event) {
765 assertEquals(DEVICE_ADDED, event.type());
766 assertDevice(DID1, SW1, event.subject());
767 addLatch.countDown();
768 }
769 };
770 final CountDownLatch updateLatch = new CountDownLatch(1);
771 DeviceStoreDelegate checkUpdate = new DeviceStoreDelegate() {
772 @Override
773 public void notify(DeviceEvent event) {
774 assertEquals(DEVICE_UPDATED, event.type());
775 assertDevice(DID1, SW2, event.subject());
776 updateLatch.countDown();
777 }
778 };
779 final CountDownLatch removeLatch = new CountDownLatch(1);
780 DeviceStoreDelegate checkRemove = new DeviceStoreDelegate() {
781 @Override
782 public void notify(DeviceEvent event) {
783 assertEquals(DEVICE_REMOVED, event.type());
784 assertDevice(DID1, SW2, event.subject());
785 removeLatch.countDown();
786 }
787 };
788
789 DeviceDescription description =
790 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
alshabib7911a052014-10-16 17:49:37 -0700791 HW, SW1, SN, CID);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700792 deviceStore.setDelegate(checkAdd);
793 deviceStore.createOrUpdateDevice(PID, DID1, description);
794 assertTrue("Add event fired", addLatch.await(1, TimeUnit.SECONDS));
795
796
797 DeviceDescription description2 =
798 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
alshabib7911a052014-10-16 17:49:37 -0700799 HW, SW2, SN, CID);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700800 deviceStore.unsetDelegate(checkAdd);
801 deviceStore.setDelegate(checkUpdate);
802 deviceStore.createOrUpdateDevice(PID, DID1, description2);
803 assertTrue("Update event fired", updateLatch.await(1, TimeUnit.SECONDS));
804
805 deviceStore.unsetDelegate(checkUpdate);
806 deviceStore.setDelegate(checkRemove);
807 deviceStore.removeDevice(DID1);
808 assertTrue("Remove event fired", removeLatch.await(1, TimeUnit.SECONDS));
809 }
810
Yuta HIGUCHIe8252bb2014-10-22 09:41:01 -0700811 private final class TestMastershipService extends MastershipServiceAdapter {
812 @Override
813 public NodeId getMasterFor(DeviceId deviceId) {
814 return NID1;
815 }
816 }
817
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700818 private static final class TestGossipDeviceStore extends GossipDeviceStore {
819
Madan Jampani53e44e62014-10-07 12:39:51 -0700820 public TestGossipDeviceStore(
Yuta HIGUCHI093e83e2014-10-10 22:26:11 -0700821 DeviceClockService deviceClockService,
Madan Jampani53e44e62014-10-07 12:39:51 -0700822 ClusterService clusterService,
823 ClusterCommunicationService clusterCommunicator) {
Yuta HIGUCHI093e83e2014-10-10 22:26:11 -0700824 this.deviceClockService = deviceClockService;
Madan Jampani53e44e62014-10-07 12:39:51 -0700825 this.clusterService = clusterService;
Madan Jampani47c93732014-10-06 20:46:08 -0700826 this.clusterCommunicator = clusterCommunicator;
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700827 }
Madan Jampani47c93732014-10-06 20:46:08 -0700828
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700829 public <T> T deserialize(byte[] bytes) {
830 return SERIALIZER.decode(bytes);
831 }
Madan Jampani47c93732014-10-06 20:46:08 -0700832 }
Madan Jampani53e44e62014-10-07 12:39:51 -0700833
Yuta HIGUCHI3e5d11a2014-11-04 14:16:44 -0800834 private static final class TestClusterService extends StaticClusterService {
Madan Jampani53e44e62014-10-07 12:39:51 -0700835
836 public TestClusterService() {
Yuta HIGUCHI3e5d11a2014-11-04 14:16:44 -0800837 localNode = ONOS1;
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700838 nodes.put(NID1, ONOS1);
839 nodeStates.put(NID1, ACTIVE);
840
841 nodes.put(NID2, ONOS2);
842 nodeStates.put(NID2, ACTIVE);
Madan Jampani53e44e62014-10-07 12:39:51 -0700843 }
Madan Jampani53e44e62014-10-07 12:39:51 -0700844 }
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700845}