Red Hat Training

A Red Hat training course is available for Red Hat Application Migration Toolkit

Chapter 4. Testing XML Rules

4.1. Create a Test Rule

Once a rule has been created, it is recommended to create a test rule to ensure the functionality meets the desired expectation. Test rules are created using a process similar to Creating XML Rules with the following differences.

  • Test rules should be placed in a tests/ directory beneath the rule to be tested.
  • Any data, such as test classes, should be placed in a data/ directory beneath the tests/ directory.
  • Test rules should use the .rhamt.test.xml extension.
  • These rules use the structure defined in Test XML Rule Structure.

In addition, it is recommended to create a test rule that follows the name of the rule it tests. For instance, if a rule were created with a filename of proprietary-rule.rhamt.xml, the test rule should be called proprietary-rule.rhamt.test.xml.

4.1.1. Test XML Rule Structure

All test XML rules are defined as elements within ruletests which contain one or more rulesets. For more details, see the RHAMT XML rule schema.

A ruletest is a group of one or more tests that targets a specific area of migration. This is the basic structure of the <ruletest> element.

  • <ruletest id="RULE_TOPIC-test">: Defines this as a unique RHAMT ruletest and gives it a unique ruletest id.

    • <testDataPath>: Defines the path to any data, such as classes or files, used for testing.
    • <sourceMode>: Indicates if the passed in data only contains source files. If an archive, such as an EAR, WAR, or JAR, is in use, then this should be set to false. Defaults to true.
    • <rulePath>: The path to the rule to be tested. This should end in the name of the rule to test.
    • <ruleset>: Rulesets containing the logic of the test cases. These are identical to the ones defined in Rulesets.

4.1.2. Test XML Rule Syntax

In addition to the tags in XML Rule Syntax, the following when conditions are commonly used for creating test rules.

In addition to the tags in Perform Action Syntax, the following perform conditions are commonly used as actions in test rules.

4.1.2.1. <not> Syntax

Summary

The <not> element is the standard logical not operator, and is commonly used to perform a <fail> if the condition is not met.

The following is an example of a test rule that fails if only a specific message exists at the end of the analysis.

<ruletest xmlns="http://windup.jboss.org/schema/jboss-ruleset"
          id="proprietary-servlet-test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://windup.jboss.org/schema/jboss-ruleset http://windup.jboss.org/schema/jboss-ruleset/windup-jboss-ruleset.xsd">
  <testDataPath>data/</testDataPath>
  <rulePath>../proprietary-servlet.rhamt.xml</rulePath>
  <ruleset>
    <rules>
      <rule id="proprietary-servlet-01000-test">
        <when>
          <!--
	    The <not> will perform a logical not operator on the elements within.
	  -->
          <not>
            <!--
	      The defined <iterable-filter> has a size of 1. This rule will only match on a single instance of the defined hint.
	    -->
            <iterable-filter size="1">
              <hint-exists message="Replace the proprietary @ProprietaryServlet annotation with the Java EE 7 standard @WebServlet annotation*" />
            </iterable-filter>
          </not>
        </when>
        <!--
	  This <perform> element is only executed if the previous <when> condition is false.
          This ensures that it only executes if there is not a single instance of the defined hint.
        -->
        <perform>
          <fail message="Hint for @ProprietaryServlet was not found!" />
        </perform>
      </rule>
    </rules>
  </ruleset>
</ruletest>

The <not> element has no unique attributes or child elements.

4.1.2.2. <iterable-filter> Syntax

Summary

The <iterable-filter> element counts the number of times a condition is verified. For additional information, see the IterableFilter class.

The following is an example that looks for four instances of the specified message.

<ruletest xmlns="http://windup.jboss.org/schema/jboss-ruleset"
          id="proprietary-servlet-test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://windup.jboss.org/schema/jboss-ruleset http://windup.jboss.org/schema/jboss-ruleset/windup-jboss-ruleset.xsd">
  <testDataPath>data/</testDataPath>
  <rulePath>../proprietary-servlet.rhamt.xml</rulePath>
  <ruleset>
    <rules>
      <rule id="proprietary-servlet-03000-test">
        <when>
          <!--
	    The <not> will perform a logical not operator on the elements within.
	  -->
          <not>
	    <!--
	      The defined <iterable-filter> has a size of 4. This rule will only match on four instances of the defined hint.
	    -->
            <iterable-filter size="4">
              <hint-exists message="Replace the proprietary @ProprietaryInitParam annotation with the Java EE 7 standard @WebInitParam annotation*" />
            </iterable-filter>
          </not>
        </when>
	<!--
	  This <perform> element is only executed if the previous <when> condition is false.
	  In this configuration, it only executes if there are not four instances of the defined hint.
	-->
        <perform>
          <fail message="Hint for @ProprietaryInitParam was not found!" />
        </perform>
      </rule>
    </rules>
  </ruleset>
</ruletest>

The <iterable-filter> element has no unique child elements.

<iterable-filter> Element Attributes
Attribute NameTypeDescription

size

integer

The number of times to be verified.

4.1.2.3. <classification-exists> Syntax

The <classification-exists> element determines if a specific classification title has been included in the analysis. For additional information, see the ClassificationExists class.

Important

When testing for a message that contains special characters, such as [ or ', you must escape each special character with a backslash (\) to correctly match.

The following is an example that searches for a specific classification title.

<ruletest xmlns="http://windup.jboss.org/schema/jboss-ruleset"
          id="proprietary-servlet-test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://windup.jboss.org/schema/jboss-ruleset http://windup.jboss.org/schema/jboss-ruleset/windup-jboss-ruleset.xsd">
  <testDataPath>data/</testDataPath>
  <rulePath>../weblogic.rhamt.xml</rulePath>
  <ruleset>
    <rules>
      <rule id="weblogic-01000-test">
        <when>
          <!--
	    The <not> will perform a logical not operator on the elements within.
	  -->
          <not>
	    <!--
	      The defined <classification-exists> is attempting to match on the defined title.
	      This classification would have been generated by a matching <classification title="WebLogic scheduled job" .../> rule.
	    -->
            <classification-exists classification="WebLogic scheduled job" />
          </not>
        </when>
	<!--
	  This <perform> element is only executed if the previous <when> condition is false.
	  In this configuration, it only executes if there is not a matching classification.
	-->
        <perform>
          <fail message="Triggerable not found" />
        </perform>
      </rule>
    </rules>
  </ruleset>
</ruletest>

The <classification-exists> has no unique child elements.

<classification-exists> Element Attributes
Attribute NameTypeDescription

classification

String

The <classification> title to search for.

in

String

An optional argument that restricts matching to files that contain the defined filename.

4.1.2.4. <hint-exists> Syntax

The <hint-exists> element determines if a specific hint has been included in the analysis. It searches for any instances of the defined message, and is typically used to search for the beginning or a specific class inside of a <message> element. For additional information, see the HintExists class.

Important

When testing for a message that contains special characters, such as [ or ', you must escape each special character with a backslash (\) to correctly match.

The following is an example that searches for a specific hint.

<ruletest xmlns="http://windup.jboss.org/schema/jboss-ruleset"
          id="proprietary-servlet-test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://windup.jboss.org/schema/jboss-ruleset http://windup.jboss.org/schema/jboss-ruleset/windup-jboss-ruleset.xsd">
  <testDataPath>data/</testDataPath>
  <rulePath>../weblogic.windup.xml</rulePath>
  <ruleset>
    <rules>
      <rule id="weblogic-eap7-05000-test">
        <when>
          <!--
	    The <not> will perform a logical not operator on the elements within.
	  -->
          <not>
	    <!--
	      The defined <hint-exists> is attempting to match on the defined message.
	      This message would have been generated by a matching <message> element on the <hint> condition.
	    -->
            <hint-exists message="Replace with the Java EE standard method .javax\.transaction\.TransactionManager\.resume\(Transaction tx\)." />
          </not>
        </when>
	<!--
	  This <perform> element is only executed if the previous <when> condition is false.
	  In this configuration, it only executes if there is not a matching hint.
	-->
        <perform>
          <fail message="Note to replace with standard TransactionManager.resume is missing!" />
        </perform>
      </rule>
    </rules>
  </ruleset>
</ruletest>

The <hint-exists> element has no unique child elements.

<hint-exists> Element Attributes
Attribute NameTypeDescription

message

String

The <hint> message to search for.

in

String

An optional argument that restricts matching to InLineHintModels that reference the given filename.

4.1.2.5. <fail> Syntax

The <fail> element reports the execution as a failure and displays the associated message. It is commonly used in conjunction with the <not> condition to display a message only if the conditions are not met.

An example is included in the <not> Syntax section.

The <fail> element has no unique child elements.

<fail> Element Attributes
Attribute NameTypeDescription

message

String

The message to be displayed.

4.2. Manually Test the XML Rule

Instead of writing a test case, it is possible to simply run the XML rule against your application file by running RHAMT in a terminal.

$ RHAMT_HOME/bin/rhamt-cli [--sourceMode] --input INPUT_ARCHIVE_OR_FOLDER --output OUTPUT_REPORT_DIRECTORY --target TARGET_TECHNOLOGY --packages PACKAGE_1 PACKAGE_2 PACKAGE_N

You should see the following result:

Report created: OUTPUT_REPORT_DIRECTORY/index.html
              Access it at this URL: file:///OUTPUT_REPORT_DIRECTORY/index.html

More examples of how to run RHAMT are located in the Red Hat Application Migration Toolkit CLI Guide.

4.3. Test the Rules Using JUnit

Once a test rule has been created, it can be analyzed as part of a JUnit test to confirm that the rule meets all criteria for execution. The WindupRulesMultipleTests class in the RHAMT rules repository is designed to test multiple rules simultaneously, and provides feedback on any missing requirements.

Prerequisites

Create the JUnit Test Configuration

The following instructions detail creating a JUnit test using the Red Hat Developer Studio. When using a different IDE it is recommended to consult your IDE’s documentation for instructions on creating a JUnit test.

  1. Import the RHAMT rulesets repository into your IDE.
  2. Copy the custom rules, along with the corresponding tests and data, into /path/to/RULESETS_REPO/rules-reviewed/RULE_NAME/. This should create the following directory structure.

    Directory Structure

    ├── rules-reviewed/  (Root directory of the rules found within the project)
    │   ├── RULE_NAME/  (Directory to contain the newly developed rule and tests)
    │   │   ├── RULE_NAME.rhamt.xml  (Custom rule)
    │   │   ├── tests/  (Directory that contains any test rules and data)
    │   │   │   ├── RULE_NAME.rhamt.test.xml (Test rule)
    │   │   │   └── data/  (Optional directory to contain test rule data)

  3. Select Run from the top menu bar.
  4. Select Run Configurations…​ from the drop down that appears.
  5. Right-click JUnit from the options on the left side and select New.
  6. Enter the following

    • Name: A name for your JUnit test, such as WindupRulesMultipleTests.
    • Project: Ensure this is set to windup-rulesets.
    • Test class: Set this to org.jboss.windup.rules.tests.WindupRulesMultipleTests.

      junit test
  7. Select the Arguments tab, and add the -DrunTestsMatching=RULE_NAME VM argument. For instance, if your rule name was community-rules, then you would add -DrunTestsMatching=community-rules as seen in the following image.

    junit test arguments
  8. Click Run in the bottom right corner to begin the test.

Once the execution completes the results will be available for analysis. If all tests passed, then the test rule is correctly formatted; otherwise, it is recommended to address each of the issues raised in the test failures. For additional information on the errors that might occur, see Reported Errors When Running the Validation Report.

4.4. Validation Report

Introduced in RHAMT 4.2, the validation report allows rule developers to confirm the test rules function as expected. It produces a report that provides details on each test rule, reporting any failures and where they occur.

Prerequisites

Create the Validation Report

  1. Navigate to the local windup-rulesets repository.
  2. Copy your custom rules and tests into the a subdirectory in the rules-reviewed directory. This should result in
  3. Run the following command from the root of the windup-rulesets repository:

    $ mvn -Dtest=WindupRulesMultipleTests -DrunTestsMatching=CUSTOM_RULES clean surefire-report:report

    For instance, if your rules were stored at the /path/to/windup-rulesets/rules-reviewed/myTests/ directory, then the following command would be used:

    $ mvn -Dtest=WindupRulesMultipleTests -DrunTestsMatching=myTests clean surefire-report:report
    Note

    Leaving off the runTestsMatching argument will result in all tests being included in the validation report, and will drastically increase the runtime.

  4. The validation report, surefire-report.html, will be generated in the target/site/ subdirectory of the windup-rulesets repository.

4.4.1. Understanding the Validation Report

The validation report is split into sections that organize any test failures into the packages and tests executed. This report contains the following sections:

Summary

The summary contains the overall number of tests executed and reports the number of errors and failures encountered. It also provides an overall success rate, and the time taken, in seconds, for the report to be generated.

Package List

The package list contains the number of tests executed per package, and reports the number of errors and failures encountered. It also provides a success rate, and the time taken, in seconds, for each package to be analyzed.

It is expected to see a single package, org.jboss.windup.rules.tests, unless additional test cases have been defined.

Test Cases

This section details each executed test. Each failure includes an optional Details section that can be expanded to show the stack trace for the assertion, including a line indicating the human readable source of the error. For additional information on the errors that might occur, see Reported Errors When Running the Validation Report.

4.4.2. Reported Errors When Running the Validation Report

The validation report will report any errors encountered while running the rules and tests. The following includes a list of these errors and how to resolve them.

Error MessageDescriptionResolution

No test file matching rule

This error occurs when a rule file exists without a corresponding test file.

Create a test file for the existing rule, as outlined in Testing XML Rules.

Test rule Ids RULE_NAME not found!

This error is thrown when a rule exists without a corresponding ruletest.

Create a test for the existing rule, as outlined in Test XML Rule Structure.

XML parse fail on file FILE_NAME

The syntax in the XML file is invalid, and unable to be parsed successfully by the rule validator.

Correct the invalid syntax.

Test file path from <testDataPath> tag has not been found. Expected path to test file is: RULE_DATA_PATH

No files are found in the path defined in the <testDataPath> tag within the test rule.

Create the path defined in the <testDataPath> tag, and ensure all necessary data files are located within this directory.

The rule with id="RULE_ID" has not been executed.

The rule with the provided id has not been executed during this validation.

Ensure that a test data file exists that matches the conditions defined in the specified rule.