use of io.quarkus.bootstrap.app.CuratedApplication 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.bootstrap.app.CuratedApplication in project quarkus by quarkusio.
the class IntegrationTestUtil method handleDevServices.
static ArtifactLauncher.InitContext.DevServicesLaunchResult handleDevServices(ExtensionContext context, boolean isDockerAppLaunch) throws Exception {
Class<?> requiredTestClass = context.getRequiredTestClass();
Path testClassLocation = getTestClassesLocation(requiredTestClass);
final Path appClassLocation = getAppClassLocationForTestLocation(testClassLocation.toString());
final PathList.Builder rootBuilder = PathList.builder();
if (!appClassLocation.equals(testClassLocation)) {
rootBuilder.add(testClassLocation);
// if test classes is a dir, we should also check whether test resources dir exists as a separate dir (gradle)
// TODO: this whole app/test path resolution logic is pretty dumb, it needs be re-worked using proper workspace discovery
final Path testResourcesLocation = PathTestHelper.getResourcesForClassesDirOrNull(testClassLocation, "test");
if (testResourcesLocation != null) {
rootBuilder.add(testResourcesLocation);
}
}
final QuarkusBootstrap.Builder runnerBuilder = QuarkusBootstrap.builder().setIsolateDeployment(true).setMode(QuarkusBootstrap.Mode.TEST);
final Path projectRoot = Paths.get("").normalize().toAbsolutePath();
runnerBuilder.setProjectRoot(projectRoot);
runnerBuilder.setTargetDirectory(PathTestHelper.getProjectBuildDir(projectRoot, testClassLocation));
rootBuilder.add(appClassLocation);
final Path appResourcesLocation = PathTestHelper.getResourcesForClassesDirOrNull(appClassLocation, "main");
if (appResourcesLocation != null) {
rootBuilder.add(appResourcesLocation);
}
// If gradle project running directly with IDE
if (System.getProperty(BootstrapConstants.SERIALIZED_TEST_APP_MODEL) == null) {
ApplicationModel model = BuildToolHelper.enableGradleAppModelForTest(projectRoot);
if (model != null && model.getApplicationModule() != null) {
final ArtifactSources testSources = model.getApplicationModule().getTestSources();
if (testSources != null) {
for (SourceDir src : testSources.getSourceDirs()) {
if (!Files.exists(src.getOutputDir())) {
final Path classes = src.getOutputDir();
if (!rootBuilder.contains(classes)) {
rootBuilder.add(classes);
}
}
}
}
for (SourceDir src : model.getApplicationModule().getMainSources().getSourceDirs()) {
if (!Files.exists(src.getOutputDir())) {
final Path classes = src.getOutputDir();
if (!rootBuilder.contains(classes)) {
rootBuilder.add(classes);
}
}
}
}
} else if (System.getProperty(BootstrapConstants.OUTPUT_SOURCES_DIR) != null) {
final String[] sourceDirectories = System.getProperty(BootstrapConstants.OUTPUT_SOURCES_DIR).split(",");
for (String sourceDirectory : sourceDirectories) {
final Path directory = Paths.get(sourceDirectory);
if (Files.exists(directory) && !rootBuilder.contains(directory)) {
rootBuilder.add(directory);
}
}
}
runnerBuilder.setApplicationRoot(rootBuilder.build());
CuratedApplication curatedApplication = runnerBuilder.setTest(true).build().bootstrap();
Index testClassesIndex = TestClassIndexer.indexTestClasses(requiredTestClass);
// we need to write the Index to make it reusable from other parts of the testing infrastructure that run in different ClassLoaders
TestClassIndexer.writeIndex(testClassesIndex, requiredTestClass);
Map<String, String> propertyMap = new HashMap<>();
AugmentAction augmentAction;
String networkId = null;
if (isDockerAppLaunch) {
// when the application is going to be launched as a docker container, we need to make containers started by DevServices
// use a shared network that the application container can then use as well
augmentAction = curatedApplication.createAugmentor("io.quarkus.deployment.builditem.DevServicesSharedNetworkBuildItem$Factory", Collections.emptyMap());
} else {
augmentAction = curatedApplication.createAugmentor();
}
augmentAction.performCustomBuild(NativeDevServicesHandler.class.getName(), new BiConsumer<String, String>() {
@Override
public void accept(String s, String s2) {
propertyMap.put(s, s2);
}
}, DevServicesLauncherConfigResultBuildItem.class.getName());
boolean manageNetwork = false;
if (isDockerAppLaunch) {
// or else we run into various ClassLoader problems
try {
Class<?> networkClass = curatedApplication.getAugmentClassLoader().loadClass("org.testcontainers.containers.Network");
Object sharedNetwork = networkClass.getField("SHARED").get(null);
networkId = (String) networkClass.getMethod("getId").invoke(sharedNetwork);
} catch (Exception e) {
// use the network the use has specified or else just generate one if none is configured
Config config = LauncherUtil.installAndGetSomeConfig();
Optional<String> networkIdOpt = config.getOptionalValue("quarkus.test.container.network", String.class);
if (networkIdOpt.isPresent()) {
networkId = networkIdOpt.get();
} else {
networkId = "quarkus-integration-test-" + RandomStringUtils.random(5, true, false);
manageNetwork = true;
}
}
}
DefaultDevServicesLaunchResult result = new DefaultDevServicesLaunchResult(propertyMap, networkId, manageNetwork, curatedApplication);
createNetworkIfNecessary(result);
return result;
}
use of io.quarkus.bootstrap.app.CuratedApplication in project quarkus by quarkusio.
the class AbstractJvmQuarkusTestExtension method createAugmentor.
protected PrepareResult createAugmentor(ExtensionContext context, Class<? extends QuarkusTestProfile> profile, Collection<Runnable> shutdownTasks) throws Exception {
Class<?> requiredTestClass = context.getRequiredTestClass();
currentJUnitTestClass = requiredTestClass;
Path testClassLocation = getTestClassesLocation(requiredTestClass);
final Path appClassLocation = getAppClassLocationForTestLocation(testClassLocation.toString());
final PathList.Builder rootBuilder = PathList.builder();
if (!appClassLocation.equals(testClassLocation)) {
rootBuilder.add(testClassLocation);
// if test classes is a dir, we should also check whether test resources dir exists as a separate dir (gradle)
// TODO: this whole app/test path resolution logic is pretty dumb, it needs be re-worked using proper workspace discovery
final Path testResourcesLocation = PathTestHelper.getResourcesForClassesDirOrNull(testClassLocation, "test");
if (testResourcesLocation != null) {
rootBuilder.add(testResourcesLocation);
}
}
originalCl = Thread.currentThread().getContextClassLoader();
Map<String, String> sysPropRestore = new HashMap<>();
sysPropRestore.put(ProfileManager.QUARKUS_TEST_PROFILE_PROP, System.getProperty(ProfileManager.QUARKUS_TEST_PROFILE_PROP));
// clear the test.url system property as the value leaks into the run when using different profiles
System.clearProperty("test.url");
Map<String, String> additional = new HashMap<>();
QuarkusTestProfile profileInstance = null;
if (profile != null) {
profileInstance = profile.getConstructor().newInstance();
additional.putAll(profileInstance.getConfigOverrides());
if (!profileInstance.getEnabledAlternatives().isEmpty()) {
additional.put("quarkus.arc.selected-alternatives", profileInstance.getEnabledAlternatives().stream().peek((c) -> {
if (!c.isAnnotationPresent(Alternative.class)) {
throw new RuntimeException("Enabled alternative " + c + " is not annotated with @Alternative");
}
}).map(Class::getName).collect(Collectors.joining(",")));
}
if (profileInstance.disableApplicationLifecycleObservers()) {
additional.put("quarkus.arc.test.disable-application-lifecycle-observers", "true");
}
if (profileInstance.getConfigProfile() != null) {
additional.put(ProfileManager.QUARKUS_TEST_PROFILE_PROP, profileInstance.getConfigProfile());
}
// we just use system properties for now
// its a lot simpler
shutdownTasks.add(RestorableSystemProperties.setProperties(additional)::close);
}
final Path projectRoot = Paths.get("").normalize().toAbsolutePath();
rootBuilder.add(appClassLocation);
final Path appResourcesLocation = PathTestHelper.getResourcesForClassesDirOrNull(appClassLocation, "main");
if (appResourcesLocation != null) {
rootBuilder.add(appResourcesLocation);
}
// If gradle project running directly with IDE
if (System.getProperty(BootstrapConstants.SERIALIZED_TEST_APP_MODEL) == null) {
ApplicationModel model = BuildToolHelper.enableGradleAppModelForTest(projectRoot);
if (model != null && model.getApplicationModule() != null) {
final ArtifactSources artifactSrc = model.getApplicationModule().getTestSources();
if (artifactSrc != null) {
for (SourceDir src : artifactSrc.getSourceDirs()) {
if (Files.exists(src.getOutputDir())) {
final Path classesDir = src.getOutputDir();
if (!rootBuilder.contains(classesDir)) {
rootBuilder.add(classesDir);
}
}
}
}
for (SourceDir src : model.getApplicationModule().getMainSources().getSourceDirs()) {
if (Files.exists(src.getOutputDir())) {
final Path classesDir = src.getOutputDir();
if (!rootBuilder.contains(classesDir)) {
rootBuilder.add(classesDir);
}
}
}
}
} else if (System.getProperty(BootstrapConstants.OUTPUT_SOURCES_DIR) != null) {
final String[] sourceDirectories = System.getProperty(BootstrapConstants.OUTPUT_SOURCES_DIR).split(",");
for (String sourceDirectory : sourceDirectories) {
final Path directory = Paths.get(sourceDirectory);
if (Files.exists(directory) && !rootBuilder.contains(directory)) {
rootBuilder.add(directory);
}
}
}
CuratedApplication curatedApplication;
if (CurrentTestApplication.curatedApplication != null) {
curatedApplication = CurrentTestApplication.curatedApplication;
} else {
final QuarkusBootstrap.Builder runnerBuilder = QuarkusBootstrap.builder().setIsolateDeployment(true).setMode(QuarkusBootstrap.Mode.TEST);
runnerBuilder.setTargetDirectory(PathTestHelper.getProjectBuildDir(projectRoot, testClassLocation));
runnerBuilder.setProjectRoot(projectRoot);
runnerBuilder.setApplicationRoot(rootBuilder.build());
curatedApplication = runnerBuilder.setTest(true).build().bootstrap();
shutdownTasks.add(curatedApplication::close);
}
if (curatedApplication.getApplicationModel().getRuntimeDependencies().isEmpty()) {
throw new RuntimeException("The tests were run against a directory that does not contain a Quarkus project. Please ensure that the test is configured to use the proper working directory.");
}
Index testClassesIndex = TestClassIndexer.indexTestClasses(requiredTestClass);
// we need to write the Index to make it reusable from other parts of the testing infrastructure that run in different ClassLoaders
TestClassIndexer.writeIndex(testClassesIndex, requiredTestClass);
Timing.staticInitStarted(curatedApplication.getBaseRuntimeClassLoader(), curatedApplication.getQuarkusBootstrap().isAuxiliaryApplication());
final Map<String, Object> props = new HashMap<>();
props.put(TEST_LOCATION, testClassLocation);
props.put(TEST_CLASS, requiredTestClass);
quarkusTestProfile = profile;
return new PrepareResult(curatedApplication.createAugmentor(QuarkusTestExtension.TestBuildChainFunction.class.getName(), props), profileInstance, curatedApplication);
}
use of io.quarkus.bootstrap.app.CuratedApplication 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.bootstrap.app.CuratedApplication in project quarkus by quarkusio.
the class ReaugmentTask method main.
public static void main(Path appRoot) throws Exception {
Path deploymentLib = appRoot.resolve(LIB).resolve(DEPLOYMENT_LIB);
Path buildSystemProps = appRoot.resolve(QUARKUS).resolve(BUILD_SYSTEM_PROPERTIES);
try (ObjectInputStream in = new ObjectInputStream(Files.newInputStream(deploymentLib.resolve(JarResultBuildStep.APPMODEL_DAT)))) {
Properties buildSystemProperties = new Properties();
try (InputStream buildIn = Files.newInputStream(buildSystemProps)) {
buildSystemProperties.load(buildIn);
}
MutableJarApplicationModel appModel = (MutableJarApplicationModel) in.readObject();
List<AdditionalDependency> additional = new ArrayList<>();
if (appModel.getUserProvidersDirectory() != null) {
// bit of a hack, but keeps things simple
System.setProperty("quarkus.package.user-providers-directory", appModel.getUserProvidersDirectory());
try (Stream<Path> files = Files.list(appRoot.resolve(appModel.getUserProvidersDirectory()))) {
files.forEach(new Consumer<Path>() {
@Override
public void accept(Path path) {
if (path.toString().endsWith(".jar")) {
additional.add(new AdditionalDependency(path, false, true));
}
}
});
}
}
final ApplicationModel existingModel = appModel.getAppModel(appRoot);
System.setProperty("quarkus.package.type", "mutable-jar");
try (CuratedApplication bootstrap = QuarkusBootstrap.builder().setAppArtifact(existingModel.getAppArtifact()).setExistingModel(existingModel).setRebuild(true).setBuildSystemProperties(buildSystemProperties).setBaseName(appModel.getBaseName()).addAdditionalApplicationArchives(additional).setApplicationRoot(existingModel.getAppArtifact().getResolvedPaths().getSinglePath()).setTargetDirectory(appRoot.getParent()).setBaseClassLoader(ReaugmentTask.class.getClassLoader()).build().bootstrap()) {
bootstrap.createAugmentor().createProductionApplication();
}
}
}
Aggregations