/** * Copyright (c) Codice Foundation * <p> * This is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, either version 3 of the * License, or any later version. * <p> * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. A copy of the GNU Lesser General Public License * is distributed along with this program and can be found at * <http://www.gnu.org/licenses/lgpl.html>. */ package org.codice.ddf.ui.admin.api; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.nullValue; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyString; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.io.IOException; import java.util.ArrayList; import java.util.Dictionary; import java.util.HashMap; import java.util.Hashtable; import java.util.List; import java.util.Map; import org.codice.ddf.ui.admin.api.plugin.ConfigurationAdminPlugin; import org.junit.Before; import org.junit.Test; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.Constants; import org.osgi.framework.Filter; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.ServiceReference; import org.osgi.service.cm.Configuration; import org.osgi.service.cm.ConfigurationAdmin; import org.osgi.service.cm.ManagedService; import org.osgi.service.cm.ManagedServiceFactory; import org.osgi.service.metatype.AttributeDefinition; import org.osgi.service.metatype.MetaTypeInformation; import org.osgi.service.metatype.MetaTypeService; import org.osgi.service.metatype.ObjectClassDefinition; public class ConfigurationAdminExtTest { final BundleContext testBundleContext = mock(BundleContext.class); final MetaTypeService testMTS = mock(MetaTypeService.class); private ConfigurationAdmin testConfigAdmin; private ConfigurationAdminExt configurationAdminExt; private static final String LIST_CONFIG_STRING = "(|(service.factoryPid=TestPID)(service.factoryPid=TestPID_disabled))"; private static final String TEST_PID = "TestPID"; private static final String BAD_PID = ">TestPID<"; private static final String TEST_FACT_FILTER = "TestFactoryFilter"; private static final String TEST_FILTER = "TestFilter"; private static final String TEST_BUNDLE_LOC = "TestBundleLocation"; private static final String TEST_OCD = "TestOCD"; private static final String TEST_BUNDLE_NAME = "TestBundle"; private static final String TEST_FACTORY_PID = "TestFactPID"; private static final String TEST_KEY = "TestKey"; private static final String TEST_VALUE = "TestValue"; private Configuration testConfig; private Bundle testBundle; private Dictionary<String, String> bundleHeaders; private MetaTypeInformation testMTI; private ObjectClassDefinition testOCD; private AttributeDefinition testAttDef; private ServiceReference testRef1; @Before public void setUpBasic() { testConfigAdmin = mock(ConfigurationAdmin.class); configurationAdminExt = new ConfigurationAdminExt(testConfigAdmin) { @Override BundleContext getBundleContext() { return testBundleContext; } @Override MetaTypeService getMetaTypeService() { return testMTS; } @Override public boolean isPermittedToViewService(String servicePid) { return true; } }; } public void setUpTestConfig() { Dictionary<String, Object> testProp = new Hashtable<>(); testProp.put(TEST_KEY, TEST_VALUE); testConfig = mock(Configuration.class); when(testConfig.getPid()).thenReturn(TEST_PID); when(testConfig.getFactoryPid()).thenReturn(TEST_FACTORY_PID); when(testConfig.getBundleLocation()).thenReturn(TEST_BUNDLE_LOC); when(testConfig.getProperties()).thenReturn(testProp); } public void setUpListServices() throws Exception { testBundle = mock(Bundle.class); bundleHeaders = mock(Dictionary.class); testMTI = mock(MetaTypeInformation.class); testOCD = mock(ObjectClassDefinition.class); testAttDef = mock(AttributeDefinition.class); testRef1 = mock(ServiceReference.class); ServiceReference[] testServRefs = {testRef1}; when(testRef1.getProperty(Constants.SERVICE_PID)).thenReturn(TEST_PID); when(testRef1.getBundle()).thenReturn(testBundle); when(testBundle.getLocation()).thenReturn(TEST_BUNDLE_LOC); when(testBundle.getHeaders(anyString())).thenReturn(bundleHeaders); when(bundleHeaders.get(Constants.BUNDLE_NAME)).thenReturn(TEST_BUNDLE_NAME); when(testOCD.getName()).thenReturn(TEST_OCD); when(testOCD.getAttributeDefinitions(ObjectClassDefinition.ALL)).thenReturn(new AttributeDefinition[] { testAttDef}); when(testMTI.getBundle()).thenReturn(testBundle); when(testMTI.getFactoryPids()).thenReturn(new String[] {TEST_FACTORY_PID}); when(testMTI.getPids()).thenReturn(new String[] {TEST_PID}); when(testMTI.getObjectClassDefinition(anyString(), anyString())).thenReturn(testOCD); when(testMTS.getMetaTypeInformation(testBundle)).thenReturn(testMTI); when(testBundleContext.getBundles()).thenReturn(new Bundle[] {testBundle}); when(testConfigAdmin.listConfigurations(anyString())).thenReturn(new Configuration[] { testConfig}); when(testBundleContext.getAllServiceReferences(ManagedService.class.getName(), TEST_FILTER)).thenReturn(testServRefs); when(testBundleContext.getAllServiceReferences(ManagedServiceFactory.class.getName(), TEST_FILTER)).thenReturn(testServRefs); } /** * Tests the {@link ConfigurationAdminExt#getConfiguration(String)} method * * @throws Exception */ @Test public void testGetConfiguration() throws Exception { Configuration testConfig = mock(Configuration.class); Configuration[] configurations = new Configuration[] {testConfig}; when(testConfigAdmin.listConfigurations( '(' + Constants.SERVICE_PID + '=' + TEST_PID + ')')).thenReturn(configurations); assertNotNull(configurationAdminExt.getConfiguration(TEST_PID)); } /** * Tests the {@link ConfigurationAdminExt#listServices(String, String)} method for the case * where there is a filter returned by the bundleContext * * @throws Exception */ @Test public void testListServicesExistingFilter() throws Exception { setUpTestConfig(); setUpListServices(); Filter testFilter = mock(Filter.class); List<ConfigurationAdminPlugin> testPluginList = new ArrayList<>(); ConfigurationAdminPlugin testPlugin = mock(ConfigurationAdminPlugin.class); testPluginList.add(testPlugin); Map<String, Object> testConfigData = new HashMap<>(); testConfigData.put(TEST_KEY, TEST_VALUE); when(testPlugin.getConfigurationData(anyString(), any(Map.class), any(BundleContext.class))).thenReturn(testConfigData); when(testFilter.match(any(Hashtable.class))).thenReturn(true); when(testBundleContext.createFilter(anyString())).thenReturn(testFilter); configurationAdminExt.setConfigurationAdminPluginList(testPluginList); List<Map<String, Object>> result = configurationAdminExt.listServices(TEST_FACT_FILTER, TEST_FILTER); assertThat("Should return the correct services.", (String) result.get(0) .get("id"), is(TEST_PID)); verify(testConfigAdmin, atLeastOnce()).listConfigurations(LIST_CONFIG_STRING); } /** * Tests the {@link ConfigurationAdminExt#listServices(String, String)} and connected methods * for the case where the Configuration's bundle location can not be found * * @throws Exception */ @Test public void testListServicesNoBundleLocation() throws Exception { setUpTestConfig(); setUpListServices(); when(testConfig.getBundleLocation()).thenReturn(null); List<Map<String, Object>> result = configurationAdminExt.listServices(TEST_FACT_FILTER, TEST_FILTER); assertThat("Should return the correct services.", (String) result.get(0) .get("id"), is(TEST_PID)); verify(testConfigAdmin, atLeastOnce()).listConfigurations(LIST_CONFIG_STRING); } /** * Tests the {@link ConfigurationAdminExt#listServices(String, String)} and connected methods * for the case where the Configuration's bundle location and factoryPid both can not be found * * @throws Exception */ @Test public void testListServicesNoBundleLocationOrFactoryPID() throws Exception { setUpTestConfig(); setUpListServices(); when(testConfig.getBundleLocation()).thenReturn(null); when(testConfig.getFactoryPid()).thenReturn(null); List<Map<String, Object>> result = configurationAdminExt.listServices(TEST_FACT_FILTER, TEST_FILTER); assertThat("Should return the correct services.", (String) result.get(0) .get("id"), is(TEST_PID)); verify(testConfigAdmin, atLeastOnce()).listConfigurations(LIST_CONFIG_STRING); } /** * Tests the {@link ConfigurationAdminExt#listServices(String, String)} and connected methods * for the case where the Configuration's factoryPid can not be found * * @throws Exception */ @Test public void testListServicesNoFactoryPID() throws Exception { setUpTestConfig(); setUpListServices(); when(testConfig.getFactoryPid()).thenReturn(null); List<Map<String, Object>> result = configurationAdminExt.listServices(TEST_FACT_FILTER, TEST_FILTER); assertThat("Should return the correct services.", (String) result.get(0) .get("id"), is(TEST_PID)); verify(testConfigAdmin, atLeastOnce()).listConfigurations(LIST_CONFIG_STRING); } /** * Tests the {@link ConfigurationAdminExt#listServices(String, String)} and connected methods * for the case where the Configuration's Pid is null * * @throws Exception */ @Test public void testListServicesNoPID() throws Exception { setUpTestConfig(); setUpListServices(); when(testConfig.getPid()).thenReturn(null); List<Map<String, Object>> result = configurationAdminExt.listServices(TEST_FACT_FILTER, TEST_FILTER); assertThat("Should return the correct services.", (String) result.get(0) .get("id"), is(TEST_PID)); verify(testConfigAdmin, atLeastOnce()).listConfigurations(LIST_CONFIG_STRING); } /** * Tests the {@link ConfigurationAdminExt#listServices(String, String)} method * and all associated methods for the case where there is no bundle name * * @throws Exception */ @Test public void testListServicesNoName() throws Exception { setUpTestConfig(); setUpListServices(); when(bundleHeaders.get(Constants.BUNDLE_NAME)).thenReturn(null); List<Map<String, Object>> result = configurationAdminExt.listServices(TEST_FACT_FILTER, TEST_FILTER); assertThat("Should return the correct services.", (String) result.get(0) .get("id"), is(TEST_PID)); } /** * Tests the {@link ConfigurationAdminExt#listServices(String, String)} method and connected * methods for the case where the Configuration contains a password property and that its value * is properly changed to "password". * * @throws Exception */ @Test public void testListServicesPasswordType() throws Exception { setUpTestConfig(); setUpListServices(); // Create a password property with a value of "secret". Dictionary<String, Object> testProp = new Hashtable<>(); testProp.put("password", "secret"); when(testAttDef.getID()).thenReturn("password"); when(testAttDef.getType()).thenReturn(AttributeDefinition.PASSWORD); when(testConfig.getProperties()).thenReturn(testProp); List<Map<String, Object>> result = configurationAdminExt.listServices(TEST_FACT_FILTER, TEST_FILTER); // Assert that the password value was changed from "secret" to "password". String password = (String) ((Map<String, Object>) ((List<Map<String, Object>>) result.get(0) .get("configurations")).get(0) .get("properties")).get("password"); assertThat(password, is(equalTo("password"))); } /** * Tests the {@link ConfigurationAdminExt#listServices(String, String)} method * and all associated methods for the case where the isAllowedPid returns false * * @throws Exception */ @Test public void testListServicesNotAllowedPid() throws Exception { setUpTestConfig(); setUpListServices(); when(testRef1.getProperty(Constants.SERVICE_PID)).thenReturn(BAD_PID); List<Map<String, Object>> result = configurationAdminExt.listServices(TEST_FACT_FILTER, TEST_FILTER); assertTrue("Should not return any services.", result.isEmpty()); } /** * Tests the {@link ConfigurationAdminExt#listServices(String, String)} method * for the case where configurationAdmin.listConfigurations(....) throws an IOException * * @throws Exception */ @Test public void testListServicesIOException() throws Exception { setUpListServices(); setUpTestConfig(); doThrow(new IOException()).when(testConfigAdmin) .listConfigurations(anyString()); List<Map<String, Object>> result = configurationAdminExt. listServices(TEST_FACT_FILTER, TEST_FILTER); assertThat("Should recover gracefully but not add to the given data.", (String) result.get(0) .get("name"), is(TEST_OCD)); assertThat("Should only contain one map.", result.size(), is(1)); } /** * Tests the {@link ConfigurationAdminExt#listServices(String, String)} method * for the case where configurationAdmin.listConfigurations(....) throws an InvalidSyntaxException * * @throws Exception */ @Test public void testListServicesInvalidSyntaxException() throws Exception { setUpListServices(); setUpTestConfig(); doThrow(new InvalidSyntaxException("", "")).when(testConfigAdmin) .listConfigurations(anyString()); List<Map<String, Object>> result = configurationAdminExt. listServices(TEST_FACT_FILTER, TEST_FILTER); assertThat("Should recover gracefully but not add to the given data.", (String) result.get(0) .get("name"), is(TEST_OCD)); assertThat("Should only contain one map.", result.size(), is(1)); } /** * Tests the {@link ConfigurationAdminExt#listServices(String, String)} method * for the case where bundle.getHeaders(..).get(Constants.BUNDLE_NAME) returns null, * bundle.getSymbolicName() returns null, and bundle.getLocation returns null. * * @throws Exception */ @Test public void testListServicesNullLocationSymNameBundleName() throws Exception { setUpTestConfig(); setUpListServices(); when(testBundle.getLocation()).thenReturn(TEST_BUNDLE_LOC) .thenReturn(TEST_BUNDLE_LOC) .thenReturn(null) .thenReturn(TEST_BUNDLE_LOC); when(testBundle.getSymbolicName()).thenReturn(null); when(bundleHeaders.get(Constants.BUNDLE_NAME)).thenReturn(null); List<Map<String, Object>> result = configurationAdminExt.listServices(TEST_FACT_FILTER, TEST_FILTER); assertThat("Should return the correct services.", (String) result.get(0) .get("id"), is(TEST_PID)); } /** * Tests the {@link ConfigurationAdminExt#getConfiguration(String)} method * for the case where configurationAdmin.listConfigurations(..) throws an InvalidSyntaxException * * @throws Exception */ @Test public void testGetConfigurationInvalidSyntaxException() throws Exception { doThrow(new InvalidSyntaxException("", "")).when(testConfigAdmin) .listConfigurations(anyString()); Configuration result = configurationAdminExt.getConfiguration(TEST_PID); assertThat("Should handle the exception gracefully and return null.", result, is(nullValue())); } /** * Tests the {@link ConfigurationAdminExt#getConfiguration(String)} method * for the case where configurationAdmin.listConfigurations(..) throws an IOException * * @throws Exception */ @Test public void testGetConfigurationIOException() throws Exception { doThrow(new IOException()).when(testConfigAdmin) .listConfigurations(anyString()); Configuration result = configurationAdminExt.getConfiguration(TEST_PID); assertThat("Should handle the exception gracefully and return null.", result, is(nullValue())); } /** * Tests the {@link ConfigurationAdminExt#getBundle(BundleContext, String)} method * for the case where the string parameter is null * * @throws Exception */ @Test public void testGetBundleNullStringParam() throws Exception { assertThat("Should return null.", configurationAdminExt.getBundle(testBundleContext, null), is(nullValue())); } /** * Tests the {@link ConfigurationAdminExt#getBundle(BundleContext, String)} method * for the case where the bundleContext has no bundles * * @throws Exception */ @Test public void testGetBundleNoBundles() throws Exception { when(testBundleContext.getBundles()).thenReturn(new Bundle[] {}); assertThat("Should return null.", configurationAdminExt.getBundle(testBundleContext, TEST_BUNDLE_LOC), is(nullValue())); } }