Yuta HIGUCHI

Add GossipLinkStoreTest

Change-Id: If3d9777583a38d911b19bb1bc50212ccb621918a
...@@ -23,6 +23,7 @@ import java.util.ArrayList; ...@@ -23,6 +23,7 @@ import java.util.ArrayList;
23 import java.util.HashSet; 23 import java.util.HashSet;
24 import java.util.List; 24 import java.util.List;
25 25
26 +import static org.junit.Assert.assertEquals;
26 import static org.onlab.onos.net.DeviceId.deviceId; 27 import static org.onlab.onos.net.DeviceId.deviceId;
27 import static org.onlab.onos.net.HostId.hostId; 28 import static org.onlab.onos.net.HostId.hostId;
28 import static org.onlab.onos.net.PortNumber.portNumber; 29 import static org.onlab.onos.net.PortNumber.portNumber;
...@@ -85,4 +86,23 @@ public final class NetTestTools { ...@@ -85,4 +86,23 @@ public final class NetTestTools {
85 return new DefaultPath(PID, links, ids.length); 86 return new DefaultPath(PID, links, ids.length);
86 } 87 }
87 88
89 +
90 + /**
91 + * Verifies that Annotations created by merging {@code annotations} is
92 + * equal to actual Annotations.
93 + *
94 + * @param actual Annotations to check
95 + * @param annotations
96 + */
97 + public static void assertAnnotationsEquals(Annotations actual, SparseAnnotations... annotations) {
98 + DefaultAnnotations expected = DefaultAnnotations.builder().build();
99 + for (SparseAnnotations a : annotations) {
100 + expected = DefaultAnnotations.merge(expected, a);
101 + }
102 + assertEquals(expected.keys(), actual.keys());
103 + for (String key : expected.keys()) {
104 + assertEquals(expected.value(key), actual.value(key));
105 + }
106 + }
107 +
88 } 108 }
......
...@@ -122,7 +122,7 @@ public class GossipLinkStore ...@@ -122,7 +122,7 @@ public class GossipLinkStore
122 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 122 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
123 protected ClusterService clusterService; 123 protected ClusterService clusterService;
124 124
125 - private static final KryoSerializer SERIALIZER = new KryoSerializer() { 125 + protected static final KryoSerializer SERIALIZER = new KryoSerializer() {
126 @Override 126 @Override
127 protected void setupKryoPool() { 127 protected void setupKryoPool() {
128 serializerPool = KryoNamespace.newBuilder() 128 serializerPool = KryoNamespace.newBuilder()
......
1 +package org.onlab.onos.store.cluster;
2 +
3 +import java.util.HashMap;
4 +import java.util.Map;
5 +import java.util.Set;
6 +
7 +import org.onlab.onos.cluster.ClusterEventListener;
8 +import org.onlab.onos.cluster.ClusterService;
9 +import org.onlab.onos.cluster.ControllerNode;
10 +import org.onlab.onos.cluster.NodeId;
11 +import org.onlab.onos.cluster.ControllerNode.State;
12 +
13 +import com.google.common.collect.Sets;
14 +
15 +public abstract class StaticClusterService implements ClusterService {
16 +
17 + protected final Map<NodeId, ControllerNode> nodes = new HashMap<>();
18 + protected final Map<NodeId, ControllerNode.State> nodeStates = new HashMap<>();
19 + protected ControllerNode localNode;
20 +
21 + @Override
22 + public ControllerNode getLocalNode() {
23 + return localNode;
24 + }
25 +
26 + @Override
27 + public Set<ControllerNode> getNodes() {
28 + return Sets.newHashSet(nodes.values());
29 + }
30 +
31 + @Override
32 + public ControllerNode getNode(NodeId nodeId) {
33 + return nodes.get(nodeId);
34 + }
35 +
36 + @Override
37 + public State getState(NodeId nodeId) {
38 + return nodeStates.get(nodeId);
39 + }
40 +
41 + @Override
42 + public void addListener(ClusterEventListener listener) {
43 + }
44 +
45 + @Override
46 + public void removeListener(ClusterEventListener listener) {
47 + }
48 +}
...\ No newline at end of file ...\ No newline at end of file
...@@ -41,10 +41,8 @@ import org.junit.Before; ...@@ -41,10 +41,8 @@ import org.junit.Before;
41 import org.junit.BeforeClass; 41 import org.junit.BeforeClass;
42 import org.junit.Ignore; 42 import org.junit.Ignore;
43 import org.junit.Test; 43 import org.junit.Test;
44 -import org.onlab.onos.cluster.ClusterEventListener;
45 import org.onlab.onos.cluster.ClusterService; 44 import org.onlab.onos.cluster.ClusterService;
46 import org.onlab.onos.cluster.ControllerNode; 45 import org.onlab.onos.cluster.ControllerNode;
47 -import org.onlab.onos.cluster.ControllerNode.State;
48 import org.onlab.onos.cluster.DefaultControllerNode; 46 import org.onlab.onos.cluster.DefaultControllerNode;
49 import org.onlab.onos.cluster.NodeId; 47 import org.onlab.onos.cluster.NodeId;
50 import org.onlab.onos.mastership.MastershipServiceAdapter; 48 import org.onlab.onos.mastership.MastershipServiceAdapter;
...@@ -65,6 +63,7 @@ import org.onlab.onos.net.device.DeviceStore; ...@@ -65,6 +63,7 @@ import org.onlab.onos.net.device.DeviceStore;
65 import org.onlab.onos.net.device.DeviceStoreDelegate; 63 import org.onlab.onos.net.device.DeviceStoreDelegate;
66 import org.onlab.onos.net.device.PortDescription; 64 import org.onlab.onos.net.device.PortDescription;
67 import org.onlab.onos.net.provider.ProviderId; 65 import org.onlab.onos.net.provider.ProviderId;
66 +import org.onlab.onos.store.cluster.StaticClusterService;
68 import org.onlab.onos.store.cluster.messaging.ClusterCommunicationService; 67 import org.onlab.onos.store.cluster.messaging.ClusterCommunicationService;
69 import org.onlab.onos.store.cluster.messaging.ClusterMessage; 68 import org.onlab.onos.store.cluster.messaging.ClusterMessage;
70 import org.onlab.onos.store.cluster.messaging.ClusterMessageHandler; 69 import org.onlab.onos.store.cluster.messaging.ClusterMessageHandler;
...@@ -133,6 +132,7 @@ public class GossipDeviceStoreTest { ...@@ -133,6 +132,7 @@ public class GossipDeviceStoreTest {
133 private DeviceClockManager deviceClockManager; 132 private DeviceClockManager deviceClockManager;
134 private DeviceClockService deviceClockService; 133 private DeviceClockService deviceClockService;
135 private ClusterCommunicationService clusterCommunicator; 134 private ClusterCommunicationService clusterCommunicator;
135 +
136 @BeforeClass 136 @BeforeClass
137 public static void setUpBeforeClass() throws Exception { 137 public static void setUpBeforeClass() throws Exception {
138 } 138 }
...@@ -838,45 +838,15 @@ public class GossipDeviceStoreTest { ...@@ -838,45 +838,15 @@ public class GossipDeviceStoreTest {
838 } 838 }
839 } 839 }
840 840
841 - private static final class TestClusterService implements ClusterService { 841 + private static final class TestClusterService extends StaticClusterService {
842 -
843 - private final Map<NodeId, ControllerNode> nodes = new HashMap<>();
844 - private final Map<NodeId, ControllerNode.State> nodeStates = new HashMap<>();
845 842
846 public TestClusterService() { 843 public TestClusterService() {
844 + localNode = ONOS1;
847 nodes.put(NID1, ONOS1); 845 nodes.put(NID1, ONOS1);
848 nodeStates.put(NID1, ACTIVE); 846 nodeStates.put(NID1, ACTIVE);
849 847
850 nodes.put(NID2, ONOS2); 848 nodes.put(NID2, ONOS2);
851 nodeStates.put(NID2, ACTIVE); 849 nodeStates.put(NID2, ACTIVE);
852 } 850 }
853 -
854 - @Override
855 - public ControllerNode getLocalNode() {
856 - return GossipDeviceStoreTest.ONOS1;
857 - }
858 -
859 - @Override
860 - public Set<ControllerNode> getNodes() {
861 - return Sets.newHashSet(nodes.values());
862 - }
863 -
864 - @Override
865 - public ControllerNode getNode(NodeId nodeId) {
866 - return nodes.get(nodeId);
867 - }
868 -
869 - @Override
870 - public State getState(NodeId nodeId) {
871 - return nodeStates.get(nodeId);
872 - }
873 -
874 - @Override
875 - public void addListener(ClusterEventListener listener) {
876 - }
877 -
878 - @Override
879 - public void removeListener(ClusterEventListener listener) {
880 - }
881 } 851 }
882 } 852 }
......
1 +/*
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 + */
16 +package org.onlab.onos.store.link.impl;
17 +
18 +import com.google.common.collect.Iterables;
19 +
20 +import org.easymock.Capture;
21 +import org.junit.After;
22 +import org.junit.AfterClass;
23 +import org.junit.Before;
24 +import org.junit.BeforeClass;
25 +import org.junit.Ignore;
26 +import org.junit.Test;
27 +import org.onlab.onos.cluster.ControllerNode;
28 +import org.onlab.onos.cluster.DefaultControllerNode;
29 +import org.onlab.onos.cluster.NodeId;
30 +import org.onlab.onos.mastership.MastershipTerm;
31 +import org.onlab.onos.net.ConnectPoint;
32 +import org.onlab.onos.net.DefaultAnnotations;
33 +import org.onlab.onos.net.DeviceId;
34 +import org.onlab.onos.net.Link;
35 +import org.onlab.onos.net.Link.Type;
36 +import org.onlab.onos.net.LinkKey;
37 +import org.onlab.onos.net.PortNumber;
38 +import org.onlab.onos.net.SparseAnnotations;
39 +import org.onlab.onos.net.device.DeviceClockService;
40 +import org.onlab.onos.net.link.DefaultLinkDescription;
41 +import org.onlab.onos.net.link.LinkDescription;
42 +import org.onlab.onos.net.link.LinkEvent;
43 +import org.onlab.onos.net.link.LinkStore;
44 +import org.onlab.onos.net.link.LinkStoreDelegate;
45 +import org.onlab.onos.net.provider.ProviderId;
46 +import org.onlab.onos.store.cluster.StaticClusterService;
47 +import org.onlab.onos.store.cluster.messaging.ClusterCommunicationService;
48 +import org.onlab.onos.store.cluster.messaging.ClusterMessage;
49 +import org.onlab.onos.store.cluster.messaging.ClusterMessageHandler;
50 +import org.onlab.onos.store.cluster.messaging.MessageSubject;
51 +import org.onlab.onos.store.device.impl.DeviceClockManager;
52 +import org.onlab.packet.IpAddress;
53 +
54 +import java.io.IOException;
55 +import java.util.HashMap;
56 +import java.util.Map;
57 +import java.util.Set;
58 +import java.util.concurrent.CountDownLatch;
59 +import java.util.concurrent.TimeUnit;
60 +
61 +import static org.easymock.EasyMock.anyObject;
62 +import static org.easymock.EasyMock.capture;
63 +import static org.easymock.EasyMock.createNiceMock;
64 +import static org.easymock.EasyMock.expect;
65 +import static org.easymock.EasyMock.expectLastCall;
66 +import static org.easymock.EasyMock.replay;
67 +import static org.easymock.EasyMock.reset;
68 +import static org.easymock.EasyMock.verify;
69 +import static org.junit.Assert.*;
70 +import static org.onlab.onos.cluster.ControllerNode.State.ACTIVE;
71 +import static org.onlab.onos.net.DeviceId.deviceId;
72 +import static org.onlab.onos.net.Link.Type.*;
73 +import static org.onlab.onos.net.link.LinkEvent.Type.*;
74 +import static org.onlab.onos.net.NetTestTools.assertAnnotationsEquals;
75 +
76 +/**
77 + * Test of the GossipLinkStoreTest implementation.
78 + */
79 +public class GossipLinkStoreTest {
80 +
81 + private static final ProviderId PID = new ProviderId("of", "foo");
82 + private static final ProviderId PIDA = new ProviderId("of", "bar", true);
83 + private static final DeviceId DID1 = deviceId("of:foo");
84 + private static final DeviceId DID2 = deviceId("of:bar");
85 +
86 + private static final PortNumber P1 = PortNumber.portNumber(1);
87 + private static final PortNumber P2 = PortNumber.portNumber(2);
88 + private static final PortNumber P3 = PortNumber.portNumber(3);
89 +
90 + private static final SparseAnnotations A1 = DefaultAnnotations.builder()
91 + .set("A1", "a1")
92 + .set("B1", "b1")
93 + .build();
94 + private static final SparseAnnotations A1_2 = DefaultAnnotations.builder()
95 + .remove("A1")
96 + .set("B3", "b3")
97 + .build();
98 + private static final SparseAnnotations A2 = DefaultAnnotations.builder()
99 + .set("A2", "a2")
100 + .set("B2", "b2")
101 + .build();
102 + private static final SparseAnnotations A2_2 = DefaultAnnotations.builder()
103 + .remove("A2")
104 + .set("B4", "b4")
105 + .build();
106 +
107 + // local node
108 + private static final NodeId NID1 = new NodeId("local");
109 + private static final ControllerNode ONOS1 =
110 + new DefaultControllerNode(NID1, IpAddress.valueOf("127.0.0.1"));
111 +
112 + // remote node
113 + private static final NodeId NID2 = new NodeId("remote");
114 + private static final ControllerNode ONOS2 =
115 + new DefaultControllerNode(NID2, IpAddress.valueOf("127.0.0.2"));
116 +
117 + private GossipLinkStore linkStoreImpl;
118 + private LinkStore linkStore;
119 +
120 + private DeviceClockManager deviceClockManager;
121 + private DeviceClockService deviceClockService;
122 + private ClusterCommunicationService clusterCommunicator;
123 +
124 +
125 + @BeforeClass
126 + public static void setUpBeforeClass() throws Exception {
127 + }
128 +
129 + @AfterClass
130 + public static void tearDownAfterClass() throws Exception {
131 + }
132 +
133 + @Before
134 + public void setUp() throws Exception {
135 + deviceClockManager = new DeviceClockManager();
136 + deviceClockManager.activate();
137 + deviceClockService = deviceClockManager;
138 +
139 + // set initial terms
140 + deviceClockManager.setMastershipTerm(DID1, MastershipTerm.of(NID1, 1));
141 + deviceClockManager.setMastershipTerm(DID2, MastershipTerm.of(NID1, 2));
142 +
143 + // TODO mock clusterCommunicator
144 + clusterCommunicator = createNiceMock(ClusterCommunicationService.class);
145 + clusterCommunicator.addSubscriber(anyObject(MessageSubject.class),
146 + anyObject(ClusterMessageHandler.class));
147 + expectLastCall().anyTimes();
148 + replay(clusterCommunicator);
149 +
150 + linkStoreImpl = new GossipLinkStore();
151 + linkStoreImpl.deviceClockService = deviceClockService;
152 + linkStoreImpl.clusterCommunicator = clusterCommunicator;
153 + linkStoreImpl.clusterService = new TestClusterService();
154 + linkStoreImpl.activate();
155 + linkStore = linkStoreImpl;
156 +
157 + verify(clusterCommunicator);
158 + reset(clusterCommunicator);
159 + }
160 +
161 + @After
162 + public void tearDown() throws Exception {
163 + linkStoreImpl.deactivate();
164 + }
165 +
166 + private void putLink(DeviceId srcId, PortNumber srcNum,
167 + DeviceId dstId, PortNumber dstNum, Type type,
168 + SparseAnnotations... annotations) {
169 + ConnectPoint src = new ConnectPoint(srcId, srcNum);
170 + ConnectPoint dst = new ConnectPoint(dstId, dstNum);
171 + reset(clusterCommunicator);
172 + try {
173 + expect(clusterCommunicator.broadcast(anyObject(ClusterMessage.class)))
174 + .andReturn(true).anyTimes();
175 + } catch (IOException e) {
176 + fail("Should never reach here");
177 + }
178 + replay(clusterCommunicator);
179 + linkStore.createOrUpdateLink(PID, new DefaultLinkDescription(src, dst, type, annotations));
180 + verify(clusterCommunicator);
181 + }
182 +
183 + private void resetCommunicatorExpectingNoBroadcast(
184 + Capture<ClusterMessage> bcast) {
185 + bcast.reset();
186 + reset(clusterCommunicator);
187 + replay(clusterCommunicator);
188 + }
189 +
190 + private void resetCommunicatorExpectingSingleBroadcast(
191 + Capture<ClusterMessage> bcast) {
192 +
193 + bcast.reset();
194 + reset(clusterCommunicator);
195 + try {
196 + expect(clusterCommunicator.broadcast(capture(bcast))).andReturn(true).once();
197 + } catch (IOException e) {
198 + fail("Should never reach here");
199 + }
200 + replay(clusterCommunicator);
201 + }
202 +
203 + private void putLink(LinkKey key, Type type, SparseAnnotations... annotations) {
204 + putLink(key.src().deviceId(), key.src().port(),
205 + key.dst().deviceId(), key.dst().port(),
206 + type, annotations);
207 + }
208 +
209 + private static void assertLink(DeviceId srcId, PortNumber srcNum,
210 + DeviceId dstId, PortNumber dstNum, Type type,
211 + Link link) {
212 + assertEquals(srcId, link.src().deviceId());
213 + assertEquals(srcNum, link.src().port());
214 + assertEquals(dstId, link.dst().deviceId());
215 + assertEquals(dstNum, link.dst().port());
216 + assertEquals(type, link.type());
217 + }
218 +
219 + private static void assertLink(LinkKey key, Type type, Link link) {
220 + assertLink(key.src().deviceId(), key.src().port(),
221 + key.dst().deviceId(), key.dst().port(),
222 + type, link);
223 + }
224 +
225 + @Test
226 + public final void testGetLinkCount() {
227 + assertEquals("initialy empty", 0, linkStore.getLinkCount());
228 +
229 + putLink(DID1, P1, DID2, P2, DIRECT);
230 + putLink(DID2, P2, DID1, P1, DIRECT);
231 + putLink(DID1, P1, DID2, P2, DIRECT);
232 +
233 + assertEquals("expecting 2 unique link", 2, linkStore.getLinkCount());
234 + }
235 +
236 + @Test
237 + public final void testGetLinks() {
238 + assertEquals("initialy empty", 0,
239 + Iterables.size(linkStore.getLinks()));
240 +
241 + LinkKey linkId1 = LinkKey.linkKey(new ConnectPoint(DID1, P1), new ConnectPoint(DID2, P2));
242 + LinkKey linkId2 = LinkKey.linkKey(new ConnectPoint(DID2, P2), new ConnectPoint(DID1, P1));
243 +
244 + putLink(linkId1, DIRECT);
245 + putLink(linkId2, DIRECT);
246 + putLink(linkId1, DIRECT);
247 +
248 + assertEquals("expecting 2 unique link", 2,
249 + Iterables.size(linkStore.getLinks()));
250 +
251 + Map<LinkKey, Link> links = new HashMap<>();
252 + for (Link link : linkStore.getLinks()) {
253 + links.put(LinkKey.linkKey(link), link);
254 + }
255 +
256 + assertLink(linkId1, DIRECT, links.get(linkId1));
257 + assertLink(linkId2, DIRECT, links.get(linkId2));
258 + }
259 +
260 + @Test
261 + public final void testGetDeviceEgressLinks() {
262 + LinkKey linkId1 = LinkKey.linkKey(new ConnectPoint(DID1, P1), new ConnectPoint(DID2, P2));
263 + LinkKey linkId2 = LinkKey.linkKey(new ConnectPoint(DID2, P2), new ConnectPoint(DID1, P1));
264 + LinkKey linkId3 = LinkKey.linkKey(new ConnectPoint(DID1, P2), new ConnectPoint(DID2, P3));
265 +
266 + putLink(linkId1, DIRECT);
267 + putLink(linkId2, DIRECT);
268 + putLink(linkId3, DIRECT);
269 +
270 + // DID1,P1 => DID2,P2
271 + // DID2,P2 => DID1,P1
272 + // DID1,P2 => DID2,P3
273 +
274 + Set<Link> links1 = linkStore.getDeviceEgressLinks(DID1);
275 + assertEquals(2, links1.size());
276 + // check
277 +
278 + Set<Link> links2 = linkStore.getDeviceEgressLinks(DID2);
279 + assertEquals(1, links2.size());
280 + assertLink(linkId2, DIRECT, links2.iterator().next());
281 + }
282 +
283 + @Test
284 + public final void testGetDeviceIngressLinks() {
285 + LinkKey linkId1 = LinkKey.linkKey(new ConnectPoint(DID1, P1), new ConnectPoint(DID2, P2));
286 + LinkKey linkId2 = LinkKey.linkKey(new ConnectPoint(DID2, P2), new ConnectPoint(DID1, P1));
287 + LinkKey linkId3 = LinkKey.linkKey(new ConnectPoint(DID1, P2), new ConnectPoint(DID2, P3));
288 +
289 + putLink(linkId1, DIRECT);
290 + putLink(linkId2, DIRECT);
291 + putLink(linkId3, DIRECT);
292 +
293 + // DID1,P1 => DID2,P2
294 + // DID2,P2 => DID1,P1
295 + // DID1,P2 => DID2,P3
296 +
297 + Set<Link> links1 = linkStore.getDeviceIngressLinks(DID2);
298 + assertEquals(2, links1.size());
299 + // check
300 +
301 + Set<Link> links2 = linkStore.getDeviceIngressLinks(DID1);
302 + assertEquals(1, links2.size());
303 + assertLink(linkId2, DIRECT, links2.iterator().next());
304 + }
305 +
306 + @Test
307 + public final void testGetLink() {
308 + ConnectPoint src = new ConnectPoint(DID1, P1);
309 + ConnectPoint dst = new ConnectPoint(DID2, P2);
310 + LinkKey linkId1 = LinkKey.linkKey(src, dst);
311 +
312 + putLink(linkId1, DIRECT);
313 +
314 + Link link = linkStore.getLink(src, dst);
315 + assertLink(linkId1, DIRECT, link);
316 +
317 + assertNull("There shouldn't be reverese link",
318 + linkStore.getLink(dst, src));
319 + }
320 +
321 + @Test
322 + public final void testGetEgressLinks() {
323 + final ConnectPoint d1P1 = new ConnectPoint(DID1, P1);
324 + final ConnectPoint d2P2 = new ConnectPoint(DID2, P2);
325 + LinkKey linkId1 = LinkKey.linkKey(d1P1, d2P2);
326 + LinkKey linkId2 = LinkKey.linkKey(d2P2, d1P1);
327 + LinkKey linkId3 = LinkKey.linkKey(new ConnectPoint(DID1, P2), new ConnectPoint(DID2, P3));
328 +
329 + putLink(linkId1, DIRECT);
330 + putLink(linkId2, DIRECT);
331 + putLink(linkId3, DIRECT);
332 +
333 + // DID1,P1 => DID2,P2
334 + // DID2,P2 => DID1,P1
335 + // DID1,P2 => DID2,P3
336 +
337 + Set<Link> links1 = linkStore.getEgressLinks(d1P1);
338 + assertEquals(1, links1.size());
339 + assertLink(linkId1, DIRECT, links1.iterator().next());
340 +
341 + Set<Link> links2 = linkStore.getEgressLinks(d2P2);
342 + assertEquals(1, links2.size());
343 + assertLink(linkId2, DIRECT, links2.iterator().next());
344 + }
345 +
346 + @Test
347 + public final void testGetIngressLinks() {
348 + final ConnectPoint d1P1 = new ConnectPoint(DID1, P1);
349 + final ConnectPoint d2P2 = new ConnectPoint(DID2, P2);
350 + LinkKey linkId1 = LinkKey.linkKey(d1P1, d2P2);
351 + LinkKey linkId2 = LinkKey.linkKey(d2P2, d1P1);
352 + LinkKey linkId3 = LinkKey.linkKey(new ConnectPoint(DID1, P2), new ConnectPoint(DID2, P3));
353 +
354 + putLink(linkId1, DIRECT);
355 + putLink(linkId2, DIRECT);
356 + putLink(linkId3, DIRECT);
357 +
358 + // DID1,P1 => DID2,P2
359 + // DID2,P2 => DID1,P1
360 + // DID1,P2 => DID2,P3
361 +
362 + Set<Link> links1 = linkStore.getIngressLinks(d2P2);
363 + assertEquals(1, links1.size());
364 + assertLink(linkId1, DIRECT, links1.iterator().next());
365 +
366 + Set<Link> links2 = linkStore.getIngressLinks(d1P1);
367 + assertEquals(1, links2.size());
368 + assertLink(linkId2, DIRECT, links2.iterator().next());
369 + }
370 +
371 + @Test
372 + public final void testCreateOrUpdateLink() {
373 + ConnectPoint src = new ConnectPoint(DID1, P1);
374 + ConnectPoint dst = new ConnectPoint(DID2, P2);
375 +
376 + Capture<ClusterMessage> bcast = new Capture<>();
377 +
378 + // add link
379 + resetCommunicatorExpectingSingleBroadcast(bcast);
380 + final DefaultLinkDescription linkDescription = new DefaultLinkDescription(src, dst, INDIRECT);
381 + LinkEvent event = linkStore.createOrUpdateLink(PID,
382 + linkDescription);
383 + verifyLinkBroadcastMessage(PID, NID1, src, dst, INDIRECT, bcast);
384 +
385 + assertLink(DID1, P1, DID2, P2, INDIRECT, event.subject());
386 + assertEquals(LINK_ADDED, event.type());
387 +
388 + // update link type
389 + resetCommunicatorExpectingSingleBroadcast(bcast);
390 + LinkEvent event2 = linkStore.createOrUpdateLink(PID,
391 + new DefaultLinkDescription(src, dst, DIRECT));
392 + verifyLinkBroadcastMessage(PID, NID1, src, dst, DIRECT, bcast);
393 +
394 + assertLink(DID1, P1, DID2, P2, DIRECT, event2.subject());
395 + assertEquals(LINK_UPDATED, event2.type());
396 +
397 + // no change
398 + resetCommunicatorExpectingSingleBroadcast(bcast);
399 + LinkEvent event3 = linkStore.createOrUpdateLink(PID,
400 + new DefaultLinkDescription(src, dst, DIRECT));
401 + verifyNoBroadcastMessage(bcast);
402 +
403 + assertNull("No change event expected", event3);
404 + }
405 +
406 + private void verifyNoBroadcastMessage(Capture<ClusterMessage> bcast) {
407 + assertFalse("No broadcast expected", bcast.hasCaptured());
408 + }
409 +
410 + private void verifyLinkBroadcastMessage(ProviderId providerId,
411 + NodeId sender,
412 + ConnectPoint src,
413 + ConnectPoint dst,
414 + Type type,
415 + Capture<ClusterMessage> actualMsg) {
416 + verify(clusterCommunicator);
417 + assertTrue(actualMsg.hasCaptured());
418 + assertEquals(sender, actualMsg.getValue().sender());
419 + assertEquals(GossipLinkStoreMessageSubjects.LINK_UPDATE,
420 + actualMsg.getValue().subject());
421 + InternalLinkEvent linkEvent
422 + = GossipLinkStore.SERIALIZER.decode(actualMsg.getValue().payload());
423 + assertEquals(providerId, linkEvent.providerId());
424 + assertLinkDescriptionEquals(src, dst, type, linkEvent.linkDescription().value());
425 +
426 + }
427 +
428 + private static void assertLinkDescriptionEquals(ConnectPoint src,
429 + ConnectPoint dst,
430 + Type type,
431 + LinkDescription actual) {
432 + assertEquals(src, actual.src());
433 + assertEquals(dst, actual.dst());
434 + assertEquals(type, actual.type());
435 + // TODO check annotations
436 + }
437 +
438 + @Test
439 + public final void testCreateOrUpdateLinkAncillary() {
440 + ConnectPoint src = new ConnectPoint(DID1, P1);
441 + ConnectPoint dst = new ConnectPoint(DID2, P2);
442 +
443 + Capture<ClusterMessage> bcast = new Capture<>();
444 +
445 + // add Ancillary link
446 + resetCommunicatorExpectingSingleBroadcast(bcast);
447 + LinkEvent event = linkStore.createOrUpdateLink(PIDA,
448 + new DefaultLinkDescription(src, dst, INDIRECT, A1));
449 + verifyLinkBroadcastMessage(PIDA, NID1, src, dst, INDIRECT, bcast);
450 +
451 + assertNotNull("Ancillary only link is ignored", event);
452 +
453 + // add Primary link
454 + resetCommunicatorExpectingSingleBroadcast(bcast);
455 + LinkEvent event2 = linkStore.createOrUpdateLink(PID,
456 + new DefaultLinkDescription(src, dst, INDIRECT, A2));
457 + verifyLinkBroadcastMessage(PID, NID1, src, dst, INDIRECT, bcast);
458 +
459 + assertLink(DID1, P1, DID2, P2, INDIRECT, event2.subject());
460 + assertAnnotationsEquals(event2.subject().annotations(), A2, A1);
461 + assertEquals(LINK_UPDATED, event2.type());
462 +
463 + // update link type
464 + resetCommunicatorExpectingSingleBroadcast(bcast);
465 + LinkEvent event3 = linkStore.createOrUpdateLink(PID,
466 + new DefaultLinkDescription(src, dst, DIRECT, A2));
467 + verifyLinkBroadcastMessage(PID, NID1, src, dst, DIRECT, bcast);
468 +
469 + assertLink(DID1, P1, DID2, P2, DIRECT, event3.subject());
470 + assertAnnotationsEquals(event3.subject().annotations(), A2, A1);
471 + assertEquals(LINK_UPDATED, event3.type());
472 +
473 +
474 + // no change
475 + resetCommunicatorExpectingNoBroadcast(bcast);
476 + LinkEvent event4 = linkStore.createOrUpdateLink(PID,
477 + new DefaultLinkDescription(src, dst, DIRECT));
478 + verifyNoBroadcastMessage(bcast);
479 +
480 + assertNull("No change event expected", event4);
481 +
482 + // update link annotation (Primary)
483 + resetCommunicatorExpectingSingleBroadcast(bcast);
484 + LinkEvent event5 = linkStore.createOrUpdateLink(PID,
485 + new DefaultLinkDescription(src, dst, DIRECT, A2_2));
486 + verifyLinkBroadcastMessage(PID, NID1, src, dst, DIRECT, bcast);
487 +
488 + assertLink(DID1, P1, DID2, P2, DIRECT, event5.subject());
489 + assertAnnotationsEquals(event5.subject().annotations(), A2, A2_2, A1);
490 + assertEquals(LINK_UPDATED, event5.type());
491 +
492 + // update link annotation (Ancillary)
493 + resetCommunicatorExpectingSingleBroadcast(bcast);
494 + LinkEvent event6 = linkStore.createOrUpdateLink(PIDA,
495 + new DefaultLinkDescription(src, dst, DIRECT, A1_2));
496 + verifyLinkBroadcastMessage(PIDA, NID1, src, dst, DIRECT, bcast);
497 +
498 + assertLink(DID1, P1, DID2, P2, DIRECT, event6.subject());
499 + assertAnnotationsEquals(event6.subject().annotations(), A2, A2_2, A1, A1_2);
500 + assertEquals(LINK_UPDATED, event6.type());
501 +
502 + // update link type (Ancillary) : ignored
503 + resetCommunicatorExpectingNoBroadcast(bcast);
504 + LinkEvent event7 = linkStore.createOrUpdateLink(PIDA,
505 + new DefaultLinkDescription(src, dst, EDGE));
506 + verifyNoBroadcastMessage(bcast);
507 + assertNull("Ancillary change other than annotation is ignored", event7);
508 + }
509 +
510 +
511 + @Test
512 + public final void testRemoveLink() {
513 + final ConnectPoint d1P1 = new ConnectPoint(DID1, P1);
514 + final ConnectPoint d2P2 = new ConnectPoint(DID2, P2);
515 + LinkKey linkId1 = LinkKey.linkKey(d1P1, d2P2);
516 + LinkKey linkId2 = LinkKey.linkKey(d2P2, d1P1);
517 +
518 + putLink(linkId1, DIRECT, A1);
519 + putLink(linkId2, DIRECT, A2);
520 +
521 + // DID1,P1 => DID2,P2
522 + // DID2,P2 => DID1,P1
523 + // DID1,P2 => DID2,P3
524 +
525 + LinkEvent event = linkStore.removeLink(d1P1, d2P2);
526 + assertEquals(LINK_REMOVED, event.type());
527 + assertAnnotationsEquals(event.subject().annotations(), A1);
528 + LinkEvent event2 = linkStore.removeLink(d1P1, d2P2);
529 + assertNull(event2);
530 +
531 + assertLink(linkId2, DIRECT, linkStore.getLink(d2P2, d1P1));
532 + assertAnnotationsEquals(linkStore.getLink(d2P2, d1P1).annotations(), A2);
533 +
534 + // annotations, etc. should not survive remove
535 + putLink(linkId1, DIRECT);
536 + assertLink(linkId1, DIRECT, linkStore.getLink(d1P1, d2P2));
537 + assertAnnotationsEquals(linkStore.getLink(d1P1, d2P2).annotations());
538 + }
539 +
540 + @Test
541 + public final void testAncillaryVisible() {
542 + ConnectPoint src = new ConnectPoint(DID1, P1);
543 + ConnectPoint dst = new ConnectPoint(DID2, P2);
544 +
545 + // add Ancillary link
546 + linkStore.createOrUpdateLink(PIDA,
547 + new DefaultLinkDescription(src, dst, INDIRECT, A1));
548 +
549 + // Ancillary only link should not be visible
550 + assertEquals(1, linkStore.getLinkCount());
551 + assertNotNull(linkStore.getLink(src, dst));
552 + }
553 +
554 + // If Delegates should be called only on remote events,
555 + // then Simple* should never call them, thus not test required.
556 + @Ignore("Ignore until Delegate spec. is clear.")
557 + @Test
558 + public final void testEvents() throws InterruptedException {
559 +
560 + final ConnectPoint d1P1 = new ConnectPoint(DID1, P1);
561 + final ConnectPoint d2P2 = new ConnectPoint(DID2, P2);
562 + final LinkKey linkId1 = LinkKey.linkKey(d1P1, d2P2);
563 +
564 + final CountDownLatch addLatch = new CountDownLatch(1);
565 + LinkStoreDelegate checkAdd = new LinkStoreDelegate() {
566 + @Override
567 + public void notify(LinkEvent event) {
568 + assertEquals(LINK_ADDED, event.type());
569 + assertLink(linkId1, INDIRECT, event.subject());
570 + addLatch.countDown();
571 + }
572 + };
573 + final CountDownLatch updateLatch = new CountDownLatch(1);
574 + LinkStoreDelegate checkUpdate = new LinkStoreDelegate() {
575 + @Override
576 + public void notify(LinkEvent event) {
577 + assertEquals(LINK_UPDATED, event.type());
578 + assertLink(linkId1, DIRECT, event.subject());
579 + updateLatch.countDown();
580 + }
581 + };
582 + final CountDownLatch removeLatch = new CountDownLatch(1);
583 + LinkStoreDelegate checkRemove = new LinkStoreDelegate() {
584 + @Override
585 + public void notify(LinkEvent event) {
586 + assertEquals(LINK_REMOVED, event.type());
587 + assertLink(linkId1, DIRECT, event.subject());
588 + removeLatch.countDown();
589 + }
590 + };
591 +
592 + linkStore.setDelegate(checkAdd);
593 + putLink(linkId1, INDIRECT);
594 + assertTrue("Add event fired", addLatch.await(1, TimeUnit.SECONDS));
595 +
596 + linkStore.unsetDelegate(checkAdd);
597 + linkStore.setDelegate(checkUpdate);
598 + putLink(linkId1, DIRECT);
599 + assertTrue("Update event fired", updateLatch.await(1, TimeUnit.SECONDS));
600 +
601 + linkStore.unsetDelegate(checkUpdate);
602 + linkStore.setDelegate(checkRemove);
603 + linkStore.removeLink(d1P1, d2P2);
604 + assertTrue("Remove event fired", removeLatch.await(1, TimeUnit.SECONDS));
605 + }
606 +
607 + private static final class TestClusterService extends StaticClusterService {
608 +
609 + public TestClusterService() {
610 + localNode = ONOS1;
611 + nodes.put(NID1, ONOS1);
612 + nodeStates.put(NID1, ACTIVE);
613 +
614 + nodes.put(NID2, ONOS2);
615 + nodeStates.put(NID2, ACTIVE);
616 + }
617 + }
618 +}
...@@ -23,6 +23,7 @@ import static org.junit.Assert.*; ...@@ -23,6 +23,7 @@ import static org.junit.Assert.*;
23 import static org.onlab.onos.net.Device.Type.SWITCH; 23 import static org.onlab.onos.net.Device.Type.SWITCH;
24 import static org.onlab.onos.net.DeviceId.deviceId; 24 import static org.onlab.onos.net.DeviceId.deviceId;
25 import static org.onlab.onos.net.device.DeviceEvent.Type.*; 25 import static org.onlab.onos.net.device.DeviceEvent.Type.*;
26 +import static org.onlab.onos.net.NetTestTools.assertAnnotationsEquals;
26 27
27 import java.util.Arrays; 28 import java.util.Arrays;
28 import java.util.HashMap; 29 import java.util.HashMap;
...@@ -38,7 +39,6 @@ import org.junit.Before; ...@@ -38,7 +39,6 @@ import org.junit.Before;
38 import org.junit.BeforeClass; 39 import org.junit.BeforeClass;
39 import org.junit.Ignore; 40 import org.junit.Ignore;
40 import org.junit.Test; 41 import org.junit.Test;
41 -import org.onlab.onos.net.Annotations;
42 import org.onlab.onos.net.DefaultAnnotations; 42 import org.onlab.onos.net.DefaultAnnotations;
43 import org.onlab.onos.net.Device; 43 import org.onlab.onos.net.Device;
44 import org.onlab.onos.net.DeviceId; 44 import org.onlab.onos.net.DeviceId;
...@@ -56,6 +56,7 @@ import org.onlab.onos.net.provider.ProviderId; ...@@ -56,6 +56,7 @@ import org.onlab.onos.net.provider.ProviderId;
56 56
57 import com.google.common.collect.Iterables; 57 import com.google.common.collect.Iterables;
58 import com.google.common.collect.Sets; 58 import com.google.common.collect.Sets;
59 +
59 import org.onlab.packet.ChassisId; 60 import org.onlab.packet.ChassisId;
60 61
61 /** 62 /**
...@@ -146,25 +147,6 @@ public class SimpleDeviceStoreTest { ...@@ -146,25 +147,6 @@ public class SimpleDeviceStoreTest {
146 assertEquals(SN, device.serialNumber()); 147 assertEquals(SN, device.serialNumber());
147 } 148 }
148 149
149 - // TODO slice this out somewhere
150 - /**
151 - * Verifies that Annotations created by merging {@code annotations} is
152 - * equal to actual Annotations.
153 - *
154 - * @param actual Annotations to check
155 - * @param annotations
156 - */
157 - public static void assertAnnotationsEquals(Annotations actual, SparseAnnotations... annotations) {
158 - DefaultAnnotations expected = DefaultAnnotations.builder().build();
159 - for (SparseAnnotations a : annotations) {
160 - expected = DefaultAnnotations.merge(expected, a);
161 - }
162 - assertEquals(expected.keys(), actual.keys());
163 - for (String key : expected.keys()) {
164 - assertEquals(expected.value(key), actual.value(key));
165 - }
166 - }
167 -
168 @Test 150 @Test
169 public final void testGetDeviceCount() { 151 public final void testGetDeviceCount() {
170 assertEquals("initialy empty", 0, deviceStore.getDeviceCount()); 152 assertEquals("initialy empty", 0, deviceStore.getDeviceCount());
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
16 package org.onlab.onos.store.trivial.impl; 16 package org.onlab.onos.store.trivial.impl;
17 17
18 import com.google.common.collect.Iterables; 18 import com.google.common.collect.Iterables;
19 +
19 import org.junit.After; 20 import org.junit.After;
20 import org.junit.AfterClass; 21 import org.junit.AfterClass;
21 import org.junit.Before; 22 import org.junit.Before;
...@@ -46,7 +47,7 @@ import static org.junit.Assert.*; ...@@ -46,7 +47,7 @@ import static org.junit.Assert.*;
46 import static org.onlab.onos.net.DeviceId.deviceId; 47 import static org.onlab.onos.net.DeviceId.deviceId;
47 import static org.onlab.onos.net.Link.Type.*; 48 import static org.onlab.onos.net.Link.Type.*;
48 import static org.onlab.onos.net.link.LinkEvent.Type.*; 49 import static org.onlab.onos.net.link.LinkEvent.Type.*;
49 -import static org.onlab.onos.store.trivial.impl.SimpleDeviceStoreTest.assertAnnotationsEquals; 50 +import static org.onlab.onos.net.NetTestTools.assertAnnotationsEquals;
50 51
51 /** 52 /**
52 * Test of the simple LinkStore implementation. 53 * Test of the simple LinkStore implementation.
......