hadoop TestMojo 源码

  • 2022-10-20
  • 浏览 (129)

haddop TestMojo 代码

文件路径:/hadoop-maven-plugins/src/main/java/org/apache/hadoop/maven/plugin/cmakebuilder/TestMojo.java

/*
 * 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.apache.hadoop.maven.plugin.cmakebuilder;

import java.util.Locale;
import org.apache.hadoop.maven.plugin.util.Exec;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.concurrent.TimeUnit;
import java.util.LinkedList;
import java.util.List;
import java.util.HashMap;
import java.util.Map;

/**
 * Goal which runs a native unit test.
 */
@Mojo(name="cmake-test", defaultPhase = LifecyclePhase.TEST)
public class TestMojo extends AbstractMojo {
  /**
   * A value for -Dtest= that runs all native tests.
   */
  private final static String ALL_NATIVE = "allNative";

  /**
   * Location of the binary to run.
   */
  @Parameter(required=true)
  private File binary;

  /**
   * Name of this test.
   *
   * Defaults to the basename of the binary.  So if your binary is /foo/bar/baz,
   * this will default to 'baz.'
   */
  @Parameter
  private String testName;

  /**
   * Environment variables to pass to the binary.
   */
  @Parameter
  private Map<String, String> env;

  /**
   * Arguments to pass to the binary.
   */
  @Parameter
  private List<String> args = new LinkedList<String>();

  /**
   * Number of seconds to wait before declaring the test failed.
   *
   */
  @Parameter(defaultValue="600")
  private int timeout;

  /**
   * The working directory to use.
   */
  @Parameter
  private File workingDirectory;

  /**
   * Path to results directory.
   */
  @Parameter(defaultValue="native-results")
  private File results;

  /**
   * A list of preconditions which must be true for this test to be run.
   */
  @Parameter
  private Map<String, String> preconditions = new HashMap<String, String>();

  /**
   * If true, pass over the test without an error if the binary is missing.
   */
  @Parameter(defaultValue="false")
  private boolean skipIfMissing;

  /**
   * What result to expect from the test
   *
   * Can be either "success", "failure", or "any".
   */
  @Parameter(defaultValue="success")
  private String expectedResult;

  /**
   * The Maven Session Object.
   */
  @Parameter(defaultValue="${session}", readonly=true, required=true)
  private MavenSession session;

  // TODO: support Windows
  private static void validatePlatform() throws MojoExecutionException {
    if (System.getProperty("os.name").toLowerCase(Locale.ENGLISH)
        .startsWith("windows")) {
      throw new MojoExecutionException("CMakeBuilder does not yet support " +
          "the Windows platform.");
    }
  }

  /**
   * The test thread waits for the process to terminate.
   *
   * Since Process#waitFor doesn't take a timeout argument, we simulate one by
   * interrupting this thread after a certain amount of time has elapsed.
   */
  private static class TestThread extends Thread {
    private Process proc;
    private int retCode = -1;

    public TestThread(Process proc) {
      this.proc = proc;
    }

    public void run() {
      try {
        retCode = proc.waitFor();
      } catch (InterruptedException e) {
        retCode = -1;
      }
    }

    public int retCode() {
      return retCode;
    }
  }

  /**
   * Write to the status file.
   *
   * The status file will contain a string describing the exit status of the
   * test.  It will be SUCCESS if the test returned success (return code 0), a
   * numerical code if it returned a non-zero status, or IN_PROGRESS or
   * TIMED_OUT.
   */
  private void writeStatusFile(String status) throws IOException {
    FileOutputStream fos = new FileOutputStream(new File(results,
                testName + ".pstatus"));
    BufferedWriter out = null;
    try {
      out = new BufferedWriter(new OutputStreamWriter(fos, "UTF8"));
      out.write(status + "\n");
    } finally {
      if (out != null) {
        out.close();
      } else {
        fos.close();
      }
    }
  }

  private static boolean isTruthy(String str) {
    if (str == null)
      return false;
    if (str.equalsIgnoreCase(""))
      return false;
    if (str.equalsIgnoreCase("false"))
      return false;
    if (str.equalsIgnoreCase("no"))
      return false;
    if (str.equalsIgnoreCase("off"))
      return false;
    if (str.equalsIgnoreCase("disable"))
      return false;
    return true;
  }


  final static private String VALID_PRECONDITION_TYPES_STR =
      "Valid precondition types are \"and\", \"andNot\"";

  /**
   * Validate the parameters that the user has passed.
   * @throws MojoExecutionException
   */
  private void validateParameters() throws MojoExecutionException {
    if (!(expectedResult.equals("success") ||
        expectedResult.equals("failure") ||
        expectedResult.equals("any"))) {
      throw new MojoExecutionException("expectedResult must be either " +
          "success, failure, or any");
    }
  }

  private boolean shouldRunTest() throws MojoExecutionException {
    // Were we told to skip all tests?
    String skipTests = session.
        getSystemProperties().getProperty("skipTests");
    if (isTruthy(skipTests)) {
      getLog().info("skipTests is in effect for test " + testName);
      return false;
    }
    // Does the binary exist?  If not, we shouldn't try to run it.
    if (!binary.exists()) {
      if (skipIfMissing) {
        getLog().info("Skipping missing test " + testName);
        return false;
      } else {
        throw new MojoExecutionException("Test " + binary +
            " was not built!  (File does not exist.)");
      }
    }
    // If there is an explicit list of tests to run, it should include this
    // test.
    String testProp = session.
        getSystemProperties().getProperty("test");
    if (testProp != null) {
      String testPropArr[] = testProp.split(",");
      boolean found = false;
      for (String test : testPropArr) {
        if (test.equals(ALL_NATIVE)) {
          found = true;
          break;
        }
        if (test.equals(testName)) {
          found = true;
          break;
        }
      }
      if (!found) {
        getLog().debug("did not find test '" + testName + "' in "
             + "list " + testProp);
        return false;
      }
    }
    // Are all the preconditions satistfied?
    if (preconditions != null) {
      int idx = 1;
      for (Map.Entry<String, String> entry : preconditions.entrySet()) {
        String key = entry.getKey();
        String val = entry.getValue();
        if (key == null) {
          throw new MojoExecutionException("NULL is not a valid " +
               "precondition type.  " + VALID_PRECONDITION_TYPES_STR);
        }
        if (key.equals("and")) {
          if (!isTruthy(val)) {
            getLog().info("Skipping test " + testName +
                " because precondition number " + idx + " was not met.");
            return false;
          }
        } else if (key.equals("andNot")) {
          if (isTruthy(val)) {
            getLog().info("Skipping test " + testName +
                " because negative precondition number " + idx +
                " was met.");
            return false;
          }
        } else {
          throw new MojoExecutionException(key + " is not a valid " +
              "precondition type.  " + VALID_PRECONDITION_TYPES_STR);
        }
        idx++;
      }
    }
    // OK, we should run this.
    return true;
  }

  public void execute() throws MojoExecutionException {
    if (testName == null) {
      testName = binary.getName();
    }
    validatePlatform();
    validateParameters();
    if (!shouldRunTest()) {
      return;
    }
    if (!results.isDirectory()) {
      if (!results.mkdirs()) {
        throw new MojoExecutionException("Failed to create " +
            "output directory '" + results + "'!");
      }
    }
    List<String> cmd = new LinkedList<String>();
    cmd.add(binary.getAbsolutePath());

    getLog().info("-------------------------------------------------------");
    getLog().info(" C M A K E B U I L D E R    T E S T");
    getLog().info("-------------------------------------------------------");
    StringBuilder bld = new StringBuilder();
    bld.append(testName).append(": running ");
    bld.append(binary.getAbsolutePath());
    for (String entry : args) {
      cmd.add(entry);
      bld.append(" ").append(entry);
    }
    getLog().info(bld.toString());
    ProcessBuilder pb = new ProcessBuilder(cmd);
    Exec.addEnvironment(pb, env);
    if (workingDirectory != null) {
      pb.directory(workingDirectory);
    }
    pb.redirectError(new File(results, testName + ".stderr"));
    pb.redirectOutput(new File(results, testName + ".stdout"));
    getLog().info("with extra environment variables " + Exec.envToString(env));
    Process proc = null;
    TestThread testThread = null;
    int retCode = -1;
    String status = "IN_PROGRESS";
    try {
      writeStatusFile(status);
    } catch (IOException e) {
      throw new MojoExecutionException("Error writing the status file", e);
    }
    long start = System.nanoTime();
    try {
      proc = pb.start();
      testThread = new TestThread(proc);
      testThread.start();
      testThread.join(timeout * 1000);
      if (!testThread.isAlive()) {
        retCode = testThread.retCode();
        testThread = null;
        proc = null;
      }
    } catch (IOException e) {
      throw new MojoExecutionException("IOException while executing the test " +
          testName, e);
    } catch (InterruptedException e) {
      throw new MojoExecutionException("Interrupted while executing " +
          "the test " + testName, e);
    } finally {
      if (testThread != null) {
        // If the test thread didn't exit yet, that means the timeout expired.
        testThread.interrupt();
        try {
          testThread.join();
        } catch (InterruptedException e) {
          getLog().error("Interrupted while waiting for testThread", e);
        }
        status = "TIMED OUT";
      } else if (retCode == 0) {
        status = "SUCCESS";
      } else {
        status = "ERROR CODE " + String.valueOf(retCode);
      }
      try {
        writeStatusFile(status);
      } catch (Exception e) {
        getLog().error("failed to write status file!", e);
      }
      if (proc != null) {
        proc.destroy();
      }
    }
    long end = System.nanoTime();
    getLog().info("STATUS: " + status + " after " +
          TimeUnit.MILLISECONDS.convert(end - start, TimeUnit.NANOSECONDS) +
          " millisecond(s).");
    getLog().info("-------------------------------------------------------");
    if (status.equals("TIMED_OUT")) {
      if (expectedResult.equals("success")) {
        throw new MojoExecutionException("Test " + binary +
            " timed out after " + timeout + " seconds!");
      }
    } else if (!status.equals("SUCCESS")) {
      if (expectedResult.equals("success")) {
        throw new MojoExecutionException("Test " + binary +
            " returned " + status);
      }
    } else if (expectedResult.equals("failure")) {
      throw new MojoExecutionException("Test " + binary +
          " succeeded, but we expected failure!");
    }
  }
}

相关信息

hadoop 源码目录

相关文章

hadoop CompileMojo 源码

0  赞