Sample Code

This sample code block implements the process executor test type, which can be used to launch any executable and extends the published ExtProcessTestLaunchBean class.

package com.borland.sctm.testlauncher;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;

import com.segue.tm.published.api.testlaunch.ExtProcessTestLaunchBean;
import com.segue.tm.published.api.testlaunch.TestLaunchResultDrain;

/**
 * Implements an Silk Central test type that can be used to launch
 * any executables, for example from a command line.
 * Extends Silk Central published process test launcher class,
 * see Silk Central API Specification (in Help -> Documentation) for
 * further details.
 */
public class ProcessExecutor extends ExtProcessTestLaunchBean {

  // test properties that will be set by Silk Central using appropriate setter 
  // methods (bean convention), 
  // property names must conform to property tags used in the XML file
  
  /**
   * Represents property <command> defined in ProcessExecutor.xml.
   */
  private String command;
  
  /**
   * Represents property <arguments> defined in ProcessExecutor.xml.
   */
  private String arguments;
  
  /**
   * Represents property <workingfolder> defined in ProcessExecutor.xml.
   */
  private String workingfolder;
  
  /**
   * Java Bean compliant setter used by Silk Central to forward the command to be
   * executed.
   * Conforms to property <command> defined in ProcessExecutor.xml.
   */
  public void setCommand(String command) {
    this.command = command;
  }

  /**
   * Java Bean compliant setter used by Silk Central to forward the arguments
   * that will be passed to the command.
   * Conforms to property <arguments> defined in ProcessExecutor.xml.
   */
  public void setArguments(String arguments) {
    this.arguments = arguments;
  }

  /**
   * Java Bean compliant setter used by Silk Central to forward the working
   * folder where the command will be executed.
   * Conforms to property <workingfolder> defined in
   * ProcessExecutor.xml.
   */
  public void setWorkingfolder(String workingfolder) {
    this.workingfolder = workingfolder;
  }

  /**
   * Main plug-in method. See Silk Central API Specification
   * (in Help &gt; Documentation) for further details.
   */
  @Override
  public boolean execute(long time, TestLaunchResultDrain context)
    throws InterruptedException {
    try {
      String[] cmd = getCommandArgs(context);
      File workingDir = getWorkingFolderFile(context);
      String[] envVariables = getEnviromentVariables(context);
      
      int processExitCode = runExternalProcess(cmd, envVariables, workingDir,
        context.getLog());      

      boolean outputXmlFound = handleOutputXmlIfExists(context); 
      
      if (! outputXmlFound && processExitCode != 0) { 
        // if no output.xml file was produced, the exit code indicates
        // success or failure
        context.publishMessage(TestLaunchResultDrain.SEVERITY_ERROR,
          "Process exited with return code "
          + String.valueOf(processExitCode));
        context.updateErrors(1, 0);
        // set error, test will get status 'failed'
      }
    } catch (IOException e) {
      // prints exception message to Messages tab in Test Run
      // Results
      context.publishMessage(TestLaunchResultDrain.SEVERITY_FATAL,
        e.getMessage());
      // prints exception stack trace to 'log.txt' that can be viewed in Files
      // tab
      e.printStackTrace(context.getLog());
      context.publishErrors(1, 0);
      return false; // set test status to 'not executed'
    }
    return true; 
  }

  /**
   * Initializes environment variables to be set additionally to those 
   * inherited from the system environment of the Execution Server.
   * @param context the test execution context
   * @return String array containing the set environment variables
   * @throws IOException
   */
  private String[] getEnviromentVariables(TestLaunchResultDrain context)
    throws IOException {
    String[] envVariables = {
      "SCTM_EXEC_RESULTSFOLDER="
      + context.getTempResultsDir().getAbsolutePath(),
      "SCTM_EXEC_SOURCESFOLDER="
      + sourceAccess().getTestContainerRootDir().getAbsolutePath(),
    };
    return envVariables;
  }

  /**
   * Let Silk Central parse the standard report xml file (output.xml) if exists.
   * See also Silk Central Web Help - Creating a Test Package. A XSD file
   * can be found in Silk Central Help -&gt; Tools -&gt; Test Package XML Schema
   * Definition File
   * @param context the test execution context
   * @return true if output.xml exists
   * @throws IOException
   */
  private boolean handleOutputXmlIfExists(TestLaunchResultDrain context)
    throws IOException {
    String outputFileName = context.getTempResultsDir().getAbsolutePath()
    + File.separator + TestLaunchResultDrain.OUTPUT_XML_RESULT_FILE;
    File outputfile = new File(outputFileName);
    boolean outputXmlExists = outputfile.exists();
    if (outputXmlExists) {
      context.parseStdResultFile(outputfile);
      context.publishMessage(TestLaunchResultDrain.SEVERITY_INFO, 
        String.format("output.xml parsed from '%s'", outputFileName));
    }
    return outputXmlExists;
  }

  /**
   * Retrieves the working folder on the Execution Server. If not configured
   * the results directory is used as working folder.
   * @param context the test execution context 
   * @return the working folder file object
   * @throws IOException
   */
  private File getWorkingFolderFile(TestLaunchResultDrain context)
    throws IOException {
    final File workingFolderFile;
    if (workingfolder != null) {
      workingFolderFile = new File(workingfolder);
    } else {
      workingFolderFile = context.getTempResultsDir();
    }
    context.publishMessage(TestLaunchResultDrain.SEVERITY_INFO,
      String.format("process is exectued in working folder '%s'",
        workingFolderFile.getAbsolutePath()));
    return workingFolderFile;
  }

  /**
   * Retrieves the command line arguments specified.
   * @param context the test execution context
   * @return an array of command line arguments 
   */
  private String[] getCommandArgs(TestLaunchResultDrain context) {
    final ArrayList<String> cmdList = new ArrayList<String>();
    final StringBuilder cmd = new StringBuilder();
    cmdList.add(command);
    cmd.append(command);
    if (arguments != null) {
      String[] lines = arguments.split("[\\r\\n]+");
      for (String line : lines) {
        cmdList.add(line);
        cmd.append(" ").append(line);
      }
    }
    context.publishMessage(TestLaunchResultDrain.SEVERITY_INFO,
      String.format("executed command '%s'", cmd.toString()));
    context.getLog().printf("start '%s'%n", cmd.toString());
    return (String[]) cmdList.toArray(new String[cmdList.size()]);
  }
}