blob: 09e0bd101411b67aa4739ebccb3648dbb3251b5e [file] [log] [blame]
Jian Li834ff722016-12-13 19:43:02 +09001/*
2 * Copyright 2016-present 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 */
16package org.onosproject.lisp.ctl.impl;
17
18import com.google.common.collect.ImmutableList;
19import com.google.common.collect.ImmutableSet;
20import com.google.common.collect.Lists;
Jian Li834ff722016-12-13 19:43:02 +090021import org.junit.After;
22import org.junit.Before;
23import org.junit.Test;
24import org.onlab.packet.IpAddress;
25import org.onosproject.cfg.ComponentConfigService;
26import org.onosproject.core.CoreService;
27import org.onosproject.lisp.ctl.LispMessageListener;
28import org.onosproject.lisp.ctl.LispRouter;
29import org.onosproject.lisp.ctl.LispRouterAdapter;
30import org.onosproject.lisp.ctl.LispRouterAgent;
31import org.onosproject.lisp.ctl.LispRouterId;
32import org.onosproject.lisp.ctl.LispRouterListener;
33import org.onosproject.lisp.msg.protocols.DefaultLispMapNotify.DefaultNotifyBuilder;
34import org.onosproject.lisp.msg.protocols.DefaultLispMapRecord.DefaultMapRecordBuilder;
35import org.onosproject.lisp.msg.protocols.DefaultLispMapRegister.DefaultRegisterBuilder;
36import org.onosproject.lisp.msg.protocols.LispMapNotify;
37import org.onosproject.lisp.msg.protocols.LispMapNotify.NotifyBuilder;
38import org.onosproject.lisp.msg.protocols.LispMapRecord;
39import org.onosproject.lisp.msg.protocols.LispMapRecord.MapRecordBuilder;
40import org.onosproject.lisp.msg.protocols.LispMapRegister;
41import org.onosproject.lisp.msg.protocols.LispMapRegister.RegisterBuilder;
42import org.onosproject.lisp.msg.protocols.LispMapReplyAction;
43import org.onosproject.lisp.msg.protocols.LispMessage;
44import org.onosproject.lisp.msg.types.LispIpv4Address;
45import org.osgi.service.component.ComponentContext;
46
47import java.net.URI;
48import java.net.URISyntaxException;
49import java.util.Dictionary;
50import java.util.Hashtable;
51import java.util.List;
52import java.util.Spliterator;
53import java.util.Spliterators;
54import java.util.concurrent.CountDownLatch;
55import java.util.stream.Stream;
56import java.util.stream.StreamSupport;
57
58import static junit.framework.TestCase.fail;
59import static org.easymock.EasyMock.anyObject;
Jian Li0dab5962016-12-15 03:44:28 +090060import static org.easymock.EasyMock.createMock;
Jian Li834ff722016-12-13 19:43:02 +090061import static org.easymock.EasyMock.expect;
62import static org.easymock.EasyMock.expectLastCall;
63import static org.easymock.EasyMock.replay;
64import static org.hamcrest.MatcherAssert.assertThat;
65import static org.hamcrest.Matchers.hasItems;
66import static org.hamcrest.Matchers.hasSize;
67import static org.hamcrest.Matchers.is;
68import static org.hamcrest.Matchers.nullValue;
69
70/**
71 * Unit tests for the LISP controller implementation class.
72 */
73public class LispControllerImplTest {
74
75 private LispRouterId routerId1;
76 private LispRouterId routerId2;
77 private LispRouterId routerId3;
78 private LispRouter router1;
79 private LispRouter router2;
80 private LispRouter router3;
81
82 private LispControllerImpl controller;
83 private LispRouterAgent agent;
84 private TestRouterListener routerListener;
85 private TestMessageListener messageListener;
86
87 /**
88 * Tests harness for a router routerListener.
89 */
90 static final class TestRouterListener implements LispRouterListener {
91
92 final List<LispRouterId> removedIds = Lists.newArrayList();
93 final List<LispRouterId> addedIds = Lists.newArrayList();
94 final List<LispRouterId> changedIds = Lists.newArrayList();
95
96 @Override
97 public void routerAdded(LispRouterId routerId) {
98 addedIds.add(routerId);
99 }
100
101 @Override
102 public void routerRemoved(LispRouterId routerId) {
103 removedIds.add(routerId);
104 }
105
106 @Override
107 public void routerChanged(LispRouterId routerId) {
108 changedIds.add(routerId);
109 }
110 }
111
112 /**
113 * Tests harness for a router messageListener.
114 */
115 static final class TestMessageListener implements LispMessageListener {
116
117 final List<LispMessage> incomingMessages = Lists.newArrayList();
118 final List<LispMessage> outgoingMessages = Lists.newArrayList();
119
120 CountDownLatch incomingLatch = new CountDownLatch(1);
121 CountDownLatch outgoingLatch = new CountDownLatch(1);
122
123 @Override
124 public void handleIncomingMessage(LispRouterId routerId, LispMessage msg) {
125 synchronized (incomingMessages) {
126 incomingMessages.add(msg);
127 incomingLatch.countDown();
128 }
129 }
130
131 @Override
132 public void handleOutgoingMessage(LispRouterId routerId, LispMessage msg) {
133 synchronized (outgoingMessages) {
134 outgoingMessages.add(msg);
135 outgoingLatch.countDown();
136 }
137 }
138
Jian Li0dab5962016-12-15 03:44:28 +0900139 void waitUntilUpdateIsCalled() throws InterruptedException {
Jian Li834ff722016-12-13 19:43:02 +0900140 incomingLatch.await();
141 outgoingLatch.await();
142 }
143 }
144
145 /**
146 * Sets up routers to use as data, mocks and launches a controller instance.
147 */
148 @Before
149 public void setUp() {
150 try {
151 router1 = new LispRouterAdapter();
152 routerId1 = LispRouterId.routerId(new URI("lisp:10.1.1.1"));
153 router2 = new LispRouterAdapter();
154 routerId2 = LispRouterId.routerId(new URI("lisp:10.1.1.2"));
155 router3 = new LispRouterAdapter();
156 routerId3 = LispRouterId.routerId(new URI("lisp:10.1.1.3"));
157
158 } catch (URISyntaxException e) {
159 // this will never happen...
160 fail();
161 }
162
163 controller = new LispControllerImpl();
164 agent = controller.agent;
165
166 routerListener = new TestRouterListener();
167 controller.addRouterListener(routerListener);
168
169 messageListener = new TestMessageListener();
170 controller.addMessageListener(messageListener);
171
Jian Li0dab5962016-12-15 03:44:28 +0900172 controller.coreService = createMock(CoreService.class);
Jian Li834ff722016-12-13 19:43:02 +0900173
174 ComponentConfigService mockConfigService =
Jian Li0dab5962016-12-15 03:44:28 +0900175 createMock(ComponentConfigService.class);
Jian Li834ff722016-12-13 19:43:02 +0900176 expect(mockConfigService.getProperties(anyObject())).andReturn(ImmutableSet.of());
177 mockConfigService.registerProperties(controller.getClass());
178 expectLastCall();
179 mockConfigService.unregisterProperties(controller.getClass(), false);
180 expectLastCall();
181 expect(mockConfigService.getProperties(anyObject())).andReturn(ImmutableSet.of());
182 controller.cfgService = mockConfigService;
183 replay(mockConfigService);
184
Jian Li0dab5962016-12-15 03:44:28 +0900185 ComponentContext mockContext = createMock(ComponentContext.class);
Jian Li834ff722016-12-13 19:43:02 +0900186 Dictionary<String, Object> properties = new Hashtable<>();
187 properties.put("lispAuthKey", "onos");
188 properties.put("lispAuthKeyId", 1);
189 expect(mockContext.getProperties()).andReturn(properties);
190 replay(mockContext);
Jian Li0dab5962016-12-15 03:44:28 +0900191
192 LispControllerBootstrap bootstrap = createMock(LispControllerBootstrap.class);
193 bootstrap.start();
194 expectLastCall();
195 controller.bootstrap = bootstrap;
196 replay(bootstrap);
197
Jian Li834ff722016-12-13 19:43:02 +0900198 controller.activate(mockContext);
199 }
200
201 @After
202 public void tearDown() {
203
Jian Li0dab5962016-12-15 03:44:28 +0900204 LispControllerBootstrap bootstrap = createMock(LispControllerBootstrap.class);
205 bootstrap.stop();
206 expectLastCall();
207 controller.bootstrap = bootstrap;
208 replay(bootstrap);
209
Jian Li834ff722016-12-13 19:43:02 +0900210 controller.removeRouterListener(routerListener);
211 controller.removeMessageListener(messageListener);
Jian Li0dab5962016-12-15 03:44:28 +0900212
Jian Li834ff722016-12-13 19:43:02 +0900213 controller.deactivate();
214 }
215
216 /**
217 * Tests adding and removing connected routers.
218 */
219 @Test
220 public void testAddRemoveConnectedRouter() {
221
222 // Test adding connected routers into agent
223 boolean addRouter1 = agent.addConnectedRouter(routerId1, router1);
224 assertThat(addRouter1, is(true));
225 boolean addRouter2 = agent.addConnectedRouter(routerId2, router2);
226 assertThat(addRouter2, is(true));
227 boolean addRouter3 = agent.addConnectedRouter(routerId3, router3);
228 assertThat(addRouter3, is(true));
229
230 // Test the callback methods that contained in router listener is fired
231 assertThat(routerListener.addedIds, hasSize(3));
232 assertThat(routerListener.addedIds, hasItems(routerId1, routerId2, routerId3));
233
234 // Test adding a router twice (duplicated router)
235 // this should return false to indicate that there is already a router
236 // has been added previously
237 boolean addBadRouter1 = agent.addConnectedRouter(routerId1, router1);
238 assertThat(addBadRouter1, is(false));
239
240 // Also make sure that the duplicated router will never increase the counter
241 assertThat(controller.connectedRouters.size(), is(3));
242
243 // Test querying the router list
244 Stream<LispRouter> queriedRouters = makeIntoStream(controller.getRouters());
245 long routerCount = queriedRouters.count();
246 assertThat(routerCount, is(3L));
247
248 // Test querying the individual router
249 LispRouter queriedRouter = controller.getRouter(routerId1);
250 assertThat(queriedRouter, is(router1));
251
252 // Test removing a router from connected router collection
253 agent.removeConnectedRouter(routerId2);
254 Stream<LispRouter> queriedRoutersAfterRemoval =
255 makeIntoStream(controller.getRouters());
256 long routerCountAfterRemoval = queriedRoutersAfterRemoval.count();
257 assertThat(routerCountAfterRemoval, is(2L));
258
259 // Test the callback methods that contained in router listener is fired
260 assertThat(routerListener.removedIds, hasSize(1));
261 assertThat(routerListener.removedIds, hasItems(routerId2));
262
263 // Test querying the removed switch
264 LispRouter queriedRouterAfterRemoval = controller.getRouter(routerId2);
265 assertThat(queriedRouterAfterRemoval, nullValue());
266 }
267
268 /**
Jian Li0dab5962016-12-15 03:44:28 +0900269 * Tests adding and removing subscribed routers.
270 */
271 @Test
272 public void testAddRemoveSubscribedRouter() {
273 router1.setSubscribed(true);
274 router2.setSubscribed(true);
275
276 // Test adding connected routers into agent
277 boolean addRouter1 = agent.addConnectedRouter(routerId1, router1);
278 assertThat(addRouter1, is(true));
279 boolean addRouter2 = agent.addConnectedRouter(routerId2, router2);
280 assertThat(addRouter2, is(true));
281
282 assertThat(Lists.newArrayList(
283 controller.getSubscribedRouters()), hasSize(2));
284 assertThat(Lists.newArrayList(
285 controller.getSubscribedRouters()), hasItems(router1, router2));
286 }
287
288 /**
Jian Li834ff722016-12-13 19:43:02 +0900289 * Tests adding and removing LISP messages.
290 */
291 @Test
292 public void testLispMessagePopulate() throws InterruptedException {
293
294 RegisterBuilder registerBuilder = new DefaultRegisterBuilder();
295 List<LispMapRecord> records = ImmutableList.of(getMapRecord(), getMapRecord());
296 LispMapRegister register = registerBuilder
297 .withIsProxyMapReply(true)
298 .withIsWantMapNotify(false)
299 .withKeyId((short) 1)
300 .withAuthKey("onos")
301 .withNonce(1L)
302 .withMapRecords(records)
303 .build();
304
305 NotifyBuilder notifyBuilder = new DefaultNotifyBuilder();
306 LispMapNotify notify = notifyBuilder
307 .withKeyId((short) 1)
308 .withAuthKey("onos")
309 .withNonce(1L)
310 .withMapRecords(records)
311 .build();
312
313 // Test the callback methods that contained in message listener is fired
314 agent.processUpstreamMessage(routerId1, register);
315 // Following line will be ignored
316 agent.processUpstreamMessage(routerId1, notify);
317
318 agent.processDownstreamMessage(routerId1, notify);
319 // Following line will be ignored
320 agent.processDownstreamMessage(routerId1, register);
321
322 messageListener.waitUntilUpdateIsCalled();
323
324 assertThat(messageListener.incomingMessages, hasSize(1));
325 assertThat(messageListener.incomingMessages, hasItems(register));
326
327 assertThat(messageListener.outgoingMessages, hasSize(1));
328 assertThat(messageListener.outgoingMessages, hasItems(notify));
329 }
330
331 /**
332 * Generates and returns a map record.
333 *
334 * @return a map record
335 */
336 private LispMapRecord getMapRecord() {
337 MapRecordBuilder builder1 = new DefaultMapRecordBuilder();
338
339 LispIpv4Address ipv4Locator1 = new LispIpv4Address(IpAddress.valueOf("192.168.1.1"));
340
341 return builder1
342 .withRecordTtl(100)
Jian Li672ebda2017-02-06 20:21:04 +0900343 .withIsAuthoritative(true)
Jian Li834ff722016-12-13 19:43:02 +0900344 .withMapVersionNumber((short) 1)
345 .withMaskLength((byte) 0x01)
346 .withAction(LispMapReplyAction.NativelyForward)
347 .withEidPrefixAfi(ipv4Locator1)
348 .build();
349 }
350
351 /**
352 * Converts an Iterable of some type into a stream of that type.
353 *
354 * @param items Iterable of objects
355 * @param <T> type of the items in the iterable
356 * @return stream of objects of type T
357 */
358 private <T> Stream<T> makeIntoStream(Iterable<T> items) {
359 return StreamSupport.stream(
360 Spliterators.spliteratorUnknownSize(
361 items.iterator(), Spliterator.ORDERED), false);
362 }
363}