A common use case for MuseIDE is building automated web tests, using Selenium. A common deployment environment for these tests is a CI/CD server, such as Jenkins. This post will show one way to accomplish this. Some of these techniques are applied in the muse-examples project.
The first problem is: How can Muse detect the environment it is running in?
When Jenkins runs a job, it sets the JOB_NAME environment variable. Muse tasks and plug-ins can access environment variables via a System Value Source. This expression creates a value-source that evaluates to true when running in a Jenkins job:
not(($$"env"."vars"."JOB_NAME") == null)
The hostname can also serve as the decision point. It can also be accessed via the env system value source, such as this example that evaluates to true when running on the buildserver.
$$"env"."hostname" == 'buildserver'
Change Inputs and Outputs
The next problem, is how to change the behavior of the tasks. Two common needs, in handling differences between development and deployment environments, are:
- change the URL of the website accessed by a task
- change the location of the outputs of a task
Both of these can be solved by injecting values into a task with Variable List and a Variable List Initializer plug-in. There are several possible approaches – here I will describe the approach taken in the muse-examples project.
Step 1 – Create VariableList resources
First, I created 2 VariableList resources – one called project-vars and one called project-vars-local. The first contains general variables for the project and the CI/CD (Jenkins) environment. Note the URL.
The second contains only those that should be different when running locally (i.e. during development of the automation). Note the different URL.
Step 2 – Create Plug-ins
Next, I created two Variable List Initializer plug-ins in the project. The first injects variables from the project-vars list.
The magic happens in the second initializer plug-in. Note the Apply only if parameter. That condition will only run this plug-in if the JOB_NAME environment variable is null…which means when NOT running in Jenkins.
As a result, the URL from the first list will be overwritten from the URL in the second list and the second will be used in local development environment. The first URL will be used when running in Jenkins.
Step 3 – Order the Plug-ins
You may not have noticed that the Apply Automatically? parameter in both of the plug-ins is false, which means they will not be applied to tasks by default. Why? Because by default, there is no implied order that the plug-ins are applied. For many of the plug-ins, that is fine. But in this case, these two must run in the correct order, since the values from one must overwrite the other and not the reverse.
To ensure the order, the Apply Automatically? is turned off and these plug-ins are added to another plug-in, which IS applied automatically. This last plug-in is a List of Plugins, which simply contains a list of other plug-ins to apply. This allows the order of plug-in initialization to be controlled, ensuring that the general variables are applied first and the local variables overwrite them.
Note also that the Task Defaults Initializer plug-in runs after both of them. By default, this plug-in will not overwrite existing values, only injecting the defaults if none are present.
Another approach would be to have only a single variable list initializer plugin that uses an environment variable to choose which list to apply (in the List id parameter). In this example, the list name comes from the INJECT_LIST environment variable.
This approach has two advantages – (1) using several different lists is easy and (2) plug-in order is irrelevant. The disadvantage is that all required variables need to be included in each list and values that are the same everywhere are duplicated.
Muse diagnostic log
By default, the Muse framework writes a diagnostic log to a local file when running a task or task suite.
In a CI/CD environment, this is not convenient. The management tools (Jenkins, etc) will capture the output written to the standard output stream (stdout) and make them conveniently available in the UI for diagnosing problems.
To better integrate into this environment, redirect the Muse diagnostic log to stdout. Two steps are required:
- provide a logback configuration file that is configured for stdout logging
- add a command-line option to use the stdout configuration file
These steps are described in the CI/CD Integration section of the user guide.
Muse event logs
Each task (or task suite) produces a separate event log. These can also be echoed to stdout, by configuring the Event Log Writer plugin. Set the //Log to stdout// parameter to true.
Note that this is not a recommend practice for general use. It can be handy for diagnosing problems when you are initially setting up your execution environment, but should be reset to the default (false) when done, for these reasons:
- The Muse Automation Framework is designed to be capable of running tasks in parallel. The resulting output would be intermingled…and thus very, very difficult to comprehend.
- Failing tasks should be analyzed separately. Reporting plug-ins, such as the JUnit Report plug-in, can include the event log in the report output, making the relevant information conveniently available for each failure.