Search in sources :

Example 1 with AugmentActionImpl

use of io.quarkus.runner.bootstrap.AugmentActionImpl in project quarkus by quarkusio.

the class QuarkusDeployableContainer method deploy.

@SuppressWarnings("rawtypes")
@Override
public ProtocolMetaData deploy(Archive<?> archive) throws DeploymentException {
    old = Thread.currentThread().getContextClassLoader();
    if (testClass.get() == null) {
        throw new IllegalStateException("Test class not available");
    }
    Class testJavaClass = testClass.get().getJavaClass();
    // some TCK tests embed random libraries such as old versions of Jackson databind
    // this breaks quarkus, so we just skip them
    boolean skipLibraries = Boolean.getBoolean("io.quarkus.arquillian.skip-libraries");
    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<Path> 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 (!skipLibraries) {
                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"))) {
                if (Files.exists(appLocation.resolve("META-INF"))) {
                    // Target directory not empty.
                    try (Stream<Path> fileTreeElements = Files.walk(tmpLocation.resolve("META-INF"), 2)) {
                        fileTreeElements.forEach(p -> {
                            try {
                                Files.createFile(p);
                            } catch (FileAlreadyExistsException faee) {
                            // Do Nothing
                            } catch (IOException e) {
                                throw new RuntimeException(e);
                            }
                        });
                    }
                } else {
                    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"))) {
                try (Stream<Path> libs = Files.walk(tmpLocation.resolve("lib"), 1)) {
                    libs.forEach((i) -> {
                        if (i.getFileName().toString().endsWith(".jar")) {
                            libraries.add(i);
                        }
                    });
                }
            }
        } else {
            appLocation = tmpLocation;
        }
        List<Consumer<BuildChainBuilder>> customizers = new ArrayList<>();
        // Test class is a bean
        customizers.add(new Consumer<BuildChainBuilder>() {

            @Override
            public void accept(BuildChainBuilder buildChainBuilder) {
                buildChainBuilder.addBuildStep(new BuildStep() {

                    @Override
                    public void execute(BuildContext context) {
                        context.produce(AdditionalBeanBuildItem.unremovableOf(testJavaClass));
                    }
                }).produces(AdditionalBeanBuildItem.class).build();
            }
        });
        QuarkusBootstrap.Builder bootstrapBuilder = QuarkusBootstrap.builder().setApplicationRoot(appLocation).setProjectRoot(appLocation).setIsolateDeployment(false).setFlatClassPath(true).setMode(QuarkusBootstrap.Mode.TEST);
        for (Path i : libraries) {
            bootstrapBuilder.addAdditionalApplicationArchive(new AdditionalDependency(i, false, true));
        }
        // Path testLocation = PathTestHelper.getTestClassesLocation(testJavaClass);
        // bootstrapBuilder.setProjectRoot(PathTestHelper.getTestClassesLocation(testJavaClass));
        CuratedApplication curatedApplication = bootstrapBuilder.build().bootstrap();
        AugmentAction augmentAction = new AugmentActionImpl(curatedApplication, customizers);
        StartupAction app = augmentAction.createInitialRuntimeApplication();
        RunningQuarkusApplication runningQuarkusApplication = app.run();
        appClassloader.set(runningQuarkusApplication.getClassLoader());
        runningApp.set(runningQuarkusApplication);
        Thread.currentThread().setContextClassLoader(runningQuarkusApplication.getClassLoader());
        // Instantiate the real test instance
        testInstance = TestInstantiator.instantiateTest(testJavaClass, runningQuarkusApplication.getClassLoader());
        // its pretty bogus
        if (Boolean.getBoolean("io.quarkus.arquillian.copy-fields")) {
            Class<?> dest = testInstance.getClass();
            Class<?> source = testClass.get().getJavaClass();
            while (source != Object.class) {
                for (Field f : source.getDeclaredFields()) {
                    try {
                        if (Modifier.isStatic(f.getModifiers()) && !Modifier.isFinal(f.getModifiers())) {
                            Field df = dest.getDeclaredField(f.getName());
                            df.setAccessible(true);
                            f.setAccessible(true);
                            df.set(null, f.get(null));
                        }
                    } catch (Exception e) {
                        LOGGER.error("Failed to copy static field", e);
                    }
                }
                source = source.getSuperclass();
                dest = dest.getSuperclass();
            }
        }
    } catch (Throwable t) {
        // clone the exception into the correct class loader
        Throwable nt;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        try (ObjectOutputStream a = new ObjectOutputStream(out)) {
            a.writeObject(t);
            a.close();
            nt = (Throwable) new ObjectInputStream(new ByteArrayInputStream(out.toByteArray())).readObject();
        } catch (Exception e) {
            throw new DeploymentException("Unable to start the runtime runner", t);
        }
        throw new DeploymentException("Unable to start the runtime runner", nt);
    } finally {
        Thread.currentThread().setContextClassLoader(old);
    }
    ProtocolMetaData metadata = new ProtocolMetaData();
    // TODO: fix this
    String testUri = TestHTTPResourceManager.getUri(runningApp.get());
    System.setProperty("test.url", testUri);
    URI uri = URI.create(testUri);
    HTTPContext httpContext = new HTTPContext(uri.getHost(), uri.getPort());
    // This is to work around https://github.com/arquillian/arquillian-core/issues/216
    httpContext.add(new Servlet("dummy", "/"));
    metadata.addContext(httpContext);
    return metadata;
}
Also used : FileAlreadyExistsException(java.nio.file.FileAlreadyExistsException) ArrayList(java.util.ArrayList) BuildStep(io.quarkus.builder.BuildStep) ObjectOutputStream(java.io.ObjectOutputStream) URI(java.net.URI) Field(java.lang.reflect.Field) Consumer(java.util.function.Consumer) Servlet(org.jboss.arquillian.container.spi.client.protocol.metadata.Servlet) AdditionalDependency(io.quarkus.bootstrap.app.AdditionalDependency) ProtocolMetaData(org.jboss.arquillian.container.spi.client.protocol.metadata.ProtocolMetaData) ExplodedExporter(org.jboss.shrinkwrap.api.exporter.ExplodedExporter) HashSet(java.util.HashSet) AugmentActionImpl(io.quarkus.runner.bootstrap.AugmentActionImpl) Path(java.nio.file.Path) AugmentAction(io.quarkus.bootstrap.app.AugmentAction) StartupAction(io.quarkus.bootstrap.app.StartupAction) RunningQuarkusApplication(io.quarkus.bootstrap.app.RunningQuarkusApplication) WebArchive(org.jboss.shrinkwrap.api.spec.WebArchive) HTTPContext(org.jboss.arquillian.container.spi.client.protocol.metadata.HTTPContext) IOException(java.io.IOException) ByteArrayOutputStream(java.io.ByteArrayOutputStream) LifecycleException(org.jboss.arquillian.container.spi.client.container.LifecycleException) IOException(java.io.IOException) FileAlreadyExistsException(java.nio.file.FileAlreadyExistsException) DeploymentException(org.jboss.arquillian.container.spi.client.container.DeploymentException) BuildContext(io.quarkus.builder.BuildContext) BuildChainBuilder(io.quarkus.builder.BuildChainBuilder) CuratedApplication(io.quarkus.bootstrap.app.CuratedApplication) ByteArrayInputStream(java.io.ByteArrayInputStream) QuarkusBootstrap(io.quarkus.bootstrap.app.QuarkusBootstrap) TestClass(org.jboss.arquillian.test.spi.TestClass) DeploymentException(org.jboss.arquillian.container.spi.client.container.DeploymentException) ObjectInputStream(java.io.ObjectInputStream)

Example 2 with AugmentActionImpl

use of io.quarkus.runner.bootstrap.AugmentActionImpl in project quarkus by quarkusio.

the class IsolatedDevModeMain method accept.

// the main entry point, but loaded inside the augmentation class loader
@Override
public void accept(CuratedApplication o, Map<String, Object> params) {
    // setup the dev mode thread pool for NIO
    System.setProperty("java.nio.channels.DefaultThreadPool.threadFactory", "io.quarkus.dev.io.NioThreadPoolThreadFactory");
    Timing.staticInitStarted(o.getBaseRuntimeClassLoader(), false);
    // https://github.com/quarkusio/quarkus/issues/9748
    // if you have an app with all daemon threads then the app thread
    // may be the only thread keeping the JVM alive
    // during the restart process when this thread is stopped then
    // the JVM will die
    // we start this thread to keep the JVM alive until the shutdown hook is run
    // even for command mode we still want the JVM to live until it receives
    // a signal to make the 'press enter to restart' function to work
    new Thread(new Runnable() {

        @Override
        public void run() {
            try {
                shutdownLatch.await();
            } catch (InterruptedException ignore) {
            }
        }
    }, "Quarkus Devmode keep alive thread").start();
    try {
        curatedApplication = o;
        Object potentialContext = params.get(DevModeContext.class.getName());
        if (potentialContext instanceof DevModeContext) {
            context = (DevModeContext) potentialContext;
        } else {
            // this was from the external class loader
            // we need to copy it into this one
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            ObjectOutputStream oo = new ObjectOutputStream(out);
            oo.writeObject(potentialContext);
            context = (DevModeContext) new ObjectInputStream(new ByteArrayInputStream(out.toByteArray())).readObject();
        }
        augmentAction = new AugmentActionImpl(curatedApplication, Collections.singletonList(new Consumer<BuildChainBuilder>() {

            @Override
            public void accept(BuildChainBuilder buildChainBuilder) {
                buildChainBuilder.addBuildStep(new BuildStep() {

                    @Override
                    public void execute(BuildContext context) {
                        // we need to make sure all hot reloadable classes are application classes
                        context.produce(new ApplicationClassPredicateBuildItem(new Predicate<String>() {

                            @Override
                            public boolean test(String s) {
                                QuarkusClassLoader cl = (QuarkusClassLoader) Thread.currentThread().getContextClassLoader();
                                // if the class file is present in this (and not the parent) CL then it is an application class
                                List<ClassPathElement> res = cl.getElementsWithResource(s.replace('.', '/') + ".class", true);
                                return !res.isEmpty();
                            }
                        }));
                    }
                }).produces(ApplicationClassPredicateBuildItem.class).build();
            }
        }), Collections.emptyList());
        List<CodeGenData> codeGens = new ArrayList<>();
        QuarkusClassLoader deploymentClassLoader = curatedApplication.createDeploymentClassLoader();
        for (DevModeContext.ModuleInfo module : context.getAllModules()) {
            if (!module.getSourceParents().isEmpty() && module.getPreBuildOutputDir() != null) {
                // it's null for remote dev
                codeGens.addAll(CodeGenerator.init(deploymentClassLoader, module.getSourceParents(), Paths.get(module.getPreBuildOutputDir()), Paths.get(module.getTargetDir()), sourcePath -> module.addSourcePathFirst(sourcePath.toAbsolutePath().toString())));
            }
        }
        RuntimeUpdatesProcessor.INSTANCE = setupRuntimeCompilation(context, (Path) params.get(APP_ROOT), (DevModeType) params.get(DevModeType.class.getName()));
        if (RuntimeUpdatesProcessor.INSTANCE != null) {
            RuntimeUpdatesProcessor.INSTANCE.checkForFileChange();
            RuntimeUpdatesProcessor.INSTANCE.checkForChangedClasses(true);
        }
        firstStart(deploymentClassLoader, codeGens);
        // doStart(false, Collections.emptySet());
        if (deploymentProblem != null || RuntimeUpdatesProcessor.INSTANCE.getCompileProblem() != null) {
            if (context.isAbortOnFailedStart()) {
                throw new RuntimeException(deploymentProblem == null ? RuntimeUpdatesProcessor.INSTANCE.getCompileProblem() : deploymentProblem);
            }
        }
        shutdownThread = new Thread(new Runnable() {

            @Override
            public void run() {
                shutdownLatch.countDown();
                synchronized (DevModeMain.class) {
                    if (runner != null) {
                        try {
                            close();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }, "Quarkus Shutdown Thread");
        Runtime.getRuntime().addShutdownHook(shutdownThread);
    } catch (Exception e) {
        close();
        throw new RuntimeException(e);
    }
}
Also used : BiFunction(java.util.function.BiFunction) ObjectInputStream(java.io.ObjectInputStream) ClassTransformingBuildStep(io.quarkus.deployment.steps.ClassTransformingBuildStep) CommandLineUtils(org.apache.maven.shared.utils.cli.CommandLineUtils) ConfigProviderResolver(org.eclipse.microprofile.config.spi.ConfigProviderResolver) ApplicationLifecycleManager(io.quarkus.runtime.ApplicationLifecycleManager) ByteArrayInputStream(java.io.ByteArrayInputStream) Map(java.util.Map) AugmentAction(io.quarkus.bootstrap.app.AugmentAction) ConsoleStateManager(io.quarkus.deployment.console.ConsoleStateManager) DevConsoleManager(io.quarkus.dev.console.DevConsoleManager) InitialConfigurator(io.quarkus.bootstrap.logging.InitialConfigurator) Path(java.nio.file.Path) ConsoleHandler(org.jboss.logmanager.handlers.ConsoleHandler) LoggingSetupRecorder(io.quarkus.runtime.logging.LoggingSetupRecorder) Predicate(java.util.function.Predicate) Collection(java.util.Collection) AugmentActionImpl(io.quarkus.runner.bootstrap.AugmentActionImpl) Set(java.util.Set) BLUE(io.quarkus.deployment.dev.testing.MessageFormat.BLUE) ServiceLoader(java.util.ServiceLoader) QuarkusClassLoader(io.quarkus.bootstrap.classloading.QuarkusClassLoader) StartupAction(io.quarkus.bootstrap.app.StartupAction) CountDownLatch(java.util.concurrent.CountDownLatch) List(java.util.List) MessageFormat(io.quarkus.deployment.dev.testing.MessageFormat) BuildStep(io.quarkus.builder.BuildStep) ColorPatternFormatter(org.jboss.logmanager.formatters.ColorPatternFormatter) BuildContext(io.quarkus.builder.BuildContext) CuratedApplication(io.quarkus.bootstrap.app.CuratedApplication) ByteArrayOutputStream(java.io.ByteArrayOutputStream) RunningQuarkusApplication(io.quarkus.bootstrap.app.RunningQuarkusApplication) DevModeType(io.quarkus.dev.spi.DevModeType) Logger(org.jboss.logging.Logger) DeploymentFailedStartHandler(io.quarkus.dev.spi.DeploymentFailedStartHandler) LaunchMode(io.quarkus.runtime.LaunchMode) ClassChangeInformation(io.quarkus.bootstrap.app.ClassChangeInformation) Timing(io.quarkus.bootstrap.runner.Timing) BindException(java.net.BindException) TestSupport(io.quarkus.deployment.dev.testing.TestSupport) CodeGenData(io.quarkus.deployment.codegen.CodeGenData) ArrayList(java.util.ArrayList) BuildChainBuilder(io.quarkus.builder.BuildChainBuilder) ApplicationClassPredicateBuildItem(io.quarkus.deployment.builditem.ApplicationClassPredicateBuildItem) BiConsumer(java.util.function.BiConsumer) ObjectOutputStream(java.io.ObjectOutputStream) ApplicationStartException(io.quarkus.dev.appstate.ApplicationStartException) QuarkusConfigFactory(io.quarkus.runtime.configuration.QuarkusConfigFactory) HotReplacementSetup(io.quarkus.dev.spi.HotReplacementSetup) Properties(java.util.Properties) ClassPathElement(io.quarkus.bootstrap.classloading.ClassPathElement) CommandLineException(org.apache.maven.shared.utils.cli.CommandLineException) IOException(java.io.IOException) ConsoleCommand(io.quarkus.deployment.console.ConsoleCommand) Consumer(java.util.function.Consumer) Paths(java.nio.file.Paths) Closeable(java.io.Closeable) CodeGenerator(io.quarkus.deployment.CodeGenerator) Comparator(java.util.Comparator) FSWatchUtil(io.quarkus.deployment.util.FSWatchUtil) Collections(java.util.Collections) ArrayList(java.util.ArrayList) ClassTransformingBuildStep(io.quarkus.deployment.steps.ClassTransformingBuildStep) BuildStep(io.quarkus.builder.BuildStep) ApplicationClassPredicateBuildItem(io.quarkus.deployment.builditem.ApplicationClassPredicateBuildItem) ClassPathElement(io.quarkus.bootstrap.classloading.ClassPathElement) ObjectOutputStream(java.io.ObjectOutputStream) Predicate(java.util.function.Predicate) AugmentActionImpl(io.quarkus.runner.bootstrap.AugmentActionImpl) Path(java.nio.file.Path) CodeGenData(io.quarkus.deployment.codegen.CodeGenData) ByteArrayOutputStream(java.io.ByteArrayOutputStream) QuarkusClassLoader(io.quarkus.bootstrap.classloading.QuarkusClassLoader) BindException(java.net.BindException) ApplicationStartException(io.quarkus.dev.appstate.ApplicationStartException) CommandLineException(org.apache.maven.shared.utils.cli.CommandLineException) IOException(java.io.IOException) BuildContext(io.quarkus.builder.BuildContext) ByteArrayInputStream(java.io.ByteArrayInputStream) BuildChainBuilder(io.quarkus.builder.BuildChainBuilder) DevModeType(io.quarkus.dev.spi.DevModeType) ObjectInputStream(java.io.ObjectInputStream)

Example 3 with AugmentActionImpl

use of io.quarkus.runner.bootstrap.AugmentActionImpl in project quarkus by quarkusio.

the class IsolatedTestModeMain method accept.

// the main entry point, but loaded inside the augmentation class loader
@Override
public void accept(CuratedApplication o, Map<String, Object> params) {
    System.setProperty("java.nio.channels.DefaultThreadPool.threadFactory", "io.quarkus.dev.io.NioThreadPoolThreadFactory");
    Timing.staticInitStarted(o.getBaseRuntimeClassLoader(), false);
    try {
        curatedApplication = o;
        Object potentialContext = params.get(DevModeContext.class.getName());
        if (potentialContext instanceof DevModeContext) {
            context = (DevModeContext) potentialContext;
        } else {
            // this was from the external class loader
            // we need to copy it into this one
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            ObjectOutputStream oo = new ObjectOutputStream(out);
            oo.writeObject(potentialContext);
            context = (DevModeContext) new ObjectInputStream(new ByteArrayInputStream(out.toByteArray())).readObject();
        }
        augmentAction = new AugmentActionImpl(curatedApplication);
        RuntimeUpdatesProcessor.INSTANCE = setupRuntimeCompilation(context, (Path) params.get(APP_ROOT));
        if (RuntimeUpdatesProcessor.INSTANCE != null) {
            RuntimeUpdatesProcessor.INSTANCE.checkForFileChange();
            RuntimeUpdatesProcessor.INSTANCE.checkForChangedClasses(true);
        }
        try {
            augmentAction.performCustomBuild(TestHandler.class.getName(), null, TestSetupBuildItem.class.getName(), LoggingSetupBuildItem.class.getName(), ConsoleFormatterBannerBuildItem.class.getName());
        } catch (Throwable t) {
            // logging may not have been started, this is more reliable
            System.err.println("Failed to start quarkus test mode");
            t.printStackTrace();
            System.exit(1);
        }
        Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {

            @Override
            public void run() {
                synchronized (DevModeMain.class) {
                    try {
                        close();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }, "Quarkus Shutdown Thread"));
        Quarkus.waitForExit();
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}
Also used : Path(java.nio.file.Path) LoggingSetupBuildItem(io.quarkus.deployment.logging.LoggingSetupBuildItem) ByteArrayOutputStream(java.io.ByteArrayOutputStream) ObjectOutputStream(java.io.ObjectOutputStream) IOException(java.io.IOException) ByteArrayInputStream(java.io.ByteArrayInputStream) ConsoleFormatterBannerBuildItem(io.quarkus.deployment.builditem.ConsoleFormatterBannerBuildItem) TestHandler(io.quarkus.deployment.dev.testing.TestHandler) TestSetupBuildItem(io.quarkus.deployment.dev.testing.TestSetupBuildItem) ObjectInputStream(java.io.ObjectInputStream) AugmentActionImpl(io.quarkus.runner.bootstrap.AugmentActionImpl)

Example 4 with AugmentActionImpl

use of io.quarkus.runner.bootstrap.AugmentActionImpl in project quarkus by quarkusio.

the class IsolatedRemoteDevModeMain method accept.

// the main entry point, but loaded inside the augmentation class loader
@Override
public void accept(CuratedApplication o, Map<String, Object> o2) {
    // we are not going to actually run an app
    LoggingSetupRecorder.handleFailedStart();
    Timing.staticInitStarted(o.getBaseRuntimeClassLoader(), false);
    try {
        curatedApplication = o;
        Object potentialContext = o2.get(DevModeContext.class.getName());
        if (potentialContext instanceof DevModeContext) {
            context = (DevModeContext) potentialContext;
        } else {
            // this was from the external class loader
            // we need to copy it into this one
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            ObjectOutputStream oo = new ObjectOutputStream(out);
            oo.writeObject(potentialContext);
            context = (DevModeContext) new ObjectInputStream(new ByteArrayInputStream(out.toByteArray())).readObject();
        }
        augmentAction = new AugmentActionImpl(curatedApplication);
        RuntimeUpdatesProcessor.INSTANCE = setupRuntimeCompilation(context, appRoot);
        if (RuntimeUpdatesProcessor.INSTANCE != null) {
            RuntimeUpdatesProcessor.INSTANCE.checkForFileChange();
            RuntimeUpdatesProcessor.INSTANCE.checkForChangedClasses(true);
        }
        JarResult result = generateApplication();
        if (result != null) {
            appRoot = result.getPath().getParent();
            currentHashes = createHashes(appRoot);
        }
        remoteDevClient = createClient(curatedApplication);
        remoteDevClientSession = doConnect();
        Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {

            @Override
            public void run() {
                synchronized (DevModeMain.class) {
                    try {
                        close();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }, "Quarkus Shutdown Thread"));
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}
Also used : ByteArrayOutputStream(java.io.ByteArrayOutputStream) JarResult(io.quarkus.bootstrap.app.JarResult) ObjectOutputStream(java.io.ObjectOutputStream) IOException(java.io.IOException) ByteArrayInputStream(java.io.ByteArrayInputStream) ObjectInputStream(java.io.ObjectInputStream) AugmentActionImpl(io.quarkus.runner.bootstrap.AugmentActionImpl)

Example 5 with AugmentActionImpl

use of io.quarkus.runner.bootstrap.AugmentActionImpl in project quarkus by quarkusio.

the class QuarkusUnitTest method beforeAll.

@Override
public void beforeAll(ExtensionContext extensionContext) throws Exception {
    // set the right launch mode in the outer CL, used by the HTTP host config source
    ProfileManager.setLaunchMode(LaunchMode.TEST);
    if (beforeAllCustomizer != null) {
        beforeAllCustomizer.run();
    }
    originalClassLoader = Thread.currentThread().getContextClassLoader();
    originalHandlers = rootLogger.getHandlers();
    rootLogger.addHandler(inMemoryLogHandler);
    timeoutTask = new TimerTask() {

        @Override
        public void run() {
            System.err.println("Test has been running for more than 5 minutes, thread dump is:");
            for (Map.Entry<Thread, StackTraceElement[]> i : Thread.getAllStackTraces().entrySet()) {
                System.err.println("\n");
                System.err.println(i.toString());
                System.err.println("\n");
                for (StackTraceElement j : i.getValue()) {
                    System.err.println(j);
                }
            }
        }
    };
    timeoutTimer = new Timer("Test thread dump timer");
    timeoutTimer.schedule(timeoutTask, 1000 * 60 * 5);
    if (logFileName != null) {
        PropertyTestUtil.setLogFileProperty(logFileName);
    } else {
        PropertyTestUtil.setLogFileProperty();
    }
    ExtensionContext.Store store = extensionContext.getRoot().getStore(ExtensionContext.Namespace.GLOBAL);
    ExclusivityChecker.checkTestType(extensionContext, QuarkusUnitTest.class);
    TestResourceManager testResourceManager = (TestResourceManager) store.get(TestResourceManager.class.getName());
    if (testResourceManager == null) {
        testResourceManager = new TestResourceManager(extensionContext.getRequiredTestClass());
        testResourceManager.init(null);
        testResourceManager.start();
        TestResourceManager tm = testResourceManager;
        store.put(TestResourceManager.class.getName(), testResourceManager);
        store.put(TestResourceManager.CLOSEABLE_NAME, new ExtensionContext.Store.CloseableResource() {

            @Override
            public void close() throws Throwable {
                tm.close();
            }
        });
    }
    Class<?> testClass = extensionContext.getRequiredTestClass();
    try {
        deploymentDir = Files.createTempDirectory("quarkus-unit-test");
        exportArchives(deploymentDir, testClass);
        List<Consumer<BuildChainBuilder>> customizers = new ArrayList<>(buildChainCustomizers);
        try {
            // this is a bit of a hack to avoid requiring a dep on the arc extension,
            // as this would mean we cannot use this to test the extension
            Class<? extends BuildItem> buildItem = Class.forName("io.quarkus.arc.deployment.AdditionalBeanBuildItem").asSubclass(BuildItem.class);
            customizers.add(new Consumer<BuildChainBuilder>() {

                @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, testClass));
                            } catch (Exception e) {
                                throw new RuntimeException(e);
                            }
                        }
                    }).produces(buildItem).build();
                    buildChainBuilder.addBuildStep(new BuildStep() {

                        @Override
                        public void execute(BuildContext context) {
                            // we need to make sure all hot reloadable classes are application classes
                            context.produce(new ApplicationClassPredicateBuildItem(new Predicate<String>() {

                                @Override
                                public boolean test(String s) {
                                    QuarkusClassLoader cl = (QuarkusClassLoader) Thread.currentThread().getContextClassLoader();
                                    // if the class file is present in this (and not the parent) CL then it is an application class
                                    List<ClassPathElement> res = cl.getElementsWithResource(s.replace(".", "/") + ".class", true);
                                    return !res.isEmpty();
                                }
                            }));
                        }
                    }).produces(ApplicationClassPredicateBuildItem.class).build();
                }
            });
        } catch (ClassNotFoundException e) {
            System.err.println("Couldn't make the test class " + testClass.getSimpleName() + " an unremovable bean" + " (probably because a dependency on io.quarkus:quarkus-arc-deployment is missing);" + " other beans may also be removed and injection may not work as expected");
        }
        final Path testLocation = PathTestHelper.getTestClassesLocation(testClass);
        try {
            QuarkusBootstrap.Builder builder = QuarkusBootstrap.builder().setApplicationRoot(deploymentDir.resolve(APP_ROOT)).setMode(QuarkusBootstrap.Mode.TEST).addExcludedPath(testLocation).setProjectRoot(testLocation).setTargetDirectory(PathTestHelper.getProjectBuildDir(Paths.get("").normalize().toAbsolutePath(), testLocation)).setFlatClassPath(flatClassPath).setForcedDependencies(forcedDependencies);
            for (JavaArchive dependency : additionalDependencies) {
                builder.addAdditionalApplicationArchive(new AdditionalDependency(deploymentDir.resolve(dependency.getName()), false, true));
            }
            if (!forcedDependencies.isEmpty()) {
                // if we have forced dependencies we can't use the cache
                // as it can screw everything up
                builder.setDisableClasspathCache(true);
            }
            if (!allowTestClassOutsideDeployment) {
                builder.setBaseClassLoader(QuarkusClassLoader.builder("QuarkusUnitTest ClassLoader", getClass().getClassLoader(), false).addClassLoaderEventListeners(this.classLoadListeners).addBannedElement(ClassPathElement.fromPath(testLocation, true)).build());
            }
            builder.addClassLoaderEventListeners(this.classLoadListeners);
            curatedApplication = builder.build().bootstrap();
            StartupActionImpl startupAction = new AugmentActionImpl(curatedApplication, customizers, classLoadListeners).createInitialRuntimeApplication();
            startupAction.overrideConfig(testResourceManager.getConfigProperties());
            runningQuarkusApplication = startupAction.run(commandLineParameters);
            // we restore the CL at the end of the test
            Thread.currentThread().setContextClassLoader(runningQuarkusApplication.getClassLoader());
            if (assertException != null) {
                fail(THE_BUILD_WAS_EXPECTED_TO_FAIL);
            }
            started = true;
            System.setProperty("test.url", TestHTTPResourceManager.getUri(runningQuarkusApplication));
            try {
                actualTestClass = Class.forName(testClass.getName(), true, Thread.currentThread().getContextClassLoader());
                actualTestInstance = runningQuarkusApplication.instance(actualTestClass);
                Class<?> resM = runningQuarkusApplication.getClassLoader().loadClass(TestHTTPResourceManager.class.getName());
                resM.getDeclaredMethod("inject", Object.class).invoke(null, actualTestInstance);
                populateTestMethodInvokers(startupAction.getClassLoader());
            } catch (Exception e) {
                throw new TestInstantiationException("Failed to create test instance", e);
            }
            extensionContext.getStore(ExtensionContext.Namespace.GLOBAL).put(testClass.getName(), actualTestInstance);
        } catch (Throwable e) {
            started = false;
            if (assertException != null) {
                if (e instanceof AssertionError && e.getMessage().equals(THE_BUILD_WAS_EXPECTED_TO_FAIL)) {
                    // don't pass the 'no failure' assertion into the assert exception function
                    throw e;
                }
                if (e instanceof RuntimeException) {
                    Throwable cause = e.getCause();
                    if (cause != null && cause instanceof BuildException) {
                        assertException.accept(unwrapException(cause.getCause()));
                    } else if (cause != null) {
                        assertException.accept(unwrapException(cause));
                    } else {
                        assertException.accept(e);
                    }
                } else {
                    assertException.accept(e);
                }
            } else {
                throw e;
            }
        }
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}
Also used : TestHTTPResourceManager(io.quarkus.test.common.http.TestHTTPResourceManager) ArrayList(java.util.ArrayList) BuildStep(io.quarkus.builder.BuildStep) ApplicationClassPredicateBuildItem(io.quarkus.deployment.builditem.ApplicationClassPredicateBuildItem) ClassPathElement(io.quarkus.bootstrap.classloading.ClassPathElement) JavaArchive(org.jboss.shrinkwrap.api.spec.JavaArchive) Predicate(java.util.function.Predicate) TimerTask(java.util.TimerTask) Consumer(java.util.function.Consumer) AdditionalDependency(io.quarkus.bootstrap.app.AdditionalDependency) AugmentActionImpl(io.quarkus.runner.bootstrap.AugmentActionImpl) Path(java.nio.file.Path) Method(java.lang.reflect.Method) QuarkusClassLoader(io.quarkus.bootstrap.classloading.QuarkusClassLoader) StartupActionImpl(io.quarkus.runner.bootstrap.StartupActionImpl) BuildException(io.quarkus.builder.BuildException) FileNotFoundException(java.io.FileNotFoundException) InvocationTargetException(java.lang.reflect.InvocationTargetException) UncheckedIOException(java.io.UncheckedIOException) TestInstantiationException(org.junit.jupiter.api.extension.TestInstantiationException) ParameterResolutionException(org.junit.jupiter.api.extension.ParameterResolutionException) IOException(java.io.IOException) TestInstantiationException(org.junit.jupiter.api.extension.TestInstantiationException) Timer(java.util.Timer) BuildContext(io.quarkus.builder.BuildContext) BuildChainBuilder(io.quarkus.builder.BuildChainBuilder) QuarkusBootstrap(io.quarkus.bootstrap.app.QuarkusBootstrap) ExtensionContext(org.junit.jupiter.api.extension.ExtensionContext) BuildException(io.quarkus.builder.BuildException) TestResourceManager(io.quarkus.test.common.TestResourceManager)

Aggregations

AugmentActionImpl (io.quarkus.runner.bootstrap.AugmentActionImpl)5 IOException (java.io.IOException)5 ByteArrayInputStream (java.io.ByteArrayInputStream)4 ByteArrayOutputStream (java.io.ByteArrayOutputStream)4 ObjectInputStream (java.io.ObjectInputStream)4 ObjectOutputStream (java.io.ObjectOutputStream)4 Path (java.nio.file.Path)4 BuildChainBuilder (io.quarkus.builder.BuildChainBuilder)3 BuildContext (io.quarkus.builder.BuildContext)3 BuildStep (io.quarkus.builder.BuildStep)3 ArrayList (java.util.ArrayList)3 Consumer (java.util.function.Consumer)3 AdditionalDependency (io.quarkus.bootstrap.app.AdditionalDependency)2 AugmentAction (io.quarkus.bootstrap.app.AugmentAction)2 CuratedApplication (io.quarkus.bootstrap.app.CuratedApplication)2 QuarkusBootstrap (io.quarkus.bootstrap.app.QuarkusBootstrap)2 RunningQuarkusApplication (io.quarkus.bootstrap.app.RunningQuarkusApplication)2 StartupAction (io.quarkus.bootstrap.app.StartupAction)2 ClassPathElement (io.quarkus.bootstrap.classloading.ClassPathElement)2 QuarkusClassLoader (io.quarkus.bootstrap.classloading.QuarkusClassLoader)2