Skip to content

Instantly share code, notes, and snippets.

@aslakknutsen
Last active September 20, 2016 09:12
Show Gist options
  • Save aslakknutsen/3975179 to your computer and use it in GitHub Desktop.
Save aslakknutsen/3975179 to your computer and use it in GitHub Desktop.
Brute Force Arquillian Suite
<?xml version="1.0" encoding="UTF-8"?>
<arquillian xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://jboss.org/schema/arquillian" xsi:schemaLocation="http://jboss.org/schema/arquillian
http://jboss.org/schema/arquillian/arquillian_1_0.xsd">
<defaultProtocol type="Servlet 3.0"/>
<extension qualifier="suite">
<property name="deploymentClass">org.jboss.arquillian.extension.suite.Deployments</property>
</extension>
</arquillian>
package org.jboss.arquillian.extension.suite;
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.client.protocol.metadata.ProtocolMetaData;
import org.jboss.arquillian.container.spi.event.DeployDeployment;
import org.jboss.arquillian.container.spi.event.DeployManagedDeployments;
import org.jboss.arquillian.container.spi.event.DeploymentEvent;
import org.jboss.arquillian.container.spi.event.UnDeployDeployment;
import org.jboss.arquillian.container.spi.event.UnDeployManagedDeployments;
import org.jboss.arquillian.container.spi.event.container.AfterStart;
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.annotation.TestScoped;
import org.jboss.arquillian.test.spi.context.ClassContext;
import org.jboss.arquillian.test.spi.event.suite.Before;
import org.jboss.arquillian.test.spi.event.suite.BeforeClass;
public class ArquillianSuiteExtension implements LoadableExtension {
public void register(ExtensionBuilder builder) {
builder.observer(SuiteDeployer.class);
}
public static class SuiteDeployer {
private Class<?> deploymentClass;
private DeploymentScenario suiteDeploymentScenario;
@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;
private ProtocolMetaData cachedProtocolMetaData;
@TestScoped
@Inject
private InstanceProducer<ProtocolMetaData> testScopedProtocolMetaData;
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 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 blockDeployManagedDeployments(@Observes EventContext<DeployManagedDeployments> ignored) {
// We need to block DeployManagedDeployments event
}
public void storeProtocolMetaData(@Observes ProtocolMetaData protocolMetaData) {
cachedProtocolMetaData = protocolMetaData;
}
public void resotreProtocolMetaData(@Observes EventContext<Before> eventContext) {
testScopedProtocolMetaData.set(cachedProtocolMetaData);
eventContext.proceed();
}
public void restoreDeploymentScenario(@Observes EventContext<BeforeClass> event) {
// Setup the Suite level scenario as if it came from the TestClass
event.proceed();
classDeploymentScenario.set(suiteDeploymentScenario);
}
public void blockUnDeployManagedDeployments(@Observes EventContext<UnDeployManagedDeployments> ignored) {
// We need to block UnDeployManagedDeployments event
}
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);
}
}
}
}
package org.jboss.arquillian.extension.suite;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.extension.suite.tests.Test1;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.EmptyAsset;
import org.jboss.shrinkwrap.api.spec.WebArchive;
public class Deployments {
@Deployment
public static WebArchive deploy() {
return ShrinkWrap.create(WebArchive.class)
.addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml")
.addPackage(Test1.class.getPackage());
}
}
org.jboss.arquillian.extension.suite.ArquillianSuiteExtension
package org.jboss.arquillian.extension.suite.tests;
import javax.enterprise.inject.spi.BeanManager;
import junit.framework.Assert;
import org.jboss.arquillian.junit.Arquillian;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(Arquillian.class)
public class Test1 {
@Test
public void shouldInject(BeanManager bm) {
System.out.println("Where are We?");
Assert.assertNotNull(bm);
}
}
@MaikelNait
Copy link

Silly question : How can I get this extension running for my Arquillian tests ? How to compile the classes , and where to put them ?

I'm pretty new to Arquillian , and I can't find good guides about how to use Extensions ( other than the Persistence extension which is available as a maven dependency ).

What is the main difference between this extension and the JRebel one ?
Are they targeted to fulfill the same goal ? ( JRebel extension seems already available as a jar )

Thanks !

@blabno
Copy link

blabno commented Apr 12, 2013

MaikeInait: JRebel extension is for development time (i.e. you should not use it on Jenkins). Suite extension is meant to run tests from several classes in single deployment (i.e. Jenkins could do 1 deployment with all tests instead of 100, not mentioning server start/stop)

Aslak: Does this run with Drone?

@blabno
Copy link

blabno commented Apr 15, 2013

I've got it working with Drone! Check out my fork: https://gist.github.com/blabno/5387599

@blabno
Copy link

blabno commented Apr 25, 2013

@lynchmaniac
Copy link

Like MaikelNait i'm really newbie on Arquillian and i don't see how to launch all the test. I made a project with all the class, compilation is OK but in my Eclipse i didn't see how to launch all the test. With maven i have several deployements, one per test. So i do something wrong i think :-)
Is anyone can help me on this problem ?

@MaikelNait
Copy link

Thanks for the clarification blabno... the only thing I'm still missing is how to integrate this Suite plugin into my Arquillian configuration. I just need to copy all the source code into my project, and make it compile ?
Where to put the "LoadableExtension" file that refers to org.jboss.arquillian.extension.suite.ArquillianSuiteExtension ?
Thanks a lot in advance !

@MaikelNait
Copy link

Mmm... searching in Internet , looks like I may need to re-compile the whole Arquillian project , to get the Suite Extension registered in a file called /META-INF/services/org.jboss.arquillian.core.spi.LoadableExtension ?!?!?

I can see this file inside arquillian-container-impl-base-1.0.3.Final.jar , and arquillian-config-impl-base-1.0.3.Final.jar,
with just one line : org.jboss.arquillian.container.impl.ContainerExtension

Can anyone just post a good documentation on how to get this Suit integrated into JBoss "for dummies" ???
Thanks a lot !!

@MaikelNait
Copy link

Ok, seems I just need to rename the "LoadableExtension" file as "org.jboss.arquillian.core.spi.LoadableExtension" , and place it under /src/main/resources/META-INF/services ( I'm using a Maven project )... Now the Suite if finally working ...!!! A good installation guide for this Extension would have been very nice .. but anyway, I finally figured it out ... phew !

@javaG
Copy link

javaG commented May 26, 2013

Hi Aslak,
I've managed to use the brute force suite solution, thank You for your well-done job. Everything works fine while one issue still exists: I see that when using the suite, arquillian deployment algorithm tries to instantiate ALL the singleton classes found on a classpath (WAR provided by the ShrinkWrap as part of @deployment). We have a large-scale project and classpath I'm trying to use is pretty big, but I'm not expecting this kind of eager loading during deployment.
My question is: is it supposed to work this way, or it's just a bug? BTW, when running arquillian tests without suite-extension, I don't see this problem at all, seems like lazy-loading model implemented then, as it supposed to be.
Thanks for your answer in advance.

@asceta
Copy link

asceta commented Jul 19, 2013

Welcome,

I am also using DBUnit extension configured as

    <extension qualifier="persistence-dbunit">
        <property name="datatypeFactory">org.dbunit.ext.h2.H2DataTypeFactory</property>
        <property name="excludePoi">true</property>
        <property name="caseSensitiveTableNames">false</property>
    </extension>

and I am facing problems during test execution:

Caused by: java.lang.NullPointerException
    at org.jboss.arquillian.persistence.core.deployment.PersistenceExtensionArchiveAppender.requiredLibraries(PersistenceExtensionArchiveAppender.java:81)
    at org.jboss.arquillian.persistence.core.deployment.PersistenceExtensionArchiveAppender.createAuxiliaryArchive(PersistenceExtensionArchiveAppender.java:58)
    at org.jboss.arquillian.container.test.impl.client.deployment.DeploymentGenerator.loadAuxiliaryArchives(DeploymentGenerator.java:209)
    at org.jboss.arquillian.container.test.impl.client.deployment.DeploymentGenerator.buildTestableDeployments(DeploymentGenerator.java:160)
    at org.jboss.arquillian.container.test.impl.client.deployment.DeploymentGenerator.createTestableDeployments(DeploymentGenerator.java:148)
    at org.jboss.arquillian.container.test.impl.client.deployment.DeploymentGenerator.generateDeployment(DeploymentGenerator.java:85)

...

at org.jboss.arquillian.extension.suite.ArquillianSuiteExtension$SuiteDeployer.executeInClassScope

Could you please help me how should I configure my env properly ?

@ingwarsw
Copy link

I just created my fork out of ITCrowd one.

I added extra Annotation for selecting global deployment.

https://github.com/ingwarsw/arquillian-suite-extension

@suikast42
Copy link

Hi Aslak,
if I run this extension with a single test ( for example mvn -Dtest=ATest test) then ARQ undeploy my app automatically. But if I run the suite with mvn test on my project everything works well but ARQ doesn't undeploy my app.

My environment:
ARQ version : 1.1.2.Final
App server: Jboss 7.2.0.Final

Did I miss something with the configuration?

@KrishnaKotari
Copy link

Hello Aslak,

I'm getting the following error while using this extension. I am using TestNG with Arrquillian

Caused by: java.lang.IllegalArgumentException: No active SuiteScoped Context to bind to
at org.jboss.arquillian.core.impl.ManagerImpl.bind(ManagerImpl.java:173)
at org.jboss.arquillian.core.impl.ManagerImpl.bindAndFire(ManagerImpl.java:235)
at org.jboss.arquillian.core.impl.InstanceImpl.set(InstanceImpl.java:74)
at org.jboss.as.arquillian.protocol.jmx.JMXProtocolAS7.getPackager(JMXProtocolAS7.java:45)
at org.jboss.arquillian.container.test.impl.client.deployment.DeploymentGenerator.buildTestableDeployments(DeploymentGenerator.java:169)
at org.jboss.arquillian.container.test.impl.client.deployment.DeploymentGenerator.createTestableDeployments(DeploymentGenerator.java:148)
at org.jboss.arquillian.container.test.impl.client.deployment.DeploymentGenerator.generateDeployment(DeploymentGenerator.java:85)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)

Can you please help, what is it that I am missing. Configured the extension as shown above.

@KrishnaKotari
Copy link

Hello Asalak,

I have injected the suiteContext at the class level

@Inject
private Instance suiteContext;

and activated the contect in the method startup
suiteContext.activate();

With this it started working like a charm.

Thanks,
Krishna.

@perabello
Copy link

Hello Asceta,

I use Persistence and DBUnit extension too (defaultDataSource, defaultDataSeedStrategy, datatypeFactory, defaultDataSetLocation, etc) .
I do not find how to configure it integrated with ArquillianSuiteExtension.
Somebody is using it?

Thanks
Pere

@Steve973
Copy link

Steve973 commented Apr 6, 2016

Hello Aslak. Does this have to use a war? I want to run tests in Karaf, so I need to deploy bundles.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment