/*
* RHQ Management Platform
* Copyright (C) 2005-2013 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.cassandra.ccm.arquillian;
import java.io.File;
import java.util.concurrent.Callable;
import org.jboss.arquillian.config.descriptor.api.ArquillianDescriptor;
import org.jboss.arquillian.container.spi.Container;
import org.jboss.arquillian.container.spi.ContainerRegistry;
import org.jboss.arquillian.container.spi.client.container.DeployableContainer;
import org.jboss.arquillian.container.spi.client.deployment.Deployment;
import org.jboss.arquillian.container.spi.client.deployment.DeploymentScenario;
import org.jboss.arquillian.container.spi.event.DeployDeployment;
import org.jboss.arquillian.container.spi.event.DeploymentEvent;
import org.jboss.arquillian.container.spi.event.UnDeployDeployment;
import org.jboss.arquillian.container.spi.event.container.AfterStart;
import org.jboss.arquillian.container.spi.event.container.AfterStop;
import org.jboss.arquillian.container.spi.event.container.BeforeStart;
import org.jboss.arquillian.container.spi.event.container.BeforeStop;
import org.jboss.arquillian.container.test.impl.client.deployment.event.GenerateDeployment;
import org.jboss.arquillian.core.api.Event;
import org.jboss.arquillian.core.api.Instance;
import org.jboss.arquillian.core.api.InstanceProducer;
import org.jboss.arquillian.core.api.annotation.Inject;
import org.jboss.arquillian.core.api.annotation.Observes;
import org.jboss.arquillian.core.api.event.ManagerStarted;
import org.jboss.arquillian.core.spi.EventContext;
import org.jboss.arquillian.core.spi.LoadableExtension;
import org.jboss.arquillian.test.spi.TestClass;
import org.jboss.arquillian.test.spi.annotation.ClassScoped;
import org.jboss.arquillian.test.spi.context.ClassContext;
import org.jboss.arquillian.test.spi.event.suite.AfterClass;
import org.jboss.arquillian.test.spi.event.suite.BeforeClass;
import org.rhq.cassandra.CassandraClusterManager;
import org.rhq.cassandra.ClusterInitService;
import org.rhq.cassandra.DeploymentOptions;
import org.rhq.cassandra.DeploymentOptionsFactory;
import org.rhq.cassandra.schema.SchemaManager;
/**
* @author John Sanda
*/
public class CCMSuiteDeploymentExtension implements LoadableExtension {
public void register(ExtensionBuilder builder) {
builder.observer(SuiteDeployer.class);
}
public static class SuiteDeployer {
private Class<?> deploymentClass;
private DeploymentScenario suiteDeploymentScenario;
private CassandraClusterManager ccm;
@Inject
@ClassScoped
private InstanceProducer<DeploymentScenario> classDeploymentScenario;
@Inject
private Event<DeploymentEvent> deploymentEvent;
@Inject
private Event<GenerateDeployment> generateDeploymentEvent;
@Inject
// Active some form of ClassContext around our deployments due to assumption bug in AS7 extension.
private Instance<ClassContext> classContext;
public void startup(@Observes(precedence = -100)
ManagerStarted event, ArquillianDescriptor descriptor) {
deploymentClass = getDeploymentClass(descriptor);
executeInClassScope(new Callable<Void>() {
public Void call() throws Exception {
generateDeploymentEvent.fire(new GenerateDeployment(new TestClass(deploymentClass)));
suiteDeploymentScenario = classDeploymentScenario.get();
return null;
}
});
}
public void initCassandra(@Observes(precedence = -100)
final BeforeStart event, ArquillianDescriptor descriptor) {
executeInClassScope(new Callable<Void>() {
public Void call() throws Exception {
SchemaManager schemaManager = null;
try {
ClusterInitService clusterInitService = new ClusterInitService();
String[] nodes = null;
int[] jmxPorts = null;
int cqlPort = -1;
if (!Boolean.valueOf(System.getProperty("itest.use-external-storage-node", "false"))) {
DeploymentOptionsFactory factory = new DeploymentOptionsFactory();
DeploymentOptions options = factory.newDeploymentOptions();
File basedir = new File("target");
File clusterDir = new File(basedir, "cassandra");
options.setUsername("rhqadmin");
options.setPassword("1eeb2f255e832171df8592078de921bc");
options.setClusterDir(clusterDir.getAbsolutePath());
options.setHeapSize("256M");
options.setHeapNewSize("64M");
options.setStartRpc(true);
ccm = new CassandraClusterManager(options);
ccm.createCluster();
nodes = ccm.getNodes();
jmxPorts = ccm.getJmxPorts();
cqlPort = ccm.getCqlPort();
ccm.startCluster(false);
try {
clusterInitService.waitForClusterToStart(nodes, jmxPorts, nodes.length, 2000, 20, 10);
schemaManager = new SchemaManager("rhqadmin", "1eeb2f255e832171df8592078de921bc", nodes,
cqlPort);
} catch (Exception e) {
if (null != ccm) {
ccm.shutdownCluster();
}
throw new RuntimeException("Cassandra cluster initialization failed", e);
}
} else {
try {
String nodesString = System.getProperty("rhq.storage.nodes", "127.0.0.1");
nodes = nodesString.split(",");
String cqlPortString = System.getProperty("rhq.storage.cql-port", "9042");
cqlPort = Integer.parseInt(cqlPortString);
String jmxPortString = System.getProperty("rhq.storage.jmx-port", "7299");
jmxPorts = new int[] { Integer.parseInt(jmxPortString) };
schemaManager = new SchemaManager("rhqadmin", "1eeb2f255e832171df8592078de921bc", nodes, cqlPort);
} catch (Exception e) {
throw new RuntimeException("External Cassandra initialization failed", e);
}
}
try {
schemaManager.install();
clusterInitService.waitForSchemaAgreement(nodes, jmxPorts);
schemaManager.updateTopology();
} catch (Exception e) {
if (null != ccm) {
ccm.shutdownCluster();
}
throw new RuntimeException("Cassandra schema initialization failed", e);
}
return null;
} finally {
if (schemaManager != null) {
schemaManager.shutdown();
}
}
}
});
}
public void deploy(@Observes
final AfterStart event, final ContainerRegistry registry) {
executeInClassScope(new Callable<Void>() {
public Void call() throws Exception {
for (Deployment d : suiteDeploymentScenario.deployments()) {
deploymentEvent.fire(new DeployDeployment(findContainer(registry,
event.getDeployableContainer()), d));
}
return null;
}
});
}
public void undeploy(@Observes
final BeforeStop event, final ContainerRegistry registry) {
executeInClassScope(new Callable<Void>() {
public Void call() throws Exception {
for (Deployment d : suiteDeploymentScenario.deployments()) {
deploymentEvent.fire(new UnDeployDeployment(findContainer(registry,
event.getDeployableContainer()), d));
}
return null;
}
});
}
public void shutdownCassandra(@Observes
final AfterStop event, ArquillianDescriptor descriptor) {
executeInClassScope(new Callable<Void>() {
public Void call() throws Exception {
if (null != ccm) {
ccm.shutdownCluster();
}
return null;
}
});
}
public void overrideBefore(@Observes
EventContext<BeforeClass> event) {
// Don't continue TestClass's BeforeClass context as normal.
// No DeploymentGeneration or Deploy will take place.
classDeploymentScenario.set(suiteDeploymentScenario);
}
public void overrideAfter(@Observes
EventContext<AfterClass> event) {
// Don't continue TestClass's AfterClass context as normal.
// No UnDeploy will take place.
}
private void executeInClassScope(Callable<Void> call) {
try {
classContext.get().activate(deploymentClass);
call.call();
} catch (Exception e) {
throw new RuntimeException("Could not invoke operation", e);
} finally {
classContext.get().deactivate();
}
}
private Container findContainer(ContainerRegistry registry, DeployableContainer<?> deployable) {
for (Container container : registry.getContainers()) {
if (container.getDeployableContainer() == deployable) {
return container;
}
}
return null;
}
private Class<?> getDeploymentClass(ArquillianDescriptor descriptor) {
if (descriptor == null) {
throw new IllegalArgumentException("Descriptor must be specified");
}
String className = descriptor.extension("suite").getExtensionProperties().get("deploymentClass");
if (className == null) {
throw new IllegalArgumentException(
"A extension element with property deploymentClass must be specified in arquillian.xml");
}
try {
return Class.forName(className);
} catch (ClassNotFoundException e) {
throw new RuntimeException("Could not load defined deploymentClass: " + className, e);
}
}
}
}