blob: 3711f7f2e525ec1f9fa76b6a12357e7febe26342 [file] [log] [blame]
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07001/*
2 * Copyright 2014 Open Networking Laboratory
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Brian O'Connorabafb502014-12-02 22:26:20 -080016package org.onosproject.store.device.impl;
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -070017
Jonathan Hart7d656f42015-01-27 14:07:23 -080018import com.google.common.collect.Iterables;
19import com.google.common.collect.Sets;
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;
Brian O'Connorabafb502014-12-02 22:26:20 -080029import org.onosproject.cluster.ClusterService;
30import org.onosproject.cluster.ControllerNode;
31import org.onosproject.cluster.DefaultControllerNode;
32import org.onosproject.cluster.NodeId;
33import org.onosproject.mastership.MastershipServiceAdapter;
34import org.onosproject.mastership.MastershipTerm;
35import org.onosproject.net.Annotations;
36import org.onosproject.net.DefaultAnnotations;
37import org.onosproject.net.Device;
38import org.onosproject.net.DeviceId;
39import org.onosproject.net.Port;
40import org.onosproject.net.PortNumber;
41import org.onosproject.net.SparseAnnotations;
42import org.onosproject.net.device.DefaultDeviceDescription;
43import org.onosproject.net.device.DefaultPortDescription;
44import org.onosproject.net.device.DeviceClockService;
45import org.onosproject.net.device.DeviceDescription;
46import org.onosproject.net.device.DeviceEvent;
47import org.onosproject.net.device.DeviceStore;
48import org.onosproject.net.device.DeviceStoreDelegate;
49import org.onosproject.net.device.PortDescription;
50import org.onosproject.net.provider.ProviderId;
51import org.onosproject.store.cluster.StaticClusterService;
52import org.onosproject.store.cluster.messaging.ClusterCommunicationService;
53import org.onosproject.store.cluster.messaging.ClusterMessage;
54import org.onosproject.store.cluster.messaging.ClusterMessageHandler;
55import org.onosproject.store.cluster.messaging.MessageSubject;
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -070056
Jonathan Hart7d656f42015-01-27 14:07:23 -080057import java.io.IOException;
58import java.util.Arrays;
59import java.util.Collections;
60import java.util.HashMap;
61import java.util.List;
62import java.util.Map;
63import java.util.Set;
64import java.util.concurrent.CountDownLatch;
65import java.util.concurrent.TimeUnit;
66
67import static java.util.Arrays.asList;
68import static org.easymock.EasyMock.*;
69import static org.junit.Assert.*;
70import static org.onosproject.cluster.ControllerNode.State.ACTIVE;
71import static org.onosproject.net.DefaultAnnotations.union;
72import static org.onosproject.net.Device.Type.SWITCH;
73import static org.onosproject.net.DeviceId.deviceId;
74import static org.onosproject.net.device.DeviceEvent.Type.*;
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -070075
76
77// TODO add tests for remote replication
78/**
79 * Test of the gossip based distributed DeviceStore implementation.
80 */
81public class GossipDeviceStoreTest {
82
83 private static final ProviderId PID = new ProviderId("of", "foo");
84 private static final ProviderId PIDA = new ProviderId("of", "bar", true);
85 private static final DeviceId DID1 = deviceId("of:foo");
86 private static final DeviceId DID2 = deviceId("of:bar");
87 private static final String MFR = "whitebox";
88 private static final String HW = "1.1.x";
89 private static final String SW1 = "3.8.1";
90 private static final String SW2 = "3.9.5";
91 private static final String SN = "43311-12345";
alshabib7911a052014-10-16 17:49:37 -070092 private static final ChassisId CID = new ChassisId();
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -070093
94 private static final PortNumber P1 = PortNumber.portNumber(1);
95 private static final PortNumber P2 = PortNumber.portNumber(2);
96 private static final PortNumber P3 = PortNumber.portNumber(3);
97
98 private static final SparseAnnotations A1 = DefaultAnnotations.builder()
99 .set("A1", "a1")
100 .set("B1", "b1")
101 .build();
102 private static final SparseAnnotations A1_2 = DefaultAnnotations.builder()
103 .remove("A1")
104 .set("B3", "b3")
105 .build();
106 private static final SparseAnnotations A2 = DefaultAnnotations.builder()
107 .set("A2", "a2")
108 .set("B2", "b2")
109 .build();
110 private static final SparseAnnotations A2_2 = DefaultAnnotations.builder()
111 .remove("A2")
112 .set("B4", "b4")
113 .build();
114
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700115 // local node
116 private static final NodeId NID1 = new NodeId("local");
117 private static final ControllerNode ONOS1 =
Pavlin Radoslavov444b5192014-10-28 10:45:19 -0700118 new DefaultControllerNode(NID1, IpAddress.valueOf("127.0.0.1"));
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700119
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700120 // remote node
121 private static final NodeId NID2 = new NodeId("remote");
122 private static final ControllerNode ONOS2 =
Pavlin Radoslavov444b5192014-10-28 10:45:19 -0700123 new DefaultControllerNode(NID2, IpAddress.valueOf("127.0.0.2"));
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700124 private static final List<SparseAnnotations> NO_ANNOTATION = Collections.<SparseAnnotations>emptyList();
125
126
127 private TestGossipDeviceStore testGossipDeviceStore;
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700128 private GossipDeviceStore gossipDeviceStore;
129 private DeviceStore deviceStore;
130
131 private DeviceClockManager deviceClockManager;
Yuta HIGUCHI093e83e2014-10-10 22:26:11 -0700132 private DeviceClockService deviceClockService;
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700133 private ClusterCommunicationService clusterCommunicator;
Yuta HIGUCHI3e5d11a2014-11-04 14:16:44 -0800134
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700135 @BeforeClass
136 public static void setUpBeforeClass() throws Exception {
137 }
138
139 @AfterClass
140 public static void tearDownAfterClass() throws Exception {
141 }
142
143
144 @Before
145 public void setUp() throws Exception {
146 deviceClockManager = new DeviceClockManager();
147 deviceClockManager.activate();
Yuta HIGUCHI093e83e2014-10-10 22:26:11 -0700148 deviceClockService = deviceClockManager;
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700149
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700150 deviceClockManager.setMastershipTerm(DID1, MastershipTerm.of(NID1, 1));
151 deviceClockManager.setMastershipTerm(DID2, MastershipTerm.of(NID1, 2));
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700152
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700153 clusterCommunicator = createNiceMock(ClusterCommunicationService.class);
154 clusterCommunicator.addSubscriber(anyObject(MessageSubject.class),
155 anyObject(ClusterMessageHandler.class));
156 expectLastCall().anyTimes();
157 replay(clusterCommunicator);
Madan Jampani53e44e62014-10-07 12:39:51 -0700158 ClusterService clusterService = new TestClusterService();
Madan Jampani47c93732014-10-06 20:46:08 -0700159
Yuta HIGUCHI093e83e2014-10-10 22:26:11 -0700160 testGossipDeviceStore = new TestGossipDeviceStore(deviceClockService, clusterService, clusterCommunicator);
Yuta HIGUCHIe8252bb2014-10-22 09:41:01 -0700161 testGossipDeviceStore.mastershipService = new TestMastershipService();
162
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700163 gossipDeviceStore = testGossipDeviceStore;
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700164 gossipDeviceStore.activate();
165 deviceStore = gossipDeviceStore;
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700166 verify(clusterCommunicator);
167 reset(clusterCommunicator);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700168 }
169
170 @After
171 public void tearDown() throws Exception {
172 gossipDeviceStore.deactivate();
173 deviceClockManager.deactivate();
174 }
175
Yuta HIGUCHI0d6a5e62014-10-03 15:54:09 -0700176 private void putDevice(DeviceId deviceId, String swVersion,
177 SparseAnnotations... annotations) {
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700178 DeviceDescription description =
179 new DefaultDeviceDescription(deviceId.uri(), SWITCH, MFR,
alshabib7911a052014-10-16 17:49:37 -0700180 HW, swVersion, SN, CID, annotations);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700181 reset(clusterCommunicator);
Jonathan Hart7d656f42015-01-27 14:07:23 -0800182 expect(clusterCommunicator.broadcast(anyObject(ClusterMessage.class)))
183 .andReturn(true).anyTimes();
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700184 replay(clusterCommunicator);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700185 deviceStore.createOrUpdateDevice(PID, deviceId, description);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700186 verify(clusterCommunicator);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700187 }
188
Yuta HIGUCHI0d6a5e62014-10-03 15:54:09 -0700189 private void putDeviceAncillary(DeviceId deviceId, String swVersion,
190 SparseAnnotations... annotations) {
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700191 DeviceDescription description =
192 new DefaultDeviceDescription(deviceId.uri(), SWITCH, MFR,
alshabib7911a052014-10-16 17:49:37 -0700193 HW, swVersion, SN, CID, annotations);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700194 deviceStore.createOrUpdateDevice(PIDA, deviceId, description);
195 }
196
197 private static void assertDevice(DeviceId id, String swVersion, Device device) {
198 assertNotNull(device);
199 assertEquals(id, device.id());
200 assertEquals(MFR, device.manufacturer());
201 assertEquals(HW, device.hwVersion());
202 assertEquals(swVersion, device.swVersion());
203 assertEquals(SN, device.serialNumber());
204 }
205
206 /**
207 * Verifies that Annotations created by merging {@code annotations} is
208 * equal to actual Annotations.
209 *
210 * @param actual Annotations to check
211 * @param annotations
212 */
213 private static void assertAnnotationsEquals(Annotations actual, SparseAnnotations... annotations) {
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700214 SparseAnnotations expected = DefaultAnnotations.builder().build();
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700215 for (SparseAnnotations a : annotations) {
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700216 expected = DefaultAnnotations.union(expected, a);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700217 }
218 assertEquals(expected.keys(), actual.keys());
219 for (String key : expected.keys()) {
220 assertEquals(expected.value(key), actual.value(key));
221 }
222 }
223
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700224 private static void assertDeviceDescriptionEquals(DeviceDescription expected,
225 DeviceDescription actual) {
226 if (expected == actual) {
227 return;
228 }
229 assertEquals(expected.deviceURI(), actual.deviceURI());
230 assertEquals(expected.hwVersion(), actual.hwVersion());
231 assertEquals(expected.manufacturer(), actual.manufacturer());
232 assertEquals(expected.serialNumber(), actual.serialNumber());
233 assertEquals(expected.swVersion(), actual.swVersion());
234
235 assertAnnotationsEquals(actual.annotations(), expected.annotations());
236 }
237
238 private static void assertDeviceDescriptionEquals(DeviceDescription expected,
239 List<SparseAnnotations> expectedAnnotations,
240 DeviceDescription actual) {
241 if (expected == actual) {
242 return;
243 }
244 assertEquals(expected.deviceURI(), actual.deviceURI());
245 assertEquals(expected.hwVersion(), actual.hwVersion());
246 assertEquals(expected.manufacturer(), actual.manufacturer());
247 assertEquals(expected.serialNumber(), actual.serialNumber());
248 assertEquals(expected.swVersion(), actual.swVersion());
249
250 assertAnnotationsEquals(actual.annotations(),
251 expectedAnnotations.toArray(new SparseAnnotations[0]));
252 }
253
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700254 @Test
255 public final void testGetDeviceCount() {
256 assertEquals("initialy empty", 0, deviceStore.getDeviceCount());
257
258 putDevice(DID1, SW1);
259 putDevice(DID2, SW2);
260 putDevice(DID1, SW1);
261
262 assertEquals("expect 2 uniq devices", 2, deviceStore.getDeviceCount());
263 }
264
265 @Test
266 public final void testGetDevices() {
267 assertEquals("initialy empty", 0, Iterables.size(deviceStore.getDevices()));
268
269 putDevice(DID1, SW1);
270 putDevice(DID2, SW2);
271 putDevice(DID1, SW1);
272
273 assertEquals("expect 2 uniq devices",
274 2, Iterables.size(deviceStore.getDevices()));
275
276 Map<DeviceId, Device> devices = new HashMap<>();
277 for (Device device : deviceStore.getDevices()) {
278 devices.put(device.id(), device);
279 }
280
281 assertDevice(DID1, SW1, devices.get(DID1));
282 assertDevice(DID2, SW2, devices.get(DID2));
283
284 // add case for new node?
285 }
286
287 @Test
288 public final void testGetDevice() {
289
290 putDevice(DID1, SW1);
291
292 assertDevice(DID1, SW1, deviceStore.getDevice(DID1));
293 assertNull("DID2 shouldn't be there", deviceStore.getDevice(DID2));
294 }
295
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700296 private void assertInternalDeviceEvent(NodeId sender,
297 DeviceId deviceId,
298 ProviderId providerId,
299 DeviceDescription expectedDesc,
300 Capture<ClusterMessage> actualMsg) {
301 assertTrue(actualMsg.hasCaptured());
302 assertEquals(sender, actualMsg.getValue().sender());
303 assertEquals(GossipDeviceStoreMessageSubjects.DEVICE_UPDATE,
304 actualMsg.getValue().subject());
305 InternalDeviceEvent addEvent
306 = testGossipDeviceStore.deserialize(actualMsg.getValue().payload());
307 assertEquals(deviceId, addEvent.deviceId());
308 assertEquals(providerId, addEvent.providerId());
309 assertDeviceDescriptionEquals(expectedDesc, addEvent.deviceDescription().value());
310 }
311
312 private void assertInternalDeviceEvent(NodeId sender,
313 DeviceId deviceId,
314 ProviderId providerId,
315 DeviceDescription expectedDesc,
316 List<SparseAnnotations> expectedAnnotations,
317 Capture<ClusterMessage> actualMsg) {
318 assertTrue(actualMsg.hasCaptured());
319 assertEquals(sender, actualMsg.getValue().sender());
320 assertEquals(GossipDeviceStoreMessageSubjects.DEVICE_UPDATE,
321 actualMsg.getValue().subject());
322 InternalDeviceEvent addEvent
323 = testGossipDeviceStore.deserialize(actualMsg.getValue().payload());
324 assertEquals(deviceId, addEvent.deviceId());
325 assertEquals(providerId, addEvent.providerId());
326 assertDeviceDescriptionEquals(expectedDesc, expectedAnnotations, addEvent.deviceDescription().value());
327 }
328
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700329 @Test
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700330 public final void testCreateOrUpdateDevice() throws IOException {
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700331 DeviceDescription description =
332 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
alshabib7911a052014-10-16 17:49:37 -0700333 HW, SW1, SN, CID);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700334 Capture<ClusterMessage> bcast = new Capture<>();
335
336 resetCommunicatorExpectingSingleBroadcast(bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700337 DeviceEvent event = deviceStore.createOrUpdateDevice(PID, DID1, description);
338 assertEquals(DEVICE_ADDED, event.type());
339 assertDevice(DID1, SW1, event.subject());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700340 verify(clusterCommunicator);
341 assertInternalDeviceEvent(NID1, DID1, PID, description, bcast);
342
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700343
344 DeviceDescription description2 =
345 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
alshabib7911a052014-10-16 17:49:37 -0700346 HW, SW2, SN, CID);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700347 resetCommunicatorExpectingSingleBroadcast(bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700348 DeviceEvent event2 = deviceStore.createOrUpdateDevice(PID, DID1, description2);
349 assertEquals(DEVICE_UPDATED, event2.type());
350 assertDevice(DID1, SW2, event2.subject());
351
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700352 verify(clusterCommunicator);
353 assertInternalDeviceEvent(NID1, DID1, PID, description2, bcast);
354 reset(clusterCommunicator);
355
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700356 assertNull("No change expected", deviceStore.createOrUpdateDevice(PID, DID1, description2));
357 }
358
359 @Test
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700360 public final void testCreateOrUpdateDeviceAncillary() throws IOException {
361 // add
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700362 DeviceDescription description =
363 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
alshabib7911a052014-10-16 17:49:37 -0700364 HW, SW1, SN, CID, A2);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700365 Capture<ClusterMessage> bcast = new Capture<>();
366
367 resetCommunicatorExpectingSingleBroadcast(bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700368 DeviceEvent event = deviceStore.createOrUpdateDevice(PIDA, DID1, description);
369 assertEquals(DEVICE_ADDED, event.type());
370 assertDevice(DID1, SW1, event.subject());
371 assertEquals(PIDA, event.subject().providerId());
372 assertAnnotationsEquals(event.subject().annotations(), A2);
373 assertFalse("Ancillary will not bring device up", deviceStore.isAvailable(DID1));
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700374 verify(clusterCommunicator);
375 assertInternalDeviceEvent(NID1, DID1, PIDA, description, bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700376
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700377 // update from primary
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700378 DeviceDescription description2 =
379 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
alshabib7911a052014-10-16 17:49:37 -0700380 HW, SW2, SN, CID, A1);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700381 resetCommunicatorExpectingSingleBroadcast(bcast);
382
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700383 DeviceEvent event2 = deviceStore.createOrUpdateDevice(PID, DID1, description2);
384 assertEquals(DEVICE_UPDATED, event2.type());
385 assertDevice(DID1, SW2, event2.subject());
386 assertEquals(PID, event2.subject().providerId());
387 assertAnnotationsEquals(event2.subject().annotations(), A1, A2);
388 assertTrue(deviceStore.isAvailable(DID1));
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700389 verify(clusterCommunicator);
390 assertInternalDeviceEvent(NID1, DID1, PID, description2, bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700391
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700392 // no-op update from primary
393 resetCommunicatorExpectingNoBroadcast(bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700394 assertNull("No change expected", deviceStore.createOrUpdateDevice(PID, DID1, description2));
395
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700396 verify(clusterCommunicator);
397 assertFalse("no broadcast expected", bcast.hasCaptured());
398
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700399 // For now, Ancillary is ignored once primary appears
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700400 resetCommunicatorExpectingNoBroadcast(bcast);
401
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700402 assertNull("No change expected", deviceStore.createOrUpdateDevice(PIDA, DID1, description));
403
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700404 verify(clusterCommunicator);
405 assertFalse("no broadcast expected", bcast.hasCaptured());
406
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700407 // But, Ancillary annotations will be in effect
408 DeviceDescription description3 =
409 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
alshabib7911a052014-10-16 17:49:37 -0700410 HW, SW1, SN, CID, A2_2);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700411 resetCommunicatorExpectingSingleBroadcast(bcast);
412
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700413 DeviceEvent event3 = deviceStore.createOrUpdateDevice(PIDA, DID1, description3);
414 assertEquals(DEVICE_UPDATED, event3.type());
415 // basic information will be the one from Primary
416 assertDevice(DID1, SW2, event3.subject());
417 assertEquals(PID, event3.subject().providerId());
418 // but annotation from Ancillary will be merged
419 assertAnnotationsEquals(event3.subject().annotations(), A1, A2, A2_2);
420 assertTrue(deviceStore.isAvailable(DID1));
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700421 verify(clusterCommunicator);
422 // note: only annotation from PIDA is sent over the wire
423 assertInternalDeviceEvent(NID1, DID1, PIDA, description3,
424 asList(union(A2, A2_2)), bcast);
425
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700426 }
427
428
429 @Test
430 public final void testMarkOffline() {
431
432 putDevice(DID1, SW1);
433 assertTrue(deviceStore.isAvailable(DID1));
434
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700435 Capture<ClusterMessage> bcast = new Capture<>();
436
437 resetCommunicatorExpectingSingleBroadcast(bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700438 DeviceEvent event = deviceStore.markOffline(DID1);
439 assertEquals(DEVICE_AVAILABILITY_CHANGED, event.type());
440 assertDevice(DID1, SW1, event.subject());
441 assertFalse(deviceStore.isAvailable(DID1));
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700442 verify(clusterCommunicator);
443 // TODO: verify broadcast message
444 assertTrue(bcast.hasCaptured());
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700445
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700446
447 resetCommunicatorExpectingNoBroadcast(bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700448 DeviceEvent event2 = deviceStore.markOffline(DID1);
449 assertNull("No change, no event", event2);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700450 verify(clusterCommunicator);
451 assertFalse(bcast.hasCaptured());
452 }
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700453
454 @Test
455 public final void testUpdatePorts() {
456 putDevice(DID1, SW1);
457 List<PortDescription> pds = Arrays.<PortDescription>asList(
458 new DefaultPortDescription(P1, true),
459 new DefaultPortDescription(P2, true)
460 );
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700461 Capture<ClusterMessage> bcast = new Capture<>();
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700462
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700463 resetCommunicatorExpectingSingleBroadcast(bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700464 List<DeviceEvent> events = deviceStore.updatePorts(PID, DID1, pds);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700465 verify(clusterCommunicator);
466 // TODO: verify broadcast message
467 assertTrue(bcast.hasCaptured());
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700468
469 Set<PortNumber> expectedPorts = Sets.newHashSet(P1, P2);
470 for (DeviceEvent event : events) {
471 assertEquals(PORT_ADDED, event.type());
472 assertDevice(DID1, SW1, event.subject());
473 assertTrue("PortNumber is one of expected",
474 expectedPorts.remove(event.port().number()));
475 assertTrue("Port is enabled", event.port().isEnabled());
476 }
477 assertTrue("Event for all expectedport appeared", expectedPorts.isEmpty());
478
479
480 List<PortDescription> pds2 = Arrays.<PortDescription>asList(
481 new DefaultPortDescription(P1, false),
482 new DefaultPortDescription(P2, true),
483 new DefaultPortDescription(P3, true)
484 );
485
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700486 resetCommunicatorExpectingSingleBroadcast(bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700487 events = deviceStore.updatePorts(PID, DID1, pds2);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700488 verify(clusterCommunicator);
489 // TODO: verify broadcast message
490 assertTrue(bcast.hasCaptured());
491
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700492 assertFalse("event should be triggered", events.isEmpty());
493 for (DeviceEvent event : events) {
494 PortNumber num = event.port().number();
495 if (P1.equals(num)) {
496 assertEquals(PORT_UPDATED, event.type());
497 assertDevice(DID1, SW1, event.subject());
498 assertFalse("Port is disabled", event.port().isEnabled());
499 } else if (P2.equals(num)) {
500 fail("P2 event not expected.");
501 } else if (P3.equals(num)) {
502 assertEquals(PORT_ADDED, event.type());
503 assertDevice(DID1, SW1, event.subject());
504 assertTrue("Port is enabled", event.port().isEnabled());
505 } else {
506 fail("Unknown port number encountered: " + num);
507 }
508 }
509
510 List<PortDescription> pds3 = Arrays.<PortDescription>asList(
511 new DefaultPortDescription(P1, false),
512 new DefaultPortDescription(P2, true)
513 );
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700514 resetCommunicatorExpectingSingleBroadcast(bcast);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700515 events = deviceStore.updatePorts(PID, DID1, pds3);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700516 verify(clusterCommunicator);
517 // TODO: verify broadcast message
518 assertTrue(bcast.hasCaptured());
519
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700520 assertFalse("event should be triggered", events.isEmpty());
521 for (DeviceEvent event : events) {
522 PortNumber num = event.port().number();
523 if (P1.equals(num)) {
524 fail("P1 event not expected.");
525 } else if (P2.equals(num)) {
526 fail("P2 event not expected.");
527 } else if (P3.equals(num)) {
528 assertEquals(PORT_REMOVED, event.type());
529 assertDevice(DID1, SW1, event.subject());
530 assertTrue("Port was enabled", event.port().isEnabled());
531 } else {
532 fail("Unknown port number encountered: " + num);
533 }
534 }
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700535 }
536
537 @Test
538 public final void testUpdatePortStatus() {
539 putDevice(DID1, SW1);
540 List<PortDescription> pds = Arrays.<PortDescription>asList(
541 new DefaultPortDescription(P1, true)
542 );
543 deviceStore.updatePorts(PID, DID1, pds);
544
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700545 Capture<ClusterMessage> bcast = new Capture<>();
546
547 resetCommunicatorExpectingSingleBroadcast(bcast);
548 final DefaultPortDescription desc = new DefaultPortDescription(P1, false);
549 DeviceEvent event = deviceStore.updatePortStatus(PID, DID1, desc);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700550 assertEquals(PORT_UPDATED, event.type());
551 assertDevice(DID1, SW1, event.subject());
552 assertEquals(P1, event.port().number());
553 assertFalse("Port is disabled", event.port().isEnabled());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700554 verify(clusterCommunicator);
555 assertInternalPortStatusEvent(NID1, DID1, PID, desc, NO_ANNOTATION, bcast);
556 assertTrue(bcast.hasCaptured());
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700557 }
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700558
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700559 @Test
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700560 public final void testUpdatePortStatusAncillary() throws IOException {
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700561 putDeviceAncillary(DID1, SW1);
562 putDevice(DID1, SW1);
563 List<PortDescription> pds = Arrays.<PortDescription>asList(
564 new DefaultPortDescription(P1, true, A1)
565 );
566 deviceStore.updatePorts(PID, DID1, pds);
567
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700568 Capture<ClusterMessage> bcast = new Capture<>();
569
570
571 // update port from primary
572 resetCommunicatorExpectingSingleBroadcast(bcast);
573 final DefaultPortDescription desc1 = new DefaultPortDescription(P1, false, A1_2);
574 DeviceEvent event = deviceStore.updatePortStatus(PID, DID1, desc1);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700575 assertEquals(PORT_UPDATED, event.type());
576 assertDevice(DID1, SW1, event.subject());
577 assertEquals(P1, event.port().number());
578 assertAnnotationsEquals(event.port().annotations(), A1, A1_2);
579 assertFalse("Port is disabled", event.port().isEnabled());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700580 verify(clusterCommunicator);
581 assertInternalPortStatusEvent(NID1, DID1, PID, desc1, asList(A1, A1_2), bcast);
582 assertTrue(bcast.hasCaptured());
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700583
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700584 // update port from ancillary with no attributes
585 resetCommunicatorExpectingNoBroadcast(bcast);
586 final DefaultPortDescription desc2 = new DefaultPortDescription(P1, true);
587 DeviceEvent event2 = deviceStore.updatePortStatus(PIDA, DID1, desc2);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700588 assertNull("Ancillary is ignored if primary exists", event2);
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700589 verify(clusterCommunicator);
590 assertFalse(bcast.hasCaptured());
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700591
592 // but, Ancillary annotation update will be notified
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700593 resetCommunicatorExpectingSingleBroadcast(bcast);
594 final DefaultPortDescription desc3 = new DefaultPortDescription(P1, true, A2);
595 DeviceEvent event3 = deviceStore.updatePortStatus(PIDA, DID1, desc3);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700596 assertEquals(PORT_UPDATED, event3.type());
597 assertDevice(DID1, SW1, event3.subject());
598 assertEquals(P1, event3.port().number());
599 assertAnnotationsEquals(event3.port().annotations(), A1, A1_2, A2);
600 assertFalse("Port is disabled", event3.port().isEnabled());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700601 verify(clusterCommunicator);
602 assertInternalPortStatusEvent(NID1, DID1, PIDA, desc3, asList(A2), bcast);
603 assertTrue(bcast.hasCaptured());
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700604
605 // port only reported from Ancillary will be notified as down
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700606 resetCommunicatorExpectingSingleBroadcast(bcast);
607 final DefaultPortDescription desc4 = new DefaultPortDescription(P2, true);
608 DeviceEvent event4 = deviceStore.updatePortStatus(PIDA, DID1, desc4);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700609 assertEquals(PORT_ADDED, event4.type());
610 assertDevice(DID1, SW1, event4.subject());
611 assertEquals(P2, event4.port().number());
612 assertAnnotationsEquals(event4.port().annotations());
613 assertFalse("Port is disabled if not given from primary provider",
614 event4.port().isEnabled());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700615 verify(clusterCommunicator);
616 // TODO: verify broadcast message content
617 assertInternalPortStatusEvent(NID1, DID1, PIDA, desc4, NO_ANNOTATION, bcast);
618 assertTrue(bcast.hasCaptured());
619 }
620
621 private void assertInternalPortStatusEvent(NodeId sender, DeviceId did,
622 ProviderId pid, DefaultPortDescription expectedDesc,
623 List<SparseAnnotations> expectedAnnotations, Capture<ClusterMessage> actualMsg) {
624
625 assertTrue(actualMsg.hasCaptured());
626 assertEquals(sender, actualMsg.getValue().sender());
627 assertEquals(GossipDeviceStoreMessageSubjects.PORT_STATUS_UPDATE,
628 actualMsg.getValue().subject());
629 InternalPortStatusEvent addEvent
630 = testGossipDeviceStore.deserialize(actualMsg.getValue().payload());
631 assertEquals(did, addEvent.deviceId());
632 assertEquals(pid, addEvent.providerId());
633 assertPortDescriptionEquals(expectedDesc, expectedAnnotations,
634 addEvent.portDescription().value());
635
636 }
637
638 private void assertPortDescriptionEquals(
639 PortDescription expectedDesc,
640 List<SparseAnnotations> expectedAnnotations,
641 PortDescription actual) {
642
643 assertEquals(expectedDesc.portNumber(), actual.portNumber());
644 assertEquals(expectedDesc.isEnabled(), actual.isEnabled());
645
646 assertAnnotationsEquals(actual.annotations(),
647 expectedAnnotations.toArray(new SparseAnnotations[0]));
648 }
649
650 private void resetCommunicatorExpectingNoBroadcast(
651 Capture<ClusterMessage> bcast) {
652 bcast.reset();
653 reset(clusterCommunicator);
654 replay(clusterCommunicator);
655 }
656
657 private void resetCommunicatorExpectingSingleBroadcast(
658 Capture<ClusterMessage> bcast) {
659
660 bcast.reset();
661 reset(clusterCommunicator);
Jonathan Hart7d656f42015-01-27 14:07:23 -0800662 expect(clusterCommunicator.broadcast(capture(bcast))).andReturn(true).once();
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700663 replay(clusterCommunicator);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700664 }
665
666 @Test
667 public final void testGetPorts() {
668 putDevice(DID1, SW1);
669 putDevice(DID2, SW1);
670 List<PortDescription> pds = Arrays.<PortDescription>asList(
671 new DefaultPortDescription(P1, true),
672 new DefaultPortDescription(P2, true)
673 );
674 deviceStore.updatePorts(PID, DID1, pds);
675
676 Set<PortNumber> expectedPorts = Sets.newHashSet(P1, P2);
677 List<Port> ports = deviceStore.getPorts(DID1);
678 for (Port port : ports) {
679 assertTrue("Port is enabled", port.isEnabled());
680 assertTrue("PortNumber is one of expected",
681 expectedPorts.remove(port.number()));
682 }
683 assertTrue("Event for all expectedport appeared", expectedPorts.isEmpty());
684
685
686 assertTrue("DID2 has no ports", deviceStore.getPorts(DID2).isEmpty());
687 }
688
689 @Test
690 public final void testGetPort() {
691 putDevice(DID1, SW1);
692 putDevice(DID2, SW1);
693 List<PortDescription> pds = Arrays.<PortDescription>asList(
694 new DefaultPortDescription(P1, true),
695 new DefaultPortDescription(P2, false)
696 );
697 deviceStore.updatePorts(PID, DID1, pds);
698
699 Port port1 = deviceStore.getPort(DID1, P1);
700 assertEquals(P1, port1.number());
701 assertTrue("Port is enabled", port1.isEnabled());
702
703 Port port2 = deviceStore.getPort(DID1, P2);
704 assertEquals(P2, port2.number());
705 assertFalse("Port is disabled", port2.isEnabled());
706
707 Port port3 = deviceStore.getPort(DID1, P3);
708 assertNull("P3 not expected", port3);
709 }
710
711 @Test
712 public final void testRemoveDevice() {
Yuta HIGUCHI0d6a5e62014-10-03 15:54:09 -0700713 putDevice(DID1, SW1, A1);
714 List<PortDescription> pds = Arrays.<PortDescription>asList(
715 new DefaultPortDescription(P1, true, A2)
716 );
717 deviceStore.updatePorts(PID, DID1, pds);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700718 putDevice(DID2, SW1);
719
720 assertEquals(2, deviceStore.getDeviceCount());
Yuta HIGUCHI0d6a5e62014-10-03 15:54:09 -0700721 assertEquals(1, deviceStore.getPorts(DID1).size());
722 assertAnnotationsEquals(deviceStore.getDevice(DID1).annotations(), A1);
723 assertAnnotationsEquals(deviceStore.getPort(DID1, P1).annotations(), A2);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700724
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700725 Capture<ClusterMessage> bcast = new Capture<>();
726
727 resetCommunicatorExpectingSingleBroadcast(bcast);
728
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700729 DeviceEvent event = deviceStore.removeDevice(DID1);
730 assertEquals(DEVICE_REMOVED, event.type());
731 assertDevice(DID1, SW1, event.subject());
732
733 assertEquals(1, deviceStore.getDeviceCount());
Yuta HIGUCHI0d6a5e62014-10-03 15:54:09 -0700734 assertEquals(0, deviceStore.getPorts(DID1).size());
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700735 verify(clusterCommunicator);
736 // TODO: verify broadcast message
737 assertTrue(bcast.hasCaptured());
Yuta HIGUCHI0d6a5e62014-10-03 15:54:09 -0700738
739 // putBack Device, Port w/o annotation
740 putDevice(DID1, SW1);
741 List<PortDescription> pds2 = Arrays.<PortDescription>asList(
742 new DefaultPortDescription(P1, true)
743 );
744 deviceStore.updatePorts(PID, DID1, pds2);
745
746 // annotations should not survive
747 assertEquals(2, deviceStore.getDeviceCount());
748 assertEquals(1, deviceStore.getPorts(DID1).size());
749 assertAnnotationsEquals(deviceStore.getDevice(DID1).annotations());
750 assertAnnotationsEquals(deviceStore.getPort(DID1, P1).annotations());
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700751 }
752
753 // If Delegates should be called only on remote events,
754 // then Simple* should never call them, thus not test required.
755 // TODO add test for Port events when we have them
756 @Ignore("Ignore until Delegate spec. is clear.")
757 @Test
758 public final void testEvents() throws InterruptedException {
759 final CountDownLatch addLatch = new CountDownLatch(1);
760 DeviceStoreDelegate checkAdd = new DeviceStoreDelegate() {
761 @Override
762 public void notify(DeviceEvent event) {
763 assertEquals(DEVICE_ADDED, event.type());
764 assertDevice(DID1, SW1, event.subject());
765 addLatch.countDown();
766 }
767 };
768 final CountDownLatch updateLatch = new CountDownLatch(1);
769 DeviceStoreDelegate checkUpdate = new DeviceStoreDelegate() {
770 @Override
771 public void notify(DeviceEvent event) {
772 assertEquals(DEVICE_UPDATED, event.type());
773 assertDevice(DID1, SW2, event.subject());
774 updateLatch.countDown();
775 }
776 };
777 final CountDownLatch removeLatch = new CountDownLatch(1);
778 DeviceStoreDelegate checkRemove = new DeviceStoreDelegate() {
779 @Override
780 public void notify(DeviceEvent event) {
781 assertEquals(DEVICE_REMOVED, event.type());
782 assertDevice(DID1, SW2, event.subject());
783 removeLatch.countDown();
784 }
785 };
786
787 DeviceDescription description =
788 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
alshabib7911a052014-10-16 17:49:37 -0700789 HW, SW1, SN, CID);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700790 deviceStore.setDelegate(checkAdd);
791 deviceStore.createOrUpdateDevice(PID, DID1, description);
792 assertTrue("Add event fired", addLatch.await(1, TimeUnit.SECONDS));
793
794
795 DeviceDescription description2 =
796 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
alshabib7911a052014-10-16 17:49:37 -0700797 HW, SW2, SN, CID);
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700798 deviceStore.unsetDelegate(checkAdd);
799 deviceStore.setDelegate(checkUpdate);
800 deviceStore.createOrUpdateDevice(PID, DID1, description2);
801 assertTrue("Update event fired", updateLatch.await(1, TimeUnit.SECONDS));
802
803 deviceStore.unsetDelegate(checkUpdate);
804 deviceStore.setDelegate(checkRemove);
805 deviceStore.removeDevice(DID1);
806 assertTrue("Remove event fired", removeLatch.await(1, TimeUnit.SECONDS));
807 }
808
Yuta HIGUCHIe8252bb2014-10-22 09:41:01 -0700809 private final class TestMastershipService extends MastershipServiceAdapter {
810 @Override
811 public NodeId getMasterFor(DeviceId deviceId) {
812 return NID1;
813 }
814 }
815
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700816 private static final class TestGossipDeviceStore extends GossipDeviceStore {
817
Madan Jampani53e44e62014-10-07 12:39:51 -0700818 public TestGossipDeviceStore(
Yuta HIGUCHI093e83e2014-10-10 22:26:11 -0700819 DeviceClockService deviceClockService,
Madan Jampani53e44e62014-10-07 12:39:51 -0700820 ClusterService clusterService,
821 ClusterCommunicationService clusterCommunicator) {
Yuta HIGUCHI093e83e2014-10-10 22:26:11 -0700822 this.deviceClockService = deviceClockService;
Madan Jampani53e44e62014-10-07 12:39:51 -0700823 this.clusterService = clusterService;
Madan Jampani47c93732014-10-06 20:46:08 -0700824 this.clusterCommunicator = clusterCommunicator;
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700825 }
Madan Jampani47c93732014-10-06 20:46:08 -0700826
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700827 public <T> T deserialize(byte[] bytes) {
828 return SERIALIZER.decode(bytes);
829 }
Madan Jampani47c93732014-10-06 20:46:08 -0700830 }
Madan Jampani53e44e62014-10-07 12:39:51 -0700831
Yuta HIGUCHI3e5d11a2014-11-04 14:16:44 -0800832 private static final class TestClusterService extends StaticClusterService {
Madan Jampani53e44e62014-10-07 12:39:51 -0700833
834 public TestClusterService() {
Yuta HIGUCHI3e5d11a2014-11-04 14:16:44 -0800835 localNode = ONOS1;
Yuta HIGUCHI47c40882014-10-10 18:44:37 -0700836 nodes.put(NID1, ONOS1);
837 nodeStates.put(NID1, ACTIVE);
838
839 nodes.put(NID2, ONOS2);
840 nodeStates.put(NID2, ACTIVE);
Madan Jampani53e44e62014-10-07 12:39:51 -0700841 }
Madan Jampani53e44e62014-10-07 12:39:51 -0700842 }
Yuta HIGUCHI67a527f2014-10-02 22:23:54 -0700843}