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