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