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;
}
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);
}
}
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);
}
}
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);
}
}
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);
}
}
Aggregations