| /* |
| * Copyright 2015 Open Networking Laboratory |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.onosproject.provider.netconf.device.impl; |
| |
| import static org.easymock.EasyMock.expect; |
| import static org.easymock.EasyMock.replay; |
| import static org.junit.Assert.assertFalse; |
| import static org.onlab.util.Tools.delay; |
| import static org.slf4j.LoggerFactory.getLogger; |
| |
| import java.io.IOException; |
| import java.net.SocketTimeoutException; |
| import java.net.URI; |
| import java.net.URISyntaxException; |
| import java.util.Collection; |
| import java.util.Dictionary; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.concurrent.ConcurrentHashMap; |
| |
| import org.easymock.EasyMock; |
| import org.junit.After; |
| import org.junit.Before; |
| import org.junit.Ignore; |
| import org.junit.Test; |
| import org.onlab.packet.ChassisId; |
| import org.onosproject.cfg.ComponentConfigService; |
| import org.onosproject.net.Device; |
| import org.onosproject.net.DeviceId; |
| import org.onosproject.net.MastershipRole; |
| import org.onosproject.net.device.DefaultDeviceDescription; |
| import org.onosproject.net.device.DeviceDescription; |
| import org.onosproject.net.device.DeviceProvider; |
| import org.onosproject.net.device.DeviceProviderRegistry; |
| import org.onosproject.net.device.DeviceProviderService; |
| import org.onosproject.net.device.PortDescription; |
| import org.onosproject.net.device.PortStatistics; |
| import org.onosproject.net.provider.ProviderId; |
| import org.osgi.service.component.ComponentContext; |
| import org.slf4j.Logger; |
| |
| import com.tailf.jnc.JNCException; |
| |
| /** |
| * Test Case to Validate Netconf Device Provider. |
| * |
| */ |
| public class NetconfDeviceProviderTest { |
| // private NetconfDevice device; |
| |
| TestDeviceCreator create; |
| |
| private final Logger log = getLogger(NetconfDeviceProviderTest.class); |
| |
| private Map<DeviceId, NetconfDevice> netconfDeviceMap = new ConcurrentHashMap<DeviceId, NetconfDevice>(); |
| |
| private DeviceProviderService providerService; |
| |
| private static final int EVENTINTERVAL = 5; |
| |
| private static final String SCHEME = "netconf"; |
| |
| private static final DeviceId DID1 = DeviceId |
| .deviceId("of:0000000000000001"); |
| |
| private final NetconfDeviceProvider provider = new NetconfDeviceProvider(); |
| private final TestDeviceRegistry registry = new TestDeviceRegistry(); |
| |
| private ComponentConfigService mockCfgService; |
| |
| @Before |
| public void setUp() { |
| mockCfgService = EasyMock.createMock(ComponentConfigService.class); |
| provider.cfgService = mockCfgService; |
| provider.providerRegistry = registry; |
| } |
| |
| @SuppressWarnings("unchecked") |
| private Dictionary<String, String> getDictionaryMock(ComponentContext componentContext) { |
| Dictionary<String, String> dictionary = EasyMock |
| .createMock(Dictionary.class); |
| expect(dictionary.get("devConfigs")) |
| .andReturn("cisco:cisco@10.18.11.14:22:active," |
| + "sanjay:b33rb3lly@10.18.24.122:2022:inactive"); |
| replay(dictionary); |
| expect(componentContext.getProperties()).andReturn(dictionary); |
| return dictionary; |
| } |
| |
| @SuppressWarnings("unchecked") |
| private Dictionary<String, String> getDictionaryMockWithoutValues(ComponentContext componentContext) { |
| Dictionary<String, String> dictionary = EasyMock |
| .createMock(Dictionary.class); |
| expect(dictionary.get("devConfigs")).andReturn(""); |
| replay(dictionary); |
| expect(componentContext.getProperties()).andReturn(dictionary); |
| return dictionary; |
| } |
| |
| @SuppressWarnings("unchecked") |
| private Dictionary<String, String> getDictionaryMockWithDeviceEntryNull(ComponentContext componentContext) { |
| Dictionary<String, String> dictionary = EasyMock |
| .createMock(Dictionary.class); |
| expect(dictionary.get("devConfigs")).andReturn("null,null"); |
| replay(dictionary); |
| expect(componentContext.getProperties()).andReturn(dictionary); |
| return dictionary; |
| } |
| |
| @SuppressWarnings("unchecked") |
| private Dictionary<String, String> getDictionaryMockDeviceEntryNumberFomatEx(ComponentContext componentContext) { |
| Dictionary<String, String> dictionary = EasyMock |
| .createMock(Dictionary.class); |
| expect(dictionary.get("devConfigs")) |
| .andReturn("cisco:cisco@10.18.11.14:cisco:active") |
| .andThrow(new NumberFormatException()); |
| replay(dictionary); |
| expect(componentContext.getProperties()).andReturn(dictionary); |
| return dictionary; |
| } |
| |
| @SuppressWarnings("unchecked") |
| private Dictionary<String, String> getDictionaryMockWithoutUsernameAndPassword(ComponentContext componentContext) { |
| Dictionary<String, String> dictionary = EasyMock |
| .createMock(Dictionary.class); |
| expect(dictionary.get("devConfigs")) |
| .andReturn("null:null@null:0:active"); |
| replay(dictionary); |
| expect(componentContext.getProperties()).andReturn(dictionary); |
| return dictionary; |
| } |
| |
| @SuppressWarnings("unchecked") |
| private Dictionary<String, String> getDictionaryMockWithDifferentDeviceState(ComponentContext componentContext) { |
| Dictionary<String, String> dictionary = EasyMock |
| .createMock(Dictionary.class); |
| expect(dictionary.get("devConfigs")) |
| .andReturn("cisco:cisco@10.18.11.14:22:active,cisco:cisco@10.18.11.18:22:inactive," |
| + "cisco:cisco@10.18.11.14:22:invalid,cisco:cisco@10.18.11.14:22:null"); |
| replay(dictionary); |
| expect(componentContext.getProperties()).andReturn(dictionary); |
| return dictionary; |
| } |
| |
| @SuppressWarnings("unchecked") |
| private Dictionary<String, String> getDictionaryMockDeviceWithArrayOutOFBoundEx(ComponentContext componentContext) { |
| Dictionary<String, String> dictionary = EasyMock |
| .createMock(Dictionary.class); |
| expect(dictionary.get("devConfigs")) |
| .andReturn("@10.18.11.14:22:active") |
| .andThrow(new ArrayIndexOutOfBoundsException()); |
| replay(dictionary); |
| expect(componentContext.getProperties()).andReturn(dictionary); |
| return dictionary; |
| } |
| |
| @SuppressWarnings("unchecked") |
| private Dictionary<String, String> getDictionaryMockDeviceEntryForDeactivate(ComponentContext componentContext) { |
| Dictionary<String, String> dictionary = EasyMock |
| .createMock(Dictionary.class); |
| expect(dictionary.get("devConfigs")) |
| .andReturn("netconf:cisco@10.18.11.14:22:active") |
| .andThrow(new ArrayIndexOutOfBoundsException()); |
| replay(dictionary); |
| expect(componentContext.getProperties()).andReturn(dictionary); |
| return dictionary; |
| } |
| |
| @Ignore("Test fails if the hard coded host actually exists.") |
| @Test(expected = SocketTimeoutException.class) |
| public void testSSHAuthentication() throws JNCException, IOException { |
| NetconfDevice netconfDevice = new NetconfDevice("10.18.14.19", 22, |
| "cisco", "cisco"); |
| netconfDevice.setConnectTimeout(1000); |
| TestDeviceCreator objForTestDev = new TestDeviceCreator(netconfDevice, |
| true); |
| objForTestDev.run(); |
| } |
| |
| @After |
| public void tearDown() { |
| provider.providerRegistry = null; |
| provider.cfgService = null; |
| } |
| |
| @Test |
| public void testActiveWithComponentContext() { |
| |
| ComponentContext componentContext = EasyMock |
| .createMock(ComponentContext.class); |
| getDictionaryMock(componentContext); |
| replay(componentContext); |
| provider.activate(componentContext); |
| } |
| |
| // To check if deviceCfgValue is empty or null |
| @Test |
| public void testActiveWithcomponentContextIsNull() { |
| |
| ComponentContext componentContext = EasyMock |
| .createMock(ComponentContext.class); |
| getDictionaryMockWithoutValues(componentContext); |
| replay(componentContext); |
| provider.activate(componentContext); |
| } |
| |
| // To check deviceEntry and device is null |
| @Test |
| public void testActiveWithDeviceEntryIsNull() { |
| |
| ComponentContext componentContext = EasyMock |
| .createMock(ComponentContext.class); |
| getDictionaryMockWithDeviceEntryNull(componentContext); |
| replay(componentContext); |
| provider.activate(componentContext); |
| } |
| |
| @Test |
| public void testActiveWithDeviceEntryWithoutUsernameAndPassword() { |
| |
| ComponentContext componentContext = EasyMock |
| .createMock(ComponentContext.class); |
| getDictionaryMockWithoutUsernameAndPassword(componentContext); |
| replay(componentContext); |
| provider.activate(componentContext); |
| } |
| |
| @Test |
| public void testActiveWithDeviceEntryWithNumberFomatEx() { |
| |
| ComponentContext componentContext = EasyMock |
| .createMock(ComponentContext.class); |
| getDictionaryMockDeviceEntryNumberFomatEx(componentContext); |
| replay(componentContext); |
| provider.activate(componentContext); |
| } |
| |
| @Test |
| public void testActiveWithDeviceEntryWithDifferentDeviceState() { |
| |
| ComponentContext componentContext = EasyMock |
| .createMock(ComponentContext.class); |
| getDictionaryMockWithDifferentDeviceState(componentContext); |
| replay(componentContext); |
| provider.activate(componentContext); |
| } |
| |
| @Test |
| public void testActiveWithDeviceEntryWithArrayOutOFBoundEx() { |
| |
| ComponentContext componentContext = EasyMock |
| .createMock(ComponentContext.class); |
| getDictionaryMockDeviceWithArrayOutOFBoundEx(componentContext); |
| replay(componentContext); |
| provider.activate(componentContext); |
| } |
| |
| @Test |
| public void isReachableWithInvalidDeviceId() { |
| assertFalse("Initially the Device ID Should not be reachable", |
| provider.isReachable(DID1)); |
| NetconfDevice device = new NetconfDevice("", 0, "", ""); |
| provider.netconfDeviceMap.put(DID1, device); |
| assertFalse("Particular Device ID cannot be Reachable", |
| provider.isReachable(DID1)); |
| } |
| |
| @Test |
| public void testDeactivate() { |
| |
| ComponentContext componentContext = EasyMock |
| .createMock(ComponentContext.class); |
| getDictionaryMockDeviceEntryForDeactivate(componentContext); |
| replay(componentContext); |
| testActiveWithComponentContext(); |
| provider.deactivate(componentContext); |
| } |
| |
| private class TestDeviceCreator { |
| |
| private NetconfDevice device; |
| private boolean createFlag; |
| |
| public TestDeviceCreator(NetconfDevice device, boolean createFlag) { |
| this.device = device; |
| this.createFlag = createFlag; |
| } |
| |
| public void run() throws JNCException, IOException { |
| if (createFlag) { |
| log.info("Trying to create Device Info on ONOS core"); |
| advertiseDevices(); |
| } else { |
| log.info("Trying to remove Device Info on ONOS core"); |
| removeDevices(); |
| } |
| } |
| |
| /** |
| * For each Netconf Device, remove the entry from the device store. |
| * @throws URISyntaxException |
| */ |
| private void removeDevices() { |
| if (device == null) { |
| log.warn("The Request Netconf Device is null, cannot proceed further"); |
| return; |
| } |
| try { |
| DeviceId did = getDeviceId(); |
| if (!netconfDeviceMap.containsKey(did)) { |
| log.error("BAD Request: 'Currently device is not discovered, " |
| + "so cannot remove/disconnect the device: " |
| + device.deviceInfo() + "'"); |
| return; |
| } |
| providerService.deviceDisconnected(did); |
| device.disconnect(); |
| netconfDeviceMap.remove(did); |
| delay(EVENTINTERVAL); |
| } catch (URISyntaxException uriSyntaxExcpetion) { |
| log.error("Syntax Error while creating URI for the device: " |
| + device.deviceInfo() |
| + " couldn't remove the device from the store", |
| uriSyntaxExcpetion); |
| } |
| } |
| |
| /** |
| * Initialize Netconf Device object, and notify core saying device |
| * connected. |
| */ |
| private void advertiseDevices() |
| throws JNCException, IOException, SocketTimeoutException { |
| try { |
| if (device == null) { |
| log.warn("The Request Netconf Device is null, cannot proceed further"); |
| return; |
| } |
| device.init(); |
| DeviceId did = getDeviceId(); |
| ChassisId cid = new ChassisId(); |
| DeviceDescription desc = new DefaultDeviceDescription( |
| did.uri(), |
| Device.Type.OTHER, |
| "", "", |
| "", "", |
| cid); |
| log.info("Persisting Device" + did.uri().toString()); |
| |
| netconfDeviceMap.put(did, device); |
| providerService.deviceConnected(did, desc); |
| log.info("Done with Device Info Creation on ONOS core. Device Info: " |
| + device.deviceInfo() + " " + did.uri().toString()); |
| delay(EVENTINTERVAL); |
| } catch (URISyntaxException e) { |
| log.error("Syntax Error while creating URI for the device: " |
| + device.deviceInfo() |
| + " couldn't persist the device onto the store", e); |
| } catch (JNCException e) { |
| throw e; |
| } catch (SocketTimeoutException e) { |
| throw e; |
| } catch (IOException e) { |
| throw e; |
| } catch (Exception e) { |
| log.error("Error while initializing session for the device: " |
| + (device != null ? device.deviceInfo() : null), e); |
| } |
| } |
| |
| private DeviceId getDeviceId() throws URISyntaxException { |
| String additionalSSP = new StringBuilder(device.getUsername()) |
| .append("@").append(device.getSshHost()).append(":") |
| .append(device.getSshPort()).toString(); |
| DeviceId did = DeviceId.deviceId(new URI(SCHEME, additionalSSP, |
| null)); |
| return did; |
| } |
| } |
| |
| private class TestDeviceRegistry implements DeviceProviderRegistry { |
| |
| @Override |
| public DeviceProviderService register(DeviceProvider provider) { |
| return new TestProviderService(); |
| } |
| |
| @Override |
| public void unregister(DeviceProvider provider) { |
| } |
| |
| @Override |
| public Set<ProviderId> getProviders() { |
| return null; |
| } |
| |
| private class TestProviderService implements DeviceProviderService { |
| |
| @Override |
| public DeviceProvider provider() { |
| return null; |
| } |
| |
| @Override |
| public void deviceConnected(DeviceId deviceId, |
| DeviceDescription deviceDescription) { |
| } |
| |
| @Override |
| public void deviceDisconnected(DeviceId deviceId) { |
| |
| } |
| |
| @Override |
| public void updatePorts(DeviceId deviceId, |
| List<PortDescription> portDescriptions) { |
| |
| } |
| |
| @Override |
| public void portStatusChanged(DeviceId deviceId, |
| PortDescription portDescription) { |
| |
| } |
| |
| @Override |
| public void receivedRoleReply(DeviceId deviceId, |
| MastershipRole requested, |
| MastershipRole response) { |
| |
| } |
| |
| @Override |
| public void updatePortStatistics(DeviceId deviceId, |
| Collection<PortStatistics> portStatistics) { |
| |
| } |
| } |
| } |
| } |