blob: 3e24ac958e323806e0239b3878e90089cf0423c0 [file] [log] [blame]
Sanjay S0d4093f2015-05-06 14:55:04 +05301/*
2 * Copyright 2015 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.provider.netconf.device.impl;
17
18import static org.easymock.EasyMock.expect;
19import static org.easymock.EasyMock.replay;
20import static org.junit.Assert.assertFalse;
21import static org.onlab.util.Tools.delay;
22import static org.slf4j.LoggerFactory.getLogger;
23
24import java.io.IOException;
Sanjay S59f86fd2015-05-20 12:23:48 +053025import java.net.SocketTimeoutException;
Sanjay S0d4093f2015-05-06 14:55:04 +053026import java.net.URI;
27import java.net.URISyntaxException;
28import java.util.Collection;
29import java.util.Dictionary;
30import java.util.List;
31import java.util.Map;
32import java.util.Set;
33import java.util.concurrent.ConcurrentHashMap;
34
35import org.easymock.EasyMock;
36import org.junit.After;
37import org.junit.Before;
HIGUCHI Yutaea39db52015-06-12 12:02:38 -070038import org.junit.Ignore;
Sanjay S0d4093f2015-05-06 14:55:04 +053039import org.junit.Test;
40import org.onlab.packet.ChassisId;
41import org.onosproject.cfg.ComponentConfigService;
42import org.onosproject.net.Device;
43import org.onosproject.net.DeviceId;
44import org.onosproject.net.MastershipRole;
45import org.onosproject.net.device.DefaultDeviceDescription;
46import org.onosproject.net.device.DeviceDescription;
47import org.onosproject.net.device.DeviceProvider;
48import org.onosproject.net.device.DeviceProviderRegistry;
49import org.onosproject.net.device.DeviceProviderService;
50import org.onosproject.net.device.PortDescription;
51import org.onosproject.net.device.PortStatistics;
52import org.onosproject.net.provider.ProviderId;
53import org.osgi.service.component.ComponentContext;
54import org.slf4j.Logger;
55
56import com.tailf.jnc.JNCException;
57
58/**
59 * Test Case to Validate Netconf Device Provider.
60 *
61 */
62public class NetconfDeviceProviderTest {
63 // private NetconfDevice device;
64
65 TestDeviceCreator create;
66
67 private final Logger log = getLogger(NetconfDeviceProviderTest.class);
68
69 private Map<DeviceId, NetconfDevice> netconfDeviceMap = new ConcurrentHashMap<DeviceId, NetconfDevice>();
70
71 private DeviceProviderService providerService;
72
73 private static final int EVENTINTERVAL = 5;
74
75 private static final String SCHEME = "netconf";
76
77 private static final DeviceId DID1 = DeviceId
78 .deviceId("of:0000000000000001");
79
80 private final NetconfDeviceProvider provider = new NetconfDeviceProvider();
81 private final TestDeviceRegistry registry = new TestDeviceRegistry();
82
83 private ComponentConfigService mockCfgService;
84
85 @Before
86 public void setUp() {
87 mockCfgService = EasyMock.createMock(ComponentConfigService.class);
88 provider.cfgService = mockCfgService;
89 provider.providerRegistry = registry;
90 }
91
92 @SuppressWarnings("unchecked")
93 private Dictionary<String, String> getDictionaryMock(ComponentContext componentContext) {
94 Dictionary<String, String> dictionary = EasyMock
95 .createMock(Dictionary.class);
96 expect(dictionary.get("devConfigs"))
97 .andReturn("cisco:cisco@10.18.11.14:22:active,"
98 + "sanjay:b33rb3lly@10.18.24.122:2022:inactive");
99 replay(dictionary);
100 expect(componentContext.getProperties()).andReturn(dictionary);
101 return dictionary;
102 }
103
104 @SuppressWarnings("unchecked")
105 private Dictionary<String, String> getDictionaryMockWithoutValues(ComponentContext componentContext) {
106 Dictionary<String, String> dictionary = EasyMock
107 .createMock(Dictionary.class);
108 expect(dictionary.get("devConfigs")).andReturn("");
109 replay(dictionary);
110 expect(componentContext.getProperties()).andReturn(dictionary);
111 return dictionary;
112 }
113
114 @SuppressWarnings("unchecked")
115 private Dictionary<String, String> getDictionaryMockWithDeviceEntryNull(ComponentContext componentContext) {
116 Dictionary<String, String> dictionary = EasyMock
117 .createMock(Dictionary.class);
118 expect(dictionary.get("devConfigs")).andReturn("null,null");
119 replay(dictionary);
120 expect(componentContext.getProperties()).andReturn(dictionary);
121 return dictionary;
122 }
123
124 @SuppressWarnings("unchecked")
125 private Dictionary<String, String> getDictionaryMockDeviceEntryNumberFomatEx(ComponentContext componentContext) {
126 Dictionary<String, String> dictionary = EasyMock
127 .createMock(Dictionary.class);
128 expect(dictionary.get("devConfigs"))
129 .andReturn("cisco:cisco@10.18.11.14:cisco:active")
130 .andThrow(new NumberFormatException());
131 replay(dictionary);
132 expect(componentContext.getProperties()).andReturn(dictionary);
133 return dictionary;
134 }
135
136 @SuppressWarnings("unchecked")
137 private Dictionary<String, String> getDictionaryMockWithoutUsernameAndPassword(ComponentContext componentContext) {
138 Dictionary<String, String> dictionary = EasyMock
139 .createMock(Dictionary.class);
140 expect(dictionary.get("devConfigs"))
141 .andReturn("null:null@null:0:active");
142 replay(dictionary);
143 expect(componentContext.getProperties()).andReturn(dictionary);
144 return dictionary;
145 }
146
147 @SuppressWarnings("unchecked")
148 private Dictionary<String, String> getDictionaryMockWithDifferentDeviceState(ComponentContext componentContext) {
149 Dictionary<String, String> dictionary = EasyMock
150 .createMock(Dictionary.class);
151 expect(dictionary.get("devConfigs"))
152 .andReturn("cisco:cisco@10.18.11.14:22:active,cisco:cisco@10.18.11.18:22:inactive,"
153 + "cisco:cisco@10.18.11.14:22:invalid,cisco:cisco@10.18.11.14:22:null");
154 replay(dictionary);
155 expect(componentContext.getProperties()).andReturn(dictionary);
156 return dictionary;
157 }
158
159 @SuppressWarnings("unchecked")
160 private Dictionary<String, String> getDictionaryMockDeviceWithArrayOutOFBoundEx(ComponentContext componentContext) {
161 Dictionary<String, String> dictionary = EasyMock
162 .createMock(Dictionary.class);
163 expect(dictionary.get("devConfigs"))
164 .andReturn("@10.18.11.14:22:active")
165 .andThrow(new ArrayIndexOutOfBoundsException());
166 replay(dictionary);
167 expect(componentContext.getProperties()).andReturn(dictionary);
168 return dictionary;
169 }
170
171 @SuppressWarnings("unchecked")
172 private Dictionary<String, String> getDictionaryMockDeviceEntryForDeactivate(ComponentContext componentContext) {
173 Dictionary<String, String> dictionary = EasyMock
174 .createMock(Dictionary.class);
175 expect(dictionary.get("devConfigs"))
176 .andReturn("netconf:cisco@10.18.11.14:22:active")
177 .andThrow(new ArrayIndexOutOfBoundsException());
178 replay(dictionary);
179 expect(componentContext.getProperties()).andReturn(dictionary);
180 return dictionary;
181 }
182
HIGUCHI Yutaea39db52015-06-12 12:02:38 -0700183 @Ignore("Test fails if the hard coded host actually exists.")
Sanjay S59f86fd2015-05-20 12:23:48 +0530184 @Test(expected = SocketTimeoutException.class)
185 public void testSSHAuthentication() throws JNCException, IOException {
186 NetconfDevice netconfDevice = new NetconfDevice("10.18.14.19", 22,
187 "cisco", "cisco");
188 netconfDevice.setConnectTimeout(1000);
189 TestDeviceCreator objForTestDev = new TestDeviceCreator(netconfDevice,
Sanjay S0d4093f2015-05-06 14:55:04 +0530190 true);
191 objForTestDev.run();
192 }
193
194 @After
195 public void tearDown() {
196 provider.providerRegistry = null;
197 provider.cfgService = null;
198 }
199
200 @Test
201 public void testActiveWithComponentContext() {
202
203 ComponentContext componentContext = EasyMock
204 .createMock(ComponentContext.class);
205 getDictionaryMock(componentContext);
206 replay(componentContext);
207 provider.activate(componentContext);
208 }
209
210 // To check if deviceCfgValue is empty or null
211 @Test
212 public void testActiveWithcomponentContextIsNull() {
213
214 ComponentContext componentContext = EasyMock
215 .createMock(ComponentContext.class);
216 getDictionaryMockWithoutValues(componentContext);
217 replay(componentContext);
218 provider.activate(componentContext);
219 }
220
221 // To check deviceEntry and device is null
222 @Test
223 public void testActiveWithDeviceEntryIsNull() {
224
225 ComponentContext componentContext = EasyMock
226 .createMock(ComponentContext.class);
227 getDictionaryMockWithDeviceEntryNull(componentContext);
228 replay(componentContext);
229 provider.activate(componentContext);
230 }
231
232 @Test
233 public void testActiveWithDeviceEntryWithoutUsernameAndPassword() {
234
235 ComponentContext componentContext = EasyMock
236 .createMock(ComponentContext.class);
237 getDictionaryMockWithoutUsernameAndPassword(componentContext);
238 replay(componentContext);
239 provider.activate(componentContext);
240 }
241
242 @Test
243 public void testActiveWithDeviceEntryWithNumberFomatEx() {
244
245 ComponentContext componentContext = EasyMock
246 .createMock(ComponentContext.class);
247 getDictionaryMockDeviceEntryNumberFomatEx(componentContext);
248 replay(componentContext);
249 provider.activate(componentContext);
250 }
251
252 @Test
253 public void testActiveWithDeviceEntryWithDifferentDeviceState() {
254
255 ComponentContext componentContext = EasyMock
256 .createMock(ComponentContext.class);
257 getDictionaryMockWithDifferentDeviceState(componentContext);
258 replay(componentContext);
259 provider.activate(componentContext);
260 }
261
262 @Test
263 public void testActiveWithDeviceEntryWithArrayOutOFBoundEx() {
264
265 ComponentContext componentContext = EasyMock
266 .createMock(ComponentContext.class);
267 getDictionaryMockDeviceWithArrayOutOFBoundEx(componentContext);
268 replay(componentContext);
269 provider.activate(componentContext);
270 }
271
272 @Test
273 public void isReachableWithInvalidDeviceId() {
274 assertFalse("Initially the Device ID Should not be reachable",
275 provider.isReachable(DID1));
276 NetconfDevice device = new NetconfDevice("", 0, "", "");
277 provider.netconfDeviceMap.put(DID1, device);
278 assertFalse("Particular Device ID cannot be Reachable",
279 provider.isReachable(DID1));
280 }
281
282 @Test
283 public void testDeactivate() {
284
285 ComponentContext componentContext = EasyMock
286 .createMock(ComponentContext.class);
287 getDictionaryMockDeviceEntryForDeactivate(componentContext);
288 replay(componentContext);
289 testActiveWithComponentContext();
290 provider.deactivate(componentContext);
291 }
292
293 private class TestDeviceCreator {
294
295 private NetconfDevice device;
296 private boolean createFlag;
297
298 public TestDeviceCreator(NetconfDevice device, boolean createFlag) {
299 this.device = device;
300 this.createFlag = createFlag;
301 }
302
303 public void run() throws JNCException, IOException {
304 if (createFlag) {
305 log.info("Trying to create Device Info on ONOS core");
306 advertiseDevices();
307 } else {
308 log.info("Trying to remove Device Info on ONOS core");
309 removeDevices();
310 }
311 }
312
313 /**
314 * For each Netconf Device, remove the entry from the device store.
315 * @throws URISyntaxException
316 */
317 private void removeDevices() {
318 if (device == null) {
319 log.warn("The Request Netconf Device is null, cannot proceed further");
320 return;
321 }
322 try {
323 DeviceId did = getDeviceId();
324 if (!netconfDeviceMap.containsKey(did)) {
325 log.error("BAD Request: 'Currently device is not discovered, "
326 + "so cannot remove/disconnect the device: "
327 + device.deviceInfo() + "'");
328 return;
329 }
330 providerService.deviceDisconnected(did);
331 device.disconnect();
332 netconfDeviceMap.remove(did);
333 delay(EVENTINTERVAL);
334 } catch (URISyntaxException uriSyntaxExcpetion) {
335 log.error("Syntax Error while creating URI for the device: "
336 + device.deviceInfo()
337 + " couldn't remove the device from the store",
338 uriSyntaxExcpetion);
339 }
340 }
341
342 /**
343 * Initialize Netconf Device object, and notify core saying device
344 * connected.
345 */
Sanjay S59f86fd2015-05-20 12:23:48 +0530346 private void advertiseDevices()
347 throws JNCException, IOException, SocketTimeoutException {
Sanjay S0d4093f2015-05-06 14:55:04 +0530348 try {
349 if (device == null) {
350 log.warn("The Request Netconf Device is null, cannot proceed further");
351 return;
352 }
353 device.init();
354 DeviceId did = getDeviceId();
355 ChassisId cid = new ChassisId();
356 DeviceDescription desc = new DefaultDeviceDescription(
357 did.uri(),
358 Device.Type.OTHER,
359 "", "",
360 "", "",
361 cid);
362 log.info("Persisting Device" + did.uri().toString());
363
364 netconfDeviceMap.put(did, device);
365 providerService.deviceConnected(did, desc);
366 log.info("Done with Device Info Creation on ONOS core. Device Info: "
367 + device.deviceInfo() + " " + did.uri().toString());
368 delay(EVENTINTERVAL);
369 } catch (URISyntaxException e) {
370 log.error("Syntax Error while creating URI for the device: "
371 + device.deviceInfo()
372 + " couldn't persist the device onto the store", e);
373 } catch (JNCException e) {
374 throw e;
Sanjay S59f86fd2015-05-20 12:23:48 +0530375 } catch (SocketTimeoutException e) {
376 throw e;
Sanjay S0d4093f2015-05-06 14:55:04 +0530377 } catch (IOException e) {
378 throw e;
379 } catch (Exception e) {
380 log.error("Error while initializing session for the device: "
Damian ONeill1937bbb2015-07-08 17:03:19 +0100381 + (device != null ? device.deviceInfo() : null), e);
Sanjay S0d4093f2015-05-06 14:55:04 +0530382 }
383 }
384
385 private DeviceId getDeviceId() throws URISyntaxException {
386 String additionalSSP = new StringBuilder(device.getUsername())
387 .append("@").append(device.getSshHost()).append(":")
388 .append(device.getSshPort()).toString();
389 DeviceId did = DeviceId.deviceId(new URI(SCHEME, additionalSSP,
390 null));
391 return did;
392 }
393 }
394
395 private class TestDeviceRegistry implements DeviceProviderRegistry {
396
397 @Override
398 public DeviceProviderService register(DeviceProvider provider) {
399 return new TestProviderService();
400 }
401
402 @Override
403 public void unregister(DeviceProvider provider) {
404 }
405
406 @Override
407 public Set<ProviderId> getProviders() {
408 return null;
409 }
410
411 private class TestProviderService implements DeviceProviderService {
412
HIGUCHI Yutaea39db52015-06-12 12:02:38 -0700413 @Override
Sanjay S0d4093f2015-05-06 14:55:04 +0530414 public DeviceProvider provider() {
415 return null;
416 }
417
HIGUCHI Yutaea39db52015-06-12 12:02:38 -0700418 @Override
Sanjay S0d4093f2015-05-06 14:55:04 +0530419 public void deviceConnected(DeviceId deviceId,
420 DeviceDescription deviceDescription) {
421 }
422
HIGUCHI Yutaea39db52015-06-12 12:02:38 -0700423 @Override
Sanjay S0d4093f2015-05-06 14:55:04 +0530424 public void deviceDisconnected(DeviceId deviceId) {
425
426 }
427
HIGUCHI Yutaea39db52015-06-12 12:02:38 -0700428 @Override
Sanjay S0d4093f2015-05-06 14:55:04 +0530429 public void updatePorts(DeviceId deviceId,
430 List<PortDescription> portDescriptions) {
431
432 }
433
HIGUCHI Yutaea39db52015-06-12 12:02:38 -0700434 @Override
Sanjay S0d4093f2015-05-06 14:55:04 +0530435 public void portStatusChanged(DeviceId deviceId,
436 PortDescription portDescription) {
437
438 }
439
HIGUCHI Yutaea39db52015-06-12 12:02:38 -0700440 @Override
Sanjay S0d4093f2015-05-06 14:55:04 +0530441 public void receivedRoleReply(DeviceId deviceId,
442 MastershipRole requested,
443 MastershipRole response) {
444
445 }
446
HIGUCHI Yutaea39db52015-06-12 12:02:38 -0700447 @Override
Sanjay S0d4093f2015-05-06 14:55:04 +0530448 public void updatePortStatistics(DeviceId deviceId,
449 Collection<PortStatistics> portStatistics) {
450
451 }
452 }
453 }
454}