/* * RHQ Management Platform * Copyright (C) 2005-2010 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ package org.rhq.enterprise.server.configuration; import java.util.HashMap; import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import org.testng.annotations.Test; import org.rhq.core.clientapi.agent.PluginContainerException; import org.rhq.core.clientapi.agent.configuration.ConfigurationAgentService; import org.rhq.core.clientapi.agent.configuration.ConfigurationUpdateRequest; import org.rhq.core.clientapi.server.configuration.ConfigurationServerService; import org.rhq.core.clientapi.server.configuration.ConfigurationUpdateResponse; import org.rhq.core.domain.authz.Permission; import org.rhq.core.domain.configuration.Configuration; import org.rhq.core.domain.configuration.ConfigurationUpdateStatus; import org.rhq.core.domain.configuration.PropertySimple; import org.rhq.enterprise.server.authz.PermissionException; import org.rhq.enterprise.server.test.LargeGroupTestBase; import org.rhq.enterprise.server.test.TestServerCommunicationsService; import org.rhq.enterprise.server.util.SessionTestHelper; @Test public class LargeGroupResourceConfigurationTest extends LargeGroupTestBase { private LargeGroupEnvironment env; private CountDownLatch latch; @Override protected void setupMockAgentServices(TestServerCommunicationsService agentServiceContainer) { TestServices testServices = new TestServices(); agentServiceContainer.configurationService = testServices; } /** * Create a large group of 1000+ resources. */ @Override protected void beforeMethod() throws Exception { super.beforeMethod(); env = createLargeGroupWithNormalUserRoleAccess(1010, Permission.CONFIGURE_READ, Permission.CONFIGURE_WRITE); SessionTestHelper.simulateLogin(env.normalSubject); } /** * Remove the group and all its members. */ @Override protected void afterMethod() throws Exception { tearDownLargeGroupWithNormalUserRoleAccess(env); SessionTestHelper.simulateLogout(env.normalSubject); super.beforeMethod(); } public void testGroupResourceConfigurationUpdate() throws Exception { // all of our platform's children are members of the group we are testing with int memberCount = env.platformResource.getChildResources().size(); // we don't have any resource config // let's see that we can obtain the current live configs for all resources in the group // our mock agent will return the live configs Map<Integer, Configuration> existingMap; System.out.println("Getting resource config for group [#members=" + memberCount + "]"); long start = System.currentTimeMillis(); existingMap = configurationManager.getResourceConfigurationsForCompatibleGroup(env.normalSubject, env.compatibleGroup.getId()); long duration = System.currentTimeMillis() - start; System.out.println("Took [" + duration + "]ms to get resource config for group [#members=" + memberCount + "]"); assert existingMap.size() == memberCount : "did not get back the amount of configs [" + existingMap.size() + "] we expected [" + memberCount + "]"; for (Map.Entry<Integer, Configuration> entry : existingMap.entrySet()) { Integer resourceId = entry.getKey(); Configuration config = entry.getValue(); assert RC_PROP1_VALUE.equals(config.getSimpleValue(RC_PROP1_NAME, null)) : "bad resource config for " + resourceId + "=" + config.toString(true); assert resourceId.toString().equals(config.getSimpleValue(RC_PROP2_NAME, null)) : "bad resource config for " + resourceId + "=" + config.toString(true); // create new resource configuration settings for this resource, we will update the group members to these new configs config.getSimple(RC_PROP2_NAME).setStringValue("UPDATE" + resourceId); } // update our group with the new resource configs System.out.println("Scheduling a group resource config update."); latch = new CountDownLatch(memberCount); // our TestService will count this down int groupUpdateId = configurationManager.scheduleGroupResourceConfigurationUpdate(env.normalSubject, env.compatibleGroup.getId(), existingMap); // group resource configuration update has been kicked off, wait for the mock agents to each complete their update System.out.print("Waiting for mock agents"); assert latch.await(5, TimeUnit.MINUTES) : "agents should not have taken this long"; System.out.println(" Mock agents are done."); // wait for group update to get out of the INPROGRESS state (it will eventually get to SUCCESS), but don't wait indefinitely // this shouldn't take too long - just have to wait for the all the DB commits to complete System.out.print("Waiting for group resource config update to be finished..."); ConfigurationUpdateStatus status = getGroupResourceConfigurationStatus(env.compatibleGroup.getId()); boolean inprogress = (status == ConfigurationUpdateStatus.INPROGRESS); for (int i = 0; i < 20 && inprogress; i++) { Thread.sleep(3000); status = getGroupResourceConfigurationStatus(env.compatibleGroup.getId()); inprogress = (status == ConfigurationUpdateStatus.INPROGRESS); } assert !inprogress : "group resource configuration update is still inprogress - this is taking too long"; System.out.println(" Done. Status=" + ((status != null) ? status.name() : "????null????")); assert status == ConfigurationUpdateStatus.SUCCESS : "should have finished in the success status"; // now see if our group resource configuration update affected all of our resources by getting the group plugin config System.out.println("Getting updated resource config for group [#members=" + memberCount + "]"); start = System.currentTimeMillis(); existingMap = configurationManager.getResourceConfigurationsForCompatibleGroup(env.normalSubject, env.compatibleGroup.getId()); duration = System.currentTimeMillis() - start; System.out.println("Took [" + duration + "]ms to get updated resource config for group [#members=" + memberCount + "]"); assert existingMap.size() == memberCount : "did not get back the amount of configs [" + existingMap.size() + "] we expected [" + memberCount + "]"; for (Map.Entry<Integer, Configuration> entry : existingMap.entrySet()) { Integer resourceId = entry.getKey(); Configuration config = entry.getValue(); assert RC_PROP1_VALUE.equals(config.getSimpleValue(RC_PROP1_NAME, null)) : "bad resource config for " + resourceId + "=" + config.toString(true); assert ("UPDATE" + resourceId.toString()).equals(config.getSimpleValue(RC_PROP2_NAME, null)) : "bad resource config for " + resourceId + "=" + config.toString(true); } // now test our authz - unauthorized user should bomb out System.out.println("Attempting unauthz access"); SessionTestHelper.simulateLogin(env.unauthzSubject); start = System.currentTimeMillis(); try { configurationManager.getResourceConfigurationsForCompatibleGroup(env.unauthzSubject, env.compatibleGroup.getId()); assert false : "should have failed - unauthz user not allowed to get resource configuration"; } catch (PermissionException expected) { } finally { duration = System.currentTimeMillis() - start; SessionTestHelper.simulateLogout(env.unauthzSubject); } System.out.println("Took [" + duration + "]ms to attempt unauthz access"); return; } /** * This class mocks out the remote agent. It will receive calls to, for example, * update configurations. */ private class TestServices implements ConfigurationAgentService { private HashMap<Integer, Configuration> configs = new HashMap<Integer, Configuration>(); @Override public void updateResourceConfiguration(ConfigurationUpdateRequest request) { try { synchronized (configs) { configs.put(request.getResourceId(), request.getConfiguration()); } ConfigurationUpdateResponse response = new ConfigurationUpdateResponse( request.getConfigurationUpdateId(), request.getConfiguration(), ConfigurationUpdateStatus.SUCCESS, null); // simulate agent calling into the server to complete the update ConfigurationServerService server = new ConfigurationServerServiceImpl(); server.completeConfigurationUpdate(response); } finally { latch.countDown(); } return; } @Override public Configuration loadResourceConfiguration(int resourceId) throws PluginContainerException { synchronized (configs) { Integer id = Integer.valueOf(resourceId); if (configs.containsKey(id)) { return configs.get(id); } else { Configuration config = new Configuration(); config.put(new PropertySimple(RC_PROP1_NAME, RC_PROP1_VALUE)); config.put(new PropertySimple(RC_PROP2_NAME, resourceId)); configs.put(id, config); return config; } } } @Override public ConfigurationUpdateResponse executeUpdateResourceConfigurationImmediately( ConfigurationUpdateRequest request) throws PluginContainerException { return null; } @Override public Configuration merge(Configuration configuration, int resourceId, boolean fromStructured) throws PluginContainerException { return null; } @Override public Configuration validate(Configuration configuration, int resourceId, boolean isStructured) throws PluginContainerException { return null; } } }