Hooks¶
In a workflow, you can use provider plugin functions. Generator plugins can also generate jobs that use provider plugin functions.
Sometimes you may want to customize the resulting steps. If you are calling those functions directly, you can add steps before or after the call, but this can be tedious if you have many calling points. And if you are using generator plugins, you have no control.
The OpenTestFactory orchestrator supports hooks that help in this regard. A hook is a point where you can alter the default behavior.
Hooks are currently defined for provider plugin functions: you can define steps that will be added before the function steps or after the function steps. They are also defined for channel handlers: you can customize the workspace preparation process as well as the workspace cleanup process of your jobs.
Hooks are statements of the form:
hooks:
- name: my pre-checkout hook
events:
- categoryPrefix: actions
category: checkout
before:
- run: echo about to perform a checkout
They have mandatory name
and events
parts. They must also have either a before
part
or an after
one (or both). Finally, they may have a conditional part, if
, to restrict their
scopes.
You can define hooks in your workflow, in which case they will apply to your workflow only. You can also define hooks for your provider plugins and channel handlers, at installation or configuration time, in which case they will apply to all workflows that use the plugin or channel handler.
Defining hooks in your workflow¶
In your workflow, you can add a hooks
section. In this example, hello world
will
be echoed in the console just before running the Robot Framework test.
apiVersion: opentestfactory.org/v1alpha1
kind: Workflow
metadata:
name: RobotFramework Example
hooks:
- name: robot setup
events:
- category: robot
categoryPrefix: robotframework
before:
- run: echo hello world
jobs:
keyword-driven:
runs-on: [windows, robotframework]
steps:
- uses: actions/checkout@v2
with:
repository: https://github.com/robotframework/RobotDemo.git
- run: 'dir'
working-directory: RobotDemo
- uses: robotframework/robot@v1
with:
datasource: RobotDemo/keyword_driven.robot
Defining provider hooks using a definition file¶
Please refer to “Common provider settings” for examples and instructions if you want to define hooks using a definition file.
Defining job hooks using a definition file¶
Please refer to “Agent channel plugin” and “SSH channel plugin” for examples and instructions if you want to define job hooks in your channel handlers using a definition file.
Use cases¶
Additional attachments¶
Context¶
On your site, you are using a specific library with your testing framework that takes
screenshots during test execution and put them in a known directory (target/screenshots
).
The screenshots will have random names, but are all in PNG format, with the .png
file name extension.
You want to have those screenshots attached to the test case execution in your test case manager.
Implementation¶
hooks:
- name: screenshots loader
events:
- categoryPrefix: robotframework
category: execute
after:
- uses: actions/get-files
with:
pattern: *.png
working-directory: target/screenshots
If you are unsure of the directory content before running the test, you can
add a before
section to ensure it is cleaned:
before:
- uses: actions/delete-file
with:
path: *.png
working-directory: target/screenshots
continue-on-error: true
The continue-on-error
argument is added so that the job can continue if the
directory does not yet exist.
You can insert this hook in your workflow or your provider plugin configuration file.
JUnit detailed execution logs¶
Context¶
JUnit execution logs can be verbose, but they are helpful when trying to investigate technical issues.
The JUnit provider stores its execution log in a target/junit-run-log.txt
file.
You want to have this execution log displayed if the test execution fails.
Implementation¶
hooks:
- name: execution logs on failure (linux)
events:
- categoryPrefix: junit
category: execute
if: runner.os == 'linux'
after:
- run: find . -name junit-run-log.txt -print | xargs cat
if: failure()
- name: execution logs on failure (windows)
events:
- categoryPrefix: junit
category: execute
if: runner.os == 'windows'
after:
- run: '@for /f %%i in (''dir /b/s "junit-run-log.txt"'') do @type %%i'
if: failure()
You insert this hook in your JUnit plugin configuration file. (You should do it in the plugin configuration file so that it applies to all workflows. You can test it in a workflow, though.)
Audit logs¶
Context¶
As a platform manager, you want to record whenever the execute
and cucumber
functions
of the Cucumber plugin are called. You have Linux and Windows execution environments.
Implementation¶
hooks:
- name: audit log (linux)
events:
- categoryPrefix: cucumber
category: execute
if: runner.os == 'linux'
before:
- run: logger -n 192.168.1.2 "Cucumber is about to be used"
- name: audit log (windows)
events:
- categoryPrefix: cucumber
category: execute
if: runner.os == 'windows'
before:
- run: eventcreate /Id 7777 /D "Cucumber is about to be used" /T INFO /L system
You insert this hook in your Cucumber plugin configuration file. (You should do it in the plugin configuration file so that it applies to all workflows. You can test it in a workflow, though.)
Keep the execution workspace on failure¶
Context¶
You want to keep the execution workspace on failure, to be able to investigate the issue.
Implementation¶
hooks:
- name: keep workspace on failure
events:
- channel: teardown
if: failure()
before:
- keep-workspace: true
if: failure()
You insert this hook in the hook definition file you have defined for your Agent channel handler or SSH channel handler.
If a job fails, there will be an entry in the execution log telling you the workspace was kept, and the workspace will be available for investigation.
[2023-06-22T16:46:53] [job ...] Keeping workspace 'C:\Users\me\work\6ca11248-a555-4a77-a186-d89d9958df04' on execution environment
Start and stop a service¶
Context¶
To save resources, you want to start a specific service before running your test using a given testing framework, and you want to stop if after the test execution.
You want this behavior for explicit use of the testing framework as well as for implicit use (for tests executed via a generator plugin).
Implementation¶
hooks:
- name: manage myservice
events:
- categoryPrefix: robotframework
category: execute
- categoryPrefix: robotframework
category: robot
before:
- run: service start myservice
after:
- run: service stop myservice
if: always()
continue-on-error: true
The continue-on-error:
argument is used so that the job can continue even if
something went wrong while stopping the service.
The if: always()
argument is used so that the service is stopped even if an
execution error occurred in a previous step.
You insert this hook in your Robot Framework plugin configuration file. (You should do it in the plugin configuration file so that it applies to all workflows. You can test it in a workflow, though.)
Conditional behavior¶
Context¶
As a platform manager, you want to provide an optional database service to your users when using a given function.
They will have to set a NEED_DATABASE
environment variable to activate it.
Example¶
jobs:
my_job:
...
steps:
...
- uses: myplugin/myfunction
variables:
NEED_DATABASE: yes
...
They may also choose to set the environment variable at job- or workflow-level, so that the service is available for all functions in the job or workflow, respectively.
Implementation¶
hooks:
- name: manage database
events:
- categoryPrefix: myplugin
category: myfunction
if: variables.NEED_DATABASE == 'yes'
before:
- run: start_db
after:
- run: stop_db
if: always()
continue-on-error: true
This differs from the ‘Start and stop a service’ use-case in that no code is added if the feature is not used.
You insert this hook in your myplugin
plugin configuration file. (You should do
it in the plugin configuration file so that it applies to all workflows. You can
test it in a workflow, though.)
Next steps¶
Here are some helpful resources for taking your next steps with the OpenTestFactory hooks:
- “Workflow syntax” for an in-depth view of all possible items you can use in hooks
- “Hooks for jobs and providers” for an in-depth view of all possible hooks you can define
- “Common provider settings” for instructions and examples on how to define hooks at provider-level