/*
* RHQ Management Platform
* Copyright (C) 2005-2014 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation version 2 of the License.
*
* 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
package org.rhq.core.pc.configuration;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;
import java.util.Set;
import java.util.concurrent.ScheduledExecutorService;
import org.hamcrest.Matcher;
import org.jmock.Expectations;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import org.rhq.core.clientapi.agent.PluginContainerException;
import org.rhq.core.clientapi.agent.configuration.ConfigurationUpdateRequest;
import org.rhq.core.clientapi.server.configuration.ConfigurationServerService;
import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.domain.configuration.PropertySimple;
import org.rhq.core.domain.configuration.RawConfiguration;
import org.rhq.core.domain.resource.ResourceType;
import org.rhq.core.pc.PluginContainerConfiguration;
import org.rhq.core.pc.ServerServices;
import org.rhq.core.pc.util.FacetLockType;
import org.rhq.core.pluginapi.configuration.ResourceConfigurationFacet;
import org.rhq.test.jmock.PropertyMatcher;
public class ConfigurationManagerTest extends ConfigManagementTest {
static final String LEGACY_AMPS_VERSION = "2.0";
static final String NON_LEGACY_AMPS_VERSION = "2.1";
boolean FROM_STRUCTURED = true;
boolean FROM_RAW = false;
ConfigManagementFactory configMgmtFactory;
ConfigurationManager configurationMgr;
@BeforeMethod
public void setup() {
configMgmtFactory = context.mock(ConfigManagementFactory.class);
PluginContainerConfiguration containerConfig = new PluginContainerConfiguration();
configurationMgr = new ConfigurationManager(containerConfig, componentService, configMgmtFactory, null, null);
}
@Test
public void strategyShouldBeCalledToLoadConfig() throws Exception {
final Configuration expectedConfig = new Configuration();
final ConfigManagement loadConfig = context.mock(ConfigManagement.class);
context.checking(new Expectations() {
{
atLeast(1).of(configMgmtFactory).getStrategy(resourceId);
will(returnValue(loadConfig));
atLeast(1).of(loadConfig).executeLoad(resourceId);
will(returnValue(expectedConfig));
}
});
Configuration actualConfig = configurationMgr.loadResourceConfiguration(resourceId);
assertNotNull(actualConfig, "Expected a non-null " + Configuration.class.getSimpleName() + " to be returned.");
}
@Test(expectedExceptions = { PluginContainerException.class })
public void exceptionShouldBeThrownIfConfigIsNull() throws Exception {
final ConfigManagement loadConfig = context.mock(ConfigManagement.class);
context.checking(new Expectations() {
{
atLeast(1).of(configMgmtFactory).getStrategy(resourceId);
will(returnValue(loadConfig));
atLeast(1).of(loadConfig).executeLoad(resourceId);
will(returnValue(null));
allowing(componentService).getResourceType(resourceId);
will(returnValue(new ResourceType()));
}
});
configurationMgr.loadResourceConfiguration(resourceId);
}
@Test(expectedExceptions = { PluginContainerException.class })
public void exceptionShouldBeThrownWhenStrategyThrowsAnException() throws Exception {
final ConfigManagement loadConfig = context.mock(ConfigManagement.class);
context.checking(new Expectations() {
{
allowing(componentService).getResourceType(resourceId);
will(returnValue(resourceType));
atLeast(1).of(configMgmtFactory).getStrategy(resourceId);
will(returnValue(loadConfig));
atLeast(1).of(loadConfig).executeLoad(resourceId);
will(throwException(new RuntimeException()));
}
});
configurationMgr.loadResourceConfiguration(resourceId);
}
@Test
public void mergingStucturedIntoRawShouldUpdateLatestRawConfigs() throws Exception {
final Configuration config = new Configuration();
config.addRawConfiguration(createRawConfiguration("/tmp/raw0.txt"));
final RawConfiguration raw1 = createRawConfiguration("/tmp/raw1.txt");
config.addRawConfiguration(raw1);
final RawConfiguration raw2 = createRawConfiguration("/tmp/raw2.txt");
final Set<RawConfiguration> latestRaws = toSet(raw1, raw2);
final RawConfiguration mergedRaw1 = createRawConfiguration("/tmp/raw1.txt");
final RawConfiguration mergedRaw2 = createRawConfiguration("/tmp/raw2.txt");
final ResourceConfigurationFacet facet = context.mock(ResourceConfigurationFacet.class);
context.checking(new Expectations() {
{
allowing(componentService).getResourceType(resourceId);
will(returnValue(resourceType));
atLeast(1).of(componentService).getComponent(resourceId, ResourceConfigurationFacet.class,
FacetLockType.READ, ConfigManagement.FACET_METHOD_TIMEOUT, daemonThread, onlyIfStarted);
will(returnValue(facet));
atLeast(1).of(facet).loadRawConfigurations();
will(returnValue(latestRaws));
oneOf(facet).mergeRawConfiguration(config, raw1);
will(returnValue(mergedRaw1));
oneOf(facet).mergeRawConfiguration(config, raw2);
will(returnValue(mergedRaw2));
}
});
Configuration mergedConfig = configurationMgr.merge(config, resourceId, FROM_STRUCTURED);
Configuration expectedConfig = new Configuration();
expectedConfig.addRawConfiguration(mergedRaw1);
expectedConfig.addRawConfiguration(mergedRaw2);
assertStructuredMergedIntoRaws(mergedConfig, expectedConfig, "Failed to update existing raw configs");
}
@Test
public void mergingStructuredIntoRawShouldIgnoreNulls() throws Exception {
final Configuration config = new Configuration();
final RawConfiguration originalRaw = createRawConfiguration("/tmp/raw.txt");
config.addRawConfiguration(originalRaw);
final Set<RawConfiguration> latestRaws = toSet(originalRaw);
final ResourceConfigurationFacet facet = context.mock(ResourceConfigurationFacet.class);
context.checking(new Expectations() {
{
allowing(componentService).getResourceType(resourceId);
will(returnValue(resourceType));
atLeast(1).of(componentService).getComponent(resourceId, ResourceConfigurationFacet.class,
FacetLockType.READ, ConfigManagement.FACET_METHOD_TIMEOUT, daemonThread, onlyIfStarted);
will(returnValue(facet));
atLeast(1).of(facet).loadRawConfigurations();
will(returnValue(latestRaws));
oneOf(facet).mergeRawConfiguration(config, originalRaw);
will(returnValue(null));
}
});
Configuration mergedConfig = configurationMgr.merge(config, resourceId, FROM_STRUCTURED);
Configuration expectedConfig = new Configuration();
expectedConfig.addRawConfiguration(originalRaw);
assertStructuredMergedIntoRaws(mergedConfig, expectedConfig, "cannot merge into a null raw.");
}
@Test
public void mergingStructuredIntoRawShouldDoNothingIfRawsAreNull() throws Exception {
RawConfiguration raw = createRawConfiguration("/tmp/foo.txt");
final Configuration config = new Configuration();
config.addRawConfiguration(raw);
final ResourceConfigurationFacet facet = context.mock(ResourceConfigurationFacet.class);
context.checking(new Expectations() {
{
allowing(componentService).getResourceType(resourceId);
will(returnValue(resourceType));
atLeast(1).of(componentService).getComponent(resourceId, ResourceConfigurationFacet.class,
FacetLockType.READ, ConfigManagement.FACET_METHOD_TIMEOUT, daemonThread, onlyIfStarted);
will(returnValue(facet));
atLeast(1).of(facet).loadRawConfigurations();
will(returnValue(null));
}
});
Configuration mergedConfig = configurationMgr.merge(config, resourceId, FROM_STRUCTURED);
Configuration expectedConfig = new Configuration();
expectedConfig.addRawConfiguration(raw);
assertStructuredMergedIntoRaws(mergedConfig, expectedConfig,
"Expected raw configs should not be modified when the facet does not return any raw configs.");
}
void assertStructuredMergedIntoRaws(Configuration actual, Configuration expected, String msg) {
Set<RawConfiguration> actualRaws = actual.getRawConfigurations();
Set<RawConfiguration> expectedRaws = expected.getRawConfigurations();
assertEquals(actualRaws.size(), expectedRaws.size(),
"Merging structured into raws failed, got back the wrong number of raws. -- " + msg);
for (RawConfiguration expectedRaw : expectedRaws) {
assertTrue(actualRaws.contains(expectedRaw),
"Merging structured into raws failed, failed to find to find raw config [" + expectedRaw + "] -- "
+ msg);
}
}
@Test
public void mergingRawsIntoStructuredShouldUpdateLatestStructuredConfig() throws Exception {
final Configuration config = new Configuration();
config.put(new PropertySimple("x", "0"));
config.put(new PropertySimple("z", "3"));
final RawConfiguration raw1 = createRawConfiguration("/tmp/foo.txt");
config.addRawConfiguration(raw1);
final RawConfiguration raw2 = createRawConfiguration("/tmp/bar.txt");
config.addRawConfiguration(raw2);
final Configuration latestStructured = new Configuration();
latestStructured.put(new PropertySimple("x", "1"));
latestStructured.put(new PropertySimple("y", "1"));
final ResourceConfigurationFacet facet = context.mock(ResourceConfigurationFacet.class);
context.checking(new Expectations() {
{
allowing(componentService).getResourceType(resourceId);
will(returnValue(resourceType));
atLeast(1).of(componentService).getComponent(resourceId, ResourceConfigurationFacet.class,
FacetLockType.READ, ConfigManagement.FACET_METHOD_TIMEOUT, daemonThread, onlyIfStarted);
will(returnValue(facet));
atLeast(1).of(facet).loadStructuredConfiguration();
will(returnValue(latestStructured));
oneOf(facet).mergeStructuredConfiguration(raw1, config);
oneOf(facet).mergeStructuredConfiguration(raw2, config);
}
});
Configuration mergedConfig = configurationMgr.merge(config, resourceId, FROM_RAW);
assertEquals(mergedConfig.getAllProperties(), latestStructured.getAllProperties(),
"Failed to merged raw into structured.");
}
@Test
public void catchExceptionThrownByFailedValidationOfRawConfigs() throws Exception {
Configuration configuration = new Configuration();
final RawConfiguration rawConfiguration = createRawConfiguration("/tmp/foo.txt");
configuration.addRawConfiguration(rawConfiguration);
final ResourceConfigurationFacet facet = context.mock(ResourceConfigurationFacet.class);
context.checking(new Expectations() {
{
allowing(componentService).getResourceType(resourceId);
will(returnValue(resourceType));
atLeast(1).of(componentService).getComponent(resourceId, ResourceConfigurationFacet.class,
FacetLockType.READ, ConfigManagement.FACET_METHOD_TIMEOUT, daemonThread, onlyIfStarted);
will(returnValue(facet));
allowing(facet).validateRawConfiguration(rawConfiguration);
will(throwException(new IllegalArgumentException("message")));
}
});
try {
configurationMgr.validate(configuration, resourceId, false);
} catch (PluginContainerException exception) {
assertTrue(false, "Validate should have caught the exception.");
}
}
@Test
public void catchExceptionThrownByFailedValidationOfStructuredConfigs() throws Exception {
final Configuration configuration = new Configuration();
//final RawConfiguration rawConfiguration = createRawConfiguration("/tmp/foo.txt");
//configuration.addRawConfiguration(rawConfiguration);
final ResourceConfigurationFacet facet = context.mock(ResourceConfigurationFacet.class);
context.checking(new Expectations() {
{
allowing(componentService).getResourceType(resourceId);
will(returnValue(resourceType));
atLeast(1).of(componentService).getComponent(resourceId, ResourceConfigurationFacet.class,
FacetLockType.READ, ConfigManagement.FACET_METHOD_TIMEOUT, daemonThread, onlyIfStarted);
will(returnValue(facet));
//allowing(facet).validateRawConfiguration(rawConfiguration);
allowing(facet).validateStructuredConfiguration(configuration);
will(throwException(new IllegalArgumentException("message")));
}
});
try {
configurationMgr.validate(configuration, resourceId, true);
} catch (PluginContainerException exception) {
assertTrue(false, "validate should have caught exception");
}
}
@Test
public void mergingRawsIntoStructuredShouldIgnoreNull() throws Exception {
Configuration config = new Configuration();
config.addRawConfiguration(createRawConfiguration("/tmp/foo.txt"));
final ResourceConfigurationFacet facet = context.mock(ResourceConfigurationFacet.class);
context.checking(new Expectations() {
{
allowing(componentService).getResourceType(resourceId);
will(returnValue(resourceType));
atLeast(1).of(componentService).getComponent(resourceId, ResourceConfigurationFacet.class,
FacetLockType.READ, ConfigManagement.FACET_METHOD_TIMEOUT, daemonThread, onlyIfStarted);
will(returnValue(facet));
atLeast(1).of(facet).loadStructuredConfiguration();
will(returnValue(null));
}
});
Configuration mergedConfig = configurationMgr.merge(config, resourceId, FROM_RAW);
assertEquals(mergedConfig, config,
"Structured config should not be modified when the facet does not return a structured config.");
}
@Test
public void updatingConfigShouldSubmitRunnerToThreadPool() throws Exception {
int configUpdateId = -1;
Configuration config = new Configuration();
ConfigurationUpdateRequest request = new ConfigurationUpdateRequest(configUpdateId, config, resourceId);
final ScheduledExecutorService threadPool = context.mock(ScheduledExecutorService.class, "threadPool");
configurationMgr.setThreadPool(threadPool);
final ConfigManagement configMgmt = context.mock(ConfigManagement.class);
final ConfigurationServerService configServerService = context.mock(ConfigurationServerService.class);
ServerServices serverServices = new ServerServices();
serverServices.setConfigurationServerService(configServerService);
final UpdateResourceConfigurationRunner updateRunner = new UpdateResourceConfigurationRunner(
configServerService, resourceType, configMgmt, request);
context.checking(new Expectations() {
{
allowing(componentService).getResourceType(resourceId);
will(returnValue(resourceType));
atLeast(1).of(configMgmtFactory).getStrategy(resourceId);
will(returnValue(configMgmt));
oneOf(threadPool).submit((Runnable) with(matchingUpdateRunner(updateRunner)));
}
});
configurationMgr.updateResourceConfiguration(request);
}
public static Matcher<UpdateResourceConfigurationRunner> matchingUpdateRunner(
UpdateResourceConfigurationRunner expected) {
return new PropertyMatcher<UpdateResourceConfigurationRunner>(expected);
}
}