blob: 8335d6478ebe003f8f270c3bb3f23f9b27554f1a [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;
21import org.easymock.EasyMock;
22import org.junit.After;
23import org.junit.Before;
24import org.junit.Test;
25import org.onlab.packet.IpAddress;
26import org.onosproject.cfg.ComponentConfigService;
27import org.onosproject.core.CoreService;
28import org.onosproject.lisp.ctl.LispMessageListener;
29import org.onosproject.lisp.ctl.LispRouter;
30import org.onosproject.lisp.ctl.LispRouterAdapter;
31import org.onosproject.lisp.ctl.LispRouterAgent;
32import org.onosproject.lisp.ctl.LispRouterId;
33import org.onosproject.lisp.ctl.LispRouterListener;
34import org.onosproject.lisp.msg.protocols.DefaultLispMapNotify.DefaultNotifyBuilder;
35import org.onosproject.lisp.msg.protocols.DefaultLispMapRecord.DefaultMapRecordBuilder;
36import org.onosproject.lisp.msg.protocols.DefaultLispMapRegister.DefaultRegisterBuilder;
37import org.onosproject.lisp.msg.protocols.LispMapNotify;
38import org.onosproject.lisp.msg.protocols.LispMapNotify.NotifyBuilder;
39import org.onosproject.lisp.msg.protocols.LispMapRecord;
40import org.onosproject.lisp.msg.protocols.LispMapRecord.MapRecordBuilder;
41import org.onosproject.lisp.msg.protocols.LispMapRegister;
42import org.onosproject.lisp.msg.protocols.LispMapRegister.RegisterBuilder;
43import org.onosproject.lisp.msg.protocols.LispMapReplyAction;
44import org.onosproject.lisp.msg.protocols.LispMessage;
45import org.onosproject.lisp.msg.types.LispIpv4Address;
46import org.osgi.service.component.ComponentContext;
47
48import java.net.URI;
49import java.net.URISyntaxException;
50import java.util.Dictionary;
51import java.util.Hashtable;
52import java.util.List;
53import java.util.Spliterator;
54import java.util.Spliterators;
55import java.util.concurrent.CountDownLatch;
56import java.util.stream.Stream;
57import java.util.stream.StreamSupport;
58
59import static junit.framework.TestCase.fail;
60import static org.easymock.EasyMock.anyObject;
61import 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
139 public void waitUntilUpdateIsCalled() throws InterruptedException {
140 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
172 controller.coreService = EasyMock.createMock(CoreService.class);
173
174 ComponentConfigService mockConfigService =
175 EasyMock.createMock(ComponentConfigService.class);
176 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
185 ComponentContext mockContext = EasyMock.createMock(ComponentContext.class);
186 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);
191 controller.activate(mockContext);
192 }
193
194 @After
195 public void tearDown() {
196
197 controller.removeRouterListener(routerListener);
198 controller.removeMessageListener(messageListener);
199 controller.deactivate();
200 }
201
202 /**
203 * Tests adding and removing connected routers.
204 */
205 @Test
206 public void testAddRemoveConnectedRouter() {
207
208 // Test adding connected routers into agent
209 boolean addRouter1 = agent.addConnectedRouter(routerId1, router1);
210 assertThat(addRouter1, is(true));
211 boolean addRouter2 = agent.addConnectedRouter(routerId2, router2);
212 assertThat(addRouter2, is(true));
213 boolean addRouter3 = agent.addConnectedRouter(routerId3, router3);
214 assertThat(addRouter3, is(true));
215
216 // Test the callback methods that contained in router listener is fired
217 assertThat(routerListener.addedIds, hasSize(3));
218 assertThat(routerListener.addedIds, hasItems(routerId1, routerId2, routerId3));
219
220 // Test adding a router twice (duplicated router)
221 // this should return false to indicate that there is already a router
222 // has been added previously
223 boolean addBadRouter1 = agent.addConnectedRouter(routerId1, router1);
224 assertThat(addBadRouter1, is(false));
225
226 // Also make sure that the duplicated router will never increase the counter
227 assertThat(controller.connectedRouters.size(), is(3));
228
229 // Test querying the router list
230 Stream<LispRouter> queriedRouters = makeIntoStream(controller.getRouters());
231 long routerCount = queriedRouters.count();
232 assertThat(routerCount, is(3L));
233
234 // Test querying the individual router
235 LispRouter queriedRouter = controller.getRouter(routerId1);
236 assertThat(queriedRouter, is(router1));
237
238 // Test removing a router from connected router collection
239 agent.removeConnectedRouter(routerId2);
240 Stream<LispRouter> queriedRoutersAfterRemoval =
241 makeIntoStream(controller.getRouters());
242 long routerCountAfterRemoval = queriedRoutersAfterRemoval.count();
243 assertThat(routerCountAfterRemoval, is(2L));
244
245 // Test the callback methods that contained in router listener is fired
246 assertThat(routerListener.removedIds, hasSize(1));
247 assertThat(routerListener.removedIds, hasItems(routerId2));
248
249 // Test querying the removed switch
250 LispRouter queriedRouterAfterRemoval = controller.getRouter(routerId2);
251 assertThat(queriedRouterAfterRemoval, nullValue());
252 }
253
254 /**
255 * Tests adding and removing LISP messages.
256 */
257 @Test
258 public void testLispMessagePopulate() throws InterruptedException {
259
260 RegisterBuilder registerBuilder = new DefaultRegisterBuilder();
261 List<LispMapRecord> records = ImmutableList.of(getMapRecord(), getMapRecord());
262 LispMapRegister register = registerBuilder
263 .withIsProxyMapReply(true)
264 .withIsWantMapNotify(false)
265 .withKeyId((short) 1)
266 .withAuthKey("onos")
267 .withNonce(1L)
268 .withMapRecords(records)
269 .build();
270
271 NotifyBuilder notifyBuilder = new DefaultNotifyBuilder();
272 LispMapNotify notify = notifyBuilder
273 .withKeyId((short) 1)
274 .withAuthKey("onos")
275 .withNonce(1L)
276 .withMapRecords(records)
277 .build();
278
279 // Test the callback methods that contained in message listener is fired
280 agent.processUpstreamMessage(routerId1, register);
281 // Following line will be ignored
282 agent.processUpstreamMessage(routerId1, notify);
283
284 agent.processDownstreamMessage(routerId1, notify);
285 // Following line will be ignored
286 agent.processDownstreamMessage(routerId1, register);
287
288 messageListener.waitUntilUpdateIsCalled();
289
290 assertThat(messageListener.incomingMessages, hasSize(1));
291 assertThat(messageListener.incomingMessages, hasItems(register));
292
293 assertThat(messageListener.outgoingMessages, hasSize(1));
294 assertThat(messageListener.outgoingMessages, hasItems(notify));
295 }
296
297 /**
298 * Generates and returns a map record.
299 *
300 * @return a map record
301 */
302 private LispMapRecord getMapRecord() {
303 MapRecordBuilder builder1 = new DefaultMapRecordBuilder();
304
305 LispIpv4Address ipv4Locator1 = new LispIpv4Address(IpAddress.valueOf("192.168.1.1"));
306
307 return builder1
308 .withRecordTtl(100)
309 .withAuthoritative(true)
310 .withMapVersionNumber((short) 1)
311 .withMaskLength((byte) 0x01)
312 .withAction(LispMapReplyAction.NativelyForward)
313 .withEidPrefixAfi(ipv4Locator1)
314 .build();
315 }
316
317 /**
318 * Converts an Iterable of some type into a stream of that type.
319 *
320 * @param items Iterable of objects
321 * @param <T> type of the items in the iterable
322 * @return stream of objects of type T
323 */
324 private <T> Stream<T> makeIntoStream(Iterable<T> items) {
325 return StreamSupport.stream(
326 Spliterators.spliteratorUnknownSize(
327 items.iterator(), Spliterator.ORDERED), false);
328 }
329}