blob: f565f0a640a855a35f92479a7400742f7f6678e2 [file] [log] [blame]
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2014-present Open Networking Foundation
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07003 *
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;
Yuta HIGUCHI47c40882014-10-10 18:44:37 -070020import org.easymock.Capture;
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -070021import org.junit.After;
22import org.junit.AfterClass;
23import org.junit.Before;
24import org.junit.BeforeClass;
25import org.junit.Ignore;
26import org.junit.Test;
Jonathan Hart7d656f42015-01-27 14:07:23 -080027import org.onlab.packet.ChassisId;
28import org.onlab.packet.IpAddress;
Madan Jampanif4c88502016-01-21 12:35:36 -080029import org.onlab.util.KryoNamespace;
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;
Brian O'Connorabafb502014-12-02 22:26:20 -080035import org.onosproject.net.Annotations;
36import org.onosproject.net.DefaultAnnotations;
37import org.onosproject.net.Device;
38import org.onosproject.net.DeviceId;
Madan Jampanic6e574f2015-05-29 13:41:52 -070039import org.onosproject.net.MastershipRole;
Brian O'Connorabafb502014-12-02 22:26:20 -080040import 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;
Madan Jampani565a66a2015-07-25 17:01:13 -070046import org.onosproject.net.device.DeviceClockServiceAdapter;
Brian O'Connorabafb502014-12-02 22:26:20 -080047import org.onosproject.net.device.DeviceDescription;
48import org.onosproject.net.device.DeviceEvent;
49import org.onosproject.net.device.DeviceStore;
50import org.onosproject.net.device.DeviceStoreDelegate;
51import org.onosproject.net.device.PortDescription;
52import org.onosproject.net.provider.ProviderId;
Madan Jampani565a66a2015-07-25 17:01:13 -070053import org.onosproject.store.Timestamp;
Brian O'Connorabafb502014-12-02 22:26:20 -080054import org.onosproject.store.cluster.StaticClusterService;
55import org.onosproject.store.cluster.messaging.ClusterCommunicationService;
56import org.onosproject.store.cluster.messaging.ClusterMessage;
Brian O'Connorabafb502014-12-02 22:26:20 -080057import org.onosproject.store.cluster.messaging.MessageSubject;
Madan Jampani565a66a2015-07-25 17:01:13 -070058import org.onosproject.store.impl.MastershipBasedTimestamp;
Madan Jampanif4c88502016-01-21 12:35:36 -080059import org.onosproject.store.service.EventuallyConsistentMap;
60import org.onosproject.store.service.EventuallyConsistentMapBuilder;
61import org.onosproject.store.service.StorageService;
Jonathan Hart46ab5cc2016-09-15 15:42:39 -070062
Jonathan Hart7d656f42015-01-27 14:07:23 -080063import java.io.IOException;
64import java.util.Arrays;
65import java.util.Collections;
66import java.util.HashMap;
67import java.util.List;
68import java.util.Map;
69import java.util.Set;
Madan Jampanic6e574f2015-05-29 13:41:52 -070070import java.util.concurrent.CompletableFuture;
Jonathan Hart7d656f42015-01-27 14:07:23 -080071import java.util.concurrent.CountDownLatch;
72import java.util.concurrent.TimeUnit;
Madan Jampani565a66a2015-07-25 17:01:13 -070073import java.util.concurrent.atomic.AtomicLong;
Madan Jampanif4c88502016-01-21 12:35:36 -080074import java.util.function.BiFunction;
Madan Jampani2bfa94c2015-04-11 05:03:49 -070075import java.util.function.Function;
Jonathan Hart7d656f42015-01-27 14:07:23 -080076
77import static java.util.Arrays.asList;
Jonathan Hart46ab5cc2016-09-15 15:42:39 -070078import static org.easymock.EasyMock.anyObject;
79import static org.easymock.EasyMock.capture;
80import static org.easymock.EasyMock.createNiceMock;
81import static org.easymock.EasyMock.expect;
82import static org.easymock.EasyMock.expectLastCall;
83import static org.easymock.EasyMock.replay;
84import static org.easymock.EasyMock.reset;
85import static org.easymock.EasyMock.verify;
86import static org.junit.Assert.assertEquals;
87import static org.junit.Assert.assertFalse;
88import static org.junit.Assert.assertNotNull;
89import static org.junit.Assert.assertNull;
90import static org.junit.Assert.assertTrue;
91import static org.junit.Assert.fail;
Jonathan Hart7d656f42015-01-27 14:07:23 -080092import static org.onosproject.cluster.ControllerNode.State.ACTIVE;
93import static org.onosproject.net.DefaultAnnotations.union;
94import static org.onosproject.net.Device.Type.SWITCH;
95import static org.onosproject.net.DeviceId.deviceId;
Jonathan Hart46ab5cc2016-09-15 15:42:39 -070096import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_ADDED;
97import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED;
98import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_REMOVED;
99import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_UPDATED;
100import static org.onosproject.net.device.DeviceEvent.Type.PORT_ADDED;
101import static org.onosproject.net.device.DeviceEvent.Type.PORT_REMOVED;
102import static org.onosproject.net.device.DeviceEvent.Type.PORT_UPDATED;
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700103
104
105// TODO add tests for remote replication
106/**
107 * Test of the gossip based distributed DeviceStore implementation.
108 */
109public class GossipDeviceStoreTest {
110
111 private static final ProviderId PID = new ProviderId("of", "foo");
112 private static final ProviderId PIDA = new ProviderId("of", "bar", true);
113 private static final DeviceId DID1 = deviceId("of:foo");
114 private static final DeviceId DID2 = deviceId("of:bar");
115 private static final String MFR = "whitebox";
116 private static final String HW = "1.1.x";
117 private static final String SW1 = "3.8.1";
118 private static final String SW2 = "3.9.5";
119 private static final String SN = "43311-12345";
alshabib7911a052014-10-16 17:49:37 -0700120 private static final ChassisId CID = new ChassisId();
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700121
122 private static final PortNumber P1 = PortNumber.portNumber(1);
123 private static final PortNumber P2 = PortNumber.portNumber(2);
124 private static final PortNumber P3 = PortNumber.portNumber(3);
125
126 private static final SparseAnnotations A1 = DefaultAnnotations.builder()
127 .set("A1", "a1")
128 .set("B1", "b1")
129 .build();
130 private static final SparseAnnotations A1_2 = DefaultAnnotations.builder()
131 .remove("A1")
132 .set("B3", "b3")
133 .build();
134 private static final SparseAnnotations A2 = DefaultAnnotations.builder()
135 .set("A2", "a2")
136 .set("B2", "b2")
137 .build();
138 private static final SparseAnnotations A2_2 = DefaultAnnotations.builder()
139 .remove("A2")
140 .set("B4", "b4")
141 .build();
142
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700143 // local node
144 private static final NodeId NID1 = new NodeId("local");
145 private static final ControllerNode ONOS1 =
Pavlin Radoslavov444b5192014-10-28 10:45:19 -0700146 new DefaultControllerNode(NID1, IpAddress.valueOf("127.0.0.1"));
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700147
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700148 // remote node
149 private static final NodeId NID2 = new NodeId("remote");
150 private static final ControllerNode ONOS2 =
Pavlin Radoslavov444b5192014-10-28 10:45:19 -0700151 new DefaultControllerNode(NID2, IpAddress.valueOf("127.0.0.2"));
Sho SHIMIZU21d00692016-08-15 11:15:28 -0700152 private static final List<SparseAnnotations> NO_ANNOTATION = Collections.emptyList();
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700153
Madan Jampanif4c88502016-01-21 12:35:36 -0800154 EventuallyConsistentMapBuilder ecMapBuilder;
155 EventuallyConsistentMap ecMap;
156 StorageService testStorageService;
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700157 private TestGossipDeviceStore testGossipDeviceStore;
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700158 private GossipDeviceStore gossipDeviceStore;
159 private DeviceStore deviceStore;
160
Madan Jampani565a66a2015-07-25 17:01:13 -0700161 private DeviceClockService deviceClockService = new TestDeviceClockService();
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700162 private ClusterCommunicationService clusterCommunicator;
Yuta HIGUCHI3e5d11a2014-11-04 14:16:44 -0800163
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700164 @BeforeClass
165 public static void setUpBeforeClass() throws Exception {
166 }
167
168 @AfterClass
169 public static void tearDownAfterClass() throws Exception {
170 }
171
172
173 @Before
174 public void setUp() throws Exception {
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700175 clusterCommunicator = createNiceMock(ClusterCommunicationService.class);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700176 replay(clusterCommunicator);
Madan Jampani53e44e62014-10-07 12:39:51 -0700177 ClusterService clusterService = new TestClusterService();
Madan Jampani47c93732014-10-06 20:46:08 -0700178
Yuta HIGUCHI093e83e2014-10-10 22:26:11 -0700179 testGossipDeviceStore = new TestGossipDeviceStore(deviceClockService, clusterService, clusterCommunicator);
Yuta HIGUCHIe8252bb2014-10-22 09:41:01 -0700180 testGossipDeviceStore.mastershipService = new TestMastershipService();
181
Madan Jampanif4c88502016-01-21 12:35:36 -0800182 ecMapBuilder = createNiceMock(EventuallyConsistentMapBuilder.class);
183 expect(ecMapBuilder.withName(anyObject(String.class))).andReturn(ecMapBuilder).anyTimes();
184 expect(ecMapBuilder.withSerializer(anyObject(KryoNamespace.Builder.class))).andReturn(ecMapBuilder).anyTimes();
185 expect(ecMapBuilder.withAntiEntropyPeriod(5, TimeUnit.SECONDS)).andReturn(ecMapBuilder).anyTimes();
186 expect(ecMapBuilder.withTimestampProvider(anyObject(BiFunction.class))).andReturn(ecMapBuilder).anyTimes();
187 expect(ecMapBuilder.withTombstonesDisabled()).andReturn(ecMapBuilder).anyTimes();
188
189 ecMap = createNiceMock(EventuallyConsistentMap.class);
190 expect(ecMapBuilder.build()).andReturn(ecMap).anyTimes();
191 testStorageService = createNiceMock(StorageService.class);
192 expect(testStorageService.eventuallyConsistentMapBuilder()).andReturn(ecMapBuilder).anyTimes();
193
194 replay(testStorageService, ecMapBuilder, ecMap);
195
196 testGossipDeviceStore.storageService = testStorageService;
Madan Jampani565a66a2015-07-25 17:01:13 -0700197 testGossipDeviceStore.deviceClockService = deviceClockService;
Thomas Vachuskafdbc4c22015-05-29 15:53:01 -0700198
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700199 gossipDeviceStore = testGossipDeviceStore;
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700200 gossipDeviceStore.activate();
201 deviceStore = gossipDeviceStore;
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700202 verify(clusterCommunicator);
203 reset(clusterCommunicator);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700204 }
205
206 @After
207 public void tearDown() throws Exception {
208 gossipDeviceStore.deactivate();
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700209 }
210
Yuta HIGUCHI0d6a5e62014-10-03 15:54:09 -0700211 private void putDevice(DeviceId deviceId, String swVersion,
212 SparseAnnotations... annotations) {
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700213 DeviceDescription description =
214 new DefaultDeviceDescription(deviceId.uri(), SWITCH, MFR,
alshabib7911a052014-10-16 17:49:37 -0700215 HW, swVersion, SN, CID, annotations);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700216 reset(clusterCommunicator);
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700217 clusterCommunicator.<InternalDeviceEvent>broadcast(
218 anyObject(InternalDeviceEvent.class), anyObject(MessageSubject.class), anyObject(Function.class));
219 expectLastCall().anyTimes();
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700220 replay(clusterCommunicator);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700221 deviceStore.createOrUpdateDevice(PID, deviceId, description);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700222 verify(clusterCommunicator);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700223 }
224
Yuta HIGUCHI0d6a5e62014-10-03 15:54:09 -0700225 private void putDeviceAncillary(DeviceId deviceId, String swVersion,
226 SparseAnnotations... annotations) {
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700227 DeviceDescription description =
228 new DefaultDeviceDescription(deviceId.uri(), SWITCH, MFR,
alshabib7911a052014-10-16 17:49:37 -0700229 HW, swVersion, SN, CID, annotations);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700230 deviceStore.createOrUpdateDevice(PIDA, deviceId, description);
231 }
232
233 private static void assertDevice(DeviceId id, String swVersion, Device device) {
234 assertNotNull(device);
235 assertEquals(id, device.id());
236 assertEquals(MFR, device.manufacturer());
237 assertEquals(HW, device.hwVersion());
238 assertEquals(swVersion, device.swVersion());
239 assertEquals(SN, device.serialNumber());
240 }
241
242 /**
243 * Verifies that Annotations created by merging {@code annotations} is
244 * equal to actual Annotations.
245 *
246 * @param actual Annotations to check
247 * @param annotations
248 */
249 private static void assertAnnotationsEquals(Annotations actual, SparseAnnotations... annotations) {
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700250 SparseAnnotations expected = DefaultAnnotations.builder().build();
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700251 for (SparseAnnotations a : annotations) {
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700252 expected = DefaultAnnotations.union(expected, a);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700253 }
254 assertEquals(expected.keys(), actual.keys());
255 for (String key : expected.keys()) {
256 assertEquals(expected.value(key), actual.value(key));
257 }
258 }
259
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700260 private static void assertDeviceDescriptionEquals(DeviceDescription expected,
261 DeviceDescription actual) {
262 if (expected == actual) {
263 return;
264 }
Jonathan Hartd9df7bd2015-11-10 17:10:25 -0800265 assertEquals(expected.deviceUri(), actual.deviceUri());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700266 assertEquals(expected.hwVersion(), actual.hwVersion());
267 assertEquals(expected.manufacturer(), actual.manufacturer());
268 assertEquals(expected.serialNumber(), actual.serialNumber());
269 assertEquals(expected.swVersion(), actual.swVersion());
270
271 assertAnnotationsEquals(actual.annotations(), expected.annotations());
272 }
273
274 private static void assertDeviceDescriptionEquals(DeviceDescription expected,
275 List<SparseAnnotations> expectedAnnotations,
276 DeviceDescription actual) {
277 if (expected == actual) {
278 return;
279 }
Jonathan Hartd9df7bd2015-11-10 17:10:25 -0800280 assertEquals(expected.deviceUri(), actual.deviceUri());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700281 assertEquals(expected.hwVersion(), actual.hwVersion());
282 assertEquals(expected.manufacturer(), actual.manufacturer());
283 assertEquals(expected.serialNumber(), actual.serialNumber());
284 assertEquals(expected.swVersion(), actual.swVersion());
285
286 assertAnnotationsEquals(actual.annotations(),
287 expectedAnnotations.toArray(new SparseAnnotations[0]));
288 }
289
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700290 @Test
291 public final void testGetDeviceCount() {
292 assertEquals("initialy empty", 0, deviceStore.getDeviceCount());
293
294 putDevice(DID1, SW1);
295 putDevice(DID2, SW2);
296 putDevice(DID1, SW1);
297
298 assertEquals("expect 2 uniq devices", 2, deviceStore.getDeviceCount());
299 }
300
301 @Test
mskala0d0c6832017-07-12 11:21:23 +0200302 public final void testGetAvailableDeviceCount() {
303 assertEquals("initialy empty", 0, deviceStore.getAvailableDeviceCount());
304
305 putDevice(DID1, SW1);
306 putDevice(DID2, SW2);
307
308 deviceStore.markOffline(DID1);
309
310 assertEquals("expect 1 available device", 1, deviceStore.getAvailableDeviceCount());
311
312 deviceStore.markOnline(DID1);
313
314 assertEquals("expect 2 available devices", 2, deviceStore.getAvailableDeviceCount());
315 }
316
317 @Test
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700318 public final void testGetDevices() {
319 assertEquals("initialy empty", 0, Iterables.size(deviceStore.getDevices()));
320
321 putDevice(DID1, SW1);
322 putDevice(DID2, SW2);
323 putDevice(DID1, SW1);
324
325 assertEquals("expect 2 uniq devices",
326 2, Iterables.size(deviceStore.getDevices()));
327
328 Map<DeviceId, Device> devices = new HashMap<>();
329 for (Device device : deviceStore.getDevices()) {
330 devices.put(device.id(), device);
331 }
332
333 assertDevice(DID1, SW1, devices.get(DID1));
334 assertDevice(DID2, SW2, devices.get(DID2));
335
336 // add case for new node?
337 }
338
339 @Test
340 public final void testGetDevice() {
341
342 putDevice(DID1, SW1);
343
344 assertDevice(DID1, SW1, deviceStore.getDevice(DID1));
345 assertNull("DID2 shouldn't be there", deviceStore.getDevice(DID2));
346 }
347
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700348 private void assertInternalDeviceEvent(NodeId sender,
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700349 DeviceId deviceId,
350 ProviderId providerId,
351 DeviceDescription expectedDesc,
352 Capture<InternalDeviceEvent> actualEvent,
353 Capture<MessageSubject> actualSubject,
354 Capture<Function<InternalDeviceEvent, byte[]>> actualEncoder) {
355 assertTrue(actualEvent.hasCaptured());
356 assertTrue(actualSubject.hasCaptured());
357 assertTrue(actualEncoder.hasCaptured());
358
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700359 assertEquals(GossipDeviceStoreMessageSubjects.DEVICE_UPDATE,
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700360 actualSubject.getValue());
361 assertEquals(deviceId, actualEvent.getValue().deviceId());
362 assertEquals(providerId, actualEvent.getValue().providerId());
363 assertDeviceDescriptionEquals(expectedDesc, actualEvent.getValue().deviceDescription().value());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700364 }
365
366 private void assertInternalDeviceEvent(NodeId sender,
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700367 DeviceId deviceId,
368 ProviderId providerId,
369 DeviceDescription expectedDesc,
370 List<SparseAnnotations> expectedAnnotations,
371 Capture<InternalDeviceEvent> actualEvent,
372 Capture<MessageSubject> actualSubject,
373 Capture<Function<InternalDeviceEvent, byte[]>> actualEncoder) {
374 assertTrue(actualEvent.hasCaptured());
375 assertTrue(actualSubject.hasCaptured());
376 assertTrue(actualEncoder.hasCaptured());
377
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700378 assertEquals(GossipDeviceStoreMessageSubjects.DEVICE_UPDATE,
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700379 actualSubject.getValue());
380 assertEquals(deviceId, actualEvent.getValue().deviceId());
381 assertEquals(providerId, actualEvent.getValue().providerId());
382 assertDeviceDescriptionEquals(
383 expectedDesc,
384 expectedAnnotations,
385 actualEvent.getValue().deviceDescription().value());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700386 }
387
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700388 @Test
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700389 public final void testCreateOrUpdateDevice() throws IOException {
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700390 DeviceDescription description =
391 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
alshabib7911a052014-10-16 17:49:37 -0700392 HW, SW1, SN, CID);
Carmelo Cascone21eb0422019-06-17 12:00:33 -0700393 Capture<InternalDeviceEvent> message = Capture.newInstance();
394 Capture<MessageSubject> subject = Capture.newInstance();
395 Capture<Function<InternalDeviceEvent, byte[]>> encoder = Capture.newInstance();
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700396
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700397 resetCommunicatorExpectingSingleBroadcast(message, subject, encoder);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700398 DeviceEvent event = deviceStore.createOrUpdateDevice(PID, DID1, description);
399 assertEquals(DEVICE_ADDED, event.type());
400 assertDevice(DID1, SW1, event.subject());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700401 verify(clusterCommunicator);
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700402 assertInternalDeviceEvent(NID1, DID1, PID, description, message, subject, encoder);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700403
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700404
405 DeviceDescription description2 =
406 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
alshabib7911a052014-10-16 17:49:37 -0700407 HW, SW2, SN, CID);
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700408 resetCommunicatorExpectingSingleBroadcast(message, subject, encoder);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700409 DeviceEvent event2 = deviceStore.createOrUpdateDevice(PID, DID1, description2);
410 assertEquals(DEVICE_UPDATED, event2.type());
411 assertDevice(DID1, SW2, event2.subject());
412
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700413 verify(clusterCommunicator);
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700414 assertInternalDeviceEvent(NID1, DID1, PID, description2, message, subject, encoder);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700415 reset(clusterCommunicator);
416
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700417 assertNull("No change expected", deviceStore.createOrUpdateDevice(PID, DID1, description2));
418 }
419
420 @Test
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700421 public final void testCreateOrUpdateDeviceAncillary() throws IOException {
422 // add
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700423 DeviceDescription description =
424 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
alshabib7911a052014-10-16 17:49:37 -0700425 HW, SW1, SN, CID, A2);
Carmelo Cascone21eb0422019-06-17 12:00:33 -0700426 Capture<ClusterMessage> bcast = Capture.newInstance();
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700427
Carmelo Cascone21eb0422019-06-17 12:00:33 -0700428 Capture<InternalDeviceEvent> message = Capture.newInstance();
429 Capture<MessageSubject> subject = Capture.newInstance();
430 Capture<Function<InternalDeviceEvent, byte[]>> encoder = Capture.newInstance();
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700431
432 resetCommunicatorExpectingSingleBroadcast(message, subject, encoder);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700433 DeviceEvent event = deviceStore.createOrUpdateDevice(PIDA, DID1, description);
434 assertEquals(DEVICE_ADDED, event.type());
435 assertDevice(DID1, SW1, event.subject());
436 assertEquals(PIDA, event.subject().providerId());
437 assertAnnotationsEquals(event.subject().annotations(), A2);
438 assertFalse("Ancillary will not bring device up", deviceStore.isAvailable(DID1));
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700439 verify(clusterCommunicator);
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700440 assertInternalDeviceEvent(NID1, DID1, PIDA, description, message, subject, encoder);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700441
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700442 // update from primary
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700443 DeviceDescription description2 =
444 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
alshabib7911a052014-10-16 17:49:37 -0700445 HW, SW2, SN, CID, A1);
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700446 resetCommunicatorExpectingSingleBroadcast(message, subject, encoder);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700447
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700448 DeviceEvent event2 = deviceStore.createOrUpdateDevice(PID, DID1, description2);
449 assertEquals(DEVICE_UPDATED, event2.type());
450 assertDevice(DID1, SW2, event2.subject());
451 assertEquals(PID, event2.subject().providerId());
452 assertAnnotationsEquals(event2.subject().annotations(), A1, A2);
453 assertTrue(deviceStore.isAvailable(DID1));
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700454 verify(clusterCommunicator);
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700455 assertInternalDeviceEvent(NID1, DID1, PID, description2, message, subject, encoder);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700456
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700457 // no-op update from primary
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700458 resetCommunicatorExpectingNoBroadcast(message, subject, encoder);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700459 assertNull("No change expected", deviceStore.createOrUpdateDevice(PID, DID1, description2));
460
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700461 verify(clusterCommunicator);
462 assertFalse("no broadcast expected", bcast.hasCaptured());
463
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700464 // For now, Ancillary is ignored once primary appears
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700465 resetCommunicatorExpectingNoBroadcast(message, subject, encoder);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700466
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700467 assertNull("No change expected", deviceStore.createOrUpdateDevice(PIDA, DID1, description));
468
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700469 verify(clusterCommunicator);
470 assertFalse("no broadcast expected", bcast.hasCaptured());
471
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700472 // But, Ancillary annotations will be in effect
473 DeviceDescription description3 =
474 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
alshabib7911a052014-10-16 17:49:37 -0700475 HW, SW1, SN, CID, A2_2);
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700476 resetCommunicatorExpectingSingleBroadcast(message, subject, encoder);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700477
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700478 DeviceEvent event3 = deviceStore.createOrUpdateDevice(PIDA, DID1, description3);
479 assertEquals(DEVICE_UPDATED, event3.type());
480 // basic information will be the one from Primary
481 assertDevice(DID1, SW2, event3.subject());
482 assertEquals(PID, event3.subject().providerId());
483 // but annotation from Ancillary will be merged
484 assertAnnotationsEquals(event3.subject().annotations(), A1, A2, A2_2);
485 assertTrue(deviceStore.isAvailable(DID1));
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700486 verify(clusterCommunicator);
487 // note: only annotation from PIDA is sent over the wire
488 assertInternalDeviceEvent(NID1, DID1, PIDA, description3,
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700489 asList(union(A2, A2_2)), message, subject, encoder);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700490
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700491 }
492
493
494 @Test
495 public final void testMarkOffline() {
496
497 putDevice(DID1, SW1);
498 assertTrue(deviceStore.isAvailable(DID1));
499
Carmelo Cascone21eb0422019-06-17 12:00:33 -0700500 Capture<InternalDeviceEvent> message = Capture.newInstance();
501 Capture<MessageSubject> subject = Capture.newInstance();
502 Capture<Function<InternalDeviceEvent, byte[]>> encoder = Capture.newInstance();
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700503
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700504 resetCommunicatorExpectingSingleBroadcast(message, subject, encoder);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700505 DeviceEvent event = deviceStore.markOffline(DID1);
506 assertEquals(DEVICE_AVAILABILITY_CHANGED, event.type());
507 assertDevice(DID1, SW1, event.subject());
508 assertFalse(deviceStore.isAvailable(DID1));
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700509 verify(clusterCommunicator);
510 // TODO: verify broadcast message
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700511 assertTrue(message.hasCaptured());
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700512
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700513
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700514 resetCommunicatorExpectingNoBroadcast(message, subject, encoder);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700515 DeviceEvent event2 = deviceStore.markOffline(DID1);
516 assertNull("No change, no event", event2);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700517 verify(clusterCommunicator);
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700518 assertFalse(message.hasCaptured());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700519 }
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700520
521 @Test
522 public final void testUpdatePorts() {
523 putDevice(DID1, SW1);
Sho SHIMIZU21d00692016-08-15 11:15:28 -0700524 List<PortDescription> pds = Arrays.asList(
Yuta HIGUCHI53e47962018-03-01 23:50:48 -0800525 DefaultPortDescription.builder().withPortNumber(P1).isEnabled(true).build(),
526 DefaultPortDescription.builder().withPortNumber(P2).isEnabled(true).build()
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700527 );
Carmelo Cascone21eb0422019-06-17 12:00:33 -0700528 Capture<InternalDeviceEvent> message = Capture.newInstance();
529 Capture<MessageSubject> subject = Capture.newInstance();
530 Capture<Function<InternalDeviceEvent, byte[]>> encoder = Capture.newInstance();
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700531
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700532 resetCommunicatorExpectingSingleBroadcast(message, subject, encoder);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700533 List<DeviceEvent> events = deviceStore.updatePorts(PID, DID1, pds);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700534 verify(clusterCommunicator);
535 // TODO: verify broadcast message
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700536 assertTrue(message.hasCaptured());
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700537
538 Set<PortNumber> expectedPorts = Sets.newHashSet(P1, P2);
539 for (DeviceEvent event : events) {
540 assertEquals(PORT_ADDED, event.type());
541 assertDevice(DID1, SW1, event.subject());
542 assertTrue("PortNumber is one of expected",
543 expectedPorts.remove(event.port().number()));
544 assertTrue("Port is enabled", event.port().isEnabled());
545 }
546 assertTrue("Event for all expectedport appeared", expectedPorts.isEmpty());
547
548
Sho SHIMIZU21d00692016-08-15 11:15:28 -0700549 List<PortDescription> pds2 = Arrays.asList(
Yuta HIGUCHI53e47962018-03-01 23:50:48 -0800550 DefaultPortDescription.builder().withPortNumber(P1).isEnabled(false).build(),
551 DefaultPortDescription.builder().withPortNumber(P2).isEnabled(true).build(),
552 DefaultPortDescription.builder().withPortNumber(P3).isEnabled(true).build()
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700553 );
554
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700555 resetCommunicatorExpectingSingleBroadcast(message, subject, encoder);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700556 events = deviceStore.updatePorts(PID, DID1, pds2);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700557 verify(clusterCommunicator);
558 // TODO: verify broadcast message
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700559 assertTrue(message.hasCaptured());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700560
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700561 assertFalse("event should be triggered", events.isEmpty());
562 for (DeviceEvent event : events) {
563 PortNumber num = event.port().number();
564 if (P1.equals(num)) {
565 assertEquals(PORT_UPDATED, event.type());
566 assertDevice(DID1, SW1, event.subject());
567 assertFalse("Port is disabled", event.port().isEnabled());
568 } else if (P2.equals(num)) {
569 fail("P2 event not expected.");
570 } else if (P3.equals(num)) {
571 assertEquals(PORT_ADDED, event.type());
572 assertDevice(DID1, SW1, event.subject());
573 assertTrue("Port is enabled", event.port().isEnabled());
574 } else {
575 fail("Unknown port number encountered: " + num);
576 }
577 }
578
Sho SHIMIZU21d00692016-08-15 11:15:28 -0700579 List<PortDescription> pds3 = Arrays.asList(
Yuta HIGUCHI53e47962018-03-01 23:50:48 -0800580 DefaultPortDescription.builder().withPortNumber(P1).isEnabled(false).build(),
581 DefaultPortDescription.builder().withPortNumber(P2).isEnabled(true).build()
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700582 );
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700583 resetCommunicatorExpectingSingleBroadcast(message, subject, encoder);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700584 events = deviceStore.updatePorts(PID, DID1, pds3);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700585 verify(clusterCommunicator);
586 // TODO: verify broadcast message
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700587 assertTrue(message.hasCaptured());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700588
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700589 assertFalse("event should be triggered", events.isEmpty());
590 for (DeviceEvent event : events) {
591 PortNumber num = event.port().number();
592 if (P1.equals(num)) {
593 fail("P1 event not expected.");
594 } else if (P2.equals(num)) {
595 fail("P2 event not expected.");
596 } else if (P3.equals(num)) {
597 assertEquals(PORT_REMOVED, event.type());
598 assertDevice(DID1, SW1, event.subject());
599 assertTrue("Port was enabled", event.port().isEnabled());
600 } else {
601 fail("Unknown port number encountered: " + num);
602 }
603 }
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700604 }
605
606 @Test
607 public final void testUpdatePortStatus() {
608 putDevice(DID1, SW1);
Sho SHIMIZU21d00692016-08-15 11:15:28 -0700609 List<PortDescription> pds = Arrays.asList(
Yuta HIGUCHI53e47962018-03-01 23:50:48 -0800610 DefaultPortDescription.builder().withPortNumber(P1).isEnabled(true).build()
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700611 );
612 deviceStore.updatePorts(PID, DID1, pds);
613
Carmelo Cascone21eb0422019-06-17 12:00:33 -0700614 Capture<InternalPortStatusEvent> message = Capture.newInstance();
615 Capture<MessageSubject> subject = Capture.newInstance();
616 Capture<Function<InternalPortStatusEvent, byte[]>> encoder = Capture.newInstance();
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700617
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700618 resetCommunicatorExpectingSingleBroadcast(message, subject, encoder);
Yuta HIGUCHI53e47962018-03-01 23:50:48 -0800619 final DefaultPortDescription desc = DefaultPortDescription.builder().withPortNumber(P1)
620 .isEnabled(false).build();
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700621 DeviceEvent event = deviceStore.updatePortStatus(PID, DID1, desc);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700622 assertEquals(PORT_UPDATED, event.type());
623 assertDevice(DID1, SW1, event.subject());
624 assertEquals(P1, event.port().number());
625 assertFalse("Port is disabled", event.port().isEnabled());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700626 verify(clusterCommunicator);
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700627 assertInternalPortStatusEvent(NID1, DID1, PID, desc, NO_ANNOTATION, message, subject, encoder);
628 assertTrue(message.hasCaptured());
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700629 }
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700630
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700631 @Test
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700632 public final void testUpdatePortStatusAncillary() throws IOException {
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700633 putDeviceAncillary(DID1, SW1);
634 putDevice(DID1, SW1);
Sho SHIMIZU21d00692016-08-15 11:15:28 -0700635 List<PortDescription> pds = Arrays.asList(
Yuta HIGUCHI53e47962018-03-01 23:50:48 -0800636 DefaultPortDescription.builder().withPortNumber(P1).isEnabled(true).annotations(A1).build()
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700637 );
638 deviceStore.updatePorts(PID, DID1, pds);
639
Carmelo Cascone21eb0422019-06-17 12:00:33 -0700640 Capture<InternalPortStatusEvent> message = Capture.newInstance();
641 Capture<MessageSubject> subject = Capture.newInstance();
642 Capture<Function<InternalPortStatusEvent, byte[]>> encoder = Capture.newInstance();
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700643
644 // update port from primary
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700645 resetCommunicatorExpectingSingleBroadcast(message, subject, encoder);
646
Yuta HIGUCHI53e47962018-03-01 23:50:48 -0800647 final DefaultPortDescription desc1 = DefaultPortDescription.builder().withPortNumber(P1).isEnabled(false)
648 .annotations(A1_2).build();
649
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700650 DeviceEvent event = deviceStore.updatePortStatus(PID, DID1, desc1);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700651 assertEquals(PORT_UPDATED, event.type());
652 assertDevice(DID1, SW1, event.subject());
653 assertEquals(P1, event.port().number());
654 assertAnnotationsEquals(event.port().annotations(), A1, A1_2);
655 assertFalse("Port is disabled", event.port().isEnabled());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700656 verify(clusterCommunicator);
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700657 assertInternalPortStatusEvent(NID1, DID1, PID, desc1, asList(A1, A1_2), message, subject, encoder);
658 assertTrue(message.hasCaptured());
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700659
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700660 // update port from ancillary with no attributes
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700661 resetCommunicatorExpectingNoBroadcast(message, subject, encoder);
Yuta HIGUCHI53e47962018-03-01 23:50:48 -0800662 final DefaultPortDescription desc2 = DefaultPortDescription.builder()
663 .withPortNumber(P1).isEnabled(true).build();
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700664 DeviceEvent event2 = deviceStore.updatePortStatus(PIDA, DID1, desc2);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700665 assertNull("Ancillary is ignored if primary exists", event2);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700666 verify(clusterCommunicator);
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700667 assertFalse(message.hasCaptured());
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700668
669 // but, Ancillary annotation update will be notified
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700670 resetCommunicatorExpectingSingleBroadcast(message, subject, encoder);
Yuta HIGUCHI53e47962018-03-01 23:50:48 -0800671 final DefaultPortDescription desc3 = DefaultPortDescription.builder().withPortNumber(P1)
672 .isEnabled(true).annotations(A2).build();
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700673 DeviceEvent event3 = deviceStore.updatePortStatus(PIDA, DID1, desc3);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700674 assertEquals(PORT_UPDATED, event3.type());
675 assertDevice(DID1, SW1, event3.subject());
676 assertEquals(P1, event3.port().number());
677 assertAnnotationsEquals(event3.port().annotations(), A1, A1_2, A2);
678 assertFalse("Port is disabled", event3.port().isEnabled());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700679 verify(clusterCommunicator);
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700680 assertInternalPortStatusEvent(NID1, DID1, PIDA, desc3, asList(A2), message, subject, encoder);
681 assertTrue(message.hasCaptured());
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700682
683 // port only reported from Ancillary will be notified as down
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700684 resetCommunicatorExpectingSingleBroadcast(message, subject, encoder);
Yuta HIGUCHI53e47962018-03-01 23:50:48 -0800685 final DefaultPortDescription desc4 = DefaultPortDescription.builder()
686 .withPortNumber(P2).isEnabled(true).build();
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700687 DeviceEvent event4 = deviceStore.updatePortStatus(PIDA, DID1, desc4);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700688 assertEquals(PORT_ADDED, event4.type());
689 assertDevice(DID1, SW1, event4.subject());
690 assertEquals(P2, event4.port().number());
691 assertAnnotationsEquals(event4.port().annotations());
692 assertFalse("Port is disabled if not given from primary provider",
693 event4.port().isEnabled());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700694 verify(clusterCommunicator);
695 // TODO: verify broadcast message content
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700696 assertInternalPortStatusEvent(NID1, DID1, PIDA, desc4, NO_ANNOTATION, message, subject, encoder);
697 assertTrue(message.hasCaptured());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700698 }
699
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700700 private void assertInternalPortStatusEvent(NodeId sender,
701 DeviceId did,
702 ProviderId pid,
703 DefaultPortDescription expectedDesc,
704 List<SparseAnnotations> expectedAnnotations,
705 Capture<InternalPortStatusEvent> actualEvent,
706 Capture<MessageSubject> actualSubject,
707 Capture<Function<InternalPortStatusEvent, byte[]>> actualEncoder) {
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700708
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700709 assertTrue(actualEvent.hasCaptured());
710 assertTrue(actualSubject.hasCaptured());
711 assertTrue(actualEncoder.hasCaptured());
712
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700713 assertEquals(GossipDeviceStoreMessageSubjects.PORT_STATUS_UPDATE,
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700714 actualSubject.getValue());
715 assertEquals(did, actualEvent.getValue().deviceId());
716 assertEquals(pid, actualEvent.getValue().providerId());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700717 assertPortDescriptionEquals(expectedDesc, expectedAnnotations,
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700718 actualEvent.getValue().portDescription().value());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700719 }
720
721 private void assertPortDescriptionEquals(
722 PortDescription expectedDesc,
723 List<SparseAnnotations> expectedAnnotations,
724 PortDescription actual) {
725
726 assertEquals(expectedDesc.portNumber(), actual.portNumber());
727 assertEquals(expectedDesc.isEnabled(), actual.isEnabled());
728
729 assertAnnotationsEquals(actual.annotations(),
730 expectedAnnotations.toArray(new SparseAnnotations[0]));
731 }
732
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700733 private <T> void resetCommunicatorExpectingNoBroadcast(
734 Capture<T> message,
735 Capture<MessageSubject> subject,
736 Capture<Function<T, byte[]>> encoder) {
737 message.reset();
738 subject.reset();
739 encoder.reset();
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700740 reset(clusterCommunicator);
741 replay(clusterCommunicator);
742 }
743
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700744 private <T> void resetCommunicatorExpectingSingleBroadcast(
745 Capture<T> message,
746 Capture<MessageSubject> subject,
747 Capture<Function<T, byte[]>> encoder) {
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700748
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700749 message.reset();
750 subject.reset();
751 encoder.reset();
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700752 reset(clusterCommunicator);
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700753 clusterCommunicator.broadcast(
754 capture(message),
755 capture(subject),
756 capture(encoder));
757 expectLastCall().once();
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700758 replay(clusterCommunicator);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700759 }
760
761 @Test
762 public final void testGetPorts() {
763 putDevice(DID1, SW1);
764 putDevice(DID2, SW1);
Sho SHIMIZU21d00692016-08-15 11:15:28 -0700765 List<PortDescription> pds = Arrays.asList(
Yuta HIGUCHI53e47962018-03-01 23:50:48 -0800766 DefaultPortDescription.builder().withPortNumber(P1).isEnabled(true).build(),
767 DefaultPortDescription.builder().withPortNumber(P2).isEnabled(true).build()
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700768 );
769 deviceStore.updatePorts(PID, DID1, pds);
770
771 Set<PortNumber> expectedPorts = Sets.newHashSet(P1, P2);
772 List<Port> ports = deviceStore.getPorts(DID1);
773 for (Port port : ports) {
774 assertTrue("Port is enabled", port.isEnabled());
775 assertTrue("PortNumber is one of expected",
776 expectedPorts.remove(port.number()));
777 }
778 assertTrue("Event for all expectedport appeared", expectedPorts.isEmpty());
779
780
781 assertTrue("DID2 has no ports", deviceStore.getPorts(DID2).isEmpty());
782 }
783
784 @Test
785 public final void testGetPort() {
786 putDevice(DID1, SW1);
787 putDevice(DID2, SW1);
Sho SHIMIZU21d00692016-08-15 11:15:28 -0700788 List<PortDescription> pds = Arrays.asList(
Yuta HIGUCHI53e47962018-03-01 23:50:48 -0800789 DefaultPortDescription.builder().withPortNumber(P1).isEnabled(true).build(),
790 DefaultPortDescription.builder().withPortNumber(P2).isEnabled(false).build()
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700791 );
792 deviceStore.updatePorts(PID, DID1, pds);
793
794 Port port1 = deviceStore.getPort(DID1, P1);
795 assertEquals(P1, port1.number());
796 assertTrue("Port is enabled", port1.isEnabled());
797
798 Port port2 = deviceStore.getPort(DID1, P2);
799 assertEquals(P2, port2.number());
800 assertFalse("Port is disabled", port2.isEnabled());
801
802 Port port3 = deviceStore.getPort(DID1, P3);
803 assertNull("P3 not expected", port3);
804 }
805
806 @Test
807 public final void testRemoveDevice() {
Yuta HIGUCHI0d6a5e62014-10-03 15:54:09 -0700808 putDevice(DID1, SW1, A1);
Sho SHIMIZU21d00692016-08-15 11:15:28 -0700809 List<PortDescription> pds = Arrays.asList(
Yuta HIGUCHI53e47962018-03-01 23:50:48 -0800810 DefaultPortDescription.builder().withPortNumber(P1).isEnabled(true).annotations(A2).build()
Yuta HIGUCHI0d6a5e62014-10-03 15:54:09 -0700811 );
812 deviceStore.updatePorts(PID, DID1, pds);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700813 putDevice(DID2, SW1);
814
815 assertEquals(2, deviceStore.getDeviceCount());
Yuta HIGUCHI0d6a5e62014-10-03 15:54:09 -0700816 assertEquals(1, deviceStore.getPorts(DID1).size());
817 assertAnnotationsEquals(deviceStore.getDevice(DID1).annotations(), A1);
818 assertAnnotationsEquals(deviceStore.getPort(DID1, P1).annotations(), A2);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700819
Carmelo Cascone21eb0422019-06-17 12:00:33 -0700820 Capture<InternalDeviceEvent> message = Capture.newInstance();
821 Capture<MessageSubject> subject = Capture.newInstance();
822 Capture<Function<InternalDeviceEvent, byte[]>> encoder = Capture.newInstance();
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700823
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700824 resetCommunicatorExpectingSingleBroadcast(message, subject, encoder);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700825
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700826 DeviceEvent event = deviceStore.removeDevice(DID1);
827 assertEquals(DEVICE_REMOVED, event.type());
828 assertDevice(DID1, SW1, event.subject());
829
830 assertEquals(1, deviceStore.getDeviceCount());
Yuta HIGUCHI0d6a5e62014-10-03 15:54:09 -0700831 assertEquals(0, deviceStore.getPorts(DID1).size());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700832 verify(clusterCommunicator);
833 // TODO: verify broadcast message
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700834 assertTrue(message.hasCaptured());
Yuta HIGUCHI0d6a5e62014-10-03 15:54:09 -0700835
836 // putBack Device, Port w/o annotation
837 putDevice(DID1, SW1);
Sho SHIMIZU21d00692016-08-15 11:15:28 -0700838 List<PortDescription> pds2 = Arrays.asList(
Yuta HIGUCHI53e47962018-03-01 23:50:48 -0800839 DefaultPortDescription.builder().withPortNumber(P1).isEnabled(true).build()
Yuta HIGUCHI0d6a5e62014-10-03 15:54:09 -0700840 );
841 deviceStore.updatePorts(PID, DID1, pds2);
842
843 // annotations should not survive
844 assertEquals(2, deviceStore.getDeviceCount());
845 assertEquals(1, deviceStore.getPorts(DID1).size());
846 assertAnnotationsEquals(deviceStore.getDevice(DID1).annotations());
847 assertAnnotationsEquals(deviceStore.getPort(DID1, P1).annotations());
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700848 }
849
850 // If Delegates should be called only on remote events,
851 // then Simple* should never call them, thus not test required.
852 // TODO add test for Port events when we have them
853 @Ignore("Ignore until Delegate spec. is clear.")
854 @Test
855 public final void testEvents() throws InterruptedException {
856 final CountDownLatch addLatch = new CountDownLatch(1);
Sho SHIMIZU74626412015-09-11 11:46:27 -0700857 DeviceStoreDelegate checkAdd = event -> {
858 assertEquals(DEVICE_ADDED, event.type());
859 assertDevice(DID1, SW1, event.subject());
860 addLatch.countDown();
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700861 };
862 final CountDownLatch updateLatch = new CountDownLatch(1);
Sho SHIMIZU74626412015-09-11 11:46:27 -0700863 DeviceStoreDelegate checkUpdate = event -> {
864 assertEquals(DEVICE_UPDATED, event.type());
865 assertDevice(DID1, SW2, event.subject());
866 updateLatch.countDown();
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700867 };
868 final CountDownLatch removeLatch = new CountDownLatch(1);
Sho SHIMIZU74626412015-09-11 11:46:27 -0700869 DeviceStoreDelegate checkRemove = event -> {
870 assertEquals(DEVICE_REMOVED, event.type());
871 assertDevice(DID1, SW2, event.subject());
872 removeLatch.countDown();
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700873 };
874
875 DeviceDescription description =
876 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
alshabib7911a052014-10-16 17:49:37 -0700877 HW, SW1, SN, CID);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700878 deviceStore.setDelegate(checkAdd);
879 deviceStore.createOrUpdateDevice(PID, DID1, description);
880 assertTrue("Add event fired", addLatch.await(1, TimeUnit.SECONDS));
881
882
883 DeviceDescription description2 =
884 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
alshabib7911a052014-10-16 17:49:37 -0700885 HW, SW2, SN, CID);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700886 deviceStore.unsetDelegate(checkAdd);
887 deviceStore.setDelegate(checkUpdate);
888 deviceStore.createOrUpdateDevice(PID, DID1, description2);
889 assertTrue("Update event fired", updateLatch.await(1, TimeUnit.SECONDS));
890
891 deviceStore.unsetDelegate(checkUpdate);
892 deviceStore.setDelegate(checkRemove);
893 deviceStore.removeDevice(DID1);
894 assertTrue("Remove event fired", removeLatch.await(1, TimeUnit.SECONDS));
895 }
896
Yuta HIGUCHIe8252bb2014-10-22 09:41:01 -0700897 private final class TestMastershipService extends MastershipServiceAdapter {
898 @Override
899 public NodeId getMasterFor(DeviceId deviceId) {
900 return NID1;
901 }
Madan Jampanic6e574f2015-05-29 13:41:52 -0700902 @Override
903 public CompletableFuture<MastershipRole> requestRoleFor(DeviceId deviceId) {
904 return CompletableFuture.completedFuture(null);
905 }
Yuta HIGUCHIe8252bb2014-10-22 09:41:01 -0700906 }
907
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700908 private static final class TestGossipDeviceStore extends GossipDeviceStore {
909
Madan Jampani53e44e62014-10-07 12:39:51 -0700910 public TestGossipDeviceStore(
Yuta HIGUCHI093e83e2014-10-10 22:26:11 -0700911 DeviceClockService deviceClockService,
Madan Jampani53e44e62014-10-07 12:39:51 -0700912 ClusterService clusterService,
913 ClusterCommunicationService clusterCommunicator) {
Yuta HIGUCHI093e83e2014-10-10 22:26:11 -0700914 this.deviceClockService = deviceClockService;
Madan Jampani53e44e62014-10-07 12:39:51 -0700915 this.clusterService = clusterService;
Madan Jampani47c93732014-10-06 20:46:08 -0700916 this.clusterCommunicator = clusterCommunicator;
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700917 }
Madan Jampani47c93732014-10-06 20:46:08 -0700918 }
Madan Jampani53e44e62014-10-07 12:39:51 -0700919
Yuta HIGUCHI3e5d11a2014-11-04 14:16:44 -0800920 private static final class TestClusterService extends StaticClusterService {
Madan Jampani53e44e62014-10-07 12:39:51 -0700921
922 public TestClusterService() {
Yuta HIGUCHI3e5d11a2014-11-04 14:16:44 -0800923 localNode = ONOS1;
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700924 nodes.put(NID1, ONOS1);
925 nodeStates.put(NID1, ACTIVE);
926
927 nodes.put(NID2, ONOS2);
928 nodeStates.put(NID2, ACTIVE);
Madan Jampani53e44e62014-10-07 12:39:51 -0700929 }
Madan Jampani53e44e62014-10-07 12:39:51 -0700930 }
Thomas Vachuskafdbc4c22015-05-29 15:53:01 -0700931
Madan Jampani565a66a2015-07-25 17:01:13 -0700932 private final class TestDeviceClockService extends DeviceClockServiceAdapter {
933
934 private final AtomicLong ticker = new AtomicLong();
935
936 @Override
937 public Timestamp getTimestamp(DeviceId deviceId) {
938 if (DID1.equals(deviceId)) {
939 return new MastershipBasedTimestamp(1, ticker.getAndIncrement());
940 } else if (DID2.equals(deviceId)) {
941 return new MastershipBasedTimestamp(2, ticker.getAndIncrement());
942 } else {
943 throw new IllegalStateException();
944 }
945 }
946
947 @Override
948 public boolean isTimestampAvailable(DeviceId deviceId) {
949 return DID1.equals(deviceId) || DID2.equals(deviceId);
950 }
951 }
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700952}