Skip to content

Commit

Permalink
feat(#81): Adds annotation configuration for containers (#83)
Browse files Browse the repository at this point in the history
  • Loading branch information
lordofthejars committed Feb 19, 2018
1 parent 6393b52 commit b8d2ae3
Show file tree
Hide file tree
Showing 36 changed files with 1,792 additions and 5 deletions.
90 changes: 90 additions & 0 deletions README.asciidoc
Expand Up @@ -209,6 +209,96 @@ to specify a global `settings.xml` file.

The standard Maven property `-s` doesn't work as Chameleon internally uses Shrinkwrap Resolver and the property is not supported there. But you can use any of the properties described here: https://github.com/shrinkwrap/resolver#system-properties

== Arquillian Chameleon Runner

Arquillian Chameleon Container is a special container that allows you to define which container and mode without having to remember any concrete dependency of the desired container.
You've seen this at <<Get Started>>.

This approach is the most versatile one and has been here for a long time and offers a generic and global solution, but with Chameleon, you can use another approach where instead of configuring container using `arquillian.xml`, you can use an annotation to set up the test container.

The first thing to do is add next dependency:

[source, xml]
.pom.xml
----
<dependency>
<groupId>org.arquillian.container</groupId>
<artifactId>arquillian-container-chameleon-runner</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
----

Then instead of using Arquillian runner, you need to use a new one provided by Chameleon called `ArquillianChameleon`.

Then you need to annotate your test with `@ChameleonTarget("wildfly:9.0.0.Final:managed") where you set the container, version, and mode as you usually do with `chameleonTarget` in `arquillian.xml`.

But this annotation also allows you to set each of the property (even custom properties) one by one, for example:

[source, java]
----
@ChameleonTarget(container = "tomcat", version = "7.0.0", customProperties = {
@Property(name="a", value="b")
})
----

Last important thing to take into consideration is that `@ChameleonTarget` can be used in meta-annotations and inherit properties form meta-annotations.
For example, you can use next form to define `Tomcat` container:

[source, java]
.Tomcat.java
----
@Target({ ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@ChameleonTarget("tomcat:7.0.0:managed") // <1>
public @interface Tomcat {
}
----
<1> Defines container, version and mode

And then to define that the test needs to be run in `Tomcat`, you can simply do:

[source, java]
.Tomcat.java
----
@Tomcat
public class TomcatTest {
}
----

But you can even redefine meta-annotations, for example, to specify Tomcat 8 you only need to do:

[source, java]
.Tomcat8.java
----
@Target({ ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Tomcat // <1>
@ChameleonTarget(version = "8.0.0") // <2>
public @interface Tomcat8 {
}
----
<1> Inherit properties from `Tomcat` meta-annotation
<2> Override version number

All fields accept expressions like `${property:defaultValue} where property is first resolved as environment variable, if not set as the system property and if not the default value is used.

[IMPORTANT]
====
There are some limitations when using this approach.
* The first one is that test execution that occurs in the same JVM must use the same container, you cannot run in the same JVM a set of tests that require different containers (i.e some with Wildfly and others with Payara).
If you want to do this you need to isolate each of the tests in different JVMs.
* The second one is that if you are configuring extensions with `arquillian.properties` *AND* `arquillian.xml files at the same time and you run tests in parallel *within* the same JVM, then you might find some unexpected results.
Of course, this is a corner case, but a solution to this is just moving configuration of one of the files to either `arquillian.properties` or `arquillian.xml` file or run parallel tests in different JVMs.
====


== Test

To run the whole test suite with the correct configuration use profile `all`:
Expand Down
14 changes: 14 additions & 0 deletions arquillian-chameleon-runner/api/pom.xml
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>arquillian-container-chameleon-runner-parent</artifactId>
<groupId>org.arquillian.container</groupId>
<version>1.0.0.Final-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>arquillian-container-chameleon-runner-api</artifactId>

<name>Arquillian Container Chameleon Runner API</name>
</project>
@@ -0,0 +1,82 @@
package org.arquillian.container.chameleon.api;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Map;

/**
* {@code ChameleonTarget} is used to configure Chameleon container, but using an annotation instead of arquillian.xml.
*
* The annotation can be used as meta-annotation of other annotations recursively. For example:
*
* <pre>
* {@code
* @Target({ ElementType.TYPE})
* @Retention(RetentionPolicy.RUNTIME)
* @Documented
* @Inherited
* @Tomcat
* @ChameleonTarget(version = "8.0.0")
* public @interface Tomcat8 {
* }
* </pre>
*
* might inherit properties set from {@code Tomcat} annotation and override the version field with the one specified.
*
* And {@code Tomcat} annotation looks like:
*
* <pre>
* {@code
* @Target({ ElementType.TYPE})
* @Retention(RetentionPolicy.RUNTIME)
* @Documented
* @Inherited
* @ChameleonTarget("tomcat:7.0.0:managed")
* public @interface Tomcat {
* }
* </pre>
*
* All fields accept expressions like ${property:defaultValue} where {@code property} is first resolved as environment variable,
* if not set as system property and if not the default value is used.
*
*/
@Target({ ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface ChameleonTarget {

/**
* Sets Chameleon Target with form container:version:mode. For example: wildfly:9.0.0:manged.
* @return Chameleon Target
*/
String value() default "";

/**
* If {@code value} is not use, this property sets the container field.
* @return Container.
*/
String container() default "";

/**
* If {@code value} is not use, this property sets the version field.
* @return Version.
*/
String version() default "";

/**
* If {@code value} is not use, this property sets the mode field.
* @return Mode.
*/
String mode() default "managed";

/**
* Sets custom properties for container definition.
* @return Custom Properties.
*/
Property[] customProperties() default {};
}
@@ -0,0 +1,19 @@
package org.arquillian.container.chameleon.api;

public enum Mode {

EMBEDDED("embedded"),
MANAGED("managed"),
REMOTE("remote");

private String mode;

Mode(String mode) {
this.mode = mode;
}

public String mode() {
return this.mode;
}

}
@@ -0,0 +1,14 @@
package org.arquillian.container.chameleon.api;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target({})
public @interface Property {

String name();
String value();

}
52 changes: 52 additions & 0 deletions arquillian-chameleon-runner/ftest/pom.xml
@@ -0,0 +1,52 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>arquillian-container-chameleon-runner-parent</artifactId>
<groupId>org.arquillian.container</groupId>
<version>1.0.0.Final-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>arquillian-container-chameleon-runner-ftest</artifactId>

<name>Arquillian Container Chameleon Runner Functional Test</name>

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.arquillian.container</groupId>
<artifactId>arquillian-container-chameleon</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.arquillian.container</groupId>
<artifactId>arquillian-container-chameleon-runner</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.jboss.arquillian.junit</groupId>
<artifactId>arquillian-junit-container</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>

</dependencies>

</project>

@@ -0,0 +1,10 @@
package org.arquillian.container.chameleon;

import javax.enterprise.context.RequestScoped;

@RequestScoped
public class GreetingService {
public String greet(String who) {
return "Hello, " + who + "!";
}
}
@@ -0,0 +1,34 @@
package org.arquillian.container.chameleon;

import javax.inject.Inject;
import org.arquillian.container.chameleon.runner.ArquillianChameleon;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.junit.Assert.assertThat;

@Wildfly
@RunWith(ArquillianChameleon.class)
public class GreetingServiceTest {

@Deployment
public static WebArchive deployService() {
return ShrinkWrap.create(WebArchive.class)
.addClass(GreetingService.class);
}

@Inject
private GreetingService service;

@Test
public void should_get_greetings() {
assertThat(service, is(notNullValue()));
}

}
@@ -0,0 +1,17 @@
package org.arquillian.container.chameleon;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.arquillian.container.chameleon.api.ChameleonTarget;

@Target({ ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@ChameleonTarget("wildfly:9.0.0.Final:managed")
public @interface Wildfly {
}
23 changes: 23 additions & 0 deletions arquillian-chameleon-runner/pom.xml
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>arquillian-container-chameleon-parent</artifactId>
<groupId>org.arquillian.container</groupId>
<version>1.0.0.Final-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>arquillian-container-chameleon-runner-parent</artifactId>
<packaging>pom</packaging>


<name>Arquillian Container Chameleon Runner Parent</name>

<modules>
<module>runner</module>
<module>api</module>
<module>ftest</module>
</modules>

</project>

0 comments on commit b8d2ae3

Please sign in to comment.