Launcher script extension¶
It is common that a user test environment needs to do a couple of things like:
prepare the environment before the test execution,
execute additional actions after the test execution,
offer configurable features.
To do so, the user test environment may define its own launcher script, as illustrated by the demo/run-demo.py file.
Command line argument extension¶
About configurable features, configuration files come as a straight forward solution.
Nevertheless, it is sometimes faster in use to provide command line options to the test launcher script also.
To do so, our ‘demo/run-demo.py’ first overloads the ScenarioArgs
class:
The final program description is set with the
Args.setdescription()
method.Extra arguments may be defined thanks to the
Args.addarg()
thenArgInfo.define()
methods.
class DemoArgs(scenario.ScenarioArgs):
def __init__(self):
scenario.ScenarioArgs.__init__(self)
self.setdescription("Demo test launcher.")
self.welcome_message = "Hello you!"
self.bye_message = "Bye!"
self.addarg("Name", "welcome_message", str).define(
"--welcome", metavar="NAME",
action="store", type=str,
help="User name.",
)
self.show_config_db = False
self.addarg("Show configuration database", "show_config_db", bool).define(
"--show-configs",
action="store_true",
help="Show the configuration values with their origin, then stop.",
)
The Args._checkargs()
method may be overloaded in order to check additional constraints,
after the arguments have been parsed, and the Args
attributes have been updated:
Start or finish with calling the mother class’s
ScenarioArgs._checkargs()
method.This method is expected to return
True
orFalse
whether an error has been detected or not.
def _checkargs(self, args):
if not super()._checkargs(args):
return False
if not self.welcome_message:
scenario.logging.error(f"Wrong name {self.welcome_message!r}")
return False
if not self.welcome_message.startswith("Hello"):
_name = self.welcome_message
self.welcome_message = f"Hello {_name}!"
self.bye_message = f"Bye {_name}!"
return True
Then, in the main part, prior to calling the ScenarioRunner.main()
method:
Set an instance of our
DemoArgs
class with theArgs.setinstance()
method.Call the
Args.parse()
method to parse the command line arguments.
# Command line arguments.
scenario.Args.setinstance(DemoArgs())
if not scenario.Args.getinstance().parse(sys.argv[1:]):
sys.exit(int(scenario.Args.getinstance().error_code))
At this point, the user test environment can use the extra arguments added with the DemoArgs
class,
but regular arguments as well.
# --show-configs option.
if DemoArgs.getinstance().show_config_db:
scenario.conf.show(logging.INFO)
sys.exit(int(scenario.ErrorCode.SUCCESS))
# Welcome message.
scenario.logging.info(DemoArgs.getinstance().welcome_message)
# File logging: use the first scenario file name to determine the output log file name.
_outpath = DemoArgs.getinstance().scenario_paths[0].with_suffix(".log")
scenario.conf.set("scenario.log_file", _outpath)
scenario.logging.info(f"Test log saved in '{_outpath}'")
Using the --help
option displays both:
the usual
ScenarioArgs
options,and the extra options added by the
DemoArgs
class.
$ ./demo/run-demo.py --help
usage: run-demo.py [-h] [--config-file CONFIG_PATH] [--config-value KEY VALUE]
[--debug-class DEBUG_CLASS] [--doc-only]
[--issue-level-error ISSUE_LEVEL]
[--issue-level-ignored ISSUE_LEVEL]
[--json-report JSON_REPORT_PATH]
[--extra-info ATTRIBUTE_NAME] [--welcome NAME]
[--show-configs]
SCENARIO_PATH [SCENARIO_PATH ...]
Demo test launcher.
positional arguments:
SCENARIO_PATH Scenario script(s) to execute.
optional arguments:
-h, --help Show this help message and exit.
--config-file CONFIG_PATH
Input configuration file path. This option may be
called several times.
--config-value KEY VALUE
Single configuration value. This option may be called
several times.
--debug-class DEBUG_CLASS
Activate debugging for the given class.
--doc-only Generate documentation without executing the test(s).
--issue-level-error ISSUE_LEVEL
Define the issue level from and above which known
issues should be considered as errors. None by
default, i.e. all known issues are considered as
warnings.
--issue-level-ignored ISSUE_LEVEL
Define the issue level from and under which known
issues should be ignored. None by default, i.e. no
known issue ignored by default.
--json-report JSON_REPORT_PATH
Save the report in the given JSON output file path.
Single scenario only.
--extra-info ATTRIBUTE_NAME
Scenario attribute to display for extra info when
displaying results. Applicable when executing several
tests. This option may be called several times to
display more info.
--welcome NAME User name.
--show-configs Show the configuration values with their origin, then
stop.
Pre & post-operations¶
As introduced above, extending the launcher script gives you the opportunity to add pre-operations, as soon as the command line arguments have been parsed, and post-operations after the test execution.
Our demo/run-demo.py script gives examples of pre & post-operations:
a welcome message displayed before the test is executed:
# Welcome message.
scenario.logging.info(DemoArgs.getinstance().welcome_message)
a bye message displayed just before the command line ends:
# Bye message.
scenario.logging.info(DemoArgs.getinstance().bye_message)
optional display of the configuration database:
# --show-configs option.
if DemoArgs.getinstance().show_config_db:
scenario.conf.show(logging.INFO)
sys.exit(int(scenario.ErrorCode.SUCCESS))
configuration value settings that enable file logging:
# File logging: use the first scenario file name to determine the output log file name.
_outpath = DemoArgs.getinstance().scenario_paths[0].with_suffix(".log")
scenario.conf.set("scenario.log_file", _outpath)
scenario.logging.info(f"Test log saved in '{_outpath}'")
Base launcher execution¶
The call to the ScenarioRunner.main()
method will not analyze command line arguments twice,
and use the values given by our DemoArgs
instance already set.
# Scenario execution.
_res = scenario.runner.main()
Return code¶
Eventually, convert the enum value returned by ScenarioRunner.main()
into a simple integer value,
so that the error can be handled in the shell that launched the command line.
# Error code.
sys.exit(int(_res))
Campaign launcher script extension¶
Extending the campaign launcher script works the same, except that:
the
CampaignArgs
class may be overloaded to add extra command line arguments,the
CampaignRunner.main()
must be called in the end.
Setting the main path (optional)¶
Another thing that a launcher script may do is to set the main path
(see Path.setmainpath()
).
A main path shall be set for the current test projet.
This way, all paths displayed during the tests may be nicely displayed as pretty path from this main path,
whatever the current working directory
(see Path.prettypath
).
# Main path.
scenario.Path.setmainpath(scenario.Path(__file__).parents[1])
Tip
For display purpose, it is advised to set the main path after the program arguments have been analyzed.