Configuration database¶
The scenario framework provides a general configuration database.
It is available through the scenario.conf
attribute.
Configuration nodes¶
The database configuration is a tree of sections, sub-sections, sub-sub-sections, … ending with final values.
The ConfigNode
class describes a node in the resulting configuration tree,
either a section or a final value.
Configuration tree & keys¶
Configuration keys are a simplified form of JSONPath: they are dot-separated strings, with the ability to index a single list item with a number between square brackets.
With the following sample data:
a:
b:
c: 55
x:
y:
- z: 100
- z: 101
- z: 102
- z: 104
“a.b.c” points to the 55 value,
“x.y[2].z” points to the 102 value,
“a.b” points to the so-named sub-section (the corresponding data being a
dict
),“x.y” points to the so-named list (the corresponding data being a
list
),“” (empty string) points to root node.
Tip
Configuration keys may be passed as strings or string enums.
Loading and setting configurations through the command line¶
Configuration values are basically set through the command line,
with the --config-file
and/or --config-value
options of test and campaign launchers.
usage: run-test.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]
SCENARIO_PATH [SCENARIO_PATH ...]
Scenario test execution.
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.
Configuration files can be in one of the following formats:
Format |
File extensions |
---|---|
INI (as handled by configparser) |
.ini, .INI |
JSON |
.json, .JSON |
YAML (requires PyYAML to be installed) |
.yaml, .yml, .YAML, .YML |
Several files may be loaded consecutively by repeating the --config-file
option.
This makes it possible to split configuration files on various purposes:
the kind of software / system under test,
the environment used to execute the tests,
the identity of the person who launches the tests,
…
The configuration data from the different files is merged all together in the resulting tree, the values set from the latter files overloading the ones already set by the formers files.
Then, the single values set by the --config-value
options finally update the configuration tree.
Boolean value conversions
When configuration values are boolean values, they may be passed as strings in one of the usual forms recognized:
- True values:
any non-zero integer or integer string, strings like “True”, “TRUE”, “true”, “Yes, “YES”, “yes”, “Y”, “y”
- False values:
0 (zero) or “0”, strings like “False”, “FALSE”, “false”, “No”, “NO”, “no”, “N”, “n”
Manipulating configurations from the code¶
The code can then access configuration values (resp. ConfigNode
instances)
through the ConfigDatabase.get()
method (resp. ConfigDatabase.getnode()
).
# Access a final value (`None` if the value does not exist).
_any = scenario.conf.get("a.b.c") # type: typing.Optional[typing.Any]
# Access a final value of the given type (`None` if the value does not exist).
_int1 = scenario.conf.get("a.b.c", type=int) # type: typing.Optional[int]
# Access a final value, or fallback to a default value.
_int2 = scenario.conf.get("a.b.c", type=int, default=100) # type: int
# Access a whole section as a JSON dictionary (`None` if the section does not exist).
_section = scenario.conf.get("a", type=dict) # type: typing.Optional[typing.Dict[str, typing.Any]]
# Access a whole list as a JSON list (`None` if the list does not exist).
_list = scenario.conf.get("x.y", type=list) # type: typing.Optional[typing.List[typing.Any]]
The configuration keys available can be listed with the ConfigDatabase.getkeys()
method.
Configuration files can be loaded from the code (see ConfigDatabase.loadfile()
).
# Load a configuration file.
scenario.conf.loadfile("demo/conf.yml")
Configuration data can also be set (either sections or lists or single values, see ConfigDatabase.set()
).
# Set a single value.
scenario.conf.set("a.b.c", 150)
# Update a whole section (possibly with sub-sections).
scenario.conf.set("a.b", {"c": 200})
scenario.conf.set("a", {"b": {"c": 200}})
Automatic configuration data conversions
When setting data from the code, the configuration database applies the following conversions:
Input data type |
Storage |
---|---|
Path-likes |
|
|
|
|
|
Other |
|
Configuration nodes can be accessed directly from the code, and provide an API that can be used from the user code
(see ConfigNode
).
# Access a configuration node (`None` if the node does not exist).
_node = scenario.conf.getnode("a.b.c") # type: typing.Optional[scenario.ConfigNode]
Configuration origins¶
In case configurations lead to some erroneous situation,
the configuration database keeps memory of configuration origins
(see ConfigNode.origins
and ConfigNode.origin
).
This information can help a user fix his/her configuration files when something goes wrong.
For the purpose, the ConfigNode.errmsg()
method
builds error messages giving the representative origin of the given configuration node.
The ConfigDatabase.show()
and ConfigNode.show()
methods
also display the configuration tree with origins.
$ ./demo/run-demo.py --config-file demo/conf.json --config-value x.y[0].z 0 --show-configs demo/htmllogin.py
INFO Main path: '/path/to/scenario'
INFO [scenario.ConfigDatabase] a:
INFO [scenario.ConfigDatabase] a.b:
INFO [scenario.ConfigDatabase] a.b.c: 55 # from demo/conf.json
INFO [scenario.ConfigDatabase] x:
INFO [scenario.ConfigDatabase] x.y[0]:
INFO [scenario.ConfigDatabase] x.y[0].z: '0' # from <args>
INFO [scenario.ConfigDatabase] x.y[1]:
INFO [scenario.ConfigDatabase] x.y[1].z: 100 # from demo/conf.json
INFO [scenario.ConfigDatabase] x.y[2]:
INFO [scenario.ConfigDatabase] x.y[2].z: 101 # from demo/conf.json
INFO [scenario.ConfigDatabase] x.y[3]:
INFO [scenario.ConfigDatabase] x.y[3].z: 102 # from demo/conf.json
INFO [scenario.ConfigDatabase] x.y[4]:
INFO [scenario.ConfigDatabase] x.y[4].z: 103 # from demo/conf.json
scenario configurable keys and values¶
The following table describes the scenario configurable keys & values.
Tip
Use the scenario.ConfigKey
shortcut to the internal ScenarioConfig.Key
enum
from scenario user code.
Key |
Type |
Description |
Default |
|
---|---|---|---|---|
|
String |
Timezone specification. Possible values: ‘UTC’, ‘Z’, or numerical forms like ‘+01:00’, ‘-05:00’. More options when pytz is installed: ‘CET’, ‘US/Pacific’, ‘Japan’, … Execute the following Python code for the complete list: import pytz
print("\n".join(pytz.all_timezones))
|
Not set, i.e. use of the local timezone |
|
|
Boolean |
Should the log lines include a timestamp? |
Enabled |
|
|
Boolean |
Should the log lines be displayed in the console? |
Enabled |
|
|
Boolean |
Should the log lines be colored? |
Enabled |
|
|
Integer |
Console color code per log level.
See |
scenario.log_error_color: red(91), scenario.log_warning_color: yellow(33), scenario.log_info_color: white(1), scenario.log_debug_color: dark grey(2) |
|
|
File path string |
Should the log lines be written in a log file? |
Not set, i.e. no file logging |
|
|
List of strings (or comma-separated string) |
Which debug classes to display? |
Not set |
|
|
List of strings (or comma-separated string) |
Expected scenario attributes. |
Not set |
|
|
Boolean |
Should the scenarios continue on error?
If set to |
Disabled |
|
|
Float (in seconds) |
Should we wait between two step executions? |
0.001 seconds |
|
|
File path string |
Path of the scenario runner script. Useful when executing campaigns: may be used to make your own launcher script path be called. |
‘bin/run-test.py’ provided with the scenario framework |
|
|
Float (in seconds) |
Maximum time for a scenario execution. Useful when executing campaigns. |
600.0 seconds, i.e. 10 minutes |
|
|
List of strings (or comma-separated string) |
Scenario attributes to display for extra info when displaying scenario results, after a campaign execution, or when executing several tests in a single command line. |
Not set |
|
|
|
Dictionary of names associated with issue level integer values. Example: scenario:
issue_levels:
SUT: 40
TEST: 30
CONTEXT: 20
PLANNED: 10
|
Not set |
|
|
String or integer. |
Issue level from and above which known issues should be considered as errors. May be set directly as an integer value, or an issue level name if defined (see scenario.issue_levels). |
Not set |
|
|
String or integer. |
Issue level from and under which known issues should be ignored. May be set directly as an integer value, or an issue level name if defined (see scenario.issue_levels). |
Not set |