/** * Copyright 2016 Red Hat, Inc, and individual contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.wildfly.swarm.maven.plugin; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; import org.apache.maven.it.VerificationException; import org.apache.maven.it.Verifier; import org.apache.maven.it.util.ResourceExtractor; import org.jboss.shrinkwrap.api.Archive; import org.jboss.shrinkwrap.api.GenericArchive; import org.jboss.shrinkwrap.api.ShrinkWrap; import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameter; import org.junit.runners.Parameterized.Parameters; import static org.fest.assertions.Assertions.assertThat; import static org.junit.Assume.assumeTrue; /** * End-to-end tests of the Swarm Maven plugin. * * <p>The Swarm build tools, and consequently the Swarm Maven plugin, have a lot of features that interact * in subtle ways. Some of these interactions don't make a lot of sense, but they aren't prevented in any way. * So these tests "codify" the existing behavior, because it is something users tend to rely on even if that * was never the intent.</p> * * <p>The tests can be run in one of three ways:</p> * * <ul> * <li>default -- only a small number of hand-selected tests will run, to finish quickly</li> * <li>full matrix -- runs the entire testing matrix, which takes a <b>lot</b> of time; * this mode is enabled by setting system property {@code swarm.test.full}</li> * <li>single combination -- runs a single test defined by a system property {@code swarm.test.maven.plugin.single}; * the directory with the testing project will be preserved for manual inspection</li> * </ul> * * <p>Currently, there's a couple of known issues, so some of the tests are commented out. * That is expected to change over time.</p> */ @RunWith(Parameterized.class) public class MavenPluginTest { private static final String RUN_FULL_MATRIX_KEY = "swarm.test.full"; private static final String SINGLE_TESTING_PROJECT_KEY = "swarm.test.maven.plugin.single"; @Parameters(name = "{0}") public static Iterable<?> parameters() { String singleTestingProject = System.getProperty(SINGLE_TESTING_PROJECT_KEY); if (singleTestingProject != null) { return Collections.singleton(TestingProject.deserialize(singleTestingProject)); } boolean runFullMatrix = System.getProperty(RUN_FULL_MATRIX_KEY) != null; if (!runFullMatrix) { return Arrays.asList( new TestingProject(Packaging.WAR, Dependencies.FRACTIONS, Autodetection.FORCE, new IncludedTechnology[]{IncludedTechnology.SERVLET, IncludedTechnology.JAX_RS}, AdditionalDependency.NON_JAVA_EE, AdditionalFraction.NONE), // SWARM-870 /* new TestingProject(Packaging.WAR, Dependencies.JAVA_EE_APIS, Autodetection.FORCE, new IncludedTechnology[]{IncludedTechnology.SERVLET}, AdditionalDependency.NON_JAVA_EE, AdditionalFraction.ALREADY_PRESENT), */ // SWARM-814 new TestingProject(Packaging.WAR, Dependencies.JAVA_EE_APIS, Autodetection.WHEN_MISSING, new IncludedTechnology[]{IncludedTechnology.SERVLET, IncludedTechnology.EJB}, AdditionalDependency.NONE, AdditionalFraction.NONE), // SWARM-970 /* new TestingProject(Packaging.WAR, Dependencies.FRACTIONS, Autodetection.FORCE, new IncludedTechnology[]{IncludedTechnology.SERVLET, IncludedTechnology.EJB}, AdditionalDependency.NONE, AdditionalFraction.NONE), */ new TestingProject(Packaging.WAR_WITH_MAIN, Dependencies.FRACTIONS, Autodetection.NEVER, new IncludedTechnology[]{IncludedTechnology.SERVLET, IncludedTechnology.JAX_RS}, AdditionalDependency.NON_JAVA_EE, AdditionalFraction.NOT_YET_PRESENT), new TestingProject(Packaging.WAR_WITH_MAIN, Dependencies.JAVA_EE_APIS, Autodetection.WHEN_MISSING, new IncludedTechnology[]{IncludedTechnology.SERVLET, IncludedTechnology.JAX_RS}, AdditionalDependency.USING_JAVA_EE, AdditionalFraction.NONE), // SWARM-869 /* new TestingProject(Packaging.JAR_WITH_MAIN, Dependencies.FRACTIONS, Autodetection.WHEN_MISSING, new IncludedTechnology[]{IncludedTechnology.SERVLET, IncludedTechnology.JAX_RS}, AdditionalDependency.USING_JAVA_EE, AdditionalFraction.NOT_YET_PRESENT), */ new TestingProject(Packaging.JAR_WITH_MAIN, Dependencies.JAVA_EE_APIS, Autodetection.FORCE, new IncludedTechnology[]{IncludedTechnology.SERVLET, IncludedTechnology.JAX_RS}, AdditionalDependency.NONE, AdditionalFraction.ALREADY_PRESENT) ); } List<TestingProject> testingProjects = new ArrayList<>(); for (Packaging packaging : Packaging.values()) { for (Dependencies dependencies : Dependencies.values()) { for (Autodetection autodetection : Autodetection.values()) { for (AdditionalDependency additionalDependency : AdditionalDependency.values()) { for (AdditionalFraction additionalFraction : AdditionalFraction.values()) { // a lot of these fail because of SWARM-869 if (autodetection == Autodetection.WHEN_MISSING && additionalFraction != AdditionalFraction.NONE) { continue; } // a lot of these fail because of SWARM-870 if (autodetection != Autodetection.NEVER && additionalFraction == AdditionalFraction.ALREADY_PRESENT) { continue; } testingProjects.add(new TestingProject( packaging, dependencies, autodetection, new IncludedTechnology[]{IncludedTechnology.SERVLET}, additionalDependency, additionalFraction )); testingProjects.add(new TestingProject( packaging, dependencies, autodetection, new IncludedTechnology[]{IncludedTechnology.SERVLET, IncludedTechnology.JAX_RS}, additionalDependency, additionalFraction )); // a lot of these fail because of SWARM-970 if (dependencies == Dependencies.FRACTIONS && autodetection == Autodetection.FORCE) { continue; } testingProjects.add(new TestingProject( packaging, dependencies, autodetection, new IncludedTechnology[]{IncludedTechnology.SERVLET, IncludedTechnology.EJB}, additionalDependency, additionalFraction )); } } } } } return testingProjects; } @Parameter public TestingProject testingProject; @Rule public TemporaryFolder tmp = new TemporaryFolder() { @Override protected void after() { if (System.getProperty(SINGLE_TESTING_PROJECT_KEY) != null) { // the test is run manually for a single combination // don't delete the testing project directory, it's likely to be inspected manually return; } super.after(); } }; private Verifier verifier; private Path logPath; @Before public void setUpProject() throws IOException, VerificationException { assumeTrue("Set the M2_HOME environment variable", System.getenv("M2_HOME") != null); assumeTrue("Run from Maven or set the project.version system property", System.getProperty("project.version") != null); File projectDir = ResourceExtractor.extractResourcePath(getClass(), "/testing-project", tmp.getRoot(), true); testingProject.prepare(projectDir.toPath()); verifier = new Verifier(projectDir.getAbsolutePath(), true); verifier.setForkJvm(true); String settingsXml = System.getProperty("org.apache.maven.user-settings"); if (settingsXml != null && new File(settingsXml).isFile()) { verifier.addCliOption("-s"); verifier.addCliOption(settingsXml); } logPath = Paths.get(verifier.getBasedir()).resolve(verifier.getLogFileName()); } @Test public void buildUberjarAndRunTests() { try { doBuildUberjarAndRunTests(); } catch (Exception e) { String additionalMessage; if (System.getProperty(SINGLE_TESTING_PROJECT_KEY) == null) { additionalMessage = "Test failed for project [" + testingProject + "], use -D" + SINGLE_TESTING_PROJECT_KEY + "=" + testingProject.serialize() + " to run the test with this single combination again"; } else { additionalMessage = "Test failed for project [" + testingProject + "], the testing project is kept in " + verifier.getBasedir() + " for manual inspection"; } throw new AssertionError(additionalMessage + "\n\n" + e.getMessage(), e); } } public void doBuildUberjarAndRunTests() throws IOException, VerificationException, InterruptedException { String goal = "package"; if (testingProject.canRunTests()) { goal = "verify"; // a lot of these fail because of SWARM-873 if (testingProject.additionalDependency == AdditionalDependency.USING_JAVA_EE) { goal = "package"; } } try { verifier.executeGoal(goal); } catch (VerificationException e) { if (testingProject.dependencies == Dependencies.JAVA_EE_APIS && testingProject.autodetection == Autodetection.NEVER) { // the only situation when build failure is expected String log = new String(Files.readAllBytes(logPath), StandardCharsets.UTF_8); assertThat(log).contains("No WildFly Swarm Bootstrap fraction found"); return; } throw e; } verifier.assertFilePresent("target/testing-project." + testingProject.packaging.fileExtension()); verifier.assertFilePresent("target/testing-project-swarm.jar"); String log = new String(Files.readAllBytes(logPath), StandardCharsets.UTF_8); assertThat(log).doesNotContain("[ERROR]"); assertThat(log).doesNotContain("[WARNING]"); assertThat(log).contains("BUILD SUCCESS"); checkFractionAutodetection(log); File uberjarFile = new File(verifier.getBasedir(), "target/testing-project-swarm.jar"); Archive uberjar = ShrinkWrap.createFromZipFile(GenericArchive.class, uberjarFile); checkFractionsPresent(uberjar); checkMainClass(uberjar); } private void checkFractionAutodetection(String log) { if (testingProject.doesAutodetectionHappen()) { assertThat(log).contains("Scanning for needed WildFly Swarm fractions"); } else { assertThat(log).doesNotContain("Scanning for needed WildFly Swarm fractions"); } } private void checkFractionsPresent(Archive uberjar) throws IOException { assertThat(uberjar.contains("META-INF/wildfly-swarm-manifest.yaml")).isTrue(); String manifestContent = readFileFromArchive(uberjar, "META-INF/wildfly-swarm-manifest.yaml"); for (String fraction : testingProject.fractionsThatShouldBePresent()) { assertThat(manifestContent).contains("org.wildfly.swarm." + fraction); assertThat(manifestContent).contains("org.wildfly.swarm:" + fraction); assertThat(uberjar.contains("m2repo/org/wildfly/swarm/" + fraction)).isTrue(); } for (String fraction : testingProject.fractionsThatShouldBeMissing()) { assertThat(manifestContent).doesNotContain("org.wildfly.swarm." + fraction); assertThat(manifestContent).doesNotContain("org.wildfly.swarm:" + fraction); assertThat(uberjar.contains("m2repo/org/wildfly/swarm/" + fraction)).isFalse(); } } private void checkMainClass(Archive uberjar) throws IOException { String javaManifest = readFileFromArchive(uberjar, "META-INF/MANIFEST.MF"); assertThat(javaManifest).contains("Main-Class"); assertThat(javaManifest).doesNotContain("org.wildfly.swarm.test.Main"); String swarmManifest = readFileFromArchive(uberjar, "META-INF/wildfly-swarm-manifest.yaml"); if (testingProject.packaging.hasCustomMain()) { assertThat(swarmManifest).contains("main-class: org.wildfly.swarm.test.Main"); } else { assertThat(swarmManifest).doesNotContain("main-class: org.wildfly.swarm.test.Main"); } } @After public void tearDown() throws InterruptedException { if (verifier != null) { verifier.resetStreams(); } } // --- private static String readFileFromArchive(Archive archive, String path) throws IOException { try (InputStream manifest = archive.get(path).getAsset().openStream()) { BufferedReader reader = new BufferedReader(new InputStreamReader(manifest, StandardCharsets.UTF_8)); return reader.lines().collect(Collectors.joining()); } } }