View Javadoc

1   /*
2    * #%L
3    * Native ARchive plugin for Maven
4    * %%
5    * Copyright (C) 2002 - 2014 NAR Maven Plugin developers.
6    * %%
7    * Licensed under the Apache License, Version 2.0 (the "License");
8    * you may not use this file except in compliance with the License.
9    * You may obtain a copy of the License at
10   * 
11   * http://www.apache.org/licenses/LICENSE-2.0
12   * 
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   * #L%
19   */
20  package com.github.maven_nar;
21  
22  import java.io.File;
23  import java.io.IOException;
24  import java.util.ArrayList;
25  import java.util.HashSet;
26  import java.util.Iterator;
27  import java.util.List;
28  import java.util.Set;
29  
30  import org.apache.maven.artifact.Artifact;
31  import org.apache.maven.plugin.MojoExecutionException;
32  import org.apache.maven.plugin.MojoFailureException;
33  import org.apache.maven.plugins.annotations.LifecyclePhase;
34  import org.apache.maven.plugins.annotations.Mojo;
35  import org.apache.maven.plugins.annotations.Parameter;
36  import org.apache.maven.plugins.annotations.ResolutionScope;
37  import org.apache.maven.project.MavenProject;
38  import org.apache.maven.shared.artifact.filter.collection.ScopeFilter;
39  import org.codehaus.plexus.util.StringUtils;
40  
41  /**
42   * Tests NAR files. Runs Native Tests and executables if produced.
43   *
44   * @author Mark Donszelmann
45   */
46  @Mojo(name = "nar-test", defaultPhase = LifecyclePhase.TEST, requiresProject = true,
47    requiresDependencyResolution = ResolutionScope.TEST)
48  public class NarTestMojo extends AbstractCompileMojo {
49    /**
50     * The classpath elements of the project being tested.
51     */
52    @Parameter(defaultValue = "${project.testClasspathElements}", required = true, readonly = true)
53    private List classpathElements;
54  
55    /**
56     * Directory for test resources. Defaults to src/test/resources
57     */
58    @Parameter(defaultValue = "${basedir}/src/test/resources", required = true)
59    private File testResourceDirectory;
60  
61    private String[] generateEnvironment() throws MojoExecutionException, MojoFailureException {
62      final List env = new ArrayList();
63  
64      final Set/* <File> */sharedPaths = new HashSet();
65  
66      // add all shared libraries of this package
67      for (final Object element : getLibraries()) {
68        final Library lib = (Library) element;
69        if (lib.getType().equals(Library.SHARED)) {
70          final File path = getLayout().getLibDirectory(getTargetDirectory(), getMavenProject().getArtifactId(),
71              getMavenProject().getVersion(), getAOL().toString(), lib.getType());
72          getLog().debug("Adding path to shared library: " + path);
73          sharedPaths.add(path);
74        }
75      }
76  
77      // add dependent shared libraries
78      final String classifier = getAOL() + "-shared";
79      final List narArtifacts = getNarArtifacts();
80      final List dependencies = getNarManager().getAttachedNarDependencies(narArtifacts, classifier);
81      for (final Object dependency1 : dependencies) {
82        final Artifact dependency = (Artifact) dependency1;
83        getLog().debug("Looking for dependency " + dependency);
84  
85        // FIXME reported to maven developer list, isSnapshot
86        // changes behaviour
87        // of getBaseVersion, called in pathOf.
88        dependency.isSnapshot();
89  
90        final File libDirectory = getLayout()
91            .getLibDirectory(getUnpackDirectory(), dependency.getArtifactId(), dependency.getBaseVersion(),
92                getAOL().toString(), Library.SHARED);
93        sharedPaths.add(libDirectory);
94      }
95  
96      // set environment
97      if (sharedPaths.size() > 0) {
98        String sharedPath = "";
99        for (final Iterator i = sharedPaths.iterator(); i.hasNext();) {
100         sharedPath += ((File) i.next()).getPath();
101         if (i.hasNext()) {
102           sharedPath += File.pathSeparator;
103         }
104       }
105 
106       final String sharedEnv = NarUtil.addLibraryPathToEnv(sharedPath, null, getOS());
107       env.add(sharedEnv);
108     }
109 
110     // necessary to find WinSxS
111     if (getOS().equals(OS.WINDOWS)) {
112       env.add("SystemRoot=" + NarUtil.getEnv("SystemRoot", "SystemRoot", "C:\\Windows"));
113     }
114 
115     // add CLASSPATH
116     env.add("CLASSPATH=" + StringUtils.join(this.classpathElements.iterator(), File.pathSeparator));
117 
118     return env.size() > 0 ? (String[]) env.toArray(new String[env.size()]) : null;
119   }
120 
121   /**
122    * List the dependencies needed for tests executions and for executables
123    * executions, those dependencies are used
124    * to declare the paths of shared libraries for execution.
125    */
126   @Override
127   protected ScopeFilter getArtifactScopeFilter() {
128     return new ScopeFilter( Artifact.SCOPE_TEST, null );
129   }
130 
131   @Override
132   protected File getUnpackDirectory() {
133     return getTestUnpackDirectory() == null ? super.getUnpackDirectory() : getTestUnpackDirectory();
134   }
135 
136   @Override
137   public final void narExecute() throws MojoExecutionException, MojoFailureException {
138     if (this.skipTests) {
139       getLog().info("Tests are skipped");
140     } else {
141 
142       // run all tests
143       for (final Object o : getTests()) {
144         runTest((Test) o);
145       }
146 
147       for (final Object element : getLibraries()) {
148         runExecutable((Library) element);
149       }
150     }
151   }
152 
153   private void runExecutable(final Library library) throws MojoExecutionException, MojoFailureException {
154     if (library.getType().equals(Library.EXECUTABLE) && library.shouldRun()) {
155       final MavenProject project = getMavenProject();
156       // FIXME NAR-90, we could make sure we get the final name from layout
157       final String extension = getOS().equals(OS.WINDOWS) ? ".exe" : "";
158       final File executable = new File(getLayout().getBinDirectory(getTargetDirectory(),
159           getMavenProject().getArtifactId(), getMavenProject().getVersion(), getAOL().toString()),
160           project.getArtifactId() + extension);
161       if (!executable.exists()) {
162         getLog().warn("Skipping non-existing executable " + executable);
163         return;
164       }
165       getLog().info("Running executable " + executable);
166       final List args = library.getArgs();
167       final int result = NarUtil.runCommand(executable.getPath(), (String[]) args.toArray(new String[args.size()]),
168           null, generateEnvironment(), getLog());
169       if (result != 0) {
170         throw new MojoFailureException("Test " + executable + " failed with exit code: " + result + " 0x"
171             + Integer.toHexString(result));
172       }
173     }
174   }
175 
176   private void runTest(final Test test) throws MojoExecutionException, MojoFailureException {
177     // run if requested
178     if (test.shouldRun()) {
179       // NOTE should we use layout here ?
180       final String name = test.getName() + (getOS().equals(OS.WINDOWS) ? ".exe" : "");
181       File path = new File(getTestTargetDirectory(), "bin");
182       path = new File(path, getAOL().toString());
183       path = new File(path, name);
184       if (!path.exists()) {
185         getLog().warn("Skipping non-existing test " + path);
186         return;
187       }
188 
189       final File workingDir = new File(getTestTargetDirectory(), "test-reports");
190       workingDir.mkdirs();
191 
192       // Copy test resources
193       try {
194         int copied = 0;
195         if (this.testResourceDirectory.exists()) {
196           copied += NarUtil.copyDirectoryStructure(this.testResourceDirectory, workingDir, null,
197               NarUtil.DEFAULT_EXCLUDES);
198         }
199         getLog().info("Copied " + copied + " test resources");
200       } catch (final IOException e) {
201         throw new MojoExecutionException("NAR: Could not copy test resources", e);
202       }
203 
204       getLog().info("Running test " + name + " in " + workingDir);
205 
206       final List args = test.getArgs();
207       final int result = NarUtil.runCommand(path.toString(), (String[]) args.toArray(new String[args.size()]),
208           workingDir, generateEnvironment(), getLog());
209       if (result != 0) {
210         throw new MojoFailureException("Test " + name + " failed with exit code: " + result + " 0x"
211             + Integer.toHexString(result));
212       }
213     }
214   }
215 }