From b8d2ae3a5d0935ff2ae22f1e5b22f8d4b1add5f2 Mon Sep 17 00:00:00 2001 From: Alex Soto Date: Mon, 19 Feb 2018 16:06:33 +0100 Subject: [PATCH] feat(#81): Adds annotation configuration for containers (#83) --- README.asciidoc | 90 ++++++++ arquillian-chameleon-runner/api/pom.xml | 14 ++ .../chameleon/api/ChameleonTarget.java | 82 +++++++ .../container/chameleon/api/Mode.java | 19 ++ .../container/chameleon/api/Property.java | 14 ++ arquillian-chameleon-runner/ftest/pom.xml | 52 +++++ .../container/chameleon/GreetingService.java | 10 + .../chameleon/GreetingServiceTest.java | 34 +++ .../container/chameleon/Wildfly.java | 17 ++ arquillian-chameleon-runner/pom.xml | 23 ++ arquillian-chameleon-runner/runner/pom.xml | 58 +++++ .../chameleon/runner/AnnotationExtractor.java | 59 +++++ .../chameleon/runner/ArquillianChameleon.java | 74 +++++++ ...illianChameleonConfigurationGenerator.java | 103 +++++++++ .../ArquillianChameleonConfigurator.java | 81 +++++++ .../runner/ChameleonTargetConfiguration.java | 202 ++++++++++++++++++ .../chameleon/runner/DomManipulation.java | 52 +++++ .../runner/RunnerExpressionParser.java | 62 ++++++ .../runner/SystemPropertyResolver.java | 107 ++++++++++ .../ArquillianChameleonRunnerExtension.java | 11 + .../extension/ChameleonRunnerAppender.java | 20 ++ ...boss.arquillian.core.spi.LoadableExtension | 1 + .../main/resources/arquillian_template.xml | 6 + .../src/main/resources/container_template.xml | 5 + .../runner/AnnotationExtractorTest.java | 67 ++++++ ...anChameleonConfigurationGeneratorTest.java | 153 +++++++++++++ .../ArquillianChameleonConfiguratorTest.java | 133 ++++++++++++ .../ChameleonTargetConfigurationTest.java | 135 ++++++++++++ .../runner/fixtures/GenericTest.java | 10 + .../chameleon/runner/fixtures/Tomcat.java | 17 ++ .../chameleon/runner/fixtures/Tomcat8.java | 18 ++ .../runner/fixtures/Tomcat8Test.java | 5 + .../chameleon/runner/fixtures/TomcatTest.java | 5 + .../arquillian_xml_container_extension.xml | 16 ++ .../resources/arquillian_xml_extensions.xml | 10 + pom.xml | 32 ++- 36 files changed, 1792 insertions(+), 5 deletions(-) create mode 100644 arquillian-chameleon-runner/api/pom.xml create mode 100644 arquillian-chameleon-runner/api/src/main/java/org/arquillian/container/chameleon/api/ChameleonTarget.java create mode 100644 arquillian-chameleon-runner/api/src/main/java/org/arquillian/container/chameleon/api/Mode.java create mode 100644 arquillian-chameleon-runner/api/src/main/java/org/arquillian/container/chameleon/api/Property.java create mode 100644 arquillian-chameleon-runner/ftest/pom.xml create mode 100644 arquillian-chameleon-runner/ftest/src/main/java/org/arquillian/container/chameleon/GreetingService.java create mode 100644 arquillian-chameleon-runner/ftest/src/test/java/org/arquillian/container/chameleon/GreetingServiceTest.java create mode 100644 arquillian-chameleon-runner/ftest/src/test/java/org/arquillian/container/chameleon/Wildfly.java create mode 100644 arquillian-chameleon-runner/pom.xml create mode 100644 arquillian-chameleon-runner/runner/pom.xml create mode 100644 arquillian-chameleon-runner/runner/src/main/java/org/arquillian/container/chameleon/runner/AnnotationExtractor.java create mode 100644 arquillian-chameleon-runner/runner/src/main/java/org/arquillian/container/chameleon/runner/ArquillianChameleon.java create mode 100644 arquillian-chameleon-runner/runner/src/main/java/org/arquillian/container/chameleon/runner/ArquillianChameleonConfigurationGenerator.java create mode 100644 arquillian-chameleon-runner/runner/src/main/java/org/arquillian/container/chameleon/runner/ArquillianChameleonConfigurator.java create mode 100644 arquillian-chameleon-runner/runner/src/main/java/org/arquillian/container/chameleon/runner/ChameleonTargetConfiguration.java create mode 100644 arquillian-chameleon-runner/runner/src/main/java/org/arquillian/container/chameleon/runner/DomManipulation.java create mode 100644 arquillian-chameleon-runner/runner/src/main/java/org/arquillian/container/chameleon/runner/RunnerExpressionParser.java create mode 100644 arquillian-chameleon-runner/runner/src/main/java/org/arquillian/container/chameleon/runner/SystemPropertyResolver.java create mode 100644 arquillian-chameleon-runner/runner/src/main/java/org/arquillian/container/chameleon/runner/extension/ArquillianChameleonRunnerExtension.java create mode 100644 arquillian-chameleon-runner/runner/src/main/java/org/arquillian/container/chameleon/runner/extension/ChameleonRunnerAppender.java create mode 100644 arquillian-chameleon-runner/runner/src/main/resources/META-INF/services/org.jboss.arquillian.core.spi.LoadableExtension create mode 100644 arquillian-chameleon-runner/runner/src/main/resources/arquillian_template.xml create mode 100644 arquillian-chameleon-runner/runner/src/main/resources/container_template.xml create mode 100644 arquillian-chameleon-runner/runner/src/test/java/org/arquillian/container/chameleon/runner/AnnotationExtractorTest.java create mode 100644 arquillian-chameleon-runner/runner/src/test/java/org/arquillian/container/chameleon/runner/ArquillianChameleonConfigurationGeneratorTest.java create mode 100644 arquillian-chameleon-runner/runner/src/test/java/org/arquillian/container/chameleon/runner/ArquillianChameleonConfiguratorTest.java create mode 100644 arquillian-chameleon-runner/runner/src/test/java/org/arquillian/container/chameleon/runner/ChameleonTargetConfigurationTest.java create mode 100644 arquillian-chameleon-runner/runner/src/test/java/org/arquillian/container/chameleon/runner/fixtures/GenericTest.java create mode 100644 arquillian-chameleon-runner/runner/src/test/java/org/arquillian/container/chameleon/runner/fixtures/Tomcat.java create mode 100644 arquillian-chameleon-runner/runner/src/test/java/org/arquillian/container/chameleon/runner/fixtures/Tomcat8.java create mode 100644 arquillian-chameleon-runner/runner/src/test/java/org/arquillian/container/chameleon/runner/fixtures/Tomcat8Test.java create mode 100644 arquillian-chameleon-runner/runner/src/test/java/org/arquillian/container/chameleon/runner/fixtures/TomcatTest.java create mode 100644 arquillian-chameleon-runner/runner/src/test/resources/arquillian_xml_container_extension.xml create mode 100644 arquillian-chameleon-runner/runner/src/test/resources/arquillian_xml_extensions.xml diff --git a/README.asciidoc b/README.asciidoc index 7ad945f..8941a2a 100644 --- a/README.asciidoc +++ b/README.asciidoc @@ -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 <>. + +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 +---- + + org.arquillian.container + arquillian-container-chameleon-runner + ${project.version} + test + +---- + +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`: diff --git a/arquillian-chameleon-runner/api/pom.xml b/arquillian-chameleon-runner/api/pom.xml new file mode 100644 index 0000000..03a635d --- /dev/null +++ b/arquillian-chameleon-runner/api/pom.xml @@ -0,0 +1,14 @@ + + + + arquillian-container-chameleon-runner-parent + org.arquillian.container + 1.0.0.Final-SNAPSHOT + ../pom.xml + + 4.0.0 + + arquillian-container-chameleon-runner-api + + Arquillian Container Chameleon Runner API + diff --git a/arquillian-chameleon-runner/api/src/main/java/org/arquillian/container/chameleon/api/ChameleonTarget.java b/arquillian-chameleon-runner/api/src/main/java/org/arquillian/container/chameleon/api/ChameleonTarget.java new file mode 100644 index 0000000..9868992 --- /dev/null +++ b/arquillian-chameleon-runner/api/src/main/java/org/arquillian/container/chameleon/api/ChameleonTarget.java @@ -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: + * + *
+ * {@code
+ * @Target({ ElementType.TYPE})
+ * @Retention(RetentionPolicy.RUNTIME)
+ * @Documented
+ * @Inherited
+ * @Tomcat
+ * @ChameleonTarget(version = "8.0.0")
+ * public @interface Tomcat8 {
+ * }
+ * 
+ * + * might inherit properties set from {@code Tomcat} annotation and override the version field with the one specified. + * + * And {@code Tomcat} annotation looks like: + * + *
+ * {@code
+ * @Target({ ElementType.TYPE})
+ * @Retention(RetentionPolicy.RUNTIME)
+ * @Documented
+ * @Inherited
+ * @ChameleonTarget("tomcat:7.0.0:managed")
+ * public @interface Tomcat {
+ * }
+ * 
+ * + * 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 {}; +} diff --git a/arquillian-chameleon-runner/api/src/main/java/org/arquillian/container/chameleon/api/Mode.java b/arquillian-chameleon-runner/api/src/main/java/org/arquillian/container/chameleon/api/Mode.java new file mode 100644 index 0000000..a7c29c9 --- /dev/null +++ b/arquillian-chameleon-runner/api/src/main/java/org/arquillian/container/chameleon/api/Mode.java @@ -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; + } + +} diff --git a/arquillian-chameleon-runner/api/src/main/java/org/arquillian/container/chameleon/api/Property.java b/arquillian-chameleon-runner/api/src/main/java/org/arquillian/container/chameleon/api/Property.java new file mode 100644 index 0000000..fd32e89 --- /dev/null +++ b/arquillian-chameleon-runner/api/src/main/java/org/arquillian/container/chameleon/api/Property.java @@ -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(); + +} diff --git a/arquillian-chameleon-runner/ftest/pom.xml b/arquillian-chameleon-runner/ftest/pom.xml new file mode 100644 index 0000000..4438525 --- /dev/null +++ b/arquillian-chameleon-runner/ftest/pom.xml @@ -0,0 +1,52 @@ + + + + arquillian-container-chameleon-runner-parent + org.arquillian.container + 1.0.0.Final-SNAPSHOT + ../pom.xml + + 4.0.0 + + arquillian-container-chameleon-runner-ftest + + Arquillian Container Chameleon Runner Functional Test + + + + junit + junit + test + + + + org.arquillian.container + arquillian-container-chameleon + ${project.version} + test + + + + org.arquillian.container + arquillian-container-chameleon-runner + ${project.version} + test + + + + org.jboss.arquillian.junit + arquillian-junit-container + test + + + + javax + javaee-api + 7.0 + provided + + + + + + diff --git a/arquillian-chameleon-runner/ftest/src/main/java/org/arquillian/container/chameleon/GreetingService.java b/arquillian-chameleon-runner/ftest/src/main/java/org/arquillian/container/chameleon/GreetingService.java new file mode 100644 index 0000000..9a5d7e2 --- /dev/null +++ b/arquillian-chameleon-runner/ftest/src/main/java/org/arquillian/container/chameleon/GreetingService.java @@ -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 + "!"; + } +} diff --git a/arquillian-chameleon-runner/ftest/src/test/java/org/arquillian/container/chameleon/GreetingServiceTest.java b/arquillian-chameleon-runner/ftest/src/test/java/org/arquillian/container/chameleon/GreetingServiceTest.java new file mode 100644 index 0000000..55fb92e --- /dev/null +++ b/arquillian-chameleon-runner/ftest/src/test/java/org/arquillian/container/chameleon/GreetingServiceTest.java @@ -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())); + } + +} diff --git a/arquillian-chameleon-runner/ftest/src/test/java/org/arquillian/container/chameleon/Wildfly.java b/arquillian-chameleon-runner/ftest/src/test/java/org/arquillian/container/chameleon/Wildfly.java new file mode 100644 index 0000000..814c45e --- /dev/null +++ b/arquillian-chameleon-runner/ftest/src/test/java/org/arquillian/container/chameleon/Wildfly.java @@ -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 { +} diff --git a/arquillian-chameleon-runner/pom.xml b/arquillian-chameleon-runner/pom.xml new file mode 100644 index 0000000..5e9a4c3 --- /dev/null +++ b/arquillian-chameleon-runner/pom.xml @@ -0,0 +1,23 @@ + + + + arquillian-container-chameleon-parent + org.arquillian.container + 1.0.0.Final-SNAPSHOT + ../pom.xml + + 4.0.0 + + arquillian-container-chameleon-runner-parent + pom + + + Arquillian Container Chameleon Runner Parent + + + runner + api + ftest + + + diff --git a/arquillian-chameleon-runner/runner/pom.xml b/arquillian-chameleon-runner/runner/pom.xml new file mode 100644 index 0000000..df35081 --- /dev/null +++ b/arquillian-chameleon-runner/runner/pom.xml @@ -0,0 +1,58 @@ + + + + arquillian-container-chameleon-runner-parent + org.arquillian.container + 1.0.0.Final-SNAPSHOT + ../pom.xml + + 4.0.0 + + arquillian-container-chameleon-runner + + Arquillian Container Chameleon Runner + + + + + junit + junit + compile + + + org.jboss.arquillian.junit + arquillian-junit-core + provided + + + org.jboss.arquillian.container + arquillian-container-test-spi + + + org.arquillian.container + arquillian-container-chameleon-runner-api + ${project.version} + + + org.assertj + assertj-core + test + + + org.mockito + mockito-core + test + + + com.github.stefanbirkner + system-rules + test + + + io.rest-assured + xml-path + test + + + + diff --git a/arquillian-chameleon-runner/runner/src/main/java/org/arquillian/container/chameleon/runner/AnnotationExtractor.java b/arquillian-chameleon-runner/runner/src/main/java/org/arquillian/container/chameleon/runner/AnnotationExtractor.java new file mode 100644 index 0000000..6794ca0 --- /dev/null +++ b/arquillian-chameleon-runner/runner/src/main/java/org/arquillian/container/chameleon/runner/AnnotationExtractor.java @@ -0,0 +1,59 @@ +package org.arquillian.container.chameleon.runner; + +import java.lang.annotation.Annotation; +import java.util.Arrays; +import java.util.Comparator; +import org.arquillian.container.chameleon.api.ChameleonTarget; + +public class AnnotationExtractor { + + public static ChameleonTargetConfiguration extract(Annotation annotation) { + final Class annotationType = annotation.annotationType(); + + ChameleonTargetConfiguration currentConfiguration = null; + + if (annotationType == ChameleonTarget.class) { + ChameleonTarget chameleonTarget = (ChameleonTarget) annotation; + return ChameleonTargetConfiguration.from(chameleonTarget); + } + + final Annotation[] metaAnnotations = findAndSortAnnotations(annotation); + + for (Annotation metaAnnotation : metaAnnotations) { + if (! metaAnnotation.annotationType().getName().startsWith("java.lang")) { + final ChameleonTargetConfiguration chameleonTargetConfiguration = extract(metaAnnotation); + if (currentConfiguration != null) { + currentConfiguration = currentConfiguration.importConfiguration(chameleonTargetConfiguration); + } else { + currentConfiguration = chameleonTargetConfiguration; + } + } + } + return currentConfiguration; + } + + /** + * We need to sort annotations so the first one processed is ChameleonTarget so these properties has bigger preference that the inherit ones. + * @param annotation + * @return + */ + static Annotation[] findAndSortAnnotations(Annotation annotation) { + final Annotation[] metaAnnotations = annotation.annotationType().getAnnotations(); + Arrays.sort(metaAnnotations, new Comparator() { + @Override + public int compare(Annotation o1, Annotation o2) { + if (o1 instanceof ChameleonTarget) { + return -1; + } + + if (o2 instanceof ChameleonTarget) { + return 1; + } + + return 0; + + } + }); + return metaAnnotations; + } +} diff --git a/arquillian-chameleon-runner/runner/src/main/java/org/arquillian/container/chameleon/runner/ArquillianChameleon.java b/arquillian-chameleon-runner/runner/src/main/java/org/arquillian/container/chameleon/runner/ArquillianChameleon.java new file mode 100644 index 0000000..c077e92 --- /dev/null +++ b/arquillian-chameleon-runner/runner/src/main/java/org/arquillian/container/chameleon/runner/ArquillianChameleon.java @@ -0,0 +1,74 @@ +package org.arquillian.container.chameleon.runner; + +import java.io.IOException; +import java.lang.reflect.Method; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.logging.Logger; +import org.arquillian.container.chameleon.runner.extension.ChameleonRunnerAppender; +import org.jboss.arquillian.junit.Arquillian; +import org.junit.runner.notification.RunNotifier; +import org.junit.runners.model.InitializationError; + +public class ArquillianChameleon extends Arquillian { + + private static final Logger log = Logger.getLogger(ArquillianChameleon.class.getName()); + + public ArquillianChameleon(Class testClass) throws InitializationError { + super(testClass); + } + + @Override + public void run(RunNotifier notifier) { + + Class testClass = getTestClass().getJavaClass(); + + final ClassLoader parent = Thread.currentThread().getContextClassLoader(); + + synchronized (ArquillianChameleon.class) { + if (isInClientSide(parent) && !isSpecialChameleonFile(parent)) { + + try { + Path arquillianChameleonConfiguration = + new ArquillianChameleonConfigurator().setup(testClass, parent); + + log.info(String.format("Arquillian Configuration created by Chameleon runner is placed at %s.", + arquillianChameleonConfiguration.toFile().getAbsolutePath())); + + createChameleonMarkerFile(arquillianChameleonConfiguration.getParent()); + addsArquillianFile(arquillianChameleonConfiguration.getParent(), + parent); + } catch (Exception e) { + throw new IllegalArgumentException(e); + } + } + } + super.run(notifier); + } + + + // We need to create an special file and put it inside classloader. This is because Chameleon runner adds configuration files dynamically inside the classpath. + // When you run your tests from your build tool, some or all of them shares the same classloader. So we need to avoid calling the same logic all the time to not get multiple files placed at classloader + // representing different versions, because then you have uncertainty on which configuration file is really used + private void createChameleonMarkerFile(Path parent) throws IOException { + final Path chameleon = parent.resolve("chameleonrunner"); + Files.write(chameleon, "Chameleon Runner was there".getBytes()); + } + + private boolean isSpecialChameleonFile(ClassLoader parent) { + return parent.getResource("chameleonrunner") != null; + } + + private boolean isInClientSide(ClassLoader parent) { + return parent.getResourceAsStream(ChameleonRunnerAppender.CHAMELEON_RUNNER_INCONTAINER_FILE) == null; + } + + private void addsArquillianFile(Path file, ClassLoader classLoader) throws Exception { + Method method = URLClassLoader.class.getDeclaredMethod("addURL", new Class[] {URL.class}); + method.setAccessible(true); + method.invoke(classLoader, new Object[] {file.toUri().toURL()}); + } + +} diff --git a/arquillian-chameleon-runner/runner/src/main/java/org/arquillian/container/chameleon/runner/ArquillianChameleonConfigurationGenerator.java b/arquillian-chameleon-runner/runner/src/main/java/org/arquillian/container/chameleon/runner/ArquillianChameleonConfigurationGenerator.java new file mode 100644 index 0000000..3ff8ff7 --- /dev/null +++ b/arquillian-chameleon-runner/runner/src/main/java/org/arquillian/container/chameleon/runner/ArquillianChameleonConfigurationGenerator.java @@ -0,0 +1,103 @@ +package org.arquillian.container.chameleon.runner; + +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStream; +import java.lang.annotation.Annotation; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Properties; +import javax.xml.transform.TransformerException; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +public class ArquillianChameleonConfigurationGenerator { + + static final String ARQUILLIAN_CHAMELEON_XML = "arquillianchameleon.xml"; + static final String ARQUILLIAN_XML = "arquillian.xml"; + static final String ARQUILLIAN_PROPERTIES = "arquillian.properties"; + + public Path generateNewArquillianProperties(Class testClass) throws IOException { + final ChameleonTargetConfiguration chameleonTargetConfiguration = findChameleonTargetConfiguration(testClass); + + if (chameleonTargetConfiguration != null) { + + final Properties containerDefinitionAsProperties = + chameleonTargetConfiguration.getContainerDefinitionAsProperties(); + + final Path tempDirectory = Files.createTempDirectory("chameleonContainer"); + final Path arquillianPath = tempDirectory.resolve(ARQUILLIAN_PROPERTIES); + + containerDefinitionAsProperties.store(new FileWriter(arquillianPath.toFile()), ""); + + return arquillianPath; + + } + + return null; + } + + public Path generateNewArquillianXml(Class testClass) + throws IOException, TransformerException { + final ChameleonTargetConfiguration chameleonTargetConfiguration = findChameleonTargetConfiguration(testClass); + + if (chameleonTargetConfiguration != null) { + + final Node containerDefinition = chameleonTargetConfiguration.getContainerDefinitionAsXml(); + Document arquillianConfigurationDocument = DomManipulation.createDocumentFromTemplate(); + + return generate(arquillianConfigurationDocument, containerDefinition, ARQUILLIAN_XML); + + } + + return null; + } + + public Path generateAppendedArquillianXml(Class testClass, InputStream originalArquillianXml) + throws IOException, TransformerException { + + final ChameleonTargetConfiguration chameleonTargetConfiguration = findChameleonTargetConfiguration(testClass); + + if (chameleonTargetConfiguration != null) { + + final Node containerDefinition = chameleonTargetConfiguration.getContainerDefinitionAsXml(); + Document arquillianConfigurationDocument = DomManipulation.createDocumentFromInputStream(originalArquillianXml); + + return generate(arquillianConfigurationDocument, containerDefinition, ARQUILLIAN_CHAMELEON_XML); + + } + + return null; + + } + + private Path generate(Document arquillianConfigurationDocument, Node containerDefinition, String filename) + throws IOException, TransformerException { + final Element arquillianElement = (Element) arquillianConfigurationDocument.getFirstChild(); + final Node importNode = arquillianConfigurationDocument.importNode(containerDefinition, true); + arquillianElement.appendChild(importNode); + + final Path tempDirectory = Files.createTempDirectory("chameleonContainer"); + final Path arquillianPath = tempDirectory.resolve(filename); + + DomManipulation.writeToPath(arquillianConfigurationDocument, arquillianPath); + + return arquillianPath; + } + + private ChameleonTargetConfiguration findChameleonTargetConfiguration(Class testClass) { + final Annotation[] annotations = testClass.getAnnotations(); + + for (Annotation annotation : annotations) { + final ChameleonTargetConfiguration chameleonTargetConfiguration = AnnotationExtractor.extract(annotation); + + if (chameleonTargetConfiguration != null) { + return chameleonTargetConfiguration; + } + } + + return null; + } + +} diff --git a/arquillian-chameleon-runner/runner/src/main/java/org/arquillian/container/chameleon/runner/ArquillianChameleonConfigurator.java b/arquillian-chameleon-runner/runner/src/main/java/org/arquillian/container/chameleon/runner/ArquillianChameleonConfigurator.java new file mode 100644 index 0000000..e64c505 --- /dev/null +++ b/arquillian-chameleon-runner/runner/src/main/java/org/arquillian/container/chameleon/runner/ArquillianChameleonConfigurator.java @@ -0,0 +1,81 @@ +package org.arquillian.container.chameleon.runner; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Path; +import java.util.logging.Logger; +import javax.xml.transform.TransformerException; + +public class ArquillianChameleonConfigurator { + + private static final Logger log = Logger.getLogger(ArquillianChameleonConfigurator.class.getName()); + public static final String ARQUILLIAN_XML_SYS_PROPERTY = "arquillian.xml"; + + public Path setup(Class testClass, ClassLoader parent) throws IOException, TransformerException { + + final InputStream configurationProperties = + parent.getResourceAsStream(ArquillianChameleonConfigurationGenerator.ARQUILLIAN_PROPERTIES); + + ArquillianChameleonConfigurationGenerator arquillianChameleonConfigurationGenerator = new ArquillianChameleonConfigurationGenerator(); + + Path arquillianChameleonConfiguration; + if (isArquillianConfiguredWithProperties(configurationProperties)) { + + configurationProperties.close(); + + final InputStream configurationXml = getArquillianXmlConfiguration(parent); + + if (isArquillianConfiguredWithXml(configurationXml)) { + + arquillianChameleonConfiguration = arquillianChameleonConfigurationGenerator.generateAppendedArquillianXml(testClass, configurationXml); + System.setProperty(ARQUILLIAN_XML_SYS_PROPERTY, arquillianChameleonConfiguration.getFileName().toString()); + + log.warning("Current project is configured with arquillian.properties and arquillian.xml. So we have created a custom arquillian filename and set it using a JVM System property." + + " If you are planning to run tests in parallel in same JVM, this might cause some problems. We recommend to configure Arquillian either with .proeprties or .xml file approach but not both."); + + } else { + arquillianChameleonConfiguration = + arquillianChameleonConfigurationGenerator.generateNewArquillianXml(testClass); + } + + + } else { + arquillianChameleonConfiguration = + arquillianChameleonConfigurationGenerator.generateNewArquillianProperties(testClass); + } + + return arquillianChameleonConfiguration; + } + + private InputStream getArquillianXmlConfiguration(ClassLoader parent) { + + final String customConfigurationXml = System.getProperty(ARQUILLIAN_XML_SYS_PROPERTY); + + if (customConfigurationXml != null) { + final InputStream customXml = parent.getResourceAsStream(customConfigurationXml); + + if (customXml != null) { + return customXml; + } + } + + final InputStream configurationXml = + parent.getResourceAsStream(ArquillianChameleonConfigurationGenerator.ARQUILLIAN_XML); + + if (configurationXml != null) { + return configurationXml; + } + + return null; + + } + + private boolean isArquillianConfiguredWithProperties(InputStream properties) { + return properties != null; + } + + private boolean isArquillianConfiguredWithXml(InputStream xml) { + return xml != null; + } + +} diff --git a/arquillian-chameleon-runner/runner/src/main/java/org/arquillian/container/chameleon/runner/ChameleonTargetConfiguration.java b/arquillian-chameleon-runner/runner/src/main/java/org/arquillian/container/chameleon/runner/ChameleonTargetConfiguration.java new file mode 100644 index 0000000..caaa394 --- /dev/null +++ b/arquillian-chameleon-runner/runner/src/main/java/org/arquillian/container/chameleon/runner/ChameleonTargetConfiguration.java @@ -0,0 +1,202 @@ +package org.arquillian.container.chameleon.runner; + +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import org.arquillian.container.chameleon.api.ChameleonTarget; +import org.arquillian.container.chameleon.api.Mode; +import org.arquillian.container.chameleon.api.Property; +import org.w3c.dom.Attr; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import static org.arquillian.container.chameleon.runner.RunnerExpressionParser.parseExpressions; + +public class ChameleonTargetConfiguration { + + private static final int CONTAINER = 0; + public static final int VERSION = 1; + public static final int MODE = 2; + + private String container; + private String version; + private Mode mode; + + private Map customProperties = new HashMap<>(); + + protected ChameleonTargetConfiguration(String value) { + + final String[] definition = value.split(":"); + + if (definition.length != 3) { + throw new IllegalArgumentException("Value of Chameleon expression must be of form container:version:mode. For example wildfly:9.0.0.Final:managed. " + + "Refer to https://github.com/arquillian/arquillian-container-chameleon#supported-containers for the complete list of supported containers."); + } + + this.container = definition[CONTAINER]; + this.version = definition[VERSION]; + this.mode = Mode.valueOf(definition[MODE].toUpperCase()); + + } + + protected ChameleonTargetConfiguration(String container, String version, Mode mode, + Map customProperties) { + this.container = container; + this.version = version; + this.mode = mode; + this.customProperties = customProperties; + } + + + public static ChameleonTargetConfiguration from(ChameleonTarget chameleonTarget) { + + if (isContainerNotDefinedAsString(chameleonTarget)) { + return new ChameleonTargetConfiguration( + parseExpressions(chameleonTarget.container()), + parseExpressions(chameleonTarget.version()), + Mode.valueOf(parseExpressions(chameleonTarget.mode()).toUpperCase()), + toMap(chameleonTarget.customProperties())); + } else { + final ChameleonTargetConfiguration chameleonTargetConfiguration = + new ChameleonTargetConfiguration(chameleonTarget.value()); + chameleonTargetConfiguration.customProperties = toMap(chameleonTarget.customProperties()); + + return chameleonTargetConfiguration; + } + + } + + private static boolean isContainerNotDefinedAsString(ChameleonTarget chameleonTarget) { + return chameleonTarget.value().trim().isEmpty(); + } + + private static Map toMap(Property[] properties) { + final Map map = new HashMap<>(); + for (Property property : properties) { + map.put(property.name(), parseExpressions(property.value())); + } + + return map; + } + + /** + * This methods copies attribute values that are not set in this object other object + * @param other object where attribute values are copied in case of not set in this object + * @return this object with new attribute values set + */ + public ChameleonTargetConfiguration importConfiguration(ChameleonTargetConfiguration other) { + + if (this.container == null || this.container.isEmpty()) { + this.container = other.getContainer(); + } + + if (this.version == null || this.version.isEmpty()) { + this.version = other.getVersion(); + } + + if (this.mode == null) { + this.mode = other.getMode(); + } + + final Set> entries = other.getCustomProperties().entrySet(); + + for (Map.Entry entry : entries) { + if (! this.customProperties.containsKey(entry.getKey())) { + this.customProperties.put(entry.getKey(), entry.getValue()); + } + } + + return this; + } + + public Properties getContainerDefinitionAsProperties() { + + Properties properties = new Properties(); + properties.put("arq.container.chameleon.configuration.chameleonTarget", toChameleonTarget()); + properties.put("arq.container.chameleon.default", "true"); + + updateCustomProperties(properties); + + return properties; + } + + public Node getContainerDefinitionAsXml() { + Document containerDocument = DomManipulation.createDocumentFromContainerTemplate(); + + // we can get directly the properties since template only set one container element + final NodeList properties = containerDocument.getElementsByTagName("property"); + + final Element chameleonTargetProperty = findChameleonTargetProperty(properties); + + if (chameleonTargetProperty == null) { + throw new IllegalArgumentException("No property chameleonTarget found in container template"); + } + + chameleonTargetProperty.setTextContent(toChameleonTarget()); + updateCustomProperties(containerDocument); + + return containerDocument.getFirstChild(); + + } + + private void updateCustomProperties(Properties properties) { + if (! this.customProperties.isEmpty()) { + for (Map.Entry customProperty : this.customProperties.entrySet()) { + properties.put(String.format("arq.container.chameleon.configuration.%s", customProperty.getKey()), + customProperty.getValue()); + } + } + } + + private void updateCustomProperties(Document containerDocument) { + if (! this.customProperties.isEmpty()) { + final Element configuration = (Element) containerDocument.getElementsByTagName("configuration").item(0); + + for (Map.Entry customProperty : this.customProperties.entrySet()) { + final Element customPropertyElement = containerDocument.createElement("property"); + customPropertyElement.setAttribute("name", customProperty.getKey()); + customPropertyElement.setTextContent(customProperty.getValue()); + + configuration.appendChild(customPropertyElement); + + } + } + } + + private Element findChameleonTargetProperty(NodeList properties) { + for (int i = 0; i < properties.getLength(); i++) { + final Element property = (Element) properties.item(i); + + if (property.hasAttribute("name") + && "chameleonTarget".equals(property.getAttribute("name"))) { + return property; + } + } + + return null; + } + + public String getContainer() { + return container; + } + + public String getVersion() { + return version; + } + + public Mode getMode() { + return mode; + } + + public Map getCustomProperties() { + return customProperties; + } + + public String toChameleonTarget() { + return String.format("%s:%s:%s", this.container, this.version, this.mode.mode()); + } + +} diff --git a/arquillian-chameleon-runner/runner/src/main/java/org/arquillian/container/chameleon/runner/DomManipulation.java b/arquillian-chameleon-runner/runner/src/main/java/org/arquillian/container/chameleon/runner/DomManipulation.java new file mode 100644 index 0000000..eb6bf70 --- /dev/null +++ b/arquillian-chameleon-runner/runner/src/main/java/org/arquillian/container/chameleon/runner/DomManipulation.java @@ -0,0 +1,52 @@ +package org.arquillian.container.chameleon.runner; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Path; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Result; +import javax.xml.transform.Source; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; +import org.w3c.dom.Document; +import org.xml.sax.SAXException; + +public class DomManipulation { + + public static Document createDocumentFromInputStream(InputStream inputStream) { + final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + try { + DocumentBuilder builder = factory.newDocumentBuilder(); + return builder.parse(inputStream); + } catch (ParserConfigurationException | SAXException | IOException parserException) { + throw new IllegalArgumentException(parserException); + } + } + + public static Document createDocumentFromTemplate() { + return createDocumentFromInputStream(Thread + .currentThread().getContextClassLoader() + .getResourceAsStream("arquillian_template.xml")); + } + + public static Document createDocumentFromContainerTemplate() { + return createDocumentFromInputStream(Thread + .currentThread().getContextClassLoader() + .getResourceAsStream("container_template.xml")); + } + + public static void writeToPath(Document document, Path file) throws TransformerException { + Transformer transformer = TransformerFactory.newInstance().newTransformer(); + Result output = new StreamResult(file.toFile()); + Source input = new DOMSource(document); + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); + transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2"); + transformer.transform(input, output); + } +} diff --git a/arquillian-chameleon-runner/runner/src/main/java/org/arquillian/container/chameleon/runner/RunnerExpressionParser.java b/arquillian-chameleon-runner/runner/src/main/java/org/arquillian/container/chameleon/runner/RunnerExpressionParser.java new file mode 100644 index 0000000..62df18c --- /dev/null +++ b/arquillian-chameleon-runner/runner/src/main/java/org/arquillian/container/chameleon/runner/RunnerExpressionParser.java @@ -0,0 +1,62 @@ +/* + * Copyright 2016 pact-jvm project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.arquillian.container.chameleon.runner; + +import java.util.StringJoiner; + +public class RunnerExpressionParser { + + public static final String START_EXPRESSION = "${"; + public static final char END_EXPRESSION = '}'; + + private RunnerExpressionParser() { + } + + public static String parseExpressions(final String value) { + return parseExpressions(value, new SystemPropertyResolver()); + } + + public static String parseExpressions(final String value, final SystemPropertyResolver valueResolver) { + if (value.contains(START_EXPRESSION)) { + return replaceExpressions(value, valueResolver); + } + return value; + } + + private static String replaceExpressions(final String value, final SystemPropertyResolver valueResolver) { + StringJoiner joiner = new StringJoiner(""); + + String buffer = value; + int position = buffer.indexOf(START_EXPRESSION); + while (position >= 0) { + if (position > 0) { + joiner.add(buffer.substring(0, position)); + } + int endPosition = buffer.indexOf(END_EXPRESSION, position); + if (endPosition < 0) { + throw new RuntimeException("Missing closing brace in expression string \"" + value + "]\""); + } + String expression = ""; + if (endPosition - position > 2) { + expression = valueResolver.resolveValue(buffer.substring(position + 2, endPosition)); + } + joiner.add(expression); + buffer = buffer.substring(endPosition + 1); + position = buffer.indexOf(START_EXPRESSION); + } + joiner.add(buffer); + + return joiner.toString(); + } +} diff --git a/arquillian-chameleon-runner/runner/src/main/java/org/arquillian/container/chameleon/runner/SystemPropertyResolver.java b/arquillian-chameleon-runner/runner/src/main/java/org/arquillian/container/chameleon/runner/SystemPropertyResolver.java new file mode 100644 index 0000000..343200e --- /dev/null +++ b/arquillian-chameleon-runner/runner/src/main/java/org/arquillian/container/chameleon/runner/SystemPropertyResolver.java @@ -0,0 +1,107 @@ +/* + * Copyright 2016 pact-jvm project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.arquillian.container.chameleon.runner; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class SystemPropertyResolver { + public String resolveValue(final String property) { + PropertyValueTuple tuple = new PropertyValueTuple(property).invoke(); + String propertyValue = System.getProperty(tuple.getPropertyName()); + if (propertyValue == null) { + propertyValue = System.getenv(tuple.getPropertyName()); + } + if (propertyValue == null) { + propertyValue = tuple.getDefaultValue(); + } + if (propertyValue == null) { + throw new RuntimeException("Could not resolve property \"" + tuple.getPropertyName() + + "\" in the system properties or environment variables and no default value is supplied"); + } + return propertyValue; + } + + public boolean propertyDefined(String property) { + String propertyValue = System.getProperty(property); + if (propertyValue == null) { + propertyValue = System.getenv(property); + } + return propertyValue != null; + } + + private class PropertyValueTuple { + private String propertyName; + private String defaultValue; + + PropertyValueTuple(String property) { + this.propertyName = property; + this.defaultValue = null; + } + + String getPropertyName() { + return propertyName; + } + + String getDefaultValue() { + return defaultValue; + } + + PropertyValueTuple invoke() { + if (propertyName.contains(":")) { + String[] kv = splitWorker(propertyName, ':', true); + propertyName = kv[0]; + if (kv.length > 1) { + defaultValue = String.join(":", Arrays.copyOfRange(kv, 1, kv.length)); + } + } + return this; + } + + private String[] splitWorker(final String str, final char separator, final boolean preserveAllTokens) { + // Performance tuned for 2.0 (JDK1.4) + + if (str == null) { + return null; + } + final int len = str.length(); + if (len == 0) { + return new String[0]; + } + final List list = new ArrayList(); + int i = 0, start = 0; + boolean match = false; + boolean lastMatch = false; + while (i < len) { + if (str.charAt(i) == separator) { + if (match || preserveAllTokens) { + list.add(str.substring(start, i)); + match = false; + lastMatch = true; + } + start = ++i; + continue; + } + lastMatch = false; + match = true; + i++; + } + if (match || preserveAllTokens && lastMatch) { + list.add(str.substring(start, i)); + } + return list.toArray(new String[list.size()]); + } + } +} diff --git a/arquillian-chameleon-runner/runner/src/main/java/org/arquillian/container/chameleon/runner/extension/ArquillianChameleonRunnerExtension.java b/arquillian-chameleon-runner/runner/src/main/java/org/arquillian/container/chameleon/runner/extension/ArquillianChameleonRunnerExtension.java new file mode 100644 index 0000000..66893b3 --- /dev/null +++ b/arquillian-chameleon-runner/runner/src/main/java/org/arquillian/container/chameleon/runner/extension/ArquillianChameleonRunnerExtension.java @@ -0,0 +1,11 @@ +package org.arquillian.container.chameleon.runner.extension; + +import org.jboss.arquillian.container.test.spi.client.deployment.AuxiliaryArchiveAppender; +import org.jboss.arquillian.core.spi.LoadableExtension; + +public class ArquillianChameleonRunnerExtension implements LoadableExtension { + @Override + public void register(ExtensionBuilder builder) { + builder.service(AuxiliaryArchiveAppender.class, ChameleonRunnerAppender.class); + } +} diff --git a/arquillian-chameleon-runner/runner/src/main/java/org/arquillian/container/chameleon/runner/extension/ChameleonRunnerAppender.java b/arquillian-chameleon-runner/runner/src/main/java/org/arquillian/container/chameleon/runner/extension/ChameleonRunnerAppender.java new file mode 100644 index 0000000..ad84bf1 --- /dev/null +++ b/arquillian-chameleon-runner/runner/src/main/java/org/arquillian/container/chameleon/runner/extension/ChameleonRunnerAppender.java @@ -0,0 +1,20 @@ +package org.arquillian.container.chameleon.runner.extension; + +import org.arquillian.container.chameleon.runner.ArquillianChameleon; +import org.jboss.arquillian.container.test.spi.client.deployment.AuxiliaryArchiveAppender; +import org.jboss.shrinkwrap.api.Archive; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.asset.StringAsset; +import org.jboss.shrinkwrap.api.spec.JavaArchive; + +public class ChameleonRunnerAppender implements AuxiliaryArchiveAppender { + + public static final String CHAMELEON_RUNNER_INCONTAINER_FILE = "chameleonrunner.txt"; + + @Override + public Archive createAuxiliaryArchive() { + return ShrinkWrap.create(JavaArchive.class, "arquillian-chameleon-runner.jar") + .addPackage(ArquillianChameleon.class.getPackage()) + .addAsResource(new StringAsset("test"), CHAMELEON_RUNNER_INCONTAINER_FILE); + } +} diff --git a/arquillian-chameleon-runner/runner/src/main/resources/META-INF/services/org.jboss.arquillian.core.spi.LoadableExtension b/arquillian-chameleon-runner/runner/src/main/resources/META-INF/services/org.jboss.arquillian.core.spi.LoadableExtension new file mode 100644 index 0000000..cdd6a86 --- /dev/null +++ b/arquillian-chameleon-runner/runner/src/main/resources/META-INF/services/org.jboss.arquillian.core.spi.LoadableExtension @@ -0,0 +1 @@ +org.arquillian.container.chameleon.runner.extension.ArquillianChameleonRunnerExtension diff --git a/arquillian-chameleon-runner/runner/src/main/resources/arquillian_template.xml b/arquillian-chameleon-runner/runner/src/main/resources/arquillian_template.xml new file mode 100644 index 0000000..41e2104 --- /dev/null +++ b/arquillian-chameleon-runner/runner/src/main/resources/arquillian_template.xml @@ -0,0 +1,6 @@ + + + + diff --git a/arquillian-chameleon-runner/runner/src/main/resources/container_template.xml b/arquillian-chameleon-runner/runner/src/main/resources/container_template.xml new file mode 100644 index 0000000..18e8174 --- /dev/null +++ b/arquillian-chameleon-runner/runner/src/main/resources/container_template.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/arquillian-chameleon-runner/runner/src/test/java/org/arquillian/container/chameleon/runner/AnnotationExtractorTest.java b/arquillian-chameleon-runner/runner/src/test/java/org/arquillian/container/chameleon/runner/AnnotationExtractorTest.java new file mode 100644 index 0000000..9fa2612 --- /dev/null +++ b/arquillian-chameleon-runner/runner/src/test/java/org/arquillian/container/chameleon/runner/AnnotationExtractorTest.java @@ -0,0 +1,67 @@ +package org.arquillian.container.chameleon.runner; + +import java.lang.annotation.Annotation; +import java.util.Map; +import org.arquillian.container.chameleon.api.ChameleonTarget; +import org.arquillian.container.chameleon.api.Mode; +import org.arquillian.container.chameleon.runner.fixtures.GenericTest; +import org.arquillian.container.chameleon.runner.fixtures.Tomcat; +import org.arquillian.container.chameleon.runner.fixtures.Tomcat8; +import org.arquillian.container.chameleon.runner.fixtures.Tomcat8Test; +import org.arquillian.container.chameleon.runner.fixtures.TomcatTest; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.entry; + +public class AnnotationExtractorTest { + + @Test + public void should_get_roeprties_from_chameleon_annotation() { + + // given + final ChameleonTarget chameleonTarget = GenericTest.class.getAnnotation(ChameleonTarget.class); + + // when + final ChameleonTargetConfiguration chameleonTargetConfiguration = AnnotationExtractor.extract(chameleonTarget); + + // then + assertThat(chameleonTargetConfiguration.getContainer()).isEqualTo("tomcat"); + assertThat(chameleonTargetConfiguration.getVersion()).isEqualTo("7.0.0"); + assertThat(chameleonTargetConfiguration.getMode()).isEqualTo(Mode.MANAGED); + assertThat(chameleonTargetConfiguration.getCustomProperties()).contains(entry("a", "b")); + } + + @Test + public void should__get_properties_from_meta_annotations() { + + // given + final Tomcat tomcat = TomcatTest.class.getAnnotation(Tomcat.class); + + // when + final ChameleonTargetConfiguration chameleonTargetConfiguration = AnnotationExtractor.extract(tomcat); + + // then + assertThat(chameleonTargetConfiguration.getContainer()).isEqualTo("tomcat"); + assertThat(chameleonTargetConfiguration.getVersion()).isEqualTo("7.0.0"); + assertThat(chameleonTargetConfiguration.getMode()).isEqualTo(Mode.MANAGED); + + } + + @Test + public void should_navigate_through_all_hierarchy_of_configurations() { + + // given + final Tomcat8 tomcat8 = Tomcat8Test.class.getAnnotation(Tomcat8.class); + + // when + final ChameleonTargetConfiguration chameleonTargetConfiguration = AnnotationExtractor.extract(tomcat8); + + // then + assertThat(chameleonTargetConfiguration.getContainer()).isEqualTo("tomcat"); + assertThat(chameleonTargetConfiguration.getVersion()).isEqualTo("8.0.0"); + assertThat(chameleonTargetConfiguration.getMode()).isEqualTo(Mode.MANAGED); + + } + +} diff --git a/arquillian-chameleon-runner/runner/src/test/java/org/arquillian/container/chameleon/runner/ArquillianChameleonConfigurationGeneratorTest.java b/arquillian-chameleon-runner/runner/src/test/java/org/arquillian/container/chameleon/runner/ArquillianChameleonConfigurationGeneratorTest.java new file mode 100644 index 0000000..f57e152 --- /dev/null +++ b/arquillian-chameleon-runner/runner/src/test/java/org/arquillian/container/chameleon/runner/ArquillianChameleonConfigurationGeneratorTest.java @@ -0,0 +1,153 @@ +package org.arquillian.container.chameleon.runner; + +import io.restassured.path.xml.XmlPath; +import io.restassured.path.xml.config.XmlPathConfig; +import java.io.FileReader; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Path; +import java.util.Properties; +import javax.xml.transform.TransformerException; +import org.arquillian.container.chameleon.runner.fixtures.GenericTest; +import org.assertj.core.api.Assertions; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.entry; +import static org.mockito.Mockito.when; + +public class ArquillianChameleonConfigurationGeneratorTest { + + @Test + public void should_create_a_new_arquillian_properties() throws IOException { + // given + ArquillianChameleonConfigurationGenerator arquillianChameleonConfigurationGenerator = new ArquillianChameleonConfigurationGenerator(); + + // when + final Path generateArquillianProperties = arquillianChameleonConfigurationGenerator.generateNewArquillianProperties(GenericTest.class); + + // then + assertThat(generateArquillianProperties) + .hasFileName("arquillian.properties") + .exists(); + + Properties properties = new Properties(); + properties.load(new FileReader(generateArquillianProperties.toFile())); + + assertThat(properties) + .contains(entry("arq.container.chameleon.configuration.chameleonTarget", "tomcat:7.0.0:managed")); + + } + + @Test + public void should_create_a_new_arquillian_xml() throws IOException, TransformerException { + + // given + ArquillianChameleonConfigurationGenerator arquillianChameleonConfigurationGenerator = new ArquillianChameleonConfigurationGenerator(); + + // when + final Path generatedConfigurationFile = arquillianChameleonConfigurationGenerator.generateNewArquillianXml(GenericTest.class); + + // then + assertThat(generatedConfigurationFile) + .hasFileName(ArquillianChameleonConfigurationGenerator.ARQUILLIAN_XML) + .exists(); + + final XmlPath xmlPath = new XmlPath(generatedConfigurationFile.toUri()) + .setRoot("arquillian"); + + final String target = xmlPath + .getString("container.configuration.property.find{it.@name == 'chameleonTarget'}"); + assertThat(target) + .isNotNull() + .isEqualTo("tomcat:7.0.0:managed"); + + final String a = xmlPath + .getString("container.configuration.property.find{it.@name == 'a'}"); + assertThat(a) + .isNotNull() + .isEqualTo("b"); + } + + @Test + public void should_append_configured_container_into_existing_arquillian_with_extensions() + throws IOException, TransformerException { + + // given + final InputStream arquillianXml = Thread.currentThread().getContextClassLoader() + .getResourceAsStream("arquillian_xml_extensions.xml"); + + ArquillianChameleonConfigurationGenerator arquillianChameleonConfigurationGenerator = new ArquillianChameleonConfigurationGenerator(); + + // when + final Path generatedConfigurationFile = arquillianChameleonConfigurationGenerator.generateAppendedArquillianXml(GenericTest.class, arquillianXml); + + // then + assertThat(generatedConfigurationFile) + .hasFileName(ArquillianChameleonConfigurationGenerator.ARQUILLIAN_CHAMELEON_XML) + .exists(); + + final XmlPath xmlPath = new XmlPath(generatedConfigurationFile.toUri()) + .setRoot("arquillian"); + + final String target = xmlPath + .getString("container.configuration.property.find{it.@name == 'chameleonTarget'}"); + + assertThat(target) + .isNotNull() + .isEqualTo("tomcat:7.0.0:managed"); + + final String extension = xmlPath + .getString("extension.@qualifier"); + + assertThat(extension) + .isEqualTo("docker"); + + } + + @Test + public void should_append_configured_container_into_existing_arquillian_with_extensions_and_containers() + throws IOException, TransformerException { + + // given + final InputStream arquillianXml = Thread.currentThread().getContextClassLoader() + .getResourceAsStream("arquillian_xml_container_extension.xml"); + + ArquillianChameleonConfigurationGenerator arquillianChameleonConfigurationGenerator = new ArquillianChameleonConfigurationGenerator(); + + // when + final Path generatedConfigurationFile = arquillianChameleonConfigurationGenerator.generateAppendedArquillianXml(GenericTest.class, arquillianXml); + + // then + assertThat(generatedConfigurationFile) + .exists(); + + final XmlPath xmlPath = new XmlPath(generatedConfigurationFile.toUri()) + .setRoot("arquillian"); + + final String target = xmlPath + .getString("container.configuration.property.find{it.@name == 'chameleonTarget'}"); + + assertThat(target) + .isNotNull() + .isEqualTo("tomcat:7.0.0:managed"); + + final String extension = xmlPath + .getString("extension.@qualifier"); + + assertThat(extension) + .isEqualTo("docker"); + + final String propertyOfOldContainer = xmlPath + .getString("container.configuration.property.find{it.@name == 'host'}"); + + assertThat(propertyOfOldContainer) + .isEqualTo("localhost"); + + } + +} diff --git a/arquillian-chameleon-runner/runner/src/test/java/org/arquillian/container/chameleon/runner/ArquillianChameleonConfiguratorTest.java b/arquillian-chameleon-runner/runner/src/test/java/org/arquillian/container/chameleon/runner/ArquillianChameleonConfiguratorTest.java new file mode 100644 index 0000000..c6ffa5a --- /dev/null +++ b/arquillian-chameleon-runner/runner/src/test/java/org/arquillian/container/chameleon/runner/ArquillianChameleonConfiguratorTest.java @@ -0,0 +1,133 @@ +package org.arquillian.container.chameleon.runner; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.Path; +import javax.xml.transform.TransformerException; +import org.arquillian.container.chameleon.runner.fixtures.GenericTest; +import org.junit.Rule; +import org.junit.Test; +import org.junit.contrib.java.lang.system.RestoreSystemProperties; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.entry; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class ArquillianChameleonConfiguratorTest { + + @Mock + ClassLoader classLoader; + + @Mock + InputStream file; + + @Rule + public final RestoreSystemProperties restoreSystemProperties + = new RestoreSystemProperties(); + + @Test + public void should_configure_arquillian_using_properties_if_it_is_not_configured_as_such() + throws IOException, TransformerException { + + // given + final ArquillianChameleonConfigurator arquillianChameleonConfigurator = new ArquillianChameleonConfigurator(); + when(classLoader.getResourceAsStream(ArquillianChameleonConfigurationGenerator.ARQUILLIAN_PROPERTIES)) + .thenReturn(null); + + // when + final Path setup = arquillianChameleonConfigurator.setup(GenericTest.class, classLoader); + + // then + assertThat(setup) + .hasFileName(ArquillianChameleonConfigurationGenerator.ARQUILLIAN_PROPERTIES) + .exists(); + } + + @Test + public void should_configure_arquillian_using_xml_if_it_is_not_configured_as_such_and_configured_with_properties() + throws IOException, TransformerException { + + // given + final ArquillianChameleonConfigurator arquillianChameleonConfigurator = new ArquillianChameleonConfigurator(); + when(classLoader.getResourceAsStream(ArquillianChameleonConfigurationGenerator.ARQUILLIAN_PROPERTIES)) + .thenReturn(file); + + // when + final Path setup = arquillianChameleonConfigurator.setup(GenericTest.class, classLoader); + + // then + assertThat(setup) + .hasFileName(ArquillianChameleonConfigurationGenerator.ARQUILLIAN_XML) + .exists(); + + } + + @Test + public void should_override_arquillian_using_xml_if_it_is_configured_as_such_and_configured_with_properties() + throws IOException, TransformerException { + + // given + final ArquillianChameleonConfigurator arquillianChameleonConfigurator = new ArquillianChameleonConfigurator(); + when(classLoader.getResourceAsStream(ArquillianChameleonConfigurationGenerator.ARQUILLIAN_PROPERTIES)) + .thenReturn(file); + + final InputStream arquillian = + Thread.currentThread().getContextClassLoader().getResourceAsStream("arquillian_xml_extensions.xml"); + when(classLoader.getResourceAsStream(ArquillianChameleonConfigurationGenerator.ARQUILLIAN_XML)) + .thenReturn(arquillian); + + // when + final Path setup = arquillianChameleonConfigurator.setup(GenericTest.class, classLoader); + + // then + assertThat(setup) + .hasFileName(ArquillianChameleonConfigurationGenerator.ARQUILLIAN_CHAMELEON_XML) + .exists(); + + assertThat(System.getProperties()) + .contains(entry("arquillian.xml", ArquillianChameleonConfigurationGenerator.ARQUILLIAN_CHAMELEON_XML)); + + } + + @Test + public void should_override_custom_arquillian_using_xml_if_it_is_configured_as_such_and_configured_with_properties() + throws IOException, TransformerException { + + // given + final ArquillianChameleonConfigurator arquillianChameleonConfigurator = new ArquillianChameleonConfigurator(); + when(classLoader.getResourceAsStream(ArquillianChameleonConfigurationGenerator.ARQUILLIAN_PROPERTIES)) + .thenReturn(file); + + final InputStream arquillian = + Thread.currentThread().getContextClassLoader().getResourceAsStream("arquillian_xml_extensions.xml"); + + when(classLoader.getResourceAsStream("arquillian_xml_extensions.xml")) + .thenReturn(arquillian); + + System.setProperty("arquillian.xml", "arquillian_xml_extensions.xml"); + + // when + final Path setup = arquillianChameleonConfigurator.setup(GenericTest.class, classLoader); + + // then + verify(classLoader, times(1)).getResourceAsStream("arquillian_xml_extensions.xml"); + + assertThat(setup) + .hasFileName(ArquillianChameleonConfigurationGenerator.ARQUILLIAN_CHAMELEON_XML) + .exists(); + + assertThat(System.getProperties()) + .contains(entry("arquillian.xml", ArquillianChameleonConfigurationGenerator.ARQUILLIAN_CHAMELEON_XML)); + + } + +} diff --git a/arquillian-chameleon-runner/runner/src/test/java/org/arquillian/container/chameleon/runner/ChameleonTargetConfigurationTest.java b/arquillian-chameleon-runner/runner/src/test/java/org/arquillian/container/chameleon/runner/ChameleonTargetConfigurationTest.java new file mode 100644 index 0000000..2a4e3da --- /dev/null +++ b/arquillian-chameleon-runner/runner/src/test/java/org/arquillian/container/chameleon/runner/ChameleonTargetConfigurationTest.java @@ -0,0 +1,135 @@ +package org.arquillian.container.chameleon.runner; + +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; +import org.arquillian.container.chameleon.api.Mode; +import org.junit.Test; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.entry; + +public class ChameleonTargetConfigurationTest { + + @Test + public void should_override_only_not_set_fields() { + + // given + final ChameleonTargetConfiguration containerConf = new ChameleonTargetConfiguration("tomcat", "7.0.0", Mode.MANAGED, new HashMap()); + final ChameleonTargetConfiguration modeConf = new ChameleonTargetConfiguration(null, null, Mode.EMBEDDED, new HashMap()); + + // when + final ChameleonTargetConfiguration chameleonTargetConfiguration = modeConf.importConfiguration(containerConf); + + // then + assertThat(chameleonTargetConfiguration.getContainer()).isEqualTo("tomcat"); + assertThat(chameleonTargetConfiguration.getVersion()).isEqualTo("7.0.0"); + assertThat(chameleonTargetConfiguration.getMode()).isEqualTo(Mode.EMBEDDED); + + } + + @Test + public void should_append_custom_properties() { + + // given + final Map original = new HashMap<>(); + original.put("a", "b"); + original.put("c", "d"); + + final Map newOpts = new HashMap<>(); + original.put("a", "z"); + original.put("y", "x"); + + final ChameleonTargetConfiguration containerConf = new ChameleonTargetConfiguration("tomcat", "7.0.0", Mode.MANAGED, original); + final ChameleonTargetConfiguration modeConf = new ChameleonTargetConfiguration(null, null, Mode.EMBEDDED, newOpts); + + // when + final ChameleonTargetConfiguration chameleonTargetConfiguration = modeConf.importConfiguration(containerConf); + + // then + assertThat(chameleonTargetConfiguration.getCustomProperties()) + .containsOnly(entry("a", "z"), entry("y", "x"), entry("c", "d")); + } + + @Test + public void should_generate_a_container_node_object() { + + // given + final ChameleonTargetConfiguration chameleonTargetConfiguration = + new ChameleonTargetConfiguration("tomcat:8.0.0:managed"); + + // when + final Element containerDefinition = (Element) chameleonTargetConfiguration.getContainerDefinitionAsXml(); + + // then + final NodeList properties = containerDefinition.getElementsByTagName("property"); + assertThat(properties.getLength()) + .isEqualTo(1); + assertThat(properties.item(0).getTextContent()) + .isEqualTo("tomcat:8.0.0:managed"); + } + + @Test + public void should_generate_a_container_properties_object() { + + // given + final ChameleonTargetConfiguration chameleonTargetConfiguration = + new ChameleonTargetConfiguration("tomcat:8.0.0:managed"); + + // when + final Properties containerDefinitionAsProperties = + chameleonTargetConfiguration.getContainerDefinitionAsProperties(); + + // then + assertThat(containerDefinitionAsProperties) + .contains(entry("arq.container.chameleon.configuration.chameleonTarget", "tomcat:8.0.0:managed")); + } + + @Test + public void should_generate_a_container_properties_object_with_custom_properties() { + + // given + Map customProps = new HashMap<>(); + customProps.put("a", "b"); + final ChameleonTargetConfiguration chameleonTargetConfiguration = + new ChameleonTargetConfiguration("tomcat", "8.0.0", Mode.MANAGED, customProps); + + // when + final Properties containerDefinitionAsProperties = + chameleonTargetConfiguration.getContainerDefinitionAsProperties(); + + // then + assertThat(containerDefinitionAsProperties) + .contains(entry("arq.container.chameleon.configuration.a", "b")); + } + + @Test + public void should_generate_a_container_node_object_with_custom_properties() { + + // given + Map customProps = new HashMap<>(); + customProps.put("a", "b"); + final ChameleonTargetConfiguration chameleonTargetConfiguration = + new ChameleonTargetConfiguration("tomcat", "8.0.0", Mode.MANAGED, customProps); + + // when + final Element containerDefinition = (Element) chameleonTargetConfiguration.getContainerDefinitionAsXml(); + + // then + final NodeList properties = containerDefinition.getElementsByTagName("property"); + assertThat(properties.getLength()) + .isEqualTo(2); + assertThat(properties.item(0).getTextContent()) + .isEqualTo("tomcat:8.0.0:managed"); + final Element customProperty = (Element) properties.item(1); + assertThat(customProperty.getAttribute("name")) + .isEqualTo("a"); + assertThat(customProperty.getTextContent()) + .isEqualTo("b"); + + } + +} diff --git a/arquillian-chameleon-runner/runner/src/test/java/org/arquillian/container/chameleon/runner/fixtures/GenericTest.java b/arquillian-chameleon-runner/runner/src/test/java/org/arquillian/container/chameleon/runner/fixtures/GenericTest.java new file mode 100644 index 0000000..d58ff43 --- /dev/null +++ b/arquillian-chameleon-runner/runner/src/test/java/org/arquillian/container/chameleon/runner/fixtures/GenericTest.java @@ -0,0 +1,10 @@ +package org.arquillian.container.chameleon.runner.fixtures; + +import org.arquillian.container.chameleon.api.ChameleonTarget; +import org.arquillian.container.chameleon.api.Property; + +@ChameleonTarget(container = "tomcat", version = "7.0.0", customProperties = { + @Property(name="a", value="b") +}) +public class GenericTest { +} diff --git a/arquillian-chameleon-runner/runner/src/test/java/org/arquillian/container/chameleon/runner/fixtures/Tomcat.java b/arquillian-chameleon-runner/runner/src/test/java/org/arquillian/container/chameleon/runner/fixtures/Tomcat.java new file mode 100644 index 0000000..47700d7 --- /dev/null +++ b/arquillian-chameleon-runner/runner/src/test/java/org/arquillian/container/chameleon/runner/fixtures/Tomcat.java @@ -0,0 +1,17 @@ +package org.arquillian.container.chameleon.runner.fixtures; + +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("tomcat:7.0.0:managed") +public @interface Tomcat { +} diff --git a/arquillian-chameleon-runner/runner/src/test/java/org/arquillian/container/chameleon/runner/fixtures/Tomcat8.java b/arquillian-chameleon-runner/runner/src/test/java/org/arquillian/container/chameleon/runner/fixtures/Tomcat8.java new file mode 100644 index 0000000..2f65843 --- /dev/null +++ b/arquillian-chameleon-runner/runner/src/test/java/org/arquillian/container/chameleon/runner/fixtures/Tomcat8.java @@ -0,0 +1,18 @@ +package org.arquillian.container.chameleon.runner.fixtures; + +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 +@Tomcat +@ChameleonTarget(version = "8.0.0") +public @interface Tomcat8 { +} diff --git a/arquillian-chameleon-runner/runner/src/test/java/org/arquillian/container/chameleon/runner/fixtures/Tomcat8Test.java b/arquillian-chameleon-runner/runner/src/test/java/org/arquillian/container/chameleon/runner/fixtures/Tomcat8Test.java new file mode 100644 index 0000000..c2a8206 --- /dev/null +++ b/arquillian-chameleon-runner/runner/src/test/java/org/arquillian/container/chameleon/runner/fixtures/Tomcat8Test.java @@ -0,0 +1,5 @@ +package org.arquillian.container.chameleon.runner.fixtures; + +@Tomcat8 +public class Tomcat8Test { +} diff --git a/arquillian-chameleon-runner/runner/src/test/java/org/arquillian/container/chameleon/runner/fixtures/TomcatTest.java b/arquillian-chameleon-runner/runner/src/test/java/org/arquillian/container/chameleon/runner/fixtures/TomcatTest.java new file mode 100644 index 0000000..72fb081 --- /dev/null +++ b/arquillian-chameleon-runner/runner/src/test/java/org/arquillian/container/chameleon/runner/fixtures/TomcatTest.java @@ -0,0 +1,5 @@ +package org.arquillian.container.chameleon.runner.fixtures; + +@Tomcat +public class TomcatTest { +} diff --git a/arquillian-chameleon-runner/runner/src/test/resources/arquillian_xml_container_extension.xml b/arquillian-chameleon-runner/runner/src/test/resources/arquillian_xml_container_extension.xml new file mode 100644 index 0000000..9dbaefa --- /dev/null +++ b/arquillian-chameleon-runner/runner/src/test/resources/arquillian_xml_container_extension.xml @@ -0,0 +1,16 @@ + + + + + + localhost + + + + + ${arquillian.cube.autostart} + + diff --git a/arquillian-chameleon-runner/runner/src/test/resources/arquillian_xml_extensions.xml b/arquillian-chameleon-runner/runner/src/test/resources/arquillian_xml_extensions.xml new file mode 100644 index 0000000..b666a45 --- /dev/null +++ b/arquillian-chameleon-runner/runner/src/test/resources/arquillian_xml_extensions.xml @@ -0,0 +1,10 @@ + + + + + ${arquillian.cube.autostart} + + diff --git a/pom.xml b/pom.xml index a208970..44565b4 100644 --- a/pom.xml +++ b/pom.xml @@ -23,6 +23,7 @@ arquillian-chameleon-extension arquillian-chameleon-junit-container-starter arquillian-chameleon-testng-container-starter + arquillian-chameleon-runner Arquillian Container Chameleon Parent @@ -37,18 +38,21 @@ - 1.1.15.Final + 1.2.0.Final 1.0.0.Alpha1 1.0.0.Final 2.0.4.Final 1.0.0.Alpha9 - 3.5.2 + 3.9.0 1.0 2.2.6 - 1.18 + 1.19 + 2.13.0 + 3.0.6 + 1.17.0 - 1.5 - 1.5 + 1.7 + 1.7 3.0.5 @@ -81,6 +85,24 @@ ${version.assertj} test + + org.mockito + mockito-core + ${version.mockito} + test + + + com.github.stefanbirkner + system-rules + ${version.system-rules} + test + + + io.rest-assured + xml-path + ${version.xmlpath} + test +