Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
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);
}
}
@aslakknutsen

This comment has been minimized.

Copy link
Owner Author

@aslakknutsen aslakknutsen commented Oct 29, 2012

The Extension will force all Classes in a Module into a TestSuite running from the same DeploymentScenario.

The deploymentClass defined in in the "suite" extension configuration will be used as a 'template' for all other TestClass scenarios.
TestClasses in the suite will have no BeforeClass or AfterClass events, as they are overridden by this extension to avoid new deployment scenarios being generated and new deployments being deployed.

Deployments.deploy() needs to manually include all TestClasses in the deployment that should be ran incontainer. Individual TestClasses/TestMethods in the suite are still allowed to defined @RunAsClient as normal.

@aslakknutsen

This comment has been minimized.

Copy link
Owner Author

@aslakknutsen aslakknutsen commented Oct 29, 2012

Call cycle:

  • ManagerStarted
    • GenerateDeployment (Deployments.deploy) (suite)
  • AfterStart (container)
    • DeployDeployments (all in suite DeploymentScenario)
  • BeforeClass (test)
    • Swap Test DeploymentScenario with Suite DeploymentScenario
    • no more events called in BeforeClass phase
  • AfterClass (test)
    • no more events called in AfterClass phase
  • BeforeStop (container)
    • UnDeployDeployments (all in suite DeploymentScenario)
@mojavelinux

This comment has been minimized.

Copy link

@mojavelinux mojavelinux commented Nov 21, 2012

Perhaps stick this in the showcase for now?

@aslakknutsen

This comment has been minimized.

Copy link
Owner Author

@aslakknutsen aslakknutsen commented Nov 26, 2012

sure, the showcase is a good location

@rajn

This comment has been minimized.

Copy link

@rajn rajn commented Dec 14, 2012

Hi Aslak,

Is this a workaround for ARQ-567? If so can you please elaborate little bit on how to use this?

thank you,
raj

@jaygarala

This comment has been minimized.

Copy link

@jaygarala jaygarala commented Dec 17, 2012

Hi Aslak,

Thanks for uploading this code. We have updated our framework to use this but we are running into issues with TestNG tests. The following example runs correctly when the class is not extending Arquillian(simple TestNG test class) and when is it extending Arquillian but ArquillianSuiteExtension is NOT used.

But when ArquillianSuiteExtension is used, testTwo() fails "expected [This is my updated message] but found [This is my message]".

I updated the example to print out the test instance. Without the ArquillianSuiteExtension, both tests print out is the same. But when ArquillianSuiteExtension is used, they are different.

import org.jboss.arquillian.testng.Arquillian;

import org.testng.Assert;
import org.testng.annotations.Test;

public class SimpleTestNGTest extends Arquillian
{
    private String message= "This is my message";

    @Test
    public void testOne()
    {
        System.out.println(this);
        Assert.assertEquals( "This is my message", message );
        message = "This is my updated message";
    }

    @Test(dependsOnMethods = "testOne")
    public void testTwo()
    {
        System.out.println(this);
        Assert.assertNotNull( message );
        Assert.assertEquals( message, "This is my updated message" );
    }
}
@aslakknutsen

This comment has been minimized.

Copy link
Owner Author

@aslakknutsen aslakknutsen commented Dec 18, 2012

@jaygarala this is not really related to the test suite or not. Arquillian will reexecute the whole test framework lifecycle incontainer for each @test on the client side.

@Before
@Test
    -> @Before (in container)
    -> @Test (in container)
    -> @After (in container)
@After

As long as you don't define a @deployment method, the execution is not moved to the container, and 'everything' works as normal TestNG. By adding the ArquillianSuiteExtension, you're probably adding a Deployment (via the Deployments class), which then moves the default behavior to be incontainer execution.

@jaygarala

This comment has been minimized.

Copy link

@jaygarala jaygarala commented Dec 18, 2012

Hi Aslak,

Thank you for responding. The test case I posted is to simplify the issue we are experiencing. Here is a more realistic in-container test.

The createUser() will created the User and verifyUser() will assert user is non null. In each test it will print out the object instance to sout.

import org.jboss.arquillian.testng.Arquillian;
import org.testng.Assert;

import org.testng.annotations.Test;

public class SimpleTestNGTest extends Arquillian
{
    private User user;

    @Test
    public void createUser()
    {
        user = createUserInTheDb();
        System.out.println( this );
    }

    @Test(dependsOnMethods = "createUser")
    public void verifyUser()
    {
        System.out.println(this);
        Assert.assertNotNull( user );
    }

    private User createUserInTheDb()
    {
        // pseudo create user
        return new User( "123", "qwe" );
    }

    class User
    {
        private String userName, password;

        User( String userName, String password )
        {
            this.userName = userName;
            this.password = password;
        }
    }
}

When the test runs in container, here is the test output.

SimpleTestNGTest@7fa0898d
SimpleTestNGTest@2e68f296
java.lang.AssertionError: expected object to not be null

Note the instances are different. Under regular TestNG test and non-suite Arquillian test they are the same. Wondering what is causing the class instances to be different while in suite Arquillian test.

@rajn

This comment has been minimized.

Copy link

@rajn rajn commented Dec 18, 2012

Hi Aslak,

Have you put this in the showcase area as has been suggested? - That way I think I can understand a little bit better. Right now I'm able to make the suite work but when I use it along with the Seam2 extension it runs into trouble.

Thanks in advance,
raj

@aslakknutsen

This comment has been minimized.

Copy link
Owner Author

@aslakknutsen aslakknutsen commented Dec 19, 2012

@rajin there was a bug in the seam2 extension that caused some issues, this should be fixed in 1.0.0.Final-SNAPSHOT. Try fetching it from the JBoss nexus repo: https://repository.jboss.org/nexus/content/groups/public/

@rajn

This comment has been minimized.

Copy link

@rajn rajn commented Dec 19, 2012

Hi Aslak,

Super! - that was it.

Thanks a bunch
raj

@carlosmunoz

This comment has been minimized.

Copy link

@carlosmunoz carlosmunoz commented Mar 1, 2013

Hi Aslak,

I'm trying to use this extension along with the Seam2 extension but I seem to be running into trouble when starting the test. I am getting the following exception:

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:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:616)
at org.jboss.arquillian.core.impl.ObserverImpl.invoke(ObserverImpl.java:90)
at org.jboss.arquillian.core.impl.EventContextImpl.invokeObservers(EventContextImpl.java:99)
at org.jboss.arquillian.core.impl.EventContextImpl.proceed(EventContextImpl.java:81)
at org.jboss.arquillian.core.impl.ManagerImpl.fire(ManagerImpl.java:135)
at org.jboss.arquillian.core.impl.ManagerImpl.fire(ManagerImpl.java:115)
at org.jboss.arquillian.core.impl.EventImpl.fire(EventImpl.java:67)
at org.drools.guvnor.arquilliansuite.ArquillianSuiteExtension$SuiteDeployer$1.call(ArquillianSuiteExtension.java:55)
at org.drools.guvnor.arquilliansuite.ArquillianSuiteExtension$SuiteDeployer$1.call(ArquillianSuiteExtension.java:53)
at org.drools.guvnor.arquilliansuite.ArquillianSuiteExtension$SuiteDeployer.executeInClassScope(ArquillianSuiteExtension.java:95)

My test is a TestNG test, but I've also tried with the JUnit runner and get the same results. Any ideas on what may be going wrong here?

@MaikelNait

This comment has been minimized.

Copy link

@MaikelNait MaikelNait commented Mar 29, 2013

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

This comment has been minimized.

Copy link

@blabno 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

This comment has been minimized.

Copy link

@blabno blabno commented Apr 15, 2013

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

@blabno

This comment has been minimized.

@lynchmaniac

This comment has been minimized.

Copy link

@lynchmaniac lynchmaniac commented May 7, 2013

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

This comment has been minimized.

Copy link

@MaikelNait MaikelNait commented May 14, 2013

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

This comment has been minimized.

Copy link

@MaikelNait MaikelNait commented May 14, 2013

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

This comment has been minimized.

Copy link

@MaikelNait MaikelNait commented May 14, 2013

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

This comment has been minimized.

Copy link

@javaG 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

This comment has been minimized.

Copy link

@asceta 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

This comment has been minimized.

Copy link

@ingwarsw ingwarsw commented Nov 26, 2013

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

This comment has been minimized.

Copy link

@suikast42 suikast42 commented Feb 1, 2014

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

This comment has been minimized.

Copy link

@KrishnaKotari KrishnaKotari commented May 2, 2014

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

This comment has been minimized.

Copy link

@KrishnaKotari KrishnaKotari commented May 2, 2014

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

This comment has been minimized.

Copy link

@perabello perabello commented Sep 17, 2014

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

This comment has been minimized.

Copy link

@Steve973 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
You can’t perform that action at this time.