Test Configuration
From KVM
The Weird Cartesian Product KVM Test Config File Format (TWCPKVMTCFF)
This is the format used by test configuration files in kvm_runtest_2. It was designed to meet several requirements:
- Support for quick definition of multiple test scenarios (drive format, ACPI support, SMP configuration and other QEMU params) for all guests and tests
- Support for exceptions applying to specific guests/tests/scenarios
- Support for dependencies between tests
- Unification of the various config files currently used into a single (hopefully simple) framework
General Description
- The parser relies on indentation.
- The parser produces a list of dictionaries (dicts). Each dictionary contains a set of key-value pairs.
- Each dict contains at least three keys: 'name', 'shortname' and 'depend'. The values of 'name' and 'shortname' are strings, and the value of 'depend' is a list of strings.
- A list of dictionaries will henceforth be referred to as a frame.
- The initial frame contains a single dict, whose 'name' and 'shortname' are empty strings, and whose 'depend' is an empty list.
- Parsing dict contents:
- The dict parser operates on a frame, which will henceforth be referred to as the current frame.
- A statement of the form '<key> = <value>' sets the value of <key> to <value> in all dicts of the current frame. If a dict lacks <key>, it will be created.
- A statement of the form '<key> += <value>' appends <value> to the value of <key> in all dicts of the current frame. If a dict lacks <key>, it will be created.
- A statement of the form '<key> <= <value>' pre-pends <value> to the value of <key> in all dicts of the current frame. If a dict lacks <key>, it will be created.
- A statement of the form '<key> ?= <value>' sets the value of <key> to <value>, in all dicts of the current frame, but only if <key> exists in the dict. The operators ?+= and ?<= are also supported.
- A statement of the form 'no <regex>' removes from the current frame all dicts whose 'name' field matches <regex>.
- A statement of the form 'only <regex>' removes from the current frame all dicts whose 'name' field does not match <regex>.
- Parsing 'variants':
- A 'variants' block is opened by a 'variants:' statement. The contents of the block should follow the 'variants:' line and should be indented.
- A line in a 'variants' block should be of the format '- <variant_name>:'. The contents of this variant should be specified following that line, and should be indented. The contents are parsed by the dict parser described above; they may be of the format '<key> <op> <value>'. They may also contain 'variants:' statements, or whatever the dict parser recognizes.
- Each variant in a 'variants' block inherits a copy of the frame in which the 'variants:' statement appears. The 'current frame', which may be modified by the dict parser, becomes this copy.
- The name of the variant (specified in the line '- <variant_name>:') is pre-pended to the 'name' field of each dict of the variant's frame, along with a separator dot ('.').
- If the name of the variant is not preceeded by a '@' (i.e. '- @<variant_name>:'), it is pre-pended to the 'shortname' field of each dict of the variant's frame. In other words, if a variant's name is preceeded by a '@', it is omitted from the 'shortname' field.
- The frames of the variants defined in the 'variants' block are joined into a single frame which replaces the frame in which the 'variants:' statement appears.
Example
A single dictionary
The following file:
key1 = value1 key2 = value2 key3 = value3
results in the following list of dictionaries (a single dictionary):
Dictionary #0: depend = [] key1 = value1 key2 = value2 key3 = value3 name = shortname =
Adding a 'variants' block
The following file:
key1 = value1 key2 = value2 key3 = value3 variants: - one: - two: - three:
results in the following list:
Dictionary #0: depend = [] key1 = value1 key2 = value2 key3 = value3 name = one shortname = one Dictionary #1: depend = [] key1 = value1 key2 = value2 key3 = value3 name = two shortname = two Dictionary #2: depend = [] key1 = value1 key2 = value2 key3 = value3 name = three shortname = three
Modifying dictionaries inside a variant
The following file:
key1 = value1 key2 = value2 key3 = value3 variants: - one: key1 = Hello World key2 <= some_prefix_ - two: key2 <= another_prefix_ - three:
results in the following list:
Dictionary #0: depend = [] key1 = Hello World key2 = some_prefix_value2 key3 = value3 name = one shortname = one Dictionary #1: depend = [] key1 = value1 key2 = another_prefix_value2 key3 = value3 name = two shortname = two Dictionary #2: depend = [] key1 = value1 key2 = value2 key3 = value3 name = three shortname = three
Adding dependencies
The following file:
key1 = value1 key2 = value2 key3 = value3 variants: - one: key1 = Hello World key2 <= some_prefix_ - two: one key2 <= another_prefix_ - three: one two
results in the following list:
Dictionary #0: depend = [] key1 = Hello World key2 = some_prefix_value2 key3 = value3 name = one shortname = one Dictionary #1: depend = ['one'] key1 = value1 key2 = another_prefix_value2 key3 = value3 name = two shortname = two Dictionary #2: depend = ['one', 'two'] key1 = value1 key2 = value2 key3 = value3 name = three shortname = three
Multiple 'variants' blocks
The following file:
key1 = value1 key2 = value2 key3 = value3 variants: - one: key1 = Hello World key2 <= some_prefix_ - two: one key2 <= another_prefix_ - three: one two variants: - A: - B:
results in the following list:
Dictionary #0: depend = [] key1 = Hello World key2 = some_prefix_value2 key3 = value3 name = A.one shortname = A.one Dictionary #1: depend = ['A.one'] key1 = value1 key2 = another_prefix_value2 key3 = value3 name = A.two shortname = A.two Dictionary #2: depend = ['A.one', 'A.two'] key1 = value1 key2 = value2 key3 = value3 name = A.three shortname = A.three Dictionary #3: depend = [] key1 = Hello World key2 = some_prefix_value2 key3 = value3 name = B.one shortname = B.one Dictionary #4: depend = ['B.one'] key1 = value1 key2 = another_prefix_value2 key3 = value3 name = B.two shortname = B.two Dictionary #5: depend = ['B.one', 'B.two'] key1 = value1 key2 = value2 key3 = value3 name = B.three shortname = B.three
Using 'no' and 'only'
The following file:
key1 = value1 key2 = value2 key3 = value3 variants: - one: key1 = Hello World key2 <= some_prefix_ - two: one key2 <= another_prefix_ - three: one two variants: - A: no one - B: only one|three
results in the following list:
Dictionary #0: depend = ['A.one'] key1 = value1 key2 = another_prefix_value2 key3 = value3 name = A.two shortname = A.two Dictionary #1: depend = ['A.one', 'A.two'] key1 = value1 key2 = value2 key3 = value3 name = A.three shortname = A.three Dictionary #2: depend = [] key1 = Hello World key2 = some_prefix_value2 key3 = value3 name = B.one shortname = B.one Dictionary #3: depend = ['B.one', 'B.two'] key1 = value1 key2 = value2 key3 = value3 name = B.three shortname = B.three
Using '@'
The following file:
key1 = value1 key2 = value2 key3 = value3 variants: - one: key1 = Hello World key2 <= some_prefix_ - two: one key2 <= another_prefix_ - three: one two variants: - @A: no one - B: only one|three
results in the following list (note the difference between the 'name' and 'shortname' fields):
Dictionary #0: depend = ['A.one'] key1 = value1 key2 = another_prefix_value2 key3 = value3 name = A.two shortname = two Dictionary #1: depend = ['A.one', 'A.two'] key1 = value1 key2 = value2 key3 = value3 name = A.three shortname = three Dictionary #2: depend = [] key1 = Hello World key2 = some_prefix_value2 key3 = value3 name = B.one shortname = B.one Dictionary #3: depend = ['B.one', 'B.two'] key1 = value1 key2 = value2 key3 = value3 name = B.three shortname = B.three