/*
* JBoss, Home of Professional Open Source.
* Copyright 2008, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* 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 2.1 of
* the License, or (at your option) any later version.
*
* This software 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.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.test.system.controller;
import java.lang.reflect.UndeclaredThrowableException;
import java.net.URL;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import javax.management.ObjectName;
import junit.framework.AssertionFailedError;
import org.jboss.deployment.IncompleteDeploymentException;
import org.jboss.mx.server.ServerConstants;
import org.jboss.system.ServiceContext;
import org.jboss.system.ServiceControllerMBean;
import org.jboss.test.AbstractSystemTest;
import org.jboss.test.AbstractTestDelegate;
import org.jboss.test.system.controller.support.Order;
/**
* ControllerTestDelegate.
*
* @author <a href="adrian@jboss.com">Adrian Brock</a>
* @version $Revision: 85945 $
*/
public abstract class ControllerTestDelegate extends AbstractTestDelegate
{
private MBeanServer server;
private ServiceControllerMBean serviceController;
private SimpleSARDeployer deployer;
public ControllerTestDelegate(Class clazz)
{
super(clazz);
}
public MBeanServer getServer()
{
return server;
}
public ServiceControllerMBean getController()
{
return serviceController;
}
/**
* Override to:
* Set javax.management.builder.initial to org.jboss.mx.server.MBeanServerBuilderImpl
* Create jboss domain MBeanServer
* Create and register jboss.system:service=ServiceController mbean
* Create SimpleSARDeployer
* deploy the test service mbeans
* @see #deploy()
*/
public void setUp() throws Exception
{
super.setUp();
System.setProperty(ServerConstants.MBEAN_SERVER_BUILDER_CLASS_PROPERTY, ServerConstants.DEFAULT_MBEAN_SERVER_BUILDER_CLASS);
server = createMBeanServer();
serviceController = createServiceController();
server.registerMBean(serviceController, ServiceControllerMBean.OBJECT_NAME);
deployer = new SimpleSARDeployer(server, serviceController);
Order.reset();
deploy();
if (isValidateAtSetUp())
validate();
}
// TODO Temporary until the IncompleteDeploymentDescription is integrated
protected boolean isValidateAtSetUp()
{
return true;
}
protected MBeanServer createMBeanServer()
{
return MBeanServerFactory.newMBeanServer("jboss");
}
public abstract ServiceControllerMBean createServiceController() throws Exception;
public void tearDown() throws Exception
{
deployer.uninstall();
super.tearDown();
}
protected void uninstallTemporary() throws Exception
{
deployer.uninstallTemporary();
}
protected void validate() throws Exception
{
Collection<ServiceContext> waitingForClasses = new HashSet<ServiceContext>();
Collection<ServiceContext> waitingForDepends = serviceController.listIncompletelyDeployed();
Collection<ServiceContext> allServices = serviceController.listDeployed();
// Weed services that are waiting for other deployments
Collection<ServiceContext> rootCause = new HashSet<ServiceContext>(waitingForDepends);
Collection<ServiceContext> missing = new HashSet<ServiceContext>();
for (Iterator i = rootCause.iterator(); i.hasNext();)
{
ServiceContext ctx = (ServiceContext) i.next();
for (Iterator j = ctx.iDependOn.iterator(); j.hasNext(); )
{
ServiceContext dependee = (ServiceContext) j.next();
if (dependee.state != ServiceContext.RUNNING)
{
// Add missing mbean
if (allServices.contains(dependee) == false)
missing.add(dependee);
// We are not a root cause
i.remove();
break;
}
}
}
// Add missing mbeans to the root cause
rootCause.addAll(missing);
IncompleteDeploymentException ide = new IncompleteDeploymentException(
waitingForClasses,
waitingForDepends,
rootCause,
Collections.emptyList(),
Collections.emptyList());
if (ide.isEmpty() == false)
throw ide;
}
/**
* Deploy the beans by looking for an xml descriptor named
* clazz.getName().replace('.', '/') + ".xml". If the test
* clazz includes a NewUnitTestCase or OldUnitTestCase suffix,
* this is removed.
*
* @throws Exception for any error
*/
protected void deploy() throws Exception
{
String testName = clazz.getName();
testName = testName.replace('.', '/');
int index = testName.indexOf("NewUnitTestCase");
if (index != -1)
testName = testName.substring(0, index);
index = testName.indexOf("OldUnitTestCase");
if (index != -1)
testName = testName.substring(0, index);
testName += ".xml";
URL url = clazz.getClassLoader().getResource(testName);
if (url != null)
deploy(url, false);
else
log.debug("No test specific deployment " + testName);
}
protected List<ObjectName> deploy(URL url, boolean temporary) throws Exception
{
return deployer.deploy(url, temporary);
}
protected void undeploy(List<ObjectName> objectNames)
{
deployer.undeploy(objectNames);
}
protected List<ObjectName> install(URL url) throws Exception
{
return deployer.install(url);
}
protected void uninstall(List<ObjectName> objectNames)
{
deployer.uninstall(objectNames);
}
public abstract void assertMBeanFailed(ObjectName name, boolean registered) throws Exception;
protected IncompleteDeploymentException assertInvalidDeployments() throws Exception
{
try
{
validate();
throw new AssertionFailedError("Deployments should not be valid!");
}
catch (IncompleteDeploymentException expected)
{
log.debug("Got expected " + expected.getClass().getName());
return expected;
}
}
protected void assertInitialDeployFailure(URL url, ObjectName name, Class<? extends Throwable> expected) throws Exception
{
try
{
deploy(url, true);
throw new AssertionFailedError("Should have got a " + expected.getName());
}
catch (Throwable t)
{
AbstractSystemTest.checkThrowableDeep(expected, t);
}
if (name != null)
assertNoService(name);
}
public List<ObjectName> assertDeployFailure(URL url, ObjectName name, Class<? extends Throwable> expected) throws Exception
{
List<ObjectName> result = deploy(url, true);
IncompleteDeploymentException e = assertInvalidDeployments();
checkIncomplete(e, name, expected);
return result;
}
public List<ObjectName> assertMaybeDeployFailure(URL url, ObjectName name, Class<? extends Throwable> expected) throws Exception
{
return assertDeployFailure(url, name, expected);
}
public void assertMaybeParseFailure(URL url, ObjectName name, Class<? extends Throwable> expected) throws Exception
{
assertDeployFailure(url, name, expected);
assertServiceFailed(name);
}
protected void checkIncomplete(IncompleteDeploymentException e, ObjectName name, Class<? extends Throwable> expected) throws Exception
{
Collection incomplete = e.getMbeansWaitingForDepends();
for (Iterator i = incomplete.iterator(); i.hasNext();)
{
ServiceContext ctx = (ServiceContext) i.next();
if (name.equals(ctx.objectName))
{
Throwable problem = ctx.getProblem();
if (e != null || expected != null)
{
if (expected != null && problem == null)
throw new AssertionFailedError("Did not get expected " + expected.getName() + " for " + ctx);
if (expected == null && problem != null)
{
if (problem instanceof Exception)
throw (Exception) problem;
if (problem instanceof Error)
throw (Error) problem;
throw new UndeclaredThrowableException(problem);
}
if (expected != null)
{
AbstractSystemTest.checkThrowableDeep(expected, problem);
if (ServiceContext.FAILED != ctx.state)
throw new AssertionFailedError("Context is not in the FAILED state: " + ctx);
}
}
return;
}
}
throw new AssertionFailedError("Did not find " + name + " in incomplete deployments " + incomplete);
}
protected ServiceContext getServiceContext(ObjectName name) throws Exception
{
return getController().getServiceContext(name);
}
protected void assertNoService(ObjectName name) throws Exception
{
ServiceContext ctx = getServiceContext(name);
if (ctx != null && ctx.state != ServiceContext.NOTYETINSTALLED)
throw new AssertionFailedError("Should not be a service context for " + ctx);
}
protected void assertServiceFailed(ObjectName name) throws Exception
{
assertServiceFailed(name, AbstractControllerTest.OLD_REGISTERED);
}
protected void assertServiceFailed(ObjectName name, boolean registered) throws Exception
{
assertServiceState(name, ServiceContext.FAILED, registered);
assertMBeanFailed(name, registered);
}
protected void assertServiceState(ObjectName name, int expectedState, boolean registered) throws Exception
{
ServiceContext ctx = getServiceContext(name);
if (registered == false && ctx == null)
return;
if (ctx == null)
throw new AssertionFailedError("Incorrect state for " + name + " expected " + ServiceContext.getStateString(expectedState) + " but there is no context/state");
if (expectedState != ctx.state)
throw new AssertionFailedError("Incorrect state for " + name + " expected " + ServiceContext.getStateString(expectedState) + " got " + ctx.getStateString());
}
}