-
Notifications
You must be signed in to change notification settings - Fork 117
[feat] Introduce new naming scheme for tests #2355
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
vkarak
merged 65 commits into
reframe-hpc:master
from
vkarak:feat/human-readable-test-names
Jan 24, 2022
Merged
[feat] Introduce new naming scheme for tests #2355
vkarak
merged 65 commits into
reframe-hpc:master
from
vkarak:feat/human-readable-test-names
Jan 24, 2022
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
…frame into feat/human-readable-test-names
ekouts
reviewed
Jan 21, 2022
ekouts
reviewed
Jan 21, 2022
ekouts
approved these changes
Jan 24, 2022
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This PR introduces a new naming scheme for tests and fixture. The new naming scheme for test is enabled by setting the
RFM_COMPACT_TEST_NAMESenvironment variable or the corresponding configuration parameter, but fixtures are always named using the new convention. There are several improvements also in the way tests are listed. Considerable parts of the code have also been adapted to follow the new conventions. More details on what this PR offers follow below.Naming scheme
Each test receives two name attributes.
unique_name: this is the unique identifier of the test within ReFrame. This cannot be set by the users. The currentnameattribute is an alias to this. For compatibility reasons, you can still setname(and thus theunique_namebut this operation is now deprecated)display_name: this is a version of the test name that encodes useful information, such as parameterisation and scopes for fixtures. This is used when displaying tests in listings, because it is much easier to understand what the test is about.Unique names
The unique name of the test is formed as follows:
<locals>for locally defined classes) and, secondly, it facilitates the unit tests.<test_class_name>_<variant-id>. We don't use any special character in the unique name so that it is compatible with any program and filesystem (see for examplecmakebuilds fail when fixtures are used due to special characters in test names #2301). Compared to the current naming scheme, this one ensures unique name also in the case of a parameter that takes twice the same value as withx = parameter([1, 1, 3]. This generates three tests with unique names, whereas with the current naming scheme two of the generated tests would get the same name.<fixture_class_name>_<short_hash>. Theshort-hashis the first 8 characters of a SHA256 hash that is computed from all the fixture differentiating factors, namely, the variant number of the fixture, the scope encoding (e.g.,dom:gpu+gnufor an environment scope) and any variables set in the fixture.Dependencies
The name argument passed to the
depends_on()method should refer to the target test's unique name. Since there is no assumption as of how the variant numbers are assigned to the actual instances of a parameterized test, the correct way to depend on an instance of such a test is the following:This way of depending on a parameterized test is also valid with the current naming scheme and should be the preferred way of writing such dependencies.
Display names
The display name of a test or a fixture encodes the parameterisation and scope information in a human-readable way and it may or may not be unique. The display name is evaluated once, the first time the
display_nameproperty is used, and it is then cached for later access. The construction of the display name requires to recursively descend in fixture chains if a test is eventually parametrised due to a fixture down in the hierarchy; that's why we cache the display name. The display name has the following syntax:<test_class_name>(" %"<param>=<value>)+(<fixture_inst>)*where<param>can take the form<fixture_var>["."<fixture_var>]*"."<param>if the test is parametrised implicitly due to fixtures.<fixture_var>is the name of the variable fixture in the corresponding test or fixture.<fixture_inst>can take the form<fixture_scope>takes the form of<system_name>for fixtures with session scope,<partition_name>for fixtures with partition scope,<partition_name>"+"<environment_name>for fixtures with environment scope and<test_unique_name>for fixtures with test scope. The following example demonstrates the naming scheme. Assuming the test:This is how the above test and its fixtures will be displayed:
We skip the discussion about the
^character at this moment. Notice how the fixture parameters are denoted, as well as thexvariable in the fixture instantiation ofX.Formatting values
By default, parameter values are formatted by taking their string representation (i.e., calling
str()). However, this may not always be convenient especially for builtin aggregate types as in thebenchmark_infoin the following example:For this reason, the
parameter()built-in signature is extended to support an additionalfmtargument that allows custom formatting. This argument should refer to a callable accepting a single argument (the value to be formatted) and return the formatted value. The returned value may not necessarily be a string, in which case it will be converted withstr(). Passingfmt = lambda x: x[0]to the parameter definition of this example, will format thebenchmark_infoparameter using only the benchmark name.Listing dependencies
Test or fixtures that are in the dependency chain of another test are not listed in separate entries, but instead they are listed indented and prefixed with the
^character. The following shows the listing of the tests defined indeps_complex.py:Notice that only the terminal tests are listed at first level whereas their dependencies are listed in DFS order and only once (even if a test appears in multiple dependency paths).
Command line options
This PR extends the
-land-Loptions, changes the behaviour of the-noption and adds a new--describeoption.Test listings
The
-land-Loptions accept now an optional argument that controls whether a list of tests is required or a list of concretised test cases. A concretisation of a test are the test cases that it produces, along with the test cases of its fixtures, based on the selected system partitions and programming environments. The concretisation of the same test can change in different systems as well as when the-pand/or--systemoptions are passed. The default listing is for tests (as of now) and can be achieved with-lor-lT(and similarly for the-Loption). The normal listing lists the tests by their display name only, whereas the detailed listing adds the unique test name and the file where the test was defined. Here are a couple of examples:Normal listing
Detailed listing
Concretised listings
Notice that now the concretisation suffix
@<part>+<env>is added to denote where this test case will actually run. Changing the--systemoption in this case, although it will not change the normal listing, it will change the concretised listing since thecatalinasystem defines two programming environments:Selecting tests by name
The
-noption matches now the display name of a test by removing first any spaces. This allows users to select tests by their parameters easily as in the following example that selects all Amber CUDA benchmarks:You can also perform an exact match for a test using the
@<variant_num>suffix as in the following example:NOTE: Fixtures cannot be selected individually.
Describing tests
The new
--describeoption will return a JSON representation of a test that lists all of the tests public fields, as well as all its required variables. The--describeoption acts a typical action option, so it can be combined any test selection option. Here is an example output:[ { "@class": "amber_nve_check", "@file": "/Users/karakasv/Repositories/reframe/hpctestlib/sciapps/amber/nve.py", "@required": [ "perf_patterns", "sanity_patterns", "num_tasks", "executable", "descr", "energy_tol", "energy_ref", "benchmark", "input_file" ], "benchmark": "Cellulose_production_NVE", "benchmark_info": [ "Cellulose_production_NVE", -443246.0, 5e-05 ], "build_locally": true, "build_system": null, "build_time_limit": null, "container_platform": null, "descr": "Amber NVE Cellulose_production_NVE benchmark (cuda)", "display_name": "amber_nve_check %benchmark_info=Cellulose_production_NVE %variant=cuda", "energy_ref": -443246.0, "energy_tol": 5e-05, "exclusive_access": false, "executable": "pmemd.cuda.MPI", "executable_opts": [ "-O", "-i", "mdin.GPU", "-o", "amber.out" ], "extra_resources": {}, "input_file": "mdin.GPU", "keep_files": [ "amber.out" ], "local": false, "maintainers": [], "max_pending_time": null, "modules": [], "num_cpus_per_task": null, "num_gpus_per_node": 0, "num_tasks_per_core": null, "num_tasks_per_node": null, "num_tasks_per_socket": null, "output_file": "amber.out", "perf_variables": [ "perf" ], "pipeline_hooks": { "post_init": [ "prepare_test" ] }, "postbuild_cmds": [], "postrun_cmds": [], "prebuild_cmds": [], "prerun_cmds": [ "curl -LJO https://github.com/victorusu/amber_benchmark_suite/raw/main/amber_16_benchmark_suite/PME/Cellulose_production_NVE.tar.bz2", "tar xf Cellulose_production_NVE.tar.bz2" ], "readonly_files": [], "reference": null, "sourcepath": "", "sourcesdir": null, "strict_check": true, "tags": [ "sciapp", "chemistry" ], "time_limit": null, "unique_name": "amber_nve_check_1", "use_multithreading": null, "valid_prog_environs": [ "*" ], "valid_systems": [ "*" ], "variables": {}, "variant": "cuda" } ]Notice that the attributes are sorted alphabetically for easy reference. There are three special attributes starting with
@.This option, as well as the other two options returning JSON output,
--show-configand--detect-host-topologyoverride the verbosity of the output and set it toERRORso that any framework output is suppressed except errors. The verbosity is restored toINFOright before the output of these options. This ensures that if these options are successful, their output will always be a valid JSON and it can be piped to utilities such asjqregardless of the frameworks verbosity level.Implementation details
This PR changes primarily the way parameters are stored in the parameter space as well as how fixture names are constructed and set.
Changes in parameter implementation
Regarding parameters, there was a discrepancy in the way they were stored in the parameter space compared to variables and fixtures. The variable and fixture spaces stored
TestVarandTestFixtureobjects, whereas the parameter space stored only the parameter name and the values. As a result, it was not straightforward to provide parameter-level metadata, such as the formatting function passed tofmt. Now the parameter space stores parameter objects, which also take care of updating their values as parameters are inherited from the parent namespaces, an operation that used to happen inside the parameter space in the past. The current implementation of updating the values of a parameter is more natural, since the parameter object stores the information as of whether to inherit parameters and to filter them. The look-and-feel of the parameter space however does not change substantially, since iterating and accessing elements over it, still behaves as before (see the unit tests).The fact that now parameters objects are stored in their entirety in the parameter space, allows the
display_nameproperty in theRegressionTestto properly access the formatting function and format the parameters, but in the future, we could extend the metadata to include source code information (see #2308).Changes in fixtures implementation
The formatting of the fixture's display name does not happen in the fixture namespace as it was effectively happening in the past, due to no distinction between unique and display names. Instead, only the unique name is constructed, which is the class name a unique hash that derives from the metada of the fixture stored in
FixtureData. This is object is now also passed to the actual test instance, in order to be used in the actual formatting done in thedisplay_name.Other implementation improvements
nameattribute in the framework were replace to references either tounique_nameordisplay_name, depending on the context.make_testutility function is introduced (primarly due to use cases in the unit tests) that allows you to create a test programmatically as if you were declaring it with theclasskeyword. The followingis completely equivalent to
This is very useful if you want to create uniquely named tests from the same non-parametrised test.
nameattribute is deprecated and how it is made to point to_rfm_unique_name:The
deprecate()built-in creates a variable from another target variable and backs the new variable with aDeprecatedField. Additional logic is added in the variable to check and issue deprecation warnings in case the variable is accessed or set while test hierarchies are defined. After the variable is injected into the final test object, theDeprecatedFieldis responsible for issuing the warnings.Todos
namedeprecationget_variant_numsso that the values in theconditionsargument can be simple value, in which case the equality condition should be assumed. This is simply a convenience.--describeoption with some useful properties, such as theunique_nameanddisplay_name.Fixes #2248
Fixes #2222
Fixes #2301
Fixes #2313
Fixes #2382
Fixes #2391