Service handlers

The architectural approach followed by GITB TDL is to capture in the test case the high level testing flow and delegate detailed domain-specific processing to separate services. These services can cover messaging between actors, complex processing or content validation and implement APIs that are defined in the GITB specification. The components implementing these services are termed generally handlers and, depending on their purpose can be:

Another important distinction for handlers is whether they are embedded within the test bed software or external. Considering that handlers are typically used to extend the test bed for domain-specific operations, the norm is to externalise them as remotely callable services. Embedded handlers are typically defined for generic and simple use cases that are frequently encountered in test cases.

One thing that needs to be clear to test case authors is that the use of embedded handlers limits the portability of their test cases. Each embedded handler used needs to be implemented in exactly the same way in another test bed and furthermore needs to be identified using the same name.

Specifying the handler implementation

Handlers are defined in the following steps:

  • btxn: When beginning a messaging transaction.

  • bptxn: When beginning a processing transaction.

  • verify: When validating content.

The element corresponding to each of these steps defines a handler attribute to identify the handler implementation. In case an embedded handler is to be used the value specified here is the name of the handler (see Embedded handlers). Using an external handler implementation is achieved by specifying as the handler value the address where the service’s WSDL file is located. The test bed will automatically detect in this case that the handler is external and will internally replace local method invocations with web service calls.

The value provided for the handler attribute can also be provided with a pure variable reference (see Referring to variables) allowing the actual value to be determined from configuration or even dynamically based on the test session context. In such a case the variable reference is first evaluated to a string that is then considered to determine whether the handler is a remote or embedded one.

The following example shows three validation steps taking place, the first one using an embedded XSDValidator, the second one using an external validation service, and the third one using an external validation service whose address is configurable:

<!--
    Call a local, embedded validation handler called "XSDValidator"
-->
<verify handler="XSDValidator" desc="Validate content local">
    <input name="xmldocument">$docToValidate</input>
    <input name="xsddocument">$schemaFile</input>
</verify>
<!--
    Call a remote validation service handler
-->
<verify handler="https://serviceaddress?wsdl" desc="Validate content remote">
    <input name="xmldocument">$docToValidate</input>
    <input name="xsddocument">$schemaFile</input>
</verify>
<!--
    Call a remote validation service handler (address in configuration)
-->
<verify handler="$DOMAIN{validationHandlerAddress}" desc="Validate content remote">
    <input name="xmldocument">$docToValidate</input>
    <input name="xsddocument">$schemaFile</input>
</verify>

Using remote service handlers is considered a best practice based on the benefits they offer:

  • Scalability: Potentially heavy processing is handled by a dedicated service outside the test bed that can be scaled appropriately.

  • Separation of concerns: The test bed focuses on test orchestration whereas domain specific logic is captured only in the test case and the services it uses.

  • Extensibility: New capabilities can be added to the test bed by simply making available a new service to call.

  • Maintenance: Updates to service handlers can take place without impacting test bed operations or requiring new versions of the test bed software. Similarly external service updates would not require new test suite versions.

  • Better presentation: Remote service handlers can encapsulate multiple custom actions leading to better test session presentation. If e.g. a document needs to be validated by one XSD and two Schematron files we would only show a single, concise validation step versus three separate validations.

Embedded handlers

The sections that follow list the handler implementations that already exist as predefined embedded implementations in the GITB test bed software.

Embedded messaging handlers

Each following section defines a table with the information expected by each messaging handler. The meaning of this information is as follows:

  • Input: These are the inputs provided for the send step.

  • Output: These are the outputs returned from the receive step.

  • Actor configuration: These are configuration properties that will be automatically set for simulated actors using this handler.

  • Receive configuration: These are configuration properties expected by the receive step.

  • Send configuration: These are configuration properties expected by the send step.

  • Transaction configuration: These are configuration properties defined in the btxn or bptxn step.

The title of each section corresponds to the name of the handler that needs to be configured in the relevant step’s handler attribute.

HttpMessaging

Used to send or receive content over HTTP.

Element name

Element type

Required?

Type

Description

http_version

Input

No

string

The HTTP version to consider.

http_headers

Input

No

map

The map of HTTP headers to send.

http_body

Input

No

binary

The HTTP request body’s bytes.

http_parts

Input

No

map

A map including the definition of the parts (see description below).

http_method

Output

No

string

The HTTP method.

http_version

Output

No

string

The HTTP version.

http_path

Output

No

string

The HTTP request path.

http_headers

Output

No

map

The map of received headers.

http_body

Output

No

binary

The bytes of the received body.

http_parts

Output

No

map

A map including the received parts (see description below).

network.host

Actor configuration

Yes

string

The host of the actor.

network.port

Actor configuration

Yes

number

The listen port for the actor.

http.uri

Actor configuration

No

string

The request path for the request.

status.code

Receive configuration

No

string

The status code for responses.

http.method

Send configuration

Yes

string

The HTTP method to use when sending.

http.uri

Send configuration

No

string

The request path URI to send to.

http.uri.extension

Send configuration

No

string

HTTP URI extension for the address.

status.code

Send configuration

No

string

Status for responses.

http.ssl

Transaction configuration

No

boolean

Whether or not connections should be over HTTP (default) or HTTPS.

<btxn from="Actor1" to="Actor2" txnId="t1" handler="HttpMessaging"/>
<send id="dataSend" desc="Send data" from="Actor1" to="Actor2" txnId="t1">
    <config name="http.method">"POST"</input>
    <config name="http.uri">"/path/to/service"</input>
    <input name="http_body">$binaryContent</input>
</send>
<receive id="dataReceive" desc="Receive data" from="Actor2" to="Actor1" txnId="t1">
    <config name="status.code">"200"</input>
</receive>
<etxn txnId="t1"/>

Note

Isolating communications: When using a HttpMessaging handler to receive communication from a SUT, the test bed dynamically starts listening on a new port for incoming traffic. This port (along with the host) are presented to the test bed user upon test initiation so that he/she can configure the SUT accordingly. To avoid unwanted communication being received on this port that is unrelated to the test session, the test bed will only listen to requests originating from the SUT’s address, ignoring others originating from other sources. To achieve this, the test bed uses the network.host parameter configured for the SUT that needs to be provided by the tester as part of the SUT’s configuration before starting a test.

The value for the network.host parameter must be set with the public IP Address of the SUT endpoint.

Using HTTPS

The HttpMessaging handler can be used both for HTTP and (one-way) HTTPS connection. The default setting is connection over HTTP. Switching to HTTPS is done at the level of the handler’s enclosing transaction and applies to all subsequent send or receive steps. Enabling HTTPS is achieved by passing a configuration parameter named “http.ssl” with a value of true or false (case insensitive) as part of the begin transaction step (step btxn). This must be provided at this point because it is needed when creating the sender and receiver implementation.

The following example illustrates its use:

<btxn from="sender" to="receiver" txnId="t1" handler="HttpMessaging">
    <config name="http.ssl">true</config>
</btxn>
<send id="dataSend" desc="Send data" from="sender" to="receiver" txnId="t1">
    <config name="http.method">POST</config>
    <input name="http_body">$content</input>
</send>

Note that the value “true” in this example could also have been provided as a variable reference (e.g. $isHTTPS) allowing a test case to remain unaffected if the underlying communication needs to be over HTTP or HTTPS. This could be especially interesting in cases where the SoapMessaging handler is used to test SUT endpoints over which the test bed has no control over the underlying transport channel. In this case the “http.ssl” parameter could be set as part of the system’s configuration, as in the following example (assuming an endpoint name of “sutInfo” and an endpoint parameter named “isHTTPS”):

<btxn from="sender" to="receiver" txnId="t1" handler="HttpMessaging">
    <config name="http.ssl">$sutInfo{isHTTPS}</config>
</btxn>

Support for sending and receiving multipart form data

When receiving, a multipart message is detected if the ContentType header contains a boundary part. The http_parts output is a map that contains:

  • http_parts{parts}: A list of all parts in sequence.

  • http_parts{parts}{0}{header}: The part’s header as a string.

  • http_parts{parts}{0}{content}: The part’s content as a binary.

  • http_parts{partsByName}: A map of parts by name (for easy lookup of named parts):

  • http_parts{partsByName}{NAME}{header}: The part’s header as a string.

  • http_parts{partsByName}{NAME}{content}: The part’s content as a binary.

When sending, if a http_body input is present this takes precedence. If not, and a http_parts input is provided, then a multipart request is created. The http_parts input is a list of maps (one map per part). To send a part as a file the file_name property needs to be passed. Specifically the information on a part is as follows:

  • http_parts{0}{name}: The name of the part.

  • http_parts{0}{content_type}: The mime type of the part (text/plain for simple text).

  • http_parts{0}{file_name}: The name of the file to set for the part if this is a file/binary p

The following TDL example illustrates how to populate and send a multipart request with three parts (two file parts and one test part):

<imports>
    <artifact type="schema" encoding="UTF-8" name="file1">testSuite1/artifacts/file1.xml</artifact>
    <artifact type="binary" encoding="UTF-8" name="file2">testSuite1/artifacts/file2.zip</artifact>
</imports>
<variables>
    <var name="parts" type="list[map]"/>
    <var name="filePartInfo1" type="map"/>
    <var name="filePartInfo2" type="map"/>
    <var name="textPartInfo1" type="map"/>
</variables>
<actors>
    ...
</actors>
<steps>
    <!--
        Define first file part.
    -->
    <assign to="$filePartInfo1{name}" type="string">"file1"</assign>
    <assign to="$filePartInfo1{content_type}" type="string">"text/xml"</assign>
    <assign to="$filePartInfo1{file_name}" type="string">"file1.xml"</assign>
    <assign to="$filePartInfo1{content}" type="binary">$file1</assign>
    <!--
        Define second file part.
    -->
    <assign to="$filePartInfo2{name}" type="string">"file2"</assign>
    <assign to="$filePartInfo2{content_type}" type="string">"application/zip"</assign>
    <assign to="$filePartInfo2{file_name}" type="string">"file2.zip"</assign>
    <assign to="$filePartInfo2{content}" type="binary">$file2</assign>
    <!--
        Define a third text part.
    -->
    <assign to="$textPartInfo1{name}" type="string">"text1"</assign>
    <assign to="$textPartInfo1{content_type}" type="string">"text/plain"</assign>
    <assign to="$textPartInfo1{content}" type="string">"A simple text value"</assign>
    <!--
        Put all parts in a list.
    -->
    <assign to="$parts" append="true">$filePartInfo1</assign>
    <assign to="$parts" append="true">$filePartInfo2</assign>
    <assign to="$parts" append="true">$textPartInfo1</assign>
    <!--
        Send the request.
    -->
    <btxn from="Sender" to="Receiver" txnId="t1" handler="HttpMessaging"/>
    <send desc="Send file" from="Sender" to="Receiver" txnId="t1">
        <config name="http.method">POST</config>
        <input name="http_parts">$parts</input>
    </send>
    <etxn txnId="t1"/>
</steps>

HttpsMessaging

Used to send or receive content over HTTPS.

Note

Deprecation of HttpsMessaging: As of release 1.4.1 handler HttpsMessaging is deprecated in favour of the more flexible HttpMessaging which can now be configured to support HTTPS.

Element name

Element type

Required?

Type

Description

http_headers

Input

No

map

The map of HTTP headers to send.

http_body

Input

No

binary

The HTTP request body’s bytes.

http_method

Output

No

string

The HTTP method.

http_version

Output

No

string

The HTTP version.

http_uri

Output

No

string

The HTTP request path.

http_headers

Output

No

map

The map of received headers.

http_body

Output

No

binary

The bytes of the received body.

network.host

Actor configuration

Yes

string

The host of the actor.

network.port

Actor configuration

Yes

number

The listen port for the actor.

http.uri

Actor configuration

No

string

The request path for the request.

status.code

Receive configuration

No

string

The status code for responses.

http.method

Send configuration

Yes

string

The HTTP method to use when sending.

http.uri.extension

Send configuration

No

string

HTTP URI extension for the address.

status.code

Send configuration

No

string

Status for responses.

<btxn from="Actor1" to="Actor2" txnId="t1" handler="HttpsMessaging"/>
<send id="dataSend" desc="Send data" from="Actor1" to="Actor2" txnId="t1">
    <config name="http.method">"POST"</input>
    <config name="http.uri.extension">"/path/to/service"</input>
    <input name="http_body">$binaryContent</input>
</send>
<receive id="dataReceive" desc="Receive data" from="Actor2" to="Actor1" txnId="t1">
    <config name="status.code">"200"</input>
</receive>
<etxn txnId="t1"/>

Note

Isolating communications: Handler HttpsMessaging builds upon the mechanism of HttpMessaging to isolate test session communications when receiving data. Check it’s documentation on what is needed to achieve this.

HttpProxyMessaging

Used to proxy HTTP requests and responses between two actors.

Element name

Element type

Required?

Type

Description

request_data

Input

No

map

The map of data to consider. Contains the http_method, http_path, http_body, http_headers inputs from the HttpMessaging handler.

http_method

Output

No

string

The HTTP method.

http_version

Output

No

string

The HTTP version.

http_path

Output

No

string

The HTTP request path.

network.host

Actor configuration

Yes

string

The host of the actor.

network.port

Actor configuration

Yes

number

The listen port for the actor.

proxy.address

Send configuration

No

string

Address of the proxied service.

In this case the request_data input map is defined as a convenience considering that we will always be receiving a call that we want to proxy to a final destination. The HTTP-related parameters to send to the destination need to match the initial parameters received.

<btxn from="Actor1" to="Actor2" txnId="t1" handler="HttpProxyMessaging"/>
<receive id="receiveData" desc="Receive call" from="Actor1" to="Actor2" txnId="t1" />
<send desc="Send call" from="Actor2" to="Actor1" txnId="t1">
    <config name="proxy.address">http://PROXIED_SERVICE_ADDRESS</config>
    <input name="request_data" source="$receiveData" />
</send>
<etxn txnId="t1"/>

SoapMessaging

Used to send or receive payloads via SOAP web service calls.

Element name

Element type

Required?

Type

Description

http_headers

Input

No

map

A map of HTTP headers to include.

soap_message

Input

Yes

object

The SOAP envelope to send.

soap_attachments

Input

No

map

A map of binary attachments.

http_headers

Output

No

map

The HTTP headers received.

soap_header

Output

Yes

object

The received SOAP header.

soap_body

Output

Yes

object

The received SOAP body.

soap_message

Output

Yes

object

The received SOAP envelope.

soap_content

Output

Yes

object

The XML content of the received SOAP body.

soap_attachments

Output

No

map

A map of received binary attachments.

soap_attachments_size

Output

No

number

The number of attachments received.

network.host

Actor configuration

Yes

string

The host of the actor.

network.port

Actor configuration

Yes

number

The listen port for the actor.

http.uri

Actor configuration

No

string

The request path to send the SOAP request to.

soap.version

Receive configuration

Yes

string

SOAP Version. Can be 1.1 or 1.2.

soap.version

Send configuration

Yes

string

SOAP Version. Can be 1.1 or 1.2.

soap.encoding

Send configuration

No

string

Character set encoding.

http.uri.extension

Send configuration

No

string

HTTP URI extension for the address.

http.ssl

Transaction configuration

No

boolean

Whether or not connections should be over HTTP (default) or HTTPS.

<btxn from="Actor1" to="Actor2" txnId="t1" handler="SoapMessaging"/>
<send id="dataSend" desc="Send data" from="Actor1" to="Actor2" txnId="t1">
    <config name="soap.version">1.2</config>
    <input name="soap_message">$soapMessage</input>
</send>
<receive id="dataReceive" desc="Receive data" from="Actor2" to="Actor1" txnId="t1">
    <config name="soap.version">1.2</config>
</receive>
<etxn txnId="t1"/>

Using HTTPS

The SoapMessaging handler can be used both over an HTTP and (one-way) HTTPS connection. The default setting is connection over HTTP. Switching to HTTPS is done at the level of the handler’s enclosing transaction and applies to all subsequent send or receive steps. Enabling HTTPS is achieved by passing a configuration parameter named “http.ssl” with a value of true or false (case insensitive) as part of the begin transaction step (step btxn). This must be provided at this point because it is needed when creating the sender and receiver implementation.

The following example illustrates its use:

<btxn from="sender" to="receiver" txnId="t1" handler="SoapMessaging">
    <config name="http.ssl">true</config>
</btxn>
<send id="dataSend" desc="Send data" from="sender" to="receiver" txnId="t1">
    <config name="soap.version">$soapVersion</config>
    <input name="soap_message">$soapMessage</input>
</send>

Note that the value “true” in this example could also have been provided as a variable reference (e.g. $isHTTPS) allowing a test case to remain unaffected if the underlying communication needs to be over HTTP or HTTPS. This could be especially interesting in cases where the SoapMessaging handler is used to test SUT endpoints over which the test bed has no control over the underlying transport channel. In this case the “http.ssl” parameter could be set as part of the system’s configuration, as in the following example (assuming an endpoint name of “sutInfo” and an endpoint parameter named “isHTTPS”):

<btxn from="sender" to="receiver" txnId="t1" handler="SoapMessaging">
    <config name="http.ssl">$sutInfo{isHTTPS}</config>
</btxn>

Note

Isolating communications: Handler HttpsMessaging builds upon the mechanism of HttpMessaging to isolate test session communications when receiving data. Check it’s documentation on what is needed to achieve this.

TCPMessaging

Used to send or receive an arbitrary byte stream over TCP.

Element name

Element type

Required?

Type

Description

content

Input

Yes

binary

The stream of bytes to send.

content

Output

Yes

binary

The stream of bytes received.

network.host

Actor configuration

Yes

string

The host of the actor.

network.port

Actor configuration

Yes

number

The listen port for the actor.

<btxn from="Actor1" to="Actor2" txnId="t1" handler="TCPMessaging"/>
<send id="dataSend" desc="Send data" from="Actor1" to="Actor2" txnId="t1">
    <input name="content">$binaryContent</input>
</send>
<receive id="dataReceive" desc="Receive data" from="Actor2" to="Actor1" txnId="t1"/>
<etxn txnId="t1"/>

UDPMessaging

Used to send or receive arbitrary bytes over UDP.

Element name

Element type

Required?

Type

Description

content

Input

Yes

binary

The stream of bytes to send.

content

Output

Yes

binary

The stream of bytes received.

network.host

Actor configuration

Yes

string

The host of the actor.

network.port

Actor configuration

Yes

number

The listen port for the actor.

<btxn from="Actor1" to="Actor2" txnId="t1" handler="UDPMessaging"/>
<send id="dataSend" desc="Send data" from="Actor1" to="Actor2" txnId="t1">
    <input name="content">$binaryContent</input>
</send>
<receive id="dataReceive" desc="Receive data" from="Actor2" to="Actor1" txnId="t1"/>
<etxn txnId="t1"/>

Embedded processing handlers

Base64Processor

Used to manipulate Base64-encoded content for use in test cases. This processing handler supports but does not require a processing transaction to be established. The following operations are supported:

Operation

Description

Input(s)

Output(s)

encode

Receive a binary input and return a string with its Base64-encoded representation.

Yes

A string named output in the resulting step’s map.

decode

Receive a string input that is Base64-encoded and return the binary output it corresponds to.

Yes

A binary value named output in the resulting step’s map.

The input parameters expected by the different operations are as follows:

Operation

Input name

Required?

Description

encode

input

Yes

The binary value that will be encoded as a Base64 string.

encode

dataUrl

No

A boolean flag that indicates whether or not the output should be formatted as a data URL (default is false).

decode

input

Yes

The string value (expected to be Base64-encoded or formatted as a data URL) that will be processed to return its corresponding binary value.

Base64 encoding is a technique often used to represent arbitrary byte sequences as text. Using this processing handler you can work with Base64 encoded texts that need to be decoded in test cases, but also encode binary content where this is needed. In both the encoding and decoding steps there is support for Base64 content and also data URLs. Data URLs are commonly used in web representations for the inline definition of binary resources. A data URL is essentially the Base64-encoded bytes prefixed with the content’s mime type as data:[mime type],base64,[BASE64 encoded string] (e.g. data:application/xml;base64,YXNoZGl1cXcgaGRva...).

The following examples illustrate use of this handler to work with Base64 encoding:

<!--
    Encode the binary variable "aBinaryVariable" and return the encoded string as "data1{output}".
-->
<process id="data1" handler="Base64Processor">
    <operation>encode</operation>
    <input name="input">$aBinaryVariable</input>
</process>
<!--
    Encode the binary variable "aBinaryVariable" and return the encoded string as "data2{output}".
    The result in this case is formatted as a data URL.
-->
<process id="data2" handler="Base64Processor">
    <operation>encode</operation>
    <input name="input">$aBinaryVariable</input>
    <input name="dataUrl">'true'</input>
</process>
<!--
    Decode a Base-64 encoded string to return its binary equivalent as "data3{output}". In this case
    the result will be identical to the "aBinaryVariable" variable used in the first step.
-->
<process id="data3" handler="Base64Processor">
    <operation>decode</operation>
    <input name="input">$data1{output}</input>
</process>
<!--
    Decode a Base-64 encoded string to return its binary equivalent as "data4{output}". In this example
    the handler is provided the data URL produced in the second step and will result in the same output
    as "data3" that matches the original input ("aBinaryVariable").
-->
<process id="data4" handler="Base64Processor">
    <operation>decode</operation>
    <input name="input">$data2{output}</input>
</process>

CollectionUtils

Used to process collections (maps and lists) in ways not possible otherwise with TDL expressions. This processing handler does not require a processing transaction to be established. The following operations are supported:

Operation

Description

Input(s)

Output(s)

size

Receive a collection as input and return the number of elements it contains.

Yes

Yes, a number named output in the resulting step’s map.

clear

Receive a collection as input and empty it.

Yes

No.

The input parameters expected by the different operations are as follows:

Operation

Input name

Required?

Description

size

map

No

The map of which the elements are to be counted (if the collection is a map). Either this or the list input must be provided.

size

list

No

The list of which the elements are to be counted (if the collection is a list). Either this or the map input must be provided.

clear

map

No

The map to be cleared (if the collection is a map). Either this or the list input must be provided.

clear

list

No

The list to be cleared (if the collection is a list). Either this or the map input must be provided.

Collection or container variables represent flexible means of recording arbitrary sequences of data or hierarchical data structures. In particular map variables are very common as these are used to store results of processing, messaging and validation operations. Adding new elements to collections or replacing existing values is achieved using the assign step, where the expressions used may also determine collections that don’t previously exist. The CollectionUtils processing handler complements such operations by allowing further manipulations that cannot be achieved through simple expressions.

The size operation allows a test case to determine a collection’s size. This can be particularly useful in the case of operations that return an arbitrary number of data items as a list which we need to iterate over. The following examples illustrate how this operation can be used:

<!-- Create a map with three elements -->
<assign to="aMap{a}">'Value 1'</assign>
<assign to="aMap{b}">'Value 2'</assign>
<assign to="aMap{c}">'Value 3'</assign>
<!-- Create a list with two elements -->
<assign to="aList" append="true">'Value 1'</assign>
<assign to="aList" append="true">'Value 2'</assign>
<!-- Calculate the size of the map -->
<process id="aMapSize" handler="CollectionUtils">
    <operation>size</operation>
    <input name="map">$aMap</input>
</process>
<!-- Prints "3" -->
<log>$aMapSize{output}</log>
<!-- Calculate the size of the list -->
<process id="aListSize" handler="CollectionUtils">
    <operation>size</operation>
    <input name="list">$aList</input>
</process>
<!-- Prints "2" -->
<log>$aListSize{output}</log>
<!-- Print each list element. -->
<foreach desc="Iterate list" counter="index" start="0" end="$aListSize{output}">
    <do>
        <!-- Prints "Value 1" and then "Value 2" -->
        <log>aList{$index}</log>
    </do>
</foreach>

Note

Nested collections: If a collection structure contains itself further collection structures as elements, the size operation will only count the collection’s top level elements.

The clear operation on the other hand allows a test case to empty the contents of a given collection if this becomes necessary. The following examples illustrate how this works for lists and maps:

<!-- Create a map with three elements -->
<assign to="aMap{a}">'Value 1'</assign>
<assign to="aMap{b}">'Value 2'</assign>
<assign to="aMap{c}">'Value 3'</assign>
<!-- Create a list with two elements -->
<assign to="aList" append="true">'Value 1'</assign>
<assign to="aList" append="true">'Value 2'</assign>
<!-- Empty the map -->
<process handler="CollectionUtils">
    <operation>clear</operation>
    <input name="map">$aMap</input>
</process>
<!-- Empty the list -->
<process handler="CollectionUtils">
    <operation>clear</operation>
    <input name="list">$aList</input>
</process>

RegExpProcessor

Used to process texts using regular expressions, to verify whether they match a specific pattern or to extract data. This processing handler does not require a processing transaction to be established. The following operations are supported:

Operation

Description

Input(s)

Output(s)

check

Check to see if a string matches an expression.

Yes

Yes, a boolean named output in the resulting step’s map.

collect

Use an expression to collect data from a provided string based on the expression’s capturing groups.

Yes

A list of string values, one value per matched group.

The input parameters expected by the different operations are as follows:

Operation

Input name

Required?

Description

check

input

Yes

The string to check.

check

expression

Yes

A string with the expression that will be used to check the input.

collect

input

Yes

The string to process to collect data.

collect

expression

Yes

A string with the expression to collect data with. The provided expression must define at least one capturing group.

Regular expressions offer a very powerful means of describing a text’s content and extracting from it certain parts for further processing. They can be used against any text content, offering a counterpart to the use of XPath in the assign step that is best adapted, but also limited, to XML structures. The regular expressions are expected to be provided using the syntax used by the Java language.

The check operation can be used to verify whether a given text matches a specific pattern. This may at first appear similar to the RegExpValidator, however there is a subtle difference: using the RegExpValidator constitutes an assertion made by the test case which, if failed, would likely mean that the test session itself is considered failed. The check operation doesn’t presume anything for the test session’s status, but is rather used as an internal check to e.g. determine whether an optional set of steps should be followed. The following example illustrates its use:

<!-- Check if a given text includes "test" in a case-insensitive manner -->
<process id="check" handler="RegExpProcessor">
    <operation>check</operation>
    <input name="input">$someTextData</input>
    <!-- Flags are passed in embedded format -->
    <input name="expression">"(?i)test"</input>
</process>
<if desc="Optional steps">
    <cond>$check{output}</cond>
    <then>
        ...
    </then>
</if>

The collect operation is used to process a provided text using an expression that defines one or more capturing groups. This operation can be particularly powerful as it can collect data from both structured and unstructured data. Each matching group is appended to a list of string elements in the sequence with which it was matched, otherwise resulting in an empty list if no matches were made. Consider the following example to see how this can be used:

<!-- Define a firstname and lastname in an unstructured text block -->
<assign to="aText">"My firstname is 'John' and my lastname is 'Doe'."</assign>
<!-- Collect the data using an expression with two capturing groups -->
<process id="personData" handler="RegExpProcessor">
    <operation>collect</operation>
    <input name="input">$aText</input>
    <input name="expression">".+ firstname is '([\w]+)' .+ lastname is '([\w]+)'"</input>
</process>
<!-- Prints "John" -->
<log>$personData{0}</log>
<!-- Prints "Doe" -->
<log>$personData{1}</log>

TokenGenerator

Used to generate tokens that can be used as data in test cases. This processing handler supports but does not require a processing transaction to be established. The following operations are supported:

Operation

Description

Input(s)

Output(s)

uuid

Generate a random UUID text value matching a Java UUID (e.g. “123e4567-e89b-12d3-a456-556642440000”). This is a value that can be considered as unique for test purposes.

No

A string named value in the resulting step’s map.

timestamp

Generate a timestamp for the current or a provided time based on a format string.

Yes

A string named value in the resulting step’s map.

string

Generate a text token with potentially fixed and/or random parts to match a provided regular expression.

Yes

A string named value in the resulting step’s map.

The input parameters expected by the different operations are as follows:

Operation

Input name

Required?

Description

timestamp

format

No

The formatting pattern to apply provided as a string matching the Java date/time formatting specifications (see Formatting configuration). If unspecified the current Epoch milliseconds are returned.

timestamp

zone

No

The timezone to consider when generating a formatted timestamp provided as a string. Expected values are those defined by Java (see Timezone codes). If unspecified the default consider is UTC.

timestamp

time

No

A number representing the Epoch milliseconds to use as the date/time to format. If unspecified the current date/time is used.

timestamp

date

No

A string representing a date/time to use as the value to format. If specified along with time, the time input takes precedence.

timestamp

inputFormat

No

The formatting pattern to use to interpret the date input (if provided), matching the Java date/time formatting specifications (see Formatting configuration).

timestamp

diff

No

A number representing the milliseconds to consider as a diff from the considered time or date. This value (default 0) is added to the considered time or date before formatting (i.e. a negative value signals an earlier time).

string

format

Yes

A regular expression acting as a template to determine the generated token’s format.

A typical use case for the TokenGenerator is to generate text tokens that can be used in test cases either as input parameters to e.g. messaging calls (see Handler inputs and outputs) or as values to replace in loaded text templates (see Expressions and templates). The uuid operation provides a random and unique identifier where special formatting is not required, whereas the timestamp operation generates a timestamp string that includes date/time values but can also have fixed parts (e.g. if you need to generate a text token with a fixed part and a variable part based on the current date/time). Finally, the string operation is noteworthy as it can be used to generate any kind of text token with both fixed and random parts. The template to consider for the output is provided as a regular expression with the value to be returned being a random string to match it.

Note

Default format for input dates: If a date is provided without an inputFormat, the pattern of dd/MM/yyyy'T'HH:mm:ss.SSSZ is assumed by default. Moreover, all parts are considered optional allowing you to specify only parts of a date, making use of the following defaults for those that are missing:

  • Day of year (dd): The 1st day of the month.

  • Month (MM): The 1st month of the year (January).

  • Year (yyyy): The current year.

  • Time elements (HH, mm, ss and SSS): A value of zero.

  • Time zone (Z): UTC.

The examples that follow illustrate use of these operations to generate a series of tokens that are then presented to the user by means of an interact step. Note in all cases how the produced value is retrieved from the map resulting from the process step that is named based on the steps’ id. The value itself is retrieved from within each map under the value key:

<!--
    Generate a UUID.
-->
<process id="uuid" handler="TokenGenerator">
    <operation>uuid</operation>
</process>
<!--
    Generate a timestamp for the current time without specifying formatting.
    Example output would be "1560238501040".
-->
<process id="defaultTimestamp" handler="TokenGenerator">
    <operation>timestamp</operation>
</process>
<!--
    Generate a timestamp for the current time with provided formatting.
    Example output would be "DATE[2019-05-22] TIME[11:48:06]".
-->
<process id="formattedTimestamp" handler="TokenGenerator">
    <operation>timestamp</operation>
    <input name="format">"'DATE['yyyy-MM-dd'] TIME['HH:mm:ss']'"</input>
</process>
<!--
    Generate an XML timestamp for the current time.
-->
<process id="formattedTimestamp" handler="TokenGenerator">
    <operation>timestamp</operation>
    <input name="format">"yyyy-MM-dd'T'HH:mm:ss.SSSXXX"</input>
</process>
<!--
    Generate an XML timestamp for the current time but expressed in the GMT+2 timezone.
-->
<process id="formattedTimestamp" handler="TokenGenerator">
    <operation>timestamp</operation>
    <input name="format">"yyyy-MM-dd'T'HH:mm:ss.SSSXXX"</input>
    <input name="zone">"GMT+2"</input>
</process>
<!--
    Generate a timestamp for the provided time and formatting.
    The output would be "2014-05-11".
-->
<process id="formattedTimestampProvidedTime" handler="TokenGenerator">
    <operation>timestamp</operation>
    <input name="time">'1399792366000'</input>
    <input name="format">"yyyy-MM-dd"</input>
</process>
<!--
    Generate a timestamp for the current time minus one minute (600000 milliseconds) using the provided formatting.
    Example output would be "2019-06-11 10:23:10".
-->
<process id="formattedTimestampDiff" handler="TokenGenerator">
    <operation>timestamp</operation>
    <input name="diff">-600000</input>
    <input name="format">"yyyy-MM-dd HH:mm:ss"</input>
</process>
<!--
    Obtain the current time (T) and then generate two timestamps:
    - T minus one hour.
    - T plus one hour.
-->
<process id="now" handler="TokenGenerator">
    <operation>timestamp</operation>
</process>
<process id="nowMinusOneHour" handler="TokenGenerator">
    <operation>timestamp</operation>
    <input name="time">$now{value}</input>
    <input name="diff">-3600000</input>
    <input name="format">"yyyy-MM-dd HH:mm:ss"</input>
</process>
<process id="nowPlusOneHour" handler="TokenGenerator">
    <operation>timestamp</operation>
    <input name="time">$now{value}</input>
    <input name="diff">3600000</input>
    <input name="format">"yyyy-MM-dd HH:mm:ss"</input>
</process>
<!--
    Generate a timestamp based on an existing date/time string plus one hour
-->
<process id="timestampFromFormattedString1" handler="TokenGenerator">
    <operation>timestamp</operation>
    <input name="date">'20-10-2021 13:30:00'</input>
    <input name="inputFormat">'dd-MM-yyyy HH:mm:ss'</input> <!-- Assumes UTC -->
    <input name="diff">3600000</input>
</process>
<!--
    Generate a timestamp based on an existing date/time string plus one hour (default formatting)
-->
<process id="timestampFromFormattedString2" handler="TokenGenerator">
    <operation>timestamp</operation>
    <input name="date">'20/10'</input> <!-- Assumes the current year, midnight, and a UTC timezone -->
    <input name="diff">3600000</input>
</process>
<!--
    Generate a random string with 2 characters followed by 10 digits.
    Example output would be "cD6723820231".
-->
<process id="stringRandom" handler="TokenGenerator">
    <operation>string</operation>
    <input name="format">"[a-zA-Z]{2}\d{10}"</input>
</process>
<!--
    Generate a random string:
    - Starting with "PREFIX" and ending with "POSTFIX".
    - With random parts of (a) 5 digits, (b) 5 occurences of 'a', 'b' or 'c', and (c) 2 digits.
    - With hyphens between all fixed and random parts.
    Example output would be "PREFIX-32145-abcaa-02-POSTFIX".
-->
<process id="stringRandomAndFixed" handler="TokenGenerator">
    <operation>string</operation>
    <input name="format">"PREFIX-\d{5}-[abc]{5}-\d{2}-POSTFIX"</input>
</process>
<!--
    Display all generated tokens to the user.
-->
<interact desc="Generated tokens">
    <instruct desc="UUID:">$uuid{value}</instruct>
    <instruct desc="The default timestamp:">$defaultTimestamp{value}</instruct>
    <instruct desc="A formatted timestamp:">$formattedTimestamp{value}</instruct>
    <instruct desc="A formatted timestamp for provided time:">$formattedTimestampProvidedTime{value}</instruct>
    <instruct desc="A timestamp using a diff:">$formattedTimestampDiff{value}</instruct>
    <instruct desc="Now minus one hour:">$nowMinusOneHour{value}</instruct>
    <instruct desc="Now plus one hour:">$nowPlusOneHour{value}</instruct>
    <instruct desc="Plus one hour of formatted string:">$timestampFromFormattedString1{value}</instruct>
    <instruct desc="Plus one hour of default formatted string:">$timestampFromFormattedString2{value}</instruct>
    <instruct desc="A random string:">$stringRandom{value}</instruct>
    <instruct desc="A random string with fixed parts:">$stringRandomAndFixed{value}</instruct>
</interact>

Note

Timestamps for use in XML content: Formatted timestamps generated for use in XML content should match the formatting of the ISO 8601 version of the W3C XML Schema dateTime definition. The pattern to apply to get a XSD-valid timestamp is: yyyy-MM-dd'T'HH:mm:ss.SSSXXX.

Embedded validation handlers

NumberValidator

Used to verify that a provided number matches an expected value.

Input name

Required?

Type

Description

actualnumber

Yes

number

The value to check.

expectednumber

Yes

number

The expected value.

<verify handler="NumberValidator" desc="Check number">
    <input name="actualnumber">$aNumber</input>
    <input name="expectednumber">'10'</input>
</verify>

RegExpValidator

Used to verify that a provided string matches a regular expression.

Input name

Required?

Type

Description

input

Yes

string

The value to check.

expression

Yes

string

The expression to match.

<verify handler="RegExpValidator" desc="Check string">
    <input name="input">$aString</input>
    <input name="expression">'^REF\-\d+$'</input>
</verify>

SchematronValidator

Used to validate an XML document against a Schematron file.

Input name

Required?

Type

Description

schematron

Yes

schema

The Schematron file to use for the validation (XSTL or SCH).

xmldocument

Yes

object

The XML document to validate.

type

No

string

The type of Schematron file to consider (xslt or sch) in case this cannot be determined from the resource’s file suffix. The overall default considered is sch.

Note

XSLT vs SCH Schematron files: XSLT versions of Schematron files are pre-processed files and offer significantly better performance for complex rule cases. In addition, if Schematron rules import other resources, use of XSLT files is required.

<verify handler="SchematronValidator" desc="Validate content">
    <input name="xmldocument">$docToValidate</input>
    <input name="schematron">$schematronFile</input>
</verify>

StringValidator

Used to verify that a provided string matches an expected value.

Input name

Required?

Type

Description

actualstring

Yes

string

The value to check.

expectedstring

Yes

string

The expected value.

<verify handler="StringValidator" desc="Check string">
    <input name="actualstring">$aString</input>
    <input name="expectedstring">'expected_string'</input>
</verify>

XmlMatchValidator

Used to validate an XML document by matching it against a provided template.

Input name

Required?

Type

Description

xml

Yes

object

The XML file to validate.

template

Yes

object

The XML file to consider as the validation’s template.

ignoredPaths

No

list[string]

An optional list of paths provided as XPath expressions identifying sections of the XML to ignore.

The matching process takes place by normalising whitespace, ignoring comments and tolerating naming differences in namespace prefixes. In addition, texts of elements or attributes in the provided template can be specified with the special value ?. This means that any value will be allowed for this element or attribute and will be ignored as part of the matching (e.g. to ignore random tokens, timestamps, or texts with no expected value).

In case you want to ignore complete XML sections you may use the ignoredPaths attribute. This allows you to define one or more paths that identify elements that will, themselves and for all children, be ignored. For each provided path the following constraints apply:

  • It must be formed as a namespace-aware XPath expression considering the namespace prefixes of the provided template.

  • It must identify a specific element, rather than a set of elements, a text node or an attribute.

  • It must be a simple element-based path with no functions, selectors or wildcards.

The following example illustrates how this validator can be used:

<!--
    Validate an XML file based on a provided template.
-->
<verify handler="XmlMatchValidator" desc="Validate content">
    <input name="xml">$docToValidate</input>
    <input name="template">$templateFile</input>
</verify>
<!--
    Another validation that also defines a set of paths to ignore.
    Variable "pathsToSkip" is of type list[string].
-->
<assign to="$pathsToSkip" append="true">"/x:Invoice/x:BillingInformation/y:Comments"</assign>
<verify handler="XmlMatchValidator" desc="Validate content">
    <input name="xml">$docToValidate</input>
    <input name="template">$templateFile</input>
    <input name="ignoredPaths">$pathsToSkip</input>
</verify>

XPathValidator

Used to evaluate an XPath 3.0 expression against a provided XML document. The result of the expression needs to evaluate to a boolean (i.e. true for success or false for failure).

Input name

Required?

Type

Description

xmldocument

Yes

object

The XML document upon which the XPath expression will be evaluated.

xpathexpression

Yes

string

The XPath 3.0 expression passed as a string.

An important note here is that the XPath expression passed in xpathexpression is meant to be a string. This means that to run an expression as-is you need to wrap it in quotes. This is because the content of the input element can also be an expression that you want to evaluate to give you the final expression to use. The following example illustrates both cases:

<!--
    Pass a string as the expression to use.
-->
<verify handler="XPathValidator" desc="Check document">
    <input name="xmldocument">$myDocument</input>
    <input name="xpathexpression">"contains(/toc/text(), 'string to look for')"</input>
</verify>
<!--
    Evaluate an expression that will give you the final expression to use.
-->
<verify handler="XPathValidator" desc="Check document">
    <input name="xmldocument">$myDocument</input>
    <input name="xpathexpression">concat("contains(/toc/text()", ", 'string to look for')")</input>
</verify>

In the expressions you use for the validations (attribute xpathexpression) you may also make use of XML namespaces. Doing so is actually a best practice to ensure that you don’t have ambiguous results due to elements with the same local names. To use namespaces in expressions you first need to define their prefixes in the test case’s namespaces section. Moreover, keep in mind that the provided input (attribute xmldocument) also supports expressions with namespaces when determining the XML content to apply the XPath expression to (if e.g. you want to validate only a part of an XML document).

The following example illustrates how you can use namespace prefixes with your XPath expressions:

<testcase>
    <!--
        Declare the namespaces to be used.
    -->
    <namespaces>
       <ns prefix="ns1">urn:specification:foo</ns>
       <ns prefix="ns2">urn:specification:bar</ns>
    </namespaces>
    <steps>
        <!--
            Use the defined namespaces.
        -->
        <verify handler="XPathValidator" desc="Check document">
            <input name="xmldocument">$myDocument</input>
            <input name="xpathexpression">"/ns1:Foo/ns2:Bar/text() = 'EXPECTED'"</input>
        </verify>
    </steps>
</testcase>

XSDValidator

Used to validate an XML document against an XML Schema (XSD) instance.

Input name

Required?

Type

Description

xsddocument

Yes

schema

The XSD to validate the document against.

xmldocument

Yes

object

The XML document to validate.

<verify handler="XSDValidator" desc="Validate content">
    <input name="xmldocument">$docToValidate</input>
    <input name="xsddocument">$schemaFile</input>
</verify>

Authentication for external handlers

Handlers defined as external service implementations may need to be protected with access control. To support such protected services, the GITB software foresees the possibility to authenticate as part of each service call. Authentication information needs to be configured before any exchanges take place with the service and as such, cannot use the config and input elements otherwise used to pass information. Authentication configuration is handled with property elements that are used as part of the handler setup in:

  • The btxn step for messaging services.

  • The bptxn step for processing services.

  • The verify step for messaging services.

The authentication possibilities currently supported are:

  • Basic HTTP authentication for all calls to the service’s HTTP/HTTPS endpoint. This is authentication at the transport layer.

  • Authentication using the WS-Security UsernameToken profile (see here), supporting text and digest password transmission with timestamps and nonces. This is authentication at the SOAP application layer.

The properties that are supported in the property elements are listed in the following table:

Property name

Value

Description

auth.basic.username

Any string

The username to provide when prompted for basic HTTP authentication.

auth.basic.password

Any string

The password to provide when prompted for basic HTTP authentication.

auth.token.username

Any string

The username to include in the SOAP header as the UsernameToken’s username.

auth.token.password

Any string

The password to include in the SOAP header as the UsernameToken’s password.

auth.token.password.type

‘DIGEST’ (the default) or ‘TEXT’

The way the password is to be serialised in the header. ‘DIGEST’ includes it as a DIGEST whereas ‘TEXT’ adds it in plaintext.

Note that use of HTTP basic authentication and the UsernameToken are not necessarily exclusive. A case where both are provided would be where a service protects access to its WSDL using HTTP basic authentication and adds additional protection for SOAP service calls by means of a UsernameToken. Combining both approaches is rare but possible. The following example illustrates use of these authentication properties calling various test services:

<!--
    Messaging service authentication with UsernameToken (DIGEST).
-->
<btxn from="Sender" to="Receiver1" txnId="t1" handler="$messagingServiceURL">
    <property name="auth.token.username">$DOMAIN{serviceUsername1}</property>
    <property name="auth.token.password">$DOMAIN{servicePassword1}</property>
    <property name="auth.token.password.type">DIGEST</property>
</btxn>
<send id="dataSend" desc="Send message" from="Sender" to="Receiver1" txnId="t1"/>
<etxn txnId="t1"/>
<!--
    Validation service authentication with UsernameToken (DIGEST - the default) and HTTP basic authentication.
-->
<verify handler="$validationService1" desc="Validate content">
    <property name="auth.basic.username">$DOMAIN{serviceUsername2}</property>
    <property name="auth.basic.password">$DOMAIN{servicePassword2}</property>
    <property name="auth.token.username">$DOMAIN{serviceUsername3}</property>
    <property name="auth.token.password">$DOMAIN{servicePassword3}</property>
    <input name="content">$contentToValidate</input>
</verify>
<!--
    Processing service authentication with HTTP basic authentication.
-->
<bptxn txnId="t1" handler="$processingServiceURL">
    <property name="auth.basic.username">$DOMAIN{serviceUsername4}</property>
    <property name="auth.basic.password">$DOMAIN{servicePassword4}</property>
</bptxn>
<process id="result" txnId="t1">
    <operation>action</operation>
    <input name="anInput">$aValue</input>
</process>
<eptxn txnId="t1"/>
<!--
    Validation service authentication with UsernameToken (TEXT) authentication.
-->
<verify handler="$validationService2" desc="Validate content">
    <property name="auth.token.username">$DOMAIN{serviceUsername5}</property>
    <property name="auth.token.password">$DOMAIN{servicePassword5}</property>
    <property name="auth.token.password.type">TEXT</property>
    <input name="content">$contentToValidate</input>
</verify>

Handler inputs and outputs

The input and output elements used with handlers are what GITB refers to as “Binding elements”. They share the following structure:

Name

Required?

Description

@name

no

The name of the input or output element.

@lang

no

The expression language that should be considered when evaluating its contained expression (see Expressions).

@source

no

A pure variable reference identifying a source variable. Used as the target upon which to evaluate the contained expression.

@asTemplate

no

Whether or not the result will be considered as a template for placeholder replacement (see Expressions and templates). By default this is “false”.

The text content of the element is considered to be an expression (see Expressions). In the case a source attribute is provided the contained expression is evaluated on the variable identified by source to produce the value. If no source attribute is present the value is the result of the expression itself. For inputs of type object or schema (i.e. XML documents) the source attribute can also be used to pass the complete document as the value. In this case use of the source attribute to reference the relevant variable is equivalent to specifying its reference as the expression:

<verify handler="SchematronValidator" desc="Validate content">
    <!--
        Pass document through the expression.
    -->
    <input name="xmldocument">$docToValidate</input>
    <!--
        Pass document through the source attribute.
    -->
    <input name="schematron" source="$schematronFile"/>
</verify>

Note

Specifying a fixed value: Considering that the default expression language is XPath 1.0, a fixed text value is provided by enclosing it in quotes. See Expressions for further details.

The input and output options for service handlers are documented as part of their module definition. For handlers accessible via remote web service calls this information is returned when calling the handler’s getModuleDefinition operation. This is also used internally by the test bed before calling a service handler to ensure that required parameters are provided by the test case.