Package org.moyrax.maven

Source Code of org.moyrax.maven.QUnitPlugin

/* vim: set ts=2 et sw=2 cindent fo=qroca: */

package org.moyrax.maven;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;

import org.apache.commons.lang.Validate;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.DependencyResolutionRequiredException;
import org.apache.maven.artifact.factory.ArtifactFactory;
import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
import org.apache.maven.artifact.resolver.ArtifactResolutionException;
import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
import org.apache.maven.artifact.resolver.ArtifactResolver;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.artifact.InvalidDependencyVersionException;
import org.apache.maven.project.artifact.MavenMetadataSource;
import org.apache.maven.shared.model.fileset.FileSet;
import org.apache.maven.shared.model.fileset.util.FileSetManager;
import org.moyrax.javascript.ContextClassLoader;
import org.moyrax.javascript.qunit.QUnitReporter;
import org.moyrax.javascript.qunit.TestRunner;
import org.moyrax.resolver.ClassPathResolver;

import com.gargoylesoftware.htmlunit.BrowserVersion;
import com.gargoylesoftware.htmlunit.WebClient;

/** Runs a qunit based test.
*
* @goal test
* @phase test
*/
public class QUnitPlugin extends AbstractMojo {
  /**
   * Local files which will be executed using QUnit.
   *
   * @parameter
   */
  private FileSet testResources;

  /**
   * Directories that will be included to search resources.
   *
   * @parameter
   * @required
   */
  private List<Entry> contextPath = new ArrayList<Entry>();

  /**
   * URLs from whence remote tests are executed.
   *
   * @parameter
   */
  private UrlSet remoteTestResources;

  /**
   * List of classpath urls in which lookup for exportable Java classes.
   *
   * @parameter
   */
  private List<String> components = new ArrayList<String>();

  /**
   * List of classpath urls in which lookup for exportable Java classes.
   *
   * @parameter expression="${skipTests}" default-value="false"
   */
  private Boolean skipTests = false;

  /**
   * List of classpath urls in which lookup for exportable Java classes.
   *
   * @parameter expression="${maven.test.skip}" default-value="false"
   */
  private Boolean oldSkipTests = false;

  /**
   * Object to ask the files specified in the plugin configuration.
   */
  private final FileSetManager fileSetManager = new FileSetManager();

  /**
   * Testing client.
   */
  private static TestingClient client;

  /**
   * Reporting results to the console.
   */
  private QUnitReporter reporter;

  /**
   * Container for running tests.
   *
   * TODO Make the browser type configurable.
   */
  private WebClient browser = new WebClient(BrowserVersion.FIREFOX_3);

  /**
   * Testing runner.
   */
  private TestRunner runner;

  /** The Maven project object, used to generate a classloader to access the
   * classpath resources from the project.
   *
   * Injected by maven. This is never null.
   *
   * @parameter expression="${project}" @readonly
   */
  private MavenProject project;

  /**
   * @component
   */
  private ArtifactResolver artifactResolver;

  /**
   * Used to build the list of artifacts from the project's dependencies.
   *
   * @component
   */
  private ArtifactFactory artifactFactory;

  /**
   * Provides some metadata operations, like querying the remote repository for
   * a list of versions available for an artifact.
   *
   * @component
   */
  private ArtifactMetadataSource metadataSource;

  /**
   * Specifies the repository used for artifact handling.
   *
   * @parameter expression="${localRepository}"
   */
  private ArtifactRepository localRepository;

  /**
   * Executes this plugin when the build reached the defined phase and goal.
   */
  public void execute() throws MojoExecutionException, MojoFailureException {

    if (skipTests || oldSkipTests) {
      getLog().info("Tests are skipped.");
      return;
    }

    // Should have been injected by maven. Checked here as this is the entry
    // point of the module.
    Validate.notNull(project, "The project cannot be null.");

    reporter = new QUnitReporter(getReportsDirectory(),
        new MojoLogAdapter(getLog()));

    runner = new TestRunner(reporter, browser);
    initEnvironment();
    loadContextResources();

    client.runTests();
    runner.reportAll();
  }

  /**
   * Sets the {@link FileSet} which contains the rules to retrieve the testing
   * files.
   *
   * @param theResources Test resources. It cannot be null.
   */
  public void setTestResources(final FileSet theResources) {
    Validate.notNull(theResources, "The resources cannot be null.");

    testResources = theResources;
  }

  /**
   * Adds a new search path to scan for JavaScript components.
   *
   * @param classPath Classpath to search for resources. It cannot be null or
   *    empty.
   */
  public void addComponentSearchPath(final String classPath) {
    Validate.notEmpty(classPath, "The class path cannot be null or empty.");

    components.add(classPath);
  }

  /**
   * Initializes the required resources for the test environment.
   */
  private void loadContextResources() {
    final String[] dependencies = new String[] {
        /* QUnit testing framework. */
        "org/moyrax/javascript/lib/qunit.js"
    };

    for (int i = 0; i < dependencies.length; i++) {
      client.addGlobalResource(dependencies[i]);
    }
  }

  /**
   * Initializes the environment configuration and starts the testing server.
   */
  private void initEnvironment() {
    EnvironmentConfiguration env = new EnvironmentConfiguration();

    if (testResources != null) {
      env.setFiles(testResources.getDirectory(),
          fileSetManager.getIncludedFiles(testResources),
          fileSetManager.getExcludedFiles(testResources));
    }

    if (remoteTestResources != null) {
      env.setUrls(remoteTestResources.getBaseUrl(),
          remoteTestResources.getUrlFiles());
    }

    env.setLookupPackages(components.toArray(new String[] {}));

    if (contextPath != null) {
      for (Entry entry : contextPath) {
        ContextPathBuilder.addDefinition(entry.files.getDirectory(),
            entry.files.getIncludesArray(), entry.files.getExcludesArray());
      }
    }

    ContextPathBuilder.build();

    ClassLoader projectClassLoader = createProjectClassloader(project);
    ClassPathResolver resolver = new ClassPathResolver(projectClassLoader);

    env.setClassLoader(projectClassLoader);

    client = new TestingClient(runner, env, resolver);
  }

  /**
   * Returns the directory where the reports will be written.
   */
  private String getReportsDirectory() {
    File directory = new File(new File(project.getBasedir(), "target"),
      "qunit-reports");

    if (!directory.exists()) {
      directory.mkdirs();
    }

    return directory.getAbsolutePath();
  }

  /** Creates the classloader to load resources from the project under test.
   *
   * @param theProject The maven project under test.
   *
   * @return a classloader initialized from the provided maven project, never
   * null
   */
  @SuppressWarnings("unchecked")
  private ClassLoader createProjectClassloader(
      final MavenProject theProject) {

    List testClasspathElements;

    try {
      testClasspathElements = theProject.getTestClasspathElements();
    } catch (DependencyResolutionRequiredException e) {
      throw new RuntimeException(e);
    }

    URL[] testUrls = new URL[testClasspathElements.size()];

    for (int i = 0; i < testClasspathElements.size(); i++) {
      String element = (String) testClasspathElements.get(i);
      try {
        testUrls[i] = new File(element).toURI().toURL();
      } catch (MalformedURLException e) {
        throw new RuntimeException(e);
      }
    }

    ClassLoader depsClassLoader = createDependenciesClassLoader(theProject);

    URLClassLoader newLoader = new URLClassLoader(testUrls, depsClassLoader);

    return new ContextClassLoader(newLoader);
  }

  /**
   * Creates a {@link ClassLoader} which contains all the project's
   * dependencies.
   *
   * @param theProject The maven project under test. It cannot be null.
   *
   * @return Returns the created {@link ClassLoader} containing all the
   *    project's dependencies.
   */
  @SuppressWarnings("unchecked")
  private ClassLoader createDependenciesClassLoader(
      final MavenProject theProject) {

    Validate.notNull(theProject, "The project cannot be null.");

    // Make Artifacts of all the dependencies.
    Set<Artifact> dependencyArtifacts;

    try {
      dependencyArtifacts = MavenMetadataSource.createArtifacts(
          artifactFactory, theProject.getDependencies(), null, null, null );
    } catch (InvalidDependencyVersionException ex) {
      throw new RuntimeException("Cannot resolve dependencies version.", ex);
    }

    // Resolves all dependencies transitively to obtain a comprehensive list
    // of jars.
    ArtifactResolutionResult result;

    try {
      result = artifactResolver.resolveTransitively(
          dependencyArtifacts,
          theProject.getArtifact(),
          Collections.EMPTY_LIST,
          localRepository,
          metadataSource);
    } catch (ArtifactResolutionException ex) {
      throw new RuntimeException("Cannot resolve the artifact.", ex);
    } catch (ArtifactNotFoundException ex) {
      throw new RuntimeException("Artifact not found in the local"
          + " repository.", ex);
    }

    // Retrieves the filesystem path of each dependency jar.
    Set<Artifact> artifacts = result.getArtifacts();

    URL[] urls = new URL[artifacts.size()];

    int i = 0;

    for (Artifact artifact : artifacts) {
      try {
        urls[i++] = artifact.getFile().toURI().toURL();
      } catch (MalformedURLException ex) {
        throw new RuntimeException("Cannot resolve the artifact path.", ex);
      }
    }

    URLClassLoader newLoader = new URLClassLoader(urls,
        Thread.currentThread().getContextClassLoader());

    return newLoader;
  }
}
TOP

Related Classes of org.moyrax.maven.QUnitPlugin

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.