Configuration

Directory Structure

An etr test module is similar to a wtools module structure but it has an etr.yaml file instead of wscript in the root:

<root>                  # module root
|-- etr.yaml            # main configuration file
`-- src                 # source directory for test files

A minimum example using Robot Framework:

<root>
|-- etr.yaml
`-- src
    `-- tests.robot

Contents of etr.yaml:

version: "1.0"

plugins:
    - etr.plugins.robot
robot:
    tests:
        - src/tests.robot

Main Configuration File

The main etr.yaml configuration schema is described in Main Configuration {YAML} and very simple. It primarily specifies which plugins to load, then each plugin provide their own configuration schema.

A basic example of this is a configuration using the Robot Framework plugin:

version: "1.0"

# By default test execution is randomized.
randomize: false

# List of plugins to load
plugins:
    - "etr.plugins.robot"  # Python plugin module

The etr.plugins.robot plugin, like most plugins will, have their own schema with a root node. The robot plugin adds the robot property which configures the tests to execute:

version: "1.0"

plugins:
    - etr.plugins.robot
robot:
    tests:
        - src/my-test.robot
        - src/my-other-test.robot

Please refer to each plugin section on how it is configured.

Note

By default test execution order, as specified in the configuration file, is randomized. For robot this means that one should write the robot test suite files without expectation that other test suites have been executed. This has the benefit of being able to execute a subset of tests without them breaking which is useful for speed. If this is infeasible the randomize: false can be set.

Plugins

Most of the heavy lifting in etr is done with plugins, where the core application just schedules execution of plugins. This chapter documents the built in plugins and how they are configured.

Note

The plugin execution order is determined by the plugins themselves using a fixed ordering value. The order of plugins in the configuration files does not make a difference.

etr.plugins.robot

This is the plugin that enables the running of Robot Framework tests. It executes the specified tests and creates a merged report with detailed test results.

An example of etr.yaml configuration with the robot plugin that defines both variables in the file itself and from file:

version: "1.0"

plugins:
    - etr.plugins.robot

robot:
    mergedName: "top-level-suite"
    variables:
        GLOBAL_VARIABLE: "VALUE"
    variableFiles:
        - "src/resource/variables.yaml"
    tests:
        - "src/my-test.robot"
        - "src/my-other-test.robot"

A more involved example defining two test groups with different configuration for each. This is used here to repeat the same test with different variables.

version: "1.0"

plugins:
    - etr.plugins.robot
robot:
    variables:
        GLOBAL_VARIABLE: "VALUE"
    tests:
        "First Group":
            variables:
                GROUP_VARIABLE: "VALUE1"
            variableFiles:
                - "src/resource/variables.yaml"
            tests:
                - "src/my-test.robot"
                - "src/my-other-test.robot"
        "Second Group":
            variables:
                GROUP_VARIABLE: "VALUE2"
            variableFiles:
                - "src/resource/variables.yaml"
            tests:
                - "src/my-test.robot"
                - "src/my-other-test.robot"

Note

When groups are used the group name will be used in the resulting test identifier, used for example to select tests with etr --test option.

  • Without groups the test id correspond to the verbatim path provided in tests as {path}. Using example from above the first test is simply src/my-test.robot.

  • With groups the test id correspond to the group and test separated by /: {group}/{path}. Using first test in first group this is First Group/src/my-test.robot.

    The resulting test suite name in robot report use separator . with titelized names.

Note

etr also makes available keyword libraries with utilities that can be used in the robot tests. See Robot Framework Libraries for details.

See also

Schema description for the robot object

Main Configuration {YAML}.

Use etr list to list tests

List Tests.

etr.plugins.resources

To acquire test resources automatically from a set of available the plugin etr.plugins.resources can be used.

Test resources can be anything and etr does not use it directly. But attributes from acquired resources can be used to process configuration files using the etr.plugins.jinja2 plugin for example.

Resources can come from two sources:

  1. Local configuration files where configuration file must be provided with $RESOURCE_FILE or --resource-file option. See Resources File for schema documentation.

  2. Via the Resource Manager Web Service where the host must be provided with $RESOURCE_HOST or --resource-host option.

Compared to the Resource Manager Web Service the local resources it does not provide any schema validation. So a specific resource type is not guaranteed to follow a specific schema.

To use local resources, create a file with the following structure:

version: "1.0"

resources:
    <resource-id>:
        type: <type>
        tags:
            - <tag>
            - <tag>
        attributes:
            <attributes>

Where

<resource-id>

is the identifier for the resource in the file,

<type>

is the main resource type specifier.

<tag>

is an optional list of tags that can be used for filtering purposes by clients.

<attributes>

is the resource attributes that is added to the etr execution contexts so they can be used by e.g. other plugins.

An example configuration my-resources.yaml of two opcua-shutter’s with some attributes. Tags are optional and has been left empty in shutter2 in this example:

# my-resources.yaml
version: "1.0"

resources:
    "lab-shutter-1":
        type: "opcua-shutter"
        tags:
            - "v1"
        attributes:
            "server": "opc.tcp://134.171.12.186:4840"
            "namespace": 4
            "prefix": "MAIN.Shutter1"
    "lab-shutter-2":
        type: "opcua-shutter"
        attributes:
            "server": "opc.tcp://134.171.12.186:4840"
            "namespace": 4
            "prefix": "MAIN.Shutter2"

Note

The resource ids “lab-shutter-1” and “lab-shutter-2” are the identifiers for the resource and can be anything in the character class [A-Za-z0-9_-]. The resource IDs are only used for the purpose of identifying locked resources and is not directly seen by the user as the user defines their own name for the resource.

To acquire and use a resource the etr.yaml is updated to include request the resource “shutter” with type “opcua-shutter”:

version: "1.0"

plugins:
    - etr.plugins.robot
    - etr.plugins.resources

# Robot plugin configuration
robot:
    tests:
        - src/test.robot

# Resources plugin configuration
resources:
    "shutter":
        type: "opcua-shutter"

Note

The resource name “shutter” is the user provided name for the resource once it is acquired. This can be thought of as handle to the acquired resource attributes in e.g. the etr.plugins.jinja2 plugin.

etr.plugins.jinja2

The etr.plugins.jinja2 plugin allows the processing of template files using the Jinja2 template engine (c.f. the Jinja 2 documentation).

The etr.yaml configuration is simple and takes a dictionary or an array of dictionaries of files to process as "input" -> "output" files. An example that uses robot tests and Jinja2 follows:

New in version 3.0: Ability to order templates using array of objects.

version: "1.0"

plugins:
    - etr.plugins.jinja2
    - etr.plugins.robot
    - etr.plugins.resources

# Resources plugin configuration which acquires the
# required resources
resources:
    # My name/id for the acquired resource will be `shutter`.
    "shutter":
        type: "opcua-shutter"

# Jinja2 generates the src/test.robot file from the
# src/test.robot.j2 template file:
jinja2:
    files:
        "src/test.robot.j2": "src/test.robot"

# Robot finally runs the tests
robot:
    tests:
        - "src/test.robot"

To have a well-defined rendering order (first to last) the files can be specified as an array:

# ...

# Resources plugin configuration which acquires the
# required resources
resources:
    # My name/id for the acquired resource will be `shutter`.
    "shutter":
        type: "opcua-shutter"

# Order is important so an array of files is used
jinja2:
    files:
        - "src/first.j2": "src/first"
        - "src/second.j2": "src/second"

To acquire resources and run test using the resource file my-resources.yaml above etr is invoked as:

etr --resource-file=my-resources.yaml

To make use of the attributes of the acquired resource we use the resource name shutter as key in the dictionary resources which is made available in the Jinja2 environment.

Let’s imagine the acquired resource is the matching resource lab-shutter-2. The specification which includes the attributes we want to use from my-resources.yaml is again (using example from earlier):

# my-resources.yaml
# ... rest of file is omitted ...

"lab-shutter-2":
    type: "opcua-shutter"
    attributes:
        "server": "opc.tcp://134.171.12.186:4840"
        "namespace": 4
        "prefix": "MAIN.Shutter2"

Then to access e.g. the server attribute we use {{ resources.shutter.server }} for namespace we use {{ resources.shutter.namespace }}, and so on in the Jinja2 template.

Note

The name provided for a resource in the etr.yaml configuration is the local name for the resource which is used as the primary key to look up that resource in the “resources” dictionary provided in the Jinja2 template.

The file src/test.robot.j2 might look like this:

*** Settings ***
Library         Process
Library         Shutter.py

*** Variable ***
${PLC_SERVER}      {{ resources.shutter.server }}
${NAME_SPACE}      {{ resources.shutter.namespace }}
${PREFIX_DEVICE1}  {{ resources.shutter.prefix }}
${CMD_PORT}        5582

*** Test Cases ***
Reset PLC Controller
      Reset Controller  ${PLC_SERVER}    ${NAME_SPACE}    ${PREFIX_DEVICE1}
      Sleep             2

When this is rendered by Jinja2 to the specified output file src/test.robot, it contains all the expanded variables from the acquired resource (notice how Jinja2 variables are expanded):

*** Settings ***
Library         Process
Library         Shutter.py

*** Variable ***
${PLC_SERVER}      opc.tcp://134.171.12.186:4840
${NAME_SPACE}      4
${PREFIX_DEVICE1}  MAIN.Shutter1
${CMD_PORT}        5582

*** Test Cases ***
Reset PLC Controller
      Reset Controller  ${PLC_SERVER}    ${NAME_SPACE}    ${PREFIX_DEVICE1}
      Sleep             2

New in version 3.0: The ability to set and share variables across templates.

Using the do expr syntax in Jinja it is possible to set global variables that is accessible in the same and any other template that is rendered after the variable has been set (to make sure the templates are rendered in order you must use ordered files as described earlier):

{% do globals.update(variable="value") %}
{{ globals.variable }}

Where globals is the global dictionary variable provided by etr.

etr.plugins.nomad

The etr.plugins.nomad plugin allows deployment using Nomad job specification files (c.f. the Nomad documentation).

  • During setup each job specification file in nomad.jobs list is:

    1. Registered (deployed) with Nomad (if the job already exists the registration will fail).

    2. etr will monitor the job and wait for it to become stable (all tasks are running).

  • During teardown:

    1. Each job will be unregistered (undeployed) in reverse order.

The etr.yaml configuration is simple and takes dictionary of job specification files register (deploy). An example that uses nomad follows:

version: "1.0"
plugins:
    - etr.plugins.nomad

nomad:
    jobs:
        - "src/services.nomad"

Note

  • Currently support is limited to service job type.

  • Service discovery after deployment can be performed by using e.g. Consul.