From 66542f54c84c403d062bea59501c5937ae22e558 Mon Sep 17 00:00:00 2001 From: Martin Kouba Date: Mon, 6 May 2019 13:44:48 +0200 Subject: [PATCH] Introduce Arquillian adapter - resolves #206 - make use of BootstrapClassLoaderFactory - register HTTPContext to make @ArquillianResource URI injectable - add TCK parent pom and skipNexusStagingDeployMojo - close the app CL after the test - add profile to run tcks --- bom/pom.xml | 5 + build-parent/pom.xml | 4 + .../arc/runtime/ConfigDeploymentTemplate.java | 10 +- pom.xml | 11 + tcks/microprofile-config/pom.xml | 57 ++++ .../java/io/quarkus/tck/config/Dummy.java | 6 + tcks/microprofile-config/tck-suite.xml | 38 +++ tcks/microprofile-health/pom.xml | 56 ++++ .../java/io/quarkus/tck/health/Dummy.java | 6 + tcks/microprofile-health/tck-suite.xml | 14 + tcks/pom.xml | 38 +++ test-framework/arquillian/pom.xml | 81 +++++ .../arquillian/QuarkusConfiguration.java | 12 + .../QuarkusDeployableContainer.java | 285 ++++++++++++++++++ .../quarkus/arquillian/QuarkusExtension.java | 15 + .../quarkus/arquillian/QuarkusProtocol.java | 98 ++++++ ...s.arquillian.container.test.spi.TestRunner | 1 + ...boss.arquillian.core.spi.LoadableExtension | 1 + .../java/io/quarkus/arquillian/test/Foo.java | 8 + .../quarkus/arquillian/test/SimpleClass.java | 17 ++ .../quarkus/arquillian/test/SimpleTest.java | 42 +++ .../arquillian/test/SimpleWarTest.java | 37 +++ test-framework/pom.xml | 1 + 23 files changed, 840 insertions(+), 3 deletions(-) create mode 100644 tcks/microprofile-config/pom.xml create mode 100644 tcks/microprofile-config/src/test/java/io/quarkus/tck/config/Dummy.java create mode 100644 tcks/microprofile-config/tck-suite.xml create mode 100644 tcks/microprofile-health/pom.xml create mode 100644 tcks/microprofile-health/src/test/java/io/quarkus/tck/health/Dummy.java create mode 100644 tcks/microprofile-health/tck-suite.xml create mode 100644 tcks/pom.xml create mode 100644 test-framework/arquillian/pom.xml create mode 100644 test-framework/arquillian/src/main/java/io/quarkus/arquillian/QuarkusConfiguration.java create mode 100644 test-framework/arquillian/src/main/java/io/quarkus/arquillian/QuarkusDeployableContainer.java create mode 100644 test-framework/arquillian/src/main/java/io/quarkus/arquillian/QuarkusExtension.java create mode 100644 test-framework/arquillian/src/main/java/io/quarkus/arquillian/QuarkusProtocol.java create mode 100644 test-framework/arquillian/src/main/resources/META-INF/services/org.jboss.arquillian.container.test.spi.TestRunner create mode 100644 test-framework/arquillian/src/main/resources/META-INF/services/org.jboss.arquillian.core.spi.LoadableExtension create mode 100644 test-framework/arquillian/src/test/java/io/quarkus/arquillian/test/Foo.java create mode 100644 test-framework/arquillian/src/test/java/io/quarkus/arquillian/test/SimpleClass.java create mode 100644 test-framework/arquillian/src/test/java/io/quarkus/arquillian/test/SimpleTest.java create mode 100644 test-framework/arquillian/src/test/java/io/quarkus/arquillian/test/SimpleWarTest.java diff --git a/bom/pom.xml b/bom/pom.xml index a4417b4d6a9c5..5038517f2847b 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -497,6 +497,11 @@ quarkus-junit5 ${project.version} + + io.quarkus + quarkus-arquillian + ${project.version} + diff --git a/build-parent/pom.xml b/build-parent/pom.xml index 999980c9c9389..ace4a2eed0cf2 100644 --- a/build-parent/pom.xml +++ b/build-parent/pom.xml @@ -59,6 +59,10 @@ 3.6.1 0.7.6 + + + 1.0 + 1.3 diff --git a/extensions/arc/runtime/src/main/java/io/quarkus/arc/runtime/ConfigDeploymentTemplate.java b/extensions/arc/runtime/src/main/java/io/quarkus/arc/runtime/ConfigDeploymentTemplate.java index 840ba1c8af081..18a898136ef08 100644 --- a/extensions/arc/runtime/src/main/java/io/quarkus/arc/runtime/ConfigDeploymentTemplate.java +++ b/extensions/arc/runtime/src/main/java/io/quarkus/arc/runtime/ConfigDeploymentTemplate.java @@ -47,9 +47,13 @@ public void validateConfigProperties(Map> properties) { if (propertyClass.isArray() || propertyClass.getTypeParameters().length > 0) { propertyClass = String.class; } - if (!config.getOptionalValue(entry.getKey(), propertyClass).isPresent()) { - throw new DeploymentException( - "No config value of type " + entry.getValue() + " exists for: " + entry.getKey()); + try { + if (!config.getOptionalValue(entry.getKey(), propertyClass).isPresent()) { + throw new DeploymentException( + "No config value of type " + entry.getValue() + " exists for: " + entry.getKey()); + } + } catch (IllegalArgumentException e) { + throw new DeploymentException(e); } } } diff --git a/pom.xml b/pom.xml index 9005d2cfac7a7..297854f1151cd 100644 --- a/pom.xml +++ b/pom.xml @@ -302,6 +302,17 @@ + + tcks + + + tcks + + + + tcks + + diff --git a/tcks/microprofile-config/pom.xml b/tcks/microprofile-config/pom.xml new file mode 100644 index 0000000000000..5e9072bd42542 --- /dev/null +++ b/tcks/microprofile-config/pom.xml @@ -0,0 +1,57 @@ + + + quarkus-tck-parent + io.quarkus + 999-SNAPSHOT + ../pom.xml + + 4.0.0 + + quarkus-tck-microprofile-config + Quarkus - TCK - MicroProfile Config + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + tck-suite.xml + + + + 45 + true + haha + woohoo + + + + false + + + + + org.eclipse.microprofile.config:microprofile-config-tck + + + + + + + + io.quarkus + quarkus-arquillian + + + org.eclipse.microprofile.config + microprofile-config-tck + ${microprofile-config-api.version} + + + + diff --git a/tcks/microprofile-config/src/test/java/io/quarkus/tck/config/Dummy.java b/tcks/microprofile-config/src/test/java/io/quarkus/tck/config/Dummy.java new file mode 100644 index 0000000000000..d92f30060de4e --- /dev/null +++ b/tcks/microprofile-config/src/test/java/io/quarkus/tck/config/Dummy.java @@ -0,0 +1,6 @@ +package io.quarkus.tck.config; + +// We need this class so that target/test-classes is added to the class path? +public class Dummy { + +} diff --git a/tcks/microprofile-config/tck-suite.xml b/tcks/microprofile-config/tck-suite.xml new file mode 100644 index 0000000000000..15ae132f1f7f2 --- /dev/null +++ b/tcks/microprofile-config/tck-suite.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tcks/microprofile-health/pom.xml b/tcks/microprofile-health/pom.xml new file mode 100644 index 0000000000000..fd81328505eb3 --- /dev/null +++ b/tcks/microprofile-health/pom.xml @@ -0,0 +1,56 @@ + + + quarkus-tck-parent + io.quarkus + 999-SNAPSHOT + ../pom.xml + + 4.0.0 + + quarkus-tck-microprofile-health + Quarkus - TCK - MicroProfile Health + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + tck-suite.xml + + + + + org.eclipse.microprofile.health:microprofile-health-tck + + + + + + + + io.quarkus + quarkus-arquillian + + + io.quarkus + quarkus-smallrye-health + + + org.eclipse.microprofile.health + microprofile-health-tck + ${microprofile-health-api.version} + + + javax.json + javax.json-api + + + + + + diff --git a/tcks/microprofile-health/src/test/java/io/quarkus/tck/health/Dummy.java b/tcks/microprofile-health/src/test/java/io/quarkus/tck/health/Dummy.java new file mode 100644 index 0000000000000..bcb9d7ef1d575 --- /dev/null +++ b/tcks/microprofile-health/src/test/java/io/quarkus/tck/health/Dummy.java @@ -0,0 +1,6 @@ +package io.quarkus.tck.health; + +// We need this class so that target/test-classes is added to the class path? +public class Dummy { + +} diff --git a/tcks/microprofile-health/tck-suite.xml b/tcks/microprofile-health/tck-suite.xml new file mode 100644 index 0000000000000..0e587929128e1 --- /dev/null +++ b/tcks/microprofile-health/tck-suite.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/tcks/pom.xml b/tcks/pom.xml new file mode 100644 index 0000000000000..2357346cca32d --- /dev/null +++ b/tcks/pom.xml @@ -0,0 +1,38 @@ + + + quarkus-build-parent + io.quarkus + 999-SNAPSHOT + ../build-parent/pom.xml + + 4.0.0 + + quarkus-tck-parent + Quarkus - TCK - Parent + pom + + + microprofile-config + microprofile-health + + + + true + + + + + + org.sonatype.plugins + nexus-staging-maven-plugin + ${nexus-staging-maven-plugin.version} + + true + + + + + + diff --git a/test-framework/arquillian/pom.xml b/test-framework/arquillian/pom.xml new file mode 100644 index 0000000000000..ce9ce02eaf194 --- /dev/null +++ b/test-framework/arquillian/pom.xml @@ -0,0 +1,81 @@ + + + + + 4.0.0 + + + io.quarkus + quarkus-test-framework + 999-SNAPSHOT + ../ + + + quarkus-arquillian + Quarkus - Arquillian Adapter + + + + + org.jboss.arquillian + arquillian-bom + 1.4.1.Final + pom + import + + + + + + + io.quarkus + quarkus-bootstrap-core + + + io.quarkus + quarkus-test-common + + + io.quarkus + quarkus-arc-deployment + + + org.jboss.arquillian.container + arquillian-container-spi + + + org.jboss.arquillian.container + arquillian-container-test-spi + + + org.jboss.arquillian.container + arquillian-container-test-impl-base + + + org.jboss.arquillian.junit + arquillian-junit-container + + + junit + junit + compile + + + + diff --git a/test-framework/arquillian/src/main/java/io/quarkus/arquillian/QuarkusConfiguration.java b/test-framework/arquillian/src/main/java/io/quarkus/arquillian/QuarkusConfiguration.java new file mode 100644 index 0000000000000..8c1590d4556be --- /dev/null +++ b/test-framework/arquillian/src/main/java/io/quarkus/arquillian/QuarkusConfiguration.java @@ -0,0 +1,12 @@ +package io.quarkus.arquillian; + +import org.jboss.arquillian.container.spi.ConfigurationException; +import org.jboss.arquillian.container.spi.client.container.ContainerConfiguration; + +public class QuarkusConfiguration implements ContainerConfiguration { + + @Override + public void validate() throws ConfigurationException { + } + +} diff --git a/test-framework/arquillian/src/main/java/io/quarkus/arquillian/QuarkusDeployableContainer.java b/test-framework/arquillian/src/main/java/io/quarkus/arquillian/QuarkusDeployableContainer.java new file mode 100644 index 0000000000000..e57c3dce2631d --- /dev/null +++ b/test-framework/arquillian/src/main/java/io/quarkus/arquillian/QuarkusDeployableContainer.java @@ -0,0 +1,285 @@ +package io.quarkus.arquillian; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Method; +import java.net.URI; +import java.net.URLClassLoader; +import java.nio.file.FileVisitResult; +import java.nio.file.FileVisitor; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.function.Consumer; + +import org.jboss.arquillian.container.spi.client.container.DeployableContainer; +import org.jboss.arquillian.container.spi.client.container.DeploymentException; +import org.jboss.arquillian.container.spi.client.container.LifecycleException; +import org.jboss.arquillian.container.spi.client.protocol.ProtocolDescription; +import org.jboss.arquillian.container.spi.client.protocol.metadata.HTTPContext; +import org.jboss.arquillian.container.spi.client.protocol.metadata.ProtocolMetaData; +import org.jboss.arquillian.container.spi.context.annotation.DeploymentScoped; +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.test.spi.TestClass; +import org.jboss.logging.Logger; +import org.jboss.shrinkwrap.api.Archive; +import org.jboss.shrinkwrap.api.exporter.ExplodedExporter; +import org.jboss.shrinkwrap.api.spec.WebArchive; +import org.jboss.shrinkwrap.descriptor.api.Descriptor; + +import io.quarkus.bootstrap.BootstrapClassLoaderFactory; +import io.quarkus.bootstrap.BootstrapException; +import io.quarkus.bootstrap.util.PropertyUtils; +import io.quarkus.builder.BuildChainBuilder; +import io.quarkus.builder.BuildContext; +import io.quarkus.builder.BuildStep; +import io.quarkus.builder.item.BuildItem; +import io.quarkus.runner.RuntimeRunner; +import io.quarkus.runtime.LaunchMode; +import io.quarkus.test.common.PathTestHelper; +import io.quarkus.test.common.TestInjectionManager; +import io.quarkus.test.common.http.TestHTTPResourceManager; + +public class QuarkusDeployableContainer implements DeployableContainer { + + private static final Logger LOGGER = Logger.getLogger(QuarkusDeployableContainer.class); + + @Inject + @DeploymentScoped + private InstanceProducer runtimeRunner; + + @Inject + @DeploymentScoped + private InstanceProducer deploymentLocation; + + @Inject + @DeploymentScoped + private InstanceProducer appClassloader; + + @Inject + private Instance testClass; + + static Object testInstance; + + @Override + public Class getConfigurationClass() { + return QuarkusConfiguration.class; + } + + @Override + public void setup(QuarkusConfiguration configuration) { + // No-op + } + + @SuppressWarnings("rawtypes") + @Override + public ProtocolMetaData deploy(Archive archive) throws DeploymentException { + if (testClass.get() == null) { + throw new IllegalStateException("Test class not available"); + } + Class testJavaClass = testClass.get().getJavaClass(); + + try { + // Export the test archive + Path tmpLocation = Files.createTempDirectory("quarkus-arquillian-test"); + deploymentLocation.set(tmpLocation); + archive.as(ExplodedExporter.class) + .exportExplodedInto(tmpLocation.toFile()); + Path appLocation; + Set libraries = new HashSet<>(); + + if (archive instanceof WebArchive) { + // Quarkus does not support the WAR layout and so adapt the layout (similarly to quarkus-war-launcher) + appLocation = tmpLocation.resolve("app").toAbsolutePath(); + //WEB-INF/lib -> lib/ + if (Files.exists(tmpLocation.resolve("WEB-INF/lib"))) { + Files.move(tmpLocation.resolve("WEB-INF/lib"), tmpLocation.resolve("lib")); + } + //WEB-INF/classes -> archive/ + if (Files.exists(tmpLocation.resolve("WEB-INF/classes"))) { + Files.move(tmpLocation.resolve("WEB-INF/classes"), appLocation); + } else { + Files.createDirectory(appLocation); + } + //META-INF -> archive/META-INF/ + if (Files.exists(tmpLocation.resolve("META-INF"))) { + Files.move(tmpLocation.resolve("META-INF"), appLocation.resolve("META-INF")); + } + //WEB-INF -> archive/WEB-INF + if (Files.exists(tmpLocation.resolve("WEB-INF"))) { + Files.move(tmpLocation.resolve("WEB-INF"), appLocation.resolve("WEB-INF")); + } + // Collect all libraries + if (Files.exists(tmpLocation.resolve("lib"))) { + Files.walk(tmpLocation.resolve("lib"), 1).forEach(libraries::add); + } + } else { + appLocation = tmpLocation; + } + + List> customizers = new ArrayList<>(); + try { + // Test class is a bean + Class buildItem = Class + .forName("io.quarkus.arc.deployment.AdditionalBeanBuildItem").asSubclass(BuildItem.class); + customizers.add(new Consumer() { + @Override + public void accept(BuildChainBuilder buildChainBuilder) { + buildChainBuilder.addBuildStep(new BuildStep() { + @Override + public void execute(BuildContext context) { + try { + Method factoryMethod = buildItem.getMethod("unremovableOf", Class.class); + context.produce((BuildItem) factoryMethod.invoke(null, testJavaClass)); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + }).produces(buildItem) + .build(); + } + }); + } catch (ClassNotFoundException e) { + throw new IllegalStateException(e); + } + + Path testClassesLocation; + try { + testClassesLocation = PathTestHelper.getTestClassesLocation(testJavaClass); + } catch (Exception e) { + // TCK tests are usually located in a dependency jar + testClassesLocation = new File("target/test-classes").toPath(); + } + + URLClassLoader appCl; + try { + BootstrapClassLoaderFactory clFactory = BootstrapClassLoaderFactory.newInstance() + .setAppClasses(appLocation) + .setParent(testJavaClass.getClassLoader()) + .setOffline(PropertyUtils.getBooleanOrNull(BootstrapClassLoaderFactory.PROP_OFFLINE)) + .setLocalProjectsDiscovery( + PropertyUtils.getBoolean(BootstrapClassLoaderFactory.PROP_WS_DISCOVERY, true)); + for (Path library : libraries) { + clFactory.addToClassPath(library); + } + appCl = clFactory.newDeploymentClassLoader(); + + } catch (BootstrapException e) { + throw new IllegalStateException("Failed to create the boostrap class loader", e); + } + + appClassloader.set(appCl); + + RuntimeRunner runner = RuntimeRunner.builder() + .setLaunchMode(LaunchMode.TEST) + .setClassLoader(appCl) + .setTarget(appLocation) + .setFrameworkClassesPath(testClassesLocation) + .addChainCustomizers(customizers) + .addAdditionalArchives(libraries) + .build(); + + runner.run(); + runtimeRunner.set(runner); + + // Instantiate the real test instance + Object actualTestInstance = Class + .forName(testJavaClass.getName(), true, Thread.currentThread().getContextClassLoader()).newInstance(); + if (actualTestInstance != null) { + TestInjectionManager.inject(actualTestInstance); + } + testInstance = actualTestInstance; + + } catch (Exception e) { + throw new DeploymentException("Unable to start the runtime runner", e); + } + + ProtocolMetaData metadata = new ProtocolMetaData(); + URI uri = URI.create(TestHTTPResourceManager.getUri()); + metadata.addContext(new HTTPContext(uri.getHost(), uri.getPort())); + return metadata; + } + + @Override + public void undeploy(Archive archive) throws DeploymentException { + testInstance = null; + URLClassLoader cl = appClassloader.get(); + if (cl != null) { + try { + cl.close(); + } catch (IOException e) { + LOGGER.warn("Unable to close the deployment classloader: " + appClassloader.get(), e); + } + } + Path location = deploymentLocation.get(); + if (location != null) { + try { + Files.walkFileTree(location, new FileVisitor() { + @Override + public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + Files.delete(file); + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException { + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { + Files.delete(dir); + return FileVisitResult.CONTINUE; + } + }); + } catch (IOException e) { + LOGGER.warn("Unable to delete the deployment dir: " + location, e); + } + } + RuntimeRunner runner = runtimeRunner.get(); + if (runner != null) { + try { + runner.close(); + } catch (IOException e) { + throw new DeploymentException("Unable to close the runtime runner", e); + } + } + } + + @Override + public void start() throws LifecycleException { + // No-op + } + + @Override + public void stop() throws LifecycleException { + // No-op + } + + @Override + public ProtocolDescription getDefaultProtocol() { + return new ProtocolDescription("Quarkus"); + } + + @Override + public void deploy(Descriptor descriptor) throws DeploymentException { + throw new UnsupportedOperationException(); + } + + @Override + public void undeploy(Descriptor descriptor) throws DeploymentException { + throw new UnsupportedOperationException(); + } + +} diff --git a/test-framework/arquillian/src/main/java/io/quarkus/arquillian/QuarkusExtension.java b/test-framework/arquillian/src/main/java/io/quarkus/arquillian/QuarkusExtension.java new file mode 100644 index 0000000000000..da8ce6f6829f2 --- /dev/null +++ b/test-framework/arquillian/src/main/java/io/quarkus/arquillian/QuarkusExtension.java @@ -0,0 +1,15 @@ +package io.quarkus.arquillian; + +import org.jboss.arquillian.container.spi.client.container.DeployableContainer; +import org.jboss.arquillian.container.test.spi.client.protocol.Protocol; +import org.jboss.arquillian.core.spi.LoadableExtension; + +public class QuarkusExtension implements LoadableExtension { + + @Override + public void register(ExtensionBuilder builder) { + builder.service(DeployableContainer.class, QuarkusDeployableContainer.class); + builder.service(Protocol.class, QuarkusProtocol.class); + } + +} diff --git a/test-framework/arquillian/src/main/java/io/quarkus/arquillian/QuarkusProtocol.java b/test-framework/arquillian/src/main/java/io/quarkus/arquillian/QuarkusProtocol.java new file mode 100644 index 0000000000000..bbdfafd060fed --- /dev/null +++ b/test-framework/arquillian/src/main/java/io/quarkus/arquillian/QuarkusProtocol.java @@ -0,0 +1,98 @@ +package io.quarkus.arquillian; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import org.jboss.arquillian.container.spi.client.protocol.ProtocolDescription; +import org.jboss.arquillian.container.spi.client.protocol.metadata.ProtocolMetaData; +import org.jboss.arquillian.container.test.impl.client.protocol.local.LocalDeploymentPackager; +import org.jboss.arquillian.container.test.impl.execution.event.LocalExecutionEvent; +import org.jboss.arquillian.container.test.spi.ContainerMethodExecutor; +import org.jboss.arquillian.container.test.spi.client.deployment.DeploymentPackager; +import org.jboss.arquillian.container.test.spi.client.protocol.Protocol; +import org.jboss.arquillian.container.test.spi.client.protocol.ProtocolConfiguration; +import org.jboss.arquillian.container.test.spi.command.CommandCallback; +import org.jboss.arquillian.core.api.Event; +import org.jboss.arquillian.core.api.Injector; +import org.jboss.arquillian.core.api.Instance; +import org.jboss.arquillian.core.api.annotation.Inject; +import org.jboss.arquillian.test.spi.TestMethodExecutor; +import org.jboss.arquillian.test.spi.TestResult; + +import io.quarkus.arquillian.QuarkusProtocol.QuarkusProtocolConfiguration; + +class QuarkusProtocol implements Protocol { + + @Inject + Instance injector; + + @Override + public Class getProtocolConfigurationClass() { + return QuarkusProtocolConfiguration.class; + } + + @Override + public ProtocolDescription getDescription() { + return new ProtocolDescription("Quarkus"); + } + + @Override + public DeploymentPackager getPackager() { + return new LocalDeploymentPackager(); + } + + @Override + public ContainerMethodExecutor getExecutor(QuarkusProtocolConfiguration protocolConfiguration, ProtocolMetaData metaData, + CommandCallback callback) { + return injector.get().inject(new QuarkusMethodExecutor()); + } + + public static class QuarkusProtocolConfiguration implements ProtocolConfiguration { + } + + static class QuarkusMethodExecutor implements ContainerMethodExecutor { + + @Inject + Event event; + + @Inject + Instance testResult; + + @Override + public TestResult invoke(TestMethodExecutor testMethodExecutor) { + + event.fire(new LocalExecutionEvent(new TestMethodExecutor() { + + @Override + public void invoke(Object... parameters) throws Throwable { + Object actualTestInstance = QuarkusDeployableContainer.testInstance; + Method actualMethod = actualTestInstance.getClass().getMethod(getMethod().getName(), + getMethod().getParameterTypes()); + try { + actualMethod.invoke(actualTestInstance, parameters); + } catch (InvocationTargetException e) { + Throwable cause = e.getCause(); + if (cause != null) { + throw cause; + } else { + throw e; + } + } + } + + @Override + public Method getMethod() { + return testMethodExecutor.getMethod(); + } + + @Override + public Object getInstance() { + return QuarkusDeployableContainer.testInstance; + } + })); + return testResult.get(); + } + + } + +} diff --git a/test-framework/arquillian/src/main/resources/META-INF/services/org.jboss.arquillian.container.test.spi.TestRunner b/test-framework/arquillian/src/main/resources/META-INF/services/org.jboss.arquillian.container.test.spi.TestRunner new file mode 100644 index 0000000000000..21eacb1849034 --- /dev/null +++ b/test-framework/arquillian/src/main/resources/META-INF/services/org.jboss.arquillian.container.test.spi.TestRunner @@ -0,0 +1 @@ +org.jboss.arquillian.junit.container.JUnitTestRunner \ No newline at end of file diff --git a/test-framework/arquillian/src/main/resources/META-INF/services/org.jboss.arquillian.core.spi.LoadableExtension b/test-framework/arquillian/src/main/resources/META-INF/services/org.jboss.arquillian.core.spi.LoadableExtension new file mode 100644 index 0000000000000..03489cc5635c3 --- /dev/null +++ b/test-framework/arquillian/src/main/resources/META-INF/services/org.jboss.arquillian.core.spi.LoadableExtension @@ -0,0 +1 @@ +io.quarkus.arquillian.QuarkusExtension \ No newline at end of file diff --git a/test-framework/arquillian/src/test/java/io/quarkus/arquillian/test/Foo.java b/test-framework/arquillian/src/test/java/io/quarkus/arquillian/test/Foo.java new file mode 100644 index 0000000000000..08504edd18cfe --- /dev/null +++ b/test-framework/arquillian/src/test/java/io/quarkus/arquillian/test/Foo.java @@ -0,0 +1,8 @@ +package io.quarkus.arquillian.test; + +import javax.enterprise.context.Dependent; + +@Dependent +public class Foo { + +} \ No newline at end of file diff --git a/test-framework/arquillian/src/test/java/io/quarkus/arquillian/test/SimpleClass.java b/test-framework/arquillian/src/test/java/io/quarkus/arquillian/test/SimpleClass.java new file mode 100644 index 0000000000000..92a180d719bf0 --- /dev/null +++ b/test-framework/arquillian/src/test/java/io/quarkus/arquillian/test/SimpleClass.java @@ -0,0 +1,17 @@ +package io.quarkus.arquillian.test; + +import javax.enterprise.context.Dependent; +import javax.inject.Inject; + +import org.eclipse.microprofile.config.Config; + +@Dependent +public class SimpleClass { + + @Inject + Config config; + + @Inject + Foo foo; + +} \ No newline at end of file diff --git a/test-framework/arquillian/src/test/java/io/quarkus/arquillian/test/SimpleTest.java b/test-framework/arquillian/src/test/java/io/quarkus/arquillian/test/SimpleTest.java new file mode 100644 index 0000000000000..ceb52b956a1f2 --- /dev/null +++ b/test-framework/arquillian/src/test/java/io/quarkus/arquillian/test/SimpleTest.java @@ -0,0 +1,42 @@ +package io.quarkus.arquillian.test; + +import static org.junit.Assert.assertNotNull; + +import javax.enterprise.context.Dependent; +import javax.inject.Inject; + +import org.eclipse.microprofile.config.Config; +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(Arquillian.class) +public class SimpleTest { + + @Deployment + public static JavaArchive createTestArchive() { + return ShrinkWrap.create(JavaArchive.class) + .addClass(SimpleClass.class); + } + + @Inject + SimpleClass simple; + + @Test + public void testRunner() { + assertNotNull(simple); + assertNotNull(simple.config); + } + + @Dependent + public static class SimpleClass { + + @Inject + Config config; + + } + +} diff --git a/test-framework/arquillian/src/test/java/io/quarkus/arquillian/test/SimpleWarTest.java b/test-framework/arquillian/src/test/java/io/quarkus/arquillian/test/SimpleWarTest.java new file mode 100644 index 0000000000000..ea2f9816db9d7 --- /dev/null +++ b/test-framework/arquillian/src/test/java/io/quarkus/arquillian/test/SimpleWarTest.java @@ -0,0 +1,37 @@ +package io.quarkus.arquillian.test; + +import static org.junit.Assert.assertNotNull; + +import javax.inject.Inject; + +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.asset.EmptyAsset; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.jboss.shrinkwrap.api.spec.WebArchive; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(Arquillian.class) +public class SimpleWarTest { + + @Deployment + public static WebArchive createTestArchive() { + return ShrinkWrap.create(WebArchive.class) + .addAsLibrary(ShrinkWrap.create(JavaArchive.class).addClass(Foo.class) + .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml")) + .addClass(SimpleClass.class); + } + + @Inject + SimpleClass simple; + + @Test + public void testRunner() { + assertNotNull(simple); + assertNotNull(simple.config); + assertNotNull(simple.foo); + } + +} diff --git a/test-framework/pom.xml b/test-framework/pom.xml index 26452e4a303a3..b3c482469627b 100644 --- a/test-framework/pom.xml +++ b/test-framework/pom.xml @@ -36,6 +36,7 @@ junit5-internal junit5 amazon-lambda + arquillian