Skip to content

CTS Refactoring Notes

Scott M Stark edited this page Jul 2, 2024 · 8 revisions

This page contains notes on the legacy CTS framework.

Notes on the build.xml tasks

package

The package target is required in all build.xml files, but it may be imported. Typically this is either invoking ts.vehicles or it is calling other tasks like ts.ejbjar, ts.clientjar, ts.ear, ts.war, to build the test artifact(s).

ts.vehicles

The ts.vehicles macrodef defined in ts.home/bin/xml/ts.vehicles.xml defines how to build the vehicle test artifacts. It loops through all vehicles defined for a given test package and creates the artifacts. This entails calling other ts.javac, ts.ejb, ts.war, etc macros.

Notes on the vehicle runners

The main entry point to running a test is the javatest presetdef defines in the bin/xml/ts.top.import.xml files. It simply invokes the com.sun.javatest.tool.Main class with several system properties and a classpath. The transition from the JavaTest layer to the CTS layer seems to be between finding tests based on scanning the CTS src tree for @testName comment annotations and the `com.sun.ts.lib.harness.EETest abstract base class translating the collected properties into test method invocations using reflection. This happens in the com.sun.ts.lib.harness.TS class which extends the JavaTest com.sun.javatest.TestSuite class. The com.sun.javatest.Harness class seems to do most of the scanning for tests.

For each test the TS class creates a TSScript instance, and this ends up invoking a com.sun.ts.lib.harness .ExecTSTestCmd instance to run the test in a separate VM. The stack from the JavaTest code to where this call happens is:

exec:326, ProcessCommand (com.sun.javatest.lib)
run:252, ProcessCommand (com.sun.javatest.lib)
invokeClass:779, TSScript (com.sun.ts.lib.harness)
invokeCommand:727, TSScript (com.sun.ts.lib.harness)
execute:907, Script (com.sun.javatest)
execute:866, Script (com.sun.javatest)
run:458, TSScript (com.sun.ts.lib.harness)
run:241, Script (com.sun.javatest)
runTest:174, DefaultTestRunner (com.sun.javatest)
access$100:43, DefaultTestRunner (com.sun.javatest)
run:66, DefaultTestRunner$1 (com.sun.javatest)

The command that is run is either a vendor appclient command line, or the com.sun.ts.tests.common.vehicle.VehicleClient#main. The later is often the mainclass value of the appclient ear, but it can also be a direct EETest subclass for tests without vehicles.

Ultimately the com.sun.ts.tests.common.vehicle.VehicleRunnerFactory#getVehicleRunner(String) is called from com.sun.ts.lib.harness.ServiceEETest#run(String[], Properties) method to obtain the com.sun.ts.tests.common.vehicle.VehicleRunnable. The implementation is based on the vehicle type passed into getVehicleRunner, and it has a single Status run(String[] argv, Properties p) method.

Threre are:

  • 1958 EETest subclasses
  • 880 ServiceEETest subclasses

Direct subclasses of EETest include client classes for appclient vehicle tests which have a unique launch setup and we have a prototype of an Arquillian protocol for that type of vehicle.

Another direct abstract subclass is com.sun.ts.tests.common.webclient.BaseUrlClient. The 392 subclasses of this class all look to be doing a simple invocation on a servlet to validate the deployment created by the test package build.xml. This works with the existing Arquillian servlet based protocol.

Details on the ejbliteservlet vehicle

As an example, the ejbliteservlet vehicle type maps to the com.sun.ts.tests.common.vehicle.ejbliteshare.EJBLiteWebVehicleRunner. This will invoke a '/ejbliteservlet_vehicle.jsp' URL and check for a PASSED/FAILED status as shown here:

public class EJBLiteWebVehicleRunner implements VehicleRunnable {
  private final static Logger logger = Logger
      .getLogger(EJBLiteWebVehicleRunner.class.getName());

  protected String getServletPath(String vehicle) {
    return "/" + vehicle + "_vehicle.jsp";
  }

  protected String getQueryString(Properties p) {
    return "?testName=" + p.getProperty("testName");
  }

  public Status run(String[] argv, Properties p) {
    String vehicle = p.getProperty("vehicle");
    String contextRoot = p.getProperty("vehicle_archive_name");
    String requestUrl = "/" + contextRoot + getServletPath(vehicle)
        + getQueryString(p);

    TSURL ctsURL = new TSURL();
    URL url = null;
    HttpURLConnection connection = null;
    int statusCode = Status.NOT_RUN;
    String response = null;
    try {
      url = ctsURL.getURL("http", p.getProperty("webServerHost"),
          Integer.parseInt(p.getProperty("webServerPort")), requestUrl);

      connection = (HttpURLConnection) url.openConnection();
      connection.setRequestMethod("GET");
      connection.setUseCaches(false);
      logger.info("Connecting " + url.toExternalForm());
      connection.connect();

      response = TestUtil.getResponse(connection).trim();
      if (response.indexOf(TEST_PASSED) >= 0) {
        statusCode = Status.PASSED;
      } else {
        statusCode = Status.FAILED;
      }
    } catch (IOException e) {
      statusCode = Status.FAILED;
      response = "Failed to connect to the test webapp."
          + TestUtil.printStackTraceToString(e);
    }
    return new ReasonableStatus(statusCode, response);
  }
}

Commonly the tests using the ejbliteservlet vehicle will add the following src/com/sun/ts/tests/common/vehicle/ejbliteservlet/ejbliteservlet_vehicle_web.xml which maps the /ejbliteservlet_vehicle.jsp to the EJBLiteServletVehicle servlet:

<web-app version="5.0" xmlns="https://jakarta.ee/xml/ns/jakartaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd">
    <servlet>
        <servlet-name>EJBLiteServletVehicle</servlet-name>
        <servlet-class>@[email protected]</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>EJBLiteServletVehicle</servlet-name>
        <url-pattern>/ejbliteservlet_vehicle.jsp</url-pattern>
    </servlet-mapping>
</web-app>

The EJBLiteServletVehicle is generated from a src/com/sun/ts/tests/common/vehicle/ejbliteservlet/EJBLiteServletVehicle.java.txt file into the test class package, and then deleted after it is included in the test artifact. This makes it more difficult to simply use the parsed ts.vehicle target from the test package build.xml since not all classes are available. For the actual Arquillian @Deployment method, this probably won't matter unless we try to use a CTS protocol that tries to make use of the existing CTS vehicles. This is still being investigated (2024-06-11).

The EJBLiteServletVehicle extends the test package Client, which extends several common base classes, the most relevant being com.sun.ts.lib.harness.ServiceEETest which is used by all tests that are run within an EE server.

Clone this wiki locally