blob: 4df97a10f83cc7f8350a106fdb72921e0a03ec8c [file] [log] [blame]
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2014-present Open Networking Laboratory
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
302 public final void testGetDevices() {
303 assertEquals("initialy empty", 0, Iterables.size(deviceStore.getDevices()));
304
305 putDevice(DID1, SW1);
306 putDevice(DID2, SW2);
307 putDevice(DID1, SW1);
308
309 assertEquals("expect 2 uniq devices",
310 2, Iterables.size(deviceStore.getDevices()));
311
312 Map<DeviceId, Device> devices = new HashMap<>();
313 for (Device device : deviceStore.getDevices()) {
314 devices.put(device.id(), device);
315 }
316
317 assertDevice(DID1, SW1, devices.get(DID1));
318 assertDevice(DID2, SW2, devices.get(DID2));
319
320 // add case for new node?
321 }
322
323 @Test
324 public final void testGetDevice() {
325
326 putDevice(DID1, SW1);
327
328 assertDevice(DID1, SW1, deviceStore.getDevice(DID1));
329 assertNull("DID2 shouldn't be there", deviceStore.getDevice(DID2));
330 }
331
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700332 private void assertInternalDeviceEvent(NodeId sender,
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700333 DeviceId deviceId,
334 ProviderId providerId,
335 DeviceDescription expectedDesc,
336 Capture<InternalDeviceEvent> actualEvent,
337 Capture<MessageSubject> actualSubject,
338 Capture<Function<InternalDeviceEvent, byte[]>> actualEncoder) {
339 assertTrue(actualEvent.hasCaptured());
340 assertTrue(actualSubject.hasCaptured());
341 assertTrue(actualEncoder.hasCaptured());
342
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700343 assertEquals(GossipDeviceStoreMessageSubjects.DEVICE_UPDATE,
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700344 actualSubject.getValue());
345 assertEquals(deviceId, actualEvent.getValue().deviceId());
346 assertEquals(providerId, actualEvent.getValue().providerId());
347 assertDeviceDescriptionEquals(expectedDesc, actualEvent.getValue().deviceDescription().value());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700348 }
349
350 private void assertInternalDeviceEvent(NodeId sender,
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700351 DeviceId deviceId,
352 ProviderId providerId,
353 DeviceDescription expectedDesc,
354 List<SparseAnnotations> expectedAnnotations,
355 Capture<InternalDeviceEvent> actualEvent,
356 Capture<MessageSubject> actualSubject,
357 Capture<Function<InternalDeviceEvent, byte[]>> actualEncoder) {
358 assertTrue(actualEvent.hasCaptured());
359 assertTrue(actualSubject.hasCaptured());
360 assertTrue(actualEncoder.hasCaptured());
361
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700362 assertEquals(GossipDeviceStoreMessageSubjects.DEVICE_UPDATE,
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700363 actualSubject.getValue());
364 assertEquals(deviceId, actualEvent.getValue().deviceId());
365 assertEquals(providerId, actualEvent.getValue().providerId());
366 assertDeviceDescriptionEquals(
367 expectedDesc,
368 expectedAnnotations,
369 actualEvent.getValue().deviceDescription().value());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700370 }
371
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700372 @Test
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700373 public final void testCreateOrUpdateDevice() throws IOException {
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700374 DeviceDescription description =
375 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
alshabib7911a052014-10-16 17:49:37 -0700376 HW, SW1, SN, CID);
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700377 Capture<InternalDeviceEvent> message = new Capture<>();
378 Capture<MessageSubject> subject = new Capture<>();
379 Capture<Function<InternalDeviceEvent, byte[]>> encoder = new Capture<>();
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700380
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700381 resetCommunicatorExpectingSingleBroadcast(message, subject, encoder);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700382 DeviceEvent event = deviceStore.createOrUpdateDevice(PID, DID1, description);
383 assertEquals(DEVICE_ADDED, event.type());
384 assertDevice(DID1, SW1, event.subject());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700385 verify(clusterCommunicator);
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700386 assertInternalDeviceEvent(NID1, DID1, PID, description, message, subject, encoder);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700387
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700388
389 DeviceDescription description2 =
390 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
alshabib7911a052014-10-16 17:49:37 -0700391 HW, SW2, SN, CID);
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700392 resetCommunicatorExpectingSingleBroadcast(message, subject, encoder);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700393 DeviceEvent event2 = deviceStore.createOrUpdateDevice(PID, DID1, description2);
394 assertEquals(DEVICE_UPDATED, event2.type());
395 assertDevice(DID1, SW2, event2.subject());
396
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700397 verify(clusterCommunicator);
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700398 assertInternalDeviceEvent(NID1, DID1, PID, description2, message, subject, encoder);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700399 reset(clusterCommunicator);
400
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700401 assertNull("No change expected", deviceStore.createOrUpdateDevice(PID, DID1, description2));
402 }
403
404 @Test
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700405 public final void testCreateOrUpdateDeviceAncillary() throws IOException {
406 // add
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700407 DeviceDescription description =
408 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
alshabib7911a052014-10-16 17:49:37 -0700409 HW, SW1, SN, CID, A2);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700410 Capture<ClusterMessage> bcast = new Capture<>();
411
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700412 Capture<InternalDeviceEvent> message = new Capture<>();
413 Capture<MessageSubject> subject = new Capture<>();
414 Capture<Function<InternalDeviceEvent, byte[]>> encoder = new Capture<>();
415
416 resetCommunicatorExpectingSingleBroadcast(message, subject, encoder);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700417 DeviceEvent event = deviceStore.createOrUpdateDevice(PIDA, DID1, description);
418 assertEquals(DEVICE_ADDED, event.type());
419 assertDevice(DID1, SW1, event.subject());
420 assertEquals(PIDA, event.subject().providerId());
421 assertAnnotationsEquals(event.subject().annotations(), A2);
422 assertFalse("Ancillary will not bring device up", deviceStore.isAvailable(DID1));
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700423 verify(clusterCommunicator);
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700424 assertInternalDeviceEvent(NID1, DID1, PIDA, description, message, subject, encoder);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700425
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700426 // update from primary
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700427 DeviceDescription description2 =
428 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
alshabib7911a052014-10-16 17:49:37 -0700429 HW, SW2, SN, CID, A1);
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700430 resetCommunicatorExpectingSingleBroadcast(message, subject, encoder);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700431
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700432 DeviceEvent event2 = deviceStore.createOrUpdateDevice(PID, DID1, description2);
433 assertEquals(DEVICE_UPDATED, event2.type());
434 assertDevice(DID1, SW2, event2.subject());
435 assertEquals(PID, event2.subject().providerId());
436 assertAnnotationsEquals(event2.subject().annotations(), A1, A2);
437 assertTrue(deviceStore.isAvailable(DID1));
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700438 verify(clusterCommunicator);
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700439 assertInternalDeviceEvent(NID1, DID1, PID, description2, message, subject, encoder);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700440
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700441 // no-op update from primary
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700442 resetCommunicatorExpectingNoBroadcast(message, subject, encoder);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700443 assertNull("No change expected", deviceStore.createOrUpdateDevice(PID, DID1, description2));
444
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700445 verify(clusterCommunicator);
446 assertFalse("no broadcast expected", bcast.hasCaptured());
447
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700448 // For now, Ancillary is ignored once primary appears
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700449 resetCommunicatorExpectingNoBroadcast(message, subject, encoder);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700450
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700451 assertNull("No change expected", deviceStore.createOrUpdateDevice(PIDA, DID1, description));
452
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700453 verify(clusterCommunicator);
454 assertFalse("no broadcast expected", bcast.hasCaptured());
455
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700456 // But, Ancillary annotations will be in effect
457 DeviceDescription description3 =
458 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
alshabib7911a052014-10-16 17:49:37 -0700459 HW, SW1, SN, CID, A2_2);
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700460 resetCommunicatorExpectingSingleBroadcast(message, subject, encoder);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700461
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700462 DeviceEvent event3 = deviceStore.createOrUpdateDevice(PIDA, DID1, description3);
463 assertEquals(DEVICE_UPDATED, event3.type());
464 // basic information will be the one from Primary
465 assertDevice(DID1, SW2, event3.subject());
466 assertEquals(PID, event3.subject().providerId());
467 // but annotation from Ancillary will be merged
468 assertAnnotationsEquals(event3.subject().annotations(), A1, A2, A2_2);
469 assertTrue(deviceStore.isAvailable(DID1));
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700470 verify(clusterCommunicator);
471 // note: only annotation from PIDA is sent over the wire
472 assertInternalDeviceEvent(NID1, DID1, PIDA, description3,
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700473 asList(union(A2, A2_2)), message, subject, encoder);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700474
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700475 }
476
477
478 @Test
479 public final void testMarkOffline() {
480
481 putDevice(DID1, SW1);
482 assertTrue(deviceStore.isAvailable(DID1));
483
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700484 Capture<InternalDeviceEvent> message = new Capture<>();
485 Capture<MessageSubject> subject = new Capture<>();
486 Capture<Function<InternalDeviceEvent, byte[]>> encoder = new Capture<>();
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700487
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700488 resetCommunicatorExpectingSingleBroadcast(message, subject, encoder);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700489 DeviceEvent event = deviceStore.markOffline(DID1);
490 assertEquals(DEVICE_AVAILABILITY_CHANGED, event.type());
491 assertDevice(DID1, SW1, event.subject());
492 assertFalse(deviceStore.isAvailable(DID1));
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700493 verify(clusterCommunicator);
494 // TODO: verify broadcast message
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700495 assertTrue(message.hasCaptured());
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700496
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700497
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700498 resetCommunicatorExpectingNoBroadcast(message, subject, encoder);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700499 DeviceEvent event2 = deviceStore.markOffline(DID1);
500 assertNull("No change, no event", event2);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700501 verify(clusterCommunicator);
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700502 assertFalse(message.hasCaptured());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700503 }
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700504
505 @Test
506 public final void testUpdatePorts() {
507 putDevice(DID1, SW1);
Sho SHIMIZU21d00692016-08-15 11:15:28 -0700508 List<PortDescription> pds = Arrays.asList(
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700509 new DefaultPortDescription(P1, true),
510 new DefaultPortDescription(P2, true)
511 );
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700512 Capture<InternalDeviceEvent> message = new Capture<>();
513 Capture<MessageSubject> subject = new Capture<>();
514 Capture<Function<InternalDeviceEvent, byte[]>> encoder = new Capture<>();
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700515
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700516 resetCommunicatorExpectingSingleBroadcast(message, subject, encoder);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700517 List<DeviceEvent> events = deviceStore.updatePorts(PID, DID1, pds);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700518 verify(clusterCommunicator);
519 // TODO: verify broadcast message
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700520 assertTrue(message.hasCaptured());
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700521
522 Set<PortNumber> expectedPorts = Sets.newHashSet(P1, P2);
523 for (DeviceEvent event : events) {
524 assertEquals(PORT_ADDED, event.type());
525 assertDevice(DID1, SW1, event.subject());
526 assertTrue("PortNumber is one of expected",
527 expectedPorts.remove(event.port().number()));
528 assertTrue("Port is enabled", event.port().isEnabled());
529 }
530 assertTrue("Event for all expectedport appeared", expectedPorts.isEmpty());
531
532
Sho SHIMIZU21d00692016-08-15 11:15:28 -0700533 List<PortDescription> pds2 = Arrays.asList(
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700534 new DefaultPortDescription(P1, false),
535 new DefaultPortDescription(P2, true),
536 new DefaultPortDescription(P3, true)
537 );
538
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700539 resetCommunicatorExpectingSingleBroadcast(message, subject, encoder);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700540 events = deviceStore.updatePorts(PID, DID1, pds2);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700541 verify(clusterCommunicator);
542 // TODO: verify broadcast message
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700543 assertTrue(message.hasCaptured());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700544
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700545 assertFalse("event should be triggered", events.isEmpty());
546 for (DeviceEvent event : events) {
547 PortNumber num = event.port().number();
548 if (P1.equals(num)) {
549 assertEquals(PORT_UPDATED, event.type());
550 assertDevice(DID1, SW1, event.subject());
551 assertFalse("Port is disabled", event.port().isEnabled());
552 } else if (P2.equals(num)) {
553 fail("P2 event not expected.");
554 } else if (P3.equals(num)) {
555 assertEquals(PORT_ADDED, event.type());
556 assertDevice(DID1, SW1, event.subject());
557 assertTrue("Port is enabled", event.port().isEnabled());
558 } else {
559 fail("Unknown port number encountered: " + num);
560 }
561 }
562
Sho SHIMIZU21d00692016-08-15 11:15:28 -0700563 List<PortDescription> pds3 = Arrays.asList(
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700564 new DefaultPortDescription(P1, false),
565 new DefaultPortDescription(P2, true)
566 );
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700567 resetCommunicatorExpectingSingleBroadcast(message, subject, encoder);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700568 events = deviceStore.updatePorts(PID, DID1, pds3);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700569 verify(clusterCommunicator);
570 // TODO: verify broadcast message
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700571 assertTrue(message.hasCaptured());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700572
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700573 assertFalse("event should be triggered", events.isEmpty());
574 for (DeviceEvent event : events) {
575 PortNumber num = event.port().number();
576 if (P1.equals(num)) {
577 fail("P1 event not expected.");
578 } else if (P2.equals(num)) {
579 fail("P2 event not expected.");
580 } else if (P3.equals(num)) {
581 assertEquals(PORT_REMOVED, event.type());
582 assertDevice(DID1, SW1, event.subject());
583 assertTrue("Port was enabled", event.port().isEnabled());
584 } else {
585 fail("Unknown port number encountered: " + num);
586 }
587 }
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700588 }
589
590 @Test
591 public final void testUpdatePortStatus() {
592 putDevice(DID1, SW1);
Sho SHIMIZU21d00692016-08-15 11:15:28 -0700593 List<PortDescription> pds = Arrays.asList(
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700594 new DefaultPortDescription(P1, true)
595 );
596 deviceStore.updatePorts(PID, DID1, pds);
597
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700598 Capture<InternalPortStatusEvent> message = new Capture<>();
599 Capture<MessageSubject> subject = new Capture<>();
600 Capture<Function<InternalPortStatusEvent, byte[]>> encoder = new Capture<>();
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700601
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700602 resetCommunicatorExpectingSingleBroadcast(message, subject, encoder);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700603 final DefaultPortDescription desc = new DefaultPortDescription(P1, false);
604 DeviceEvent event = deviceStore.updatePortStatus(PID, DID1, desc);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700605 assertEquals(PORT_UPDATED, event.type());
606 assertDevice(DID1, SW1, event.subject());
607 assertEquals(P1, event.port().number());
608 assertFalse("Port is disabled", event.port().isEnabled());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700609 verify(clusterCommunicator);
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700610 assertInternalPortStatusEvent(NID1, DID1, PID, desc, NO_ANNOTATION, message, subject, encoder);
611 assertTrue(message.hasCaptured());
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700612 }
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700613
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700614 @Test
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700615 public final void testUpdatePortStatusAncillary() throws IOException {
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700616 putDeviceAncillary(DID1, SW1);
617 putDevice(DID1, SW1);
Sho SHIMIZU21d00692016-08-15 11:15:28 -0700618 List<PortDescription> pds = Arrays.asList(
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700619 new DefaultPortDescription(P1, true, A1)
620 );
621 deviceStore.updatePorts(PID, DID1, pds);
622
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700623 Capture<InternalPortStatusEvent> message = new Capture<>();
624 Capture<MessageSubject> subject = new Capture<>();
625 Capture<Function<InternalPortStatusEvent, byte[]>> encoder = new Capture<>();
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700626
627 // update port from primary
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700628 resetCommunicatorExpectingSingleBroadcast(message, subject, encoder);
629
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700630 final DefaultPortDescription desc1 = new DefaultPortDescription(P1, false, A1_2);
631 DeviceEvent event = deviceStore.updatePortStatus(PID, DID1, desc1);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700632 assertEquals(PORT_UPDATED, event.type());
633 assertDevice(DID1, SW1, event.subject());
634 assertEquals(P1, event.port().number());
635 assertAnnotationsEquals(event.port().annotations(), A1, A1_2);
636 assertFalse("Port is disabled", event.port().isEnabled());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700637 verify(clusterCommunicator);
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700638 assertInternalPortStatusEvent(NID1, DID1, PID, desc1, asList(A1, A1_2), message, subject, encoder);
639 assertTrue(message.hasCaptured());
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700640
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700641 // update port from ancillary with no attributes
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700642 resetCommunicatorExpectingNoBroadcast(message, subject, encoder);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700643 final DefaultPortDescription desc2 = new DefaultPortDescription(P1, true);
644 DeviceEvent event2 = deviceStore.updatePortStatus(PIDA, DID1, desc2);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700645 assertNull("Ancillary is ignored if primary exists", event2);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700646 verify(clusterCommunicator);
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700647 assertFalse(message.hasCaptured());
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700648
649 // but, Ancillary annotation update will be notified
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700650 resetCommunicatorExpectingSingleBroadcast(message, subject, encoder);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700651 final DefaultPortDescription desc3 = new DefaultPortDescription(P1, true, A2);
652 DeviceEvent event3 = deviceStore.updatePortStatus(PIDA, DID1, desc3);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700653 assertEquals(PORT_UPDATED, event3.type());
654 assertDevice(DID1, SW1, event3.subject());
655 assertEquals(P1, event3.port().number());
656 assertAnnotationsEquals(event3.port().annotations(), A1, A1_2, A2);
657 assertFalse("Port is disabled", event3.port().isEnabled());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700658 verify(clusterCommunicator);
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700659 assertInternalPortStatusEvent(NID1, DID1, PIDA, desc3, asList(A2), message, subject, encoder);
660 assertTrue(message.hasCaptured());
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700661
662 // port only reported from Ancillary will be notified as down
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700663 resetCommunicatorExpectingSingleBroadcast(message, subject, encoder);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700664 final DefaultPortDescription desc4 = new DefaultPortDescription(P2, true);
665 DeviceEvent event4 = deviceStore.updatePortStatus(PIDA, DID1, desc4);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700666 assertEquals(PORT_ADDED, event4.type());
667 assertDevice(DID1, SW1, event4.subject());
668 assertEquals(P2, event4.port().number());
669 assertAnnotationsEquals(event4.port().annotations());
670 assertFalse("Port is disabled if not given from primary provider",
671 event4.port().isEnabled());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700672 verify(clusterCommunicator);
673 // TODO: verify broadcast message content
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700674 assertInternalPortStatusEvent(NID1, DID1, PIDA, desc4, NO_ANNOTATION, message, subject, encoder);
675 assertTrue(message.hasCaptured());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700676 }
677
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700678 private void assertInternalPortStatusEvent(NodeId sender,
679 DeviceId did,
680 ProviderId pid,
681 DefaultPortDescription expectedDesc,
682 List<SparseAnnotations> expectedAnnotations,
683 Capture<InternalPortStatusEvent> actualEvent,
684 Capture<MessageSubject> actualSubject,
685 Capture<Function<InternalPortStatusEvent, byte[]>> actualEncoder) {
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700686
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700687 assertTrue(actualEvent.hasCaptured());
688 assertTrue(actualSubject.hasCaptured());
689 assertTrue(actualEncoder.hasCaptured());
690
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700691 assertEquals(GossipDeviceStoreMessageSubjects.PORT_STATUS_UPDATE,
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700692 actualSubject.getValue());
693 assertEquals(did, actualEvent.getValue().deviceId());
694 assertEquals(pid, actualEvent.getValue().providerId());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700695 assertPortDescriptionEquals(expectedDesc, expectedAnnotations,
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700696 actualEvent.getValue().portDescription().value());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700697 }
698
699 private void assertPortDescriptionEquals(
700 PortDescription expectedDesc,
701 List<SparseAnnotations> expectedAnnotations,
702 PortDescription actual) {
703
704 assertEquals(expectedDesc.portNumber(), actual.portNumber());
705 assertEquals(expectedDesc.isEnabled(), actual.isEnabled());
706
707 assertAnnotationsEquals(actual.annotations(),
708 expectedAnnotations.toArray(new SparseAnnotations[0]));
709 }
710
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700711 private <T> void resetCommunicatorExpectingNoBroadcast(
712 Capture<T> message,
713 Capture<MessageSubject> subject,
714 Capture<Function<T, byte[]>> encoder) {
715 message.reset();
716 subject.reset();
717 encoder.reset();
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700718 reset(clusterCommunicator);
719 replay(clusterCommunicator);
720 }
721
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700722 private <T> void resetCommunicatorExpectingSingleBroadcast(
723 Capture<T> message,
724 Capture<MessageSubject> subject,
725 Capture<Function<T, byte[]>> encoder) {
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700726
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700727 message.reset();
728 subject.reset();
729 encoder.reset();
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700730 reset(clusterCommunicator);
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700731 clusterCommunicator.broadcast(
732 capture(message),
733 capture(subject),
734 capture(encoder));
735 expectLastCall().once();
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700736 replay(clusterCommunicator);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700737 }
738
739 @Test
740 public final void testGetPorts() {
741 putDevice(DID1, SW1);
742 putDevice(DID2, SW1);
Sho SHIMIZU21d00692016-08-15 11:15:28 -0700743 List<PortDescription> pds = Arrays.asList(
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700744 new DefaultPortDescription(P1, true),
745 new DefaultPortDescription(P2, true)
746 );
747 deviceStore.updatePorts(PID, DID1, pds);
748
749 Set<PortNumber> expectedPorts = Sets.newHashSet(P1, P2);
750 List<Port> ports = deviceStore.getPorts(DID1);
751 for (Port port : ports) {
752 assertTrue("Port is enabled", port.isEnabled());
753 assertTrue("PortNumber is one of expected",
754 expectedPorts.remove(port.number()));
755 }
756 assertTrue("Event for all expectedport appeared", expectedPorts.isEmpty());
757
758
759 assertTrue("DID2 has no ports", deviceStore.getPorts(DID2).isEmpty());
760 }
761
762 @Test
763 public final void testGetPort() {
764 putDevice(DID1, SW1);
765 putDevice(DID2, SW1);
Sho SHIMIZU21d00692016-08-15 11:15:28 -0700766 List<PortDescription> pds = Arrays.asList(
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700767 new DefaultPortDescription(P1, true),
768 new DefaultPortDescription(P2, false)
769 );
770 deviceStore.updatePorts(PID, DID1, pds);
771
772 Port port1 = deviceStore.getPort(DID1, P1);
773 assertEquals(P1, port1.number());
774 assertTrue("Port is enabled", port1.isEnabled());
775
776 Port port2 = deviceStore.getPort(DID1, P2);
777 assertEquals(P2, port2.number());
778 assertFalse("Port is disabled", port2.isEnabled());
779
780 Port port3 = deviceStore.getPort(DID1, P3);
781 assertNull("P3 not expected", port3);
782 }
783
784 @Test
785 public final void testRemoveDevice() {
Yuta HIGUCHI0d6a5e62014-10-03 15:54:09 -0700786 putDevice(DID1, SW1, A1);
Sho SHIMIZU21d00692016-08-15 11:15:28 -0700787 List<PortDescription> pds = Arrays.asList(
Yuta HIGUCHI0d6a5e62014-10-03 15:54:09 -0700788 new DefaultPortDescription(P1, true, A2)
789 );
790 deviceStore.updatePorts(PID, DID1, pds);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700791 putDevice(DID2, SW1);
792
793 assertEquals(2, deviceStore.getDeviceCount());
Yuta HIGUCHI0d6a5e62014-10-03 15:54:09 -0700794 assertEquals(1, deviceStore.getPorts(DID1).size());
795 assertAnnotationsEquals(deviceStore.getDevice(DID1).annotations(), A1);
796 assertAnnotationsEquals(deviceStore.getPort(DID1, P1).annotations(), A2);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700797
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700798 Capture<InternalDeviceEvent> message = new Capture<>();
799 Capture<MessageSubject> subject = new Capture<>();
800 Capture<Function<InternalDeviceEvent, byte[]>> encoder = new Capture<>();
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700801
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700802 resetCommunicatorExpectingSingleBroadcast(message, subject, encoder);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700803
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700804 DeviceEvent event = deviceStore.removeDevice(DID1);
805 assertEquals(DEVICE_REMOVED, event.type());
806 assertDevice(DID1, SW1, event.subject());
807
808 assertEquals(1, deviceStore.getDeviceCount());
Yuta HIGUCHI0d6a5e62014-10-03 15:54:09 -0700809 assertEquals(0, deviceStore.getPorts(DID1).size());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700810 verify(clusterCommunicator);
811 // TODO: verify broadcast message
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700812 assertTrue(message.hasCaptured());
Yuta HIGUCHI0d6a5e62014-10-03 15:54:09 -0700813
814 // putBack Device, Port w/o annotation
815 putDevice(DID1, SW1);
Sho SHIMIZU21d00692016-08-15 11:15:28 -0700816 List<PortDescription> pds2 = Arrays.asList(
Yuta HIGUCHI0d6a5e62014-10-03 15:54:09 -0700817 new DefaultPortDescription(P1, true)
818 );
819 deviceStore.updatePorts(PID, DID1, pds2);
820
821 // annotations should not survive
822 assertEquals(2, deviceStore.getDeviceCount());
823 assertEquals(1, deviceStore.getPorts(DID1).size());
824 assertAnnotationsEquals(deviceStore.getDevice(DID1).annotations());
825 assertAnnotationsEquals(deviceStore.getPort(DID1, P1).annotations());
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700826 }
827
828 // If Delegates should be called only on remote events,
829 // then Simple* should never call them, thus not test required.
830 // TODO add test for Port events when we have them
831 @Ignore("Ignore until Delegate spec. is clear.")
832 @Test
833 public final void testEvents() throws InterruptedException {
834 final CountDownLatch addLatch = new CountDownLatch(1);
Sho SHIMIZU74626412015-09-11 11:46:27 -0700835 DeviceStoreDelegate checkAdd = event -> {
836 assertEquals(DEVICE_ADDED, event.type());
837 assertDevice(DID1, SW1, event.subject());
838 addLatch.countDown();
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700839 };
840 final CountDownLatch updateLatch = new CountDownLatch(1);
Sho SHIMIZU74626412015-09-11 11:46:27 -0700841 DeviceStoreDelegate checkUpdate = event -> {
842 assertEquals(DEVICE_UPDATED, event.type());
843 assertDevice(DID1, SW2, event.subject());
844 updateLatch.countDown();
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700845 };
846 final CountDownLatch removeLatch = new CountDownLatch(1);
Sho SHIMIZU74626412015-09-11 11:46:27 -0700847 DeviceStoreDelegate checkRemove = event -> {
848 assertEquals(DEVICE_REMOVED, event.type());
849 assertDevice(DID1, SW2, event.subject());
850 removeLatch.countDown();
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700851 };
852
853 DeviceDescription description =
854 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
alshabib7911a052014-10-16 17:49:37 -0700855 HW, SW1, SN, CID);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700856 deviceStore.setDelegate(checkAdd);
857 deviceStore.createOrUpdateDevice(PID, DID1, description);
858 assertTrue("Add event fired", addLatch.await(1, TimeUnit.SECONDS));
859
860
861 DeviceDescription description2 =
862 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
alshabib7911a052014-10-16 17:49:37 -0700863 HW, SW2, SN, CID);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700864 deviceStore.unsetDelegate(checkAdd);
865 deviceStore.setDelegate(checkUpdate);
866 deviceStore.createOrUpdateDevice(PID, DID1, description2);
867 assertTrue("Update event fired", updateLatch.await(1, TimeUnit.SECONDS));
868
869 deviceStore.unsetDelegate(checkUpdate);
870 deviceStore.setDelegate(checkRemove);
871 deviceStore.removeDevice(DID1);
872 assertTrue("Remove event fired", removeLatch.await(1, TimeUnit.SECONDS));
873 }
874
Yuta HIGUCHIe8252bb2014-10-22 09:41:01 -0700875 private final class TestMastershipService extends MastershipServiceAdapter {
876 @Override
877 public NodeId getMasterFor(DeviceId deviceId) {
878 return NID1;
879 }
Madan Jampanic6e574f2015-05-29 13:41:52 -0700880 @Override
881 public CompletableFuture<MastershipRole> requestRoleFor(DeviceId deviceId) {
882 return CompletableFuture.completedFuture(null);
883 }
Yuta HIGUCHIe8252bb2014-10-22 09:41:01 -0700884 }
885
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700886 private static final class TestGossipDeviceStore extends GossipDeviceStore {
887
Madan Jampani53e44e62014-10-07 12:39:51 -0700888 public TestGossipDeviceStore(
Yuta HIGUCHI093e83e2014-10-10 22:26:11 -0700889 DeviceClockService deviceClockService,
Madan Jampani53e44e62014-10-07 12:39:51 -0700890 ClusterService clusterService,
891 ClusterCommunicationService clusterCommunicator) {
Yuta HIGUCHI093e83e2014-10-10 22:26:11 -0700892 this.deviceClockService = deviceClockService;
Madan Jampani53e44e62014-10-07 12:39:51 -0700893 this.clusterService = clusterService;
Madan Jampani47c93732014-10-06 20:46:08 -0700894 this.clusterCommunicator = clusterCommunicator;
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700895 }
Madan Jampani47c93732014-10-06 20:46:08 -0700896 }
Madan Jampani53e44e62014-10-07 12:39:51 -0700897
Yuta HIGUCHI3e5d11a2014-11-04 14:16:44 -0800898 private static final class TestClusterService extends StaticClusterService {
Madan Jampani53e44e62014-10-07 12:39:51 -0700899
900 public TestClusterService() {
Yuta HIGUCHI3e5d11a2014-11-04 14:16:44 -0800901 localNode = ONOS1;
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700902 nodes.put(NID1, ONOS1);
903 nodeStates.put(NID1, ACTIVE);
904
905 nodes.put(NID2, ONOS2);
906 nodeStates.put(NID2, ACTIVE);
Madan Jampani53e44e62014-10-07 12:39:51 -0700907 }
Madan Jampani53e44e62014-10-07 12:39:51 -0700908 }
Thomas Vachuskafdbc4c22015-05-29 15:53:01 -0700909
Madan Jampani565a66a2015-07-25 17:01:13 -0700910 private final class TestDeviceClockService extends DeviceClockServiceAdapter {
911
912 private final AtomicLong ticker = new AtomicLong();
913
914 @Override
915 public Timestamp getTimestamp(DeviceId deviceId) {
916 if (DID1.equals(deviceId)) {
917 return new MastershipBasedTimestamp(1, ticker.getAndIncrement());
918 } else if (DID2.equals(deviceId)) {
919 return new MastershipBasedTimestamp(2, ticker.getAndIncrement());
920 } else {
921 throw new IllegalStateException();
922 }
923 }
924
925 @Override
926 public boolean isTimestampAvailable(DeviceId deviceId) {
927 return DID1.equals(deviceId) || DID2.equals(deviceId);
928 }
929 }
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700930}