diff --git a/arquillian-plugin-scanner/src/main/java/org/wildfly/glow/plugin/arquillian/ScannerMain.java b/arquillian-plugin-scanner/src/main/java/org/wildfly/glow/plugin/arquillian/ScannerMain.java index 94d894de..901259c8 100644 --- a/arquillian-plugin-scanner/src/main/java/org/wildfly/glow/plugin/arquillian/ScannerMain.java +++ b/arquillian-plugin-scanner/src/main/java/org/wildfly/glow/plugin/arquillian/ScannerMain.java @@ -53,9 +53,9 @@ public static void main(String[] args) throws Exception { boolean verbose = Boolean.parseBoolean(args[4]); // ClassLoader to load the Scanner from the classpath (equivalent to application cp). // Delegates to the application classpath to resolve Java API. - URLClassLoader cpLoader = buildClassLoader(cpArray, Thread.currentThread().getContextClassLoader(), verbose); + URLClassLoader cpLoader = buildClassLoader(cpArray, Thread.currentThread().getContextClassLoader()); // ClassLoader to load the test classes, delegate to cpLoader - URLClassLoader testLoader = buildClassLoader(urlsArray, cpLoader, verbose); + URLClassLoader testLoader = buildClassLoader(urlsArray, cpLoader); Class exporterClass = Class.forName("org.wildfly.glow.plugin.arquillian.GlowArquillianDeploymentExporter", true, cpLoader); Constructor ctr = exporterClass.getConstructor(List.class, ClassLoader.class, Path.class, Boolean.TYPE); Object obj = ctr.newInstance(classes, testLoader, outputFolder, verbose); @@ -64,12 +64,9 @@ public static void main(String[] args) throws Exception { System.exit(0); } - private static URLClassLoader buildClassLoader(String[] cpUrls, ClassLoader parent, boolean verbose) throws Exception { + private static URLClassLoader buildClassLoader(String[] cpUrls, ClassLoader parent) throws Exception { List urls = new ArrayList<>(); for (String s : cpUrls) { - if (verbose) { - System.out.println("URL " + s); - } urls.add(new File(s).toURI().toURL()); } URL[] cp = urls.toArray(new URL[0]); diff --git a/arquillian-plugin/src/main/java/org/wildfly/glow/plugin/arquillian/ScanMojo.java b/arquillian-plugin/src/main/java/org/wildfly/glow/plugin/arquillian/ScanMojo.java index b5052dc8..fa052b8c 100644 --- a/arquillian-plugin/src/main/java/org/wildfly/glow/plugin/arquillian/ScanMojo.java +++ b/arquillian-plugin/src/main/java/org/wildfly/glow/plugin/arquillian/ScanMojo.java @@ -53,6 +53,7 @@ import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collections; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Locale; @@ -73,6 +74,7 @@ import org.jboss.galleon.universe.FeaturePackLocation; import org.jboss.galleon.universe.UniverseResolver; import org.jboss.galleon.universe.maven.MavenChannel; +import org.wildfly.glow.ScanArguments; import org.wildfly.glow.error.IdentifiedError; import static org.wildfly.glow.plugin.arquillian.GlowArquillianDeploymentExporter.TEST_CLASSPATH; import static org.wildfly.glow.plugin.arquillian.GlowArquillianDeploymentExporter.TEST_PATHS; @@ -138,16 +140,11 @@ public void trace(Object s) { /** * List of feature-packs that are scanned and injected in the generated * provisioning.xml. + * This option can't be used when {@code server-version} or {@code preview} or {@code context} are used. */ @Parameter(required = false, alias = "feature-packs") List featurePacks = Collections.emptyList(); - /** - * Enable verbose output (containing identified errors, suggestions, ...). - */ - @Parameter(alias = "enable-verbose-output", property = "org.wildfly.glow.enable-verbose-output") - boolean enableVerboseOutput = false; - /** * GroupId:ArtifactId of dependencies that contain test classes to scan for * Arquillian deployments. @@ -156,10 +153,10 @@ public void trace(Object s) { private List dependenciesToScan = Collections.emptyList(); /** - * Execution profiles. + * Execution profile. */ - @Parameter(alias = "profiles", required = false, property = "org.wildfly.glow.profiles") - Set profiles = Collections.emptySet(); + @Parameter(alias = "profile", required = false, property = "org.wildfly.glow.profile") + private String profile; /** * Do not lookup deployments to scan. @@ -213,10 +210,13 @@ public void trace(Object s) { @Parameter(alias = "expected-errors", property = "org.wildfly.glow.expected-errors") private List expectedErrors = Collections.emptyList(); + /** + * Enable verbose output (containing identified errors, suggestions, ...). + */ @Parameter(property = "org.wildfly.glow.verbose") private boolean verbose = false; - /** + /** * A list of channels used for resolving artifacts while provisioning. *

* Defining a channel: @@ -253,8 +253,48 @@ public void trace(Object s) { @Parameter(alias = "channels", property = "org.wildfly.glow.channels") List channels; + /** + * A WildFly server version. The latest version is the default, only usable if no {@code feature-packs} have been set. + */ + @Parameter(alias = "server-version", property = "org.wildfly.glow.server-version") + private String serverVersion; + + /** + * Use WildFly Preview server, only usable if no {@code feature-packs} have been set. + */ + @Parameter(alias = "preview-server", property = "org.wildfly.glow.preview-server") + private boolean previewServer; + + /** + * Execution context, can be {@code cloud} or {@code bare-metal}, default value is {@code bare-metal}, + * only usable if no {@code feature-packs} have been set. + */ + @Parameter(alias = "context", property = "org.wildfly.glow.context") + private String context; + + /** + * By default the execution is aborted when unknown errors are reported. You can disable the check done for errors by + * setting this option to true. + */ + @Parameter(alias = "check-errors", property = "org.wildfly.glow.check-errors") + private boolean checkErrors = true; + @Override public void execute() throws MojoExecutionException, MojoFailureException { + + // Check configuration + if (!featurePacks.isEmpty()) { + if (serverVersion != null) { + throw new MojoExecutionException("server-version can't be set when feature-packs have been set."); + } + if (context != null) { + throw new MojoExecutionException("context can't be set when feature-packs have been set."); + } + if (previewServer) { + throw new MojoExecutionException("preview-server can't be set when feature-packs have been set."); + } + } + // Make sure that the 'hidden' properties used by the Arguments class come from the Maven configuration HiddenPropertiesAccessor.setOverrides(systemPropertyVariables); try { @@ -343,76 +383,110 @@ public void execute() throws MojoExecutionException, MojoFailureException { throw new MojoExecutionException(ex.getLocalizedMessage(), ex); } } - Arguments arguments = Arguments.scanBuilder(). + Set profiles = new HashSet<>(); + if (profile != null) { + profiles.add(profile); + } + ScanArguments.Builder argumentsBuilder = Arguments.scanBuilder(). setExecutionProfiles(profiles). setBinaries(retrieveDeployments(paths, classesRootFolder, outputFolder)). - setProvisoningXML(buildInputConfig(outputFolder, artifactResolver)). setUserEnabledAddOns(addOns). setConfigName(configName). - setSuggest((enableVerboseOutput || getLog().isDebugEnabled())). + setSuggest((verbose || getLog().isDebugEnabled())). setJndiLayers(layersForJndi). setVerbose(verbose || getLog().isDebugEnabled()). - setOutput(OutputFormat.PROVISIONING_XML).build(); + setOutput(OutputFormat.PROVISIONING_XML). + setTechPreview(previewServer). + setExecutionContext(context).setVersion(serverVersion); + + if (!featurePacks.isEmpty()) { + argumentsBuilder.setProvisoningXML(buildInputConfig(outputFolder, artifactResolver)); + } + + Arguments arguments = argumentsBuilder.build(); + try (ScanResults results = GlowSession.scan(artifactResolver, arguments, writer)) { - boolean skipTests = Boolean.getBoolean("maven.test.skip") || Boolean.getBoolean("skipTests"); - if (skipTests) { - getLog().warn("Tests are disabled, not checking for expected discovered layers."); - } else { - if (expectedDiscovery != null) { - String compact = results.getCompactInformation(); - if (!expectedDiscovery.equals(compact)) { - throw new MojoExecutionException("Error in glow discovery.\n" - + "-Expected: " + expectedDiscovery + "\n" - + "-Found : " + compact); - } - } - if (results.getErrorSession().hasErrors()) { - if (expectedErrors.isEmpty()) { - results.outputInformation(writer); - throw new MojoExecutionException("An error has been reported and expected-errors has not been set."); - } - List errors = new ArrayList<>(); - for (IdentifiedError err : results.getErrorSession().getErrors()) { - if (!err.isFixed()) { - errors.add(err); + boolean skipTests = Boolean.getBoolean("maven.test.skip") || Boolean.getBoolean("skipTests"); + if (skipTests) { + getLog().warn("Tests are disabled, not checking for expected discovered layers."); + } else { + if (expectedDiscovery != null) { + String compact = results.getCompactInformation(); + if (!expectedDiscovery.equals(compact)) { + throw new MojoExecutionException("Error in glow discovery.\n" + + "-Expected: " + expectedDiscovery + "\n" + + "-Found : " + compact); } } - if (expectedErrors.size() != errors.size()) { - List descriptions = new ArrayList<>(); - for (IdentifiedError err : errors) { - descriptions.add(err.getDescription()); + if (results.getErrorSession().hasErrors()) { + boolean errorsFound = false; + if (expectedErrors.isEmpty()) { + results.outputInformation(writer); + errorsFound = true; + String msg = "An error has been reported and expected-errors has not been set."; + if (checkErrors) { + throw new MojoExecutionException(msg); + } else { + getLog().warn(msg); + return; + } } - throw new MojoExecutionException("Number of expected errors mismatch. Expected " - + expectedErrors.size() + " reported " + errors.size() + ".\n" - + "Reported Errors " + descriptions + "\n" - + "Expected Errors " + expectedErrors); - } - Iterator it = errors.iterator(); - while (it.hasNext()) { - IdentifiedError err = it.next(); - if (expectedErrors.contains(err.getDescription())) { - it.remove(); + List errors = new ArrayList<>(); + for (IdentifiedError err : results.getErrorSession().getErrors()) { + if (!err.isFixed()) { + errors.add(err); + } } - } - it = errors.iterator(); - if (it.hasNext()) { - StringBuilder builder = new StringBuilder(); + if (expectedErrors.size() != errors.size()) { + List descriptions = new ArrayList<>(); + for (IdentifiedError err : errors) { + descriptions.add(err.getDescription()); + } + String msg = "Number of expected errors mismatch. Expected " + + expectedErrors.size() + " reported " + errors.size() + ".\n" + + "Reported Errors " + descriptions + "\n" + + "Expected Errors " + expectedErrors; + errorsFound = true; + if (checkErrors) { + throw new MojoExecutionException(msg); + } else { + getLog().warn(msg); + } + } + Iterator it = errors.iterator(); while (it.hasNext()) { IdentifiedError err = it.next(); - builder.append(err.getDescription()).append("\n"); + if (expectedErrors.contains(err.getDescription())) { + it.remove(); + } + } + it = errors.iterator(); + if (it.hasNext()) { + StringBuilder builder = new StringBuilder(); + while (it.hasNext()) { + IdentifiedError err = it.next(); + builder.append(err.getDescription()).append("\n"); + } + errorsFound = true; + String msg = "The following errors are unexpected:\n" + builder.toString(); + if (checkErrors) { + throw new MojoExecutionException(msg); + } else { + getLog().warn(msg); + } + } + if(!errorsFound) { + getLog().info("Expected errors found in glow scanning results. " + + " The test execution should fix them (eg: add missing datasources)"); + } + } else { + if (!expectedErrors.isEmpty()) { + throw new MojoExecutionException("expected-errors contains errors but no error reported."); } - throw new MojoExecutionException("The following errors are unexpected:\n" + builder.toString()); - } - getLog().info("Expected errors found in glow scanning results. " - + " The test execution should fix them (eg: add missing datasources)"); - } else { - if (!expectedErrors.isEmpty()) { - throw new MojoExecutionException("expected-errors contains errors but no error reported."); } } - } - if (enableVerboseOutput || getLog().isDebugEnabled()) { + if (verbose || getLog().isDebugEnabled()) { results.outputInformation(writer); } else { results.outputCompactInformation(writer); @@ -478,7 +552,7 @@ private Process startScanner(Path outputFolder, } Path lst = outputFolder.resolve(TEST_PATHS); Files.write(lst, pathList.toString().getBytes()); - if (enableVerboseOutput) { + if (verbose) { getLog().info("SCANNER: Test elements: " + pathList); getLog().info("SCANNER: Classes: " + classesLst); } @@ -487,10 +561,10 @@ private Process startScanner(Path outputFolder, collectCpPaths(System.getProperty("java.home"), Thread.currentThread().getContextClassLoader(), cp, - enableVerboseOutput, + verbose, reducedCp, getLog()); - if (enableVerboseOutput) { + if (verbose) { getLog().info("SCANNER: classpath: " + cp); getLog().info("SCANNER: bootstrap classpath: " + reducedCp); } @@ -510,7 +584,7 @@ private Process startScanner(Path outputFolder, cmd.add(lst.toAbsolutePath().toString()); cmd.add(classesLst.toString()); cmd.add(outputFolder.toAbsolutePath().toString()); - cmd.add(enableVerboseOutput || getLog().isDebugEnabled() ? "true" : "false"); + cmd.add(verbose || getLog().isDebugEnabled() ? "true" : "false"); final ProcessBuilder builder = new ProcessBuilder(cmd) .redirectError(ProcessBuilder.Redirect.INHERIT) .redirectOutput(ProcessBuilder.Redirect.INHERIT); @@ -528,9 +602,6 @@ private static void collectCpPaths(String javaHome, ClassLoader cl, StringBuilde for (URL url : ((URLClassLoader) cl).getURLs()) { final String filePath; File file; - if (enableVerboseOutput) { - log.info("SCANNER: CP file url " + url); - } try { file = new File(url.toURI()); filePath = file.getAbsolutePath(); diff --git a/core/src/main/java/org/wildfly/glow/DeploymentScanner.java b/core/src/main/java/org/wildfly/glow/DeploymentScanner.java index 1bf3506b..620ac1dc 100644 --- a/core/src/main/java/org/wildfly/glow/DeploymentScanner.java +++ b/core/src/main/java/org/wildfly/glow/DeploymentScanner.java @@ -175,7 +175,7 @@ private void scanAnnotations(DeploymentScanContext ctx) throws IOException { if (l != null) { ctx.layers.addAll(l); //System.out.println("Find an annotation " + ai.name().packagePrefix() + " layer being " + l); - LayerMapping.addRule(LayerMapping.RULE.ANNOTATION, l, ai.name().packagePrefix()); + LayerMapping.addRule(LayerMapping.RULE.ANNOTATION, l, ai.name().packagePrefix() + ".*"); } else { // Pattern? for (String s : ctx.mapping.getAnnotations().keySet()) { @@ -578,7 +578,7 @@ private Set lookup(String className, DeploymentScanContext ctx) { String pkgPrefix = className.substring(0, index); l = map.get(pkgPrefix); if (l != null) { - LayerMapping.addRule(LayerMapping.RULE.JAVA_TYPE,l, pkgPrefix); + LayerMapping.addRule(LayerMapping.RULE.JAVA_TYPE,l, pkgPrefix + ".*"); } } if (l == null) { diff --git a/docs/guide/test-maven-plugin/index.adoc b/docs/guide/test-maven-plugin/index.adoc index 03c5b34d..5249f962 100644 --- a/docs/guide/test-maven-plugin/index.adoc +++ b/docs/guide/test-maven-plugin/index.adoc @@ -34,6 +34,13 @@ The left part of the arrow contains the list of the discovered Layers according The right part is what will get provisioned. Composed of a base Layer (always `ee-core-profile-server`) and a list of the discovered Layers that has been cleaned-up to avoid to include dependencies. +Note: In case the `ha` profile is enabled, you need to prefix the expected discovery with the `[ha]` prefix. For example: + + +``` +[ha][cdi, ee-integration, ejb, ejb-lite, elytron-oidc-client, naming, servlet]==>ee-core-profile-server,ejb,elytron-oidc-client +``` + BTW: The link:https://github.com/wildfly/wildfly/tree/main/testsuite/integration[WildFly integration tests] contain a lot of examples of WildFly Glow scanning executions that you can use as a starting-point. @@ -61,6 +68,12 @@ That is generally an error to ignore, the test itself should add the datasource * `no default datasource found error`: It has been identified that a default datasource is required. That can be fixed by adding the add-on `h2-database:default`. +You can disable the check for errors by setting `false`. + +Note: When `true` is set, the list of expected errors can be different (it contains more details on the error), +make sure to suppress the expected errors when debugging or set `false`. + + ### Selecting a surefire execution to scan You can select a given surefire execution to scan. To do so add the following element to the plugin configuration: @@ -110,7 +123,97 @@ the dependencies coordinates (`groupId:artifactId`) can be configured in the plu ---- -### A pom.xml file extract +### Specifying an execution context + +By default the `bare-metal` context is used. In case you need to produce a server to be executed on the cloud, +use the `cloud` element. + +### Specifying an execution profile + +In case you want to produce an High Available WildFly server, use the `ha` element. + +### Using WildFly Preview server + +In case you want to use a WildFly Preview server, use the `true` element. + +### Specifying a WildFly server version + +By default the latest WildFly server version is used. +In case you want to use a specific WildFly version, set the `server version` element. + +### Using a specific set of Galleon feature-packs + +By default the latest WildFly Galleon feature-pack and extra Galleon feature-packs are used. +You have the ability to set a list of feature-packs using the `` element. + + +### Understanding which rule selected a given Galleon layer + +When setting `true`, the set of rules that selected a given layer are printed in the console. Output example: + +---- +... +layers inclusion rules +* ee-core-profile-server + - BASE_LAYER +* ee-concurrency + - JAVA_TYPE: [jakarta.enterprise.concurrent.*] +* undertow-https + - ADD_ON +... +---- + +### A simple pom.xml file extract + +In this extract, the latest WildFly server version is used. + +[source,xml,subs=attributes+] +---- +... + + + + org.wildfly.glow + wildfly-glow-arquillian-plugin + 1.0.0.Beta4 + + [cdi, ee-concurrency, ee-integration, elytron, messaging-activemq, naming, servlet, undertow]==>ee-core-profile-server,ee-concurrency,messaging-activemq + + + + scan + + scan + + test-compile + + + + + org.wildfly.plugins + wildfly-maven-plugin + 5.0.0.Alpha2 + + true + ${project.build.directory}/wildfly + ${project.build.directory}/glow-scan/provisioning.xml + + + + test-provisioning + + provision + + test-compile + + + + + +... +---- + +### A custom pom.xml file extract In this extract, WildFly 30.0.1.Final is used, the `ssl` add-on is enabled, expected discovery and expected errors are configured. The WildFly Maven Plugin is used to provision the server used by tests. diff --git a/docs/guide/wildfly-maven-plugin/index.adoc b/docs/guide/wildfly-maven-plugin/index.adoc index 98bcfff2..f6311fba 100644 --- a/docs/guide/wildfly-maven-plugin/index.adoc +++ b/docs/guide/wildfly-maven-plugin/index.adoc @@ -255,3 +255,16 @@ You can print the rules that selected the Galleon Layers. To do so set the ` ---- +An example of output: + +---- +... +layers inclusion rules +* ee-core-profile-server + - BASE_LAYER +* ee-concurrency + - JAVA_TYPE: [jakarta.enterprise.concurren.*] +* undertow-https + - ADD_ON +... +---- diff --git a/tests/arquillian-plugin-tests/pom.xml b/tests/arquillian-plugin-tests/pom.xml index 6fca88ff..75a3ae7a 100644 --- a/tests/arquillian-plugin-tests/pom.xml +++ b/tests/arquillian-plugin-tests/pom.xml @@ -44,15 +44,6 @@ org.wildfly.glow wildfly-glow-arquillian-plugin ${project.version} - - - - org.wildfly - wildfly-galleon-pack - 29.0.1.Final - - - scan @@ -61,7 +52,39 @@ test-compile - true + true + []==>ee-core-profile-server + + + + scan-cloud-ha-preview + + scan + + test-compile + + true + cloud + true + ha + [ha][]==>ee-core-profile-server + + + + scan-custom + + scan + + test-compile + + + + org.wildfly + wildfly-galleon-pack + 29.0.1.Final + + + true []==>ee-core-profile-server