Docs: Update stand-alone test information (#44755)
Update and slightly reorganize stand-alone test information to include new and improved examples and more links that can be used in PR feedback.
This commit is contained in:
parent
884a0a392d
commit
baf82c0245
@ -5194,12 +5194,6 @@ installed executable. The check is implemented as follows:
|
|||||||
reframe = Executable(self.prefix.bin.reframe)
|
reframe = Executable(self.prefix.bin.reframe)
|
||||||
reframe("-l")
|
reframe("-l")
|
||||||
|
|
||||||
.. warning::
|
|
||||||
|
|
||||||
The API for adding tests is not yet considered stable and may change
|
|
||||||
in future releases.
|
|
||||||
|
|
||||||
|
|
||||||
""""""""""""""""""""""""""""""""
|
""""""""""""""""""""""""""""""""
|
||||||
Checking build-time test results
|
Checking build-time test results
|
||||||
""""""""""""""""""""""""""""""""
|
""""""""""""""""""""""""""""""""
|
||||||
@ -5237,38 +5231,42 @@ be left in the build stage directory as illustrated below:
|
|||||||
Stand-alone tests
|
Stand-alone tests
|
||||||
^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
While build-time tests are integrated with the build process, stand-alone
|
While build-time tests are integrated with the installation process, stand-alone
|
||||||
tests are expected to run days, weeks, even months after the software is
|
tests are expected to run days, weeks, even months after the software is
|
||||||
installed. The goal is to provide a mechanism for gaining confidence that
|
installed. The goal is to provide a mechanism for gaining confidence that
|
||||||
packages work as installed **and** *continue* to work as the underlying
|
packages work as installed **and** *continue* to work as the underlying
|
||||||
software evolves. Packages can add and inherit stand-alone tests. The
|
software evolves. Packages can add and inherit stand-alone tests. The
|
||||||
`spack test`` command is used to manage stand-alone testing.
|
``spack test`` command is used for stand-alone testing.
|
||||||
|
|
||||||
.. note::
|
.. admonition:: Stand-alone test methods should complete within a few minutes.
|
||||||
|
|
||||||
Execution speed is important since these tests are intended to quickly
|
Execution speed is important since these tests are intended to quickly
|
||||||
assess whether installed specs work on the system. Consequently, they
|
assess whether installed specs work on the system. Spack cannot spare
|
||||||
should run relatively quickly -- as in on the order of at most a few
|
resources for more extensive testing of packages included in CI stacks.
|
||||||
minutes -- while ideally executing all, or at least key aspects of the
|
|
||||||
installed software.
|
|
||||||
|
|
||||||
.. note::
|
Consequently, stand-alone tests should run relatively quickly -- as in
|
||||||
|
on the order of at most a few minutes -- while testing at least key aspects
|
||||||
Failing stand-alone tests indicate problems with the installation and,
|
of the installed software. Save more extensive testing for other tools.
|
||||||
therefore, there is no reason to proceed with more resource-intensive
|
|
||||||
tests until those have been investigated.
|
|
||||||
|
|
||||||
Passing stand-alone tests indicate that more thorough testing, such
|
|
||||||
as running extensive unit or regression tests, or tests that run at
|
|
||||||
scale can proceed without wasting resources on a problematic installation.
|
|
||||||
|
|
||||||
Tests are defined in the package using methods with names beginning ``test_``.
|
Tests are defined in the package using methods with names beginning ``test_``.
|
||||||
This allows Spack to support multiple independent checks, or parts. Files
|
This allows Spack to support multiple independent checks, or parts. Files
|
||||||
needed for testing, such as source, data, and expected outputs, may be saved
|
needed for testing, such as source, data, and expected outputs, may be saved
|
||||||
from the build and or stored with the package in the repository. Regardless
|
from the build and or stored with the package in the repository. Regardless
|
||||||
of origin, these files are automatically copied to the spec's test stage
|
of origin, these files are automatically copied to the spec's test stage
|
||||||
directory prior to execution of the test method(s). Spack also provides some
|
directory prior to execution of the test method(s). Spack also provides helper
|
||||||
helper functions to facilitate processing.
|
functions to facilitate common processing.
|
||||||
|
|
||||||
|
.. tip::
|
||||||
|
|
||||||
|
**The status of stand-alone tests can be used to guide follow-up testing efforts.**
|
||||||
|
|
||||||
|
Passing stand-alone tests justify performing more thorough testing, such
|
||||||
|
as running extensive unit or regression tests or tests that run at scale,
|
||||||
|
when available. These tests are outside of the scope of Spack packaging.
|
||||||
|
|
||||||
|
Failing stand-alone tests indicate problems with the installation and,
|
||||||
|
therefore, no reason to proceed with more resource-intensive tests until
|
||||||
|
the failures have been investigated.
|
||||||
|
|
||||||
.. _configure-test-stage:
|
.. _configure-test-stage:
|
||||||
|
|
||||||
@ -5276,30 +5274,26 @@ helper functions to facilitate processing.
|
|||||||
Configuring the test stage directory
|
Configuring the test stage directory
|
||||||
""""""""""""""""""""""""""""""""""""
|
""""""""""""""""""""""""""""""""""""
|
||||||
|
|
||||||
Stand-alone tests utilize a test stage directory for building, running,
|
Stand-alone tests utilize a test stage directory to build, run, and track
|
||||||
and tracking results in the same way Spack uses a build stage directory.
|
tests in the same way Spack uses a build stage directory to install software.
|
||||||
The default test stage root directory, ``~/.spack/test``, is defined in
|
The default test stage root directory, ``$HOME/.spack/test``, is defined in
|
||||||
:ref:`etc/spack/defaults/config.yaml <config-yaml>`. This location is
|
:ref:`config.yaml <config-yaml>`. This location is customizable by adding or
|
||||||
customizable by adding or changing the ``test_stage`` path in the high-level
|
changing the ``test_stage`` path such that:
|
||||||
``config`` of the appropriate ``config.yaml`` file such that:
|
|
||||||
|
|
||||||
.. code-block:: yaml
|
.. code-block:: yaml
|
||||||
|
|
||||||
config:
|
config:
|
||||||
test_stage: /path/to/test/stage
|
test_stage: /path/to/test/stage
|
||||||
|
|
||||||
Packages can use the ``self.test_suite.stage`` property to access this setting.
|
Packages can use the ``self.test_suite.stage`` property to access the path.
|
||||||
Other package properties that provide access to spec-specific subdirectories
|
|
||||||
and files are described in :ref:`accessing staged files <accessing-files>`.
|
|
||||||
|
|
||||||
.. note::
|
.. admonition:: Each spec being tested has its own test stage directory.
|
||||||
|
|
||||||
The test stage path is the root directory for the **entire suite**.
|
The ``config:test_stage`` option is the path to the root of a
|
||||||
In other words, it is the root directory for **all specs** being
|
**test suite**'s stage directories.
|
||||||
tested by the ``spack test run`` command. Each spec gets its own
|
|
||||||
stage subdirectory. Use ``self.test_suite.test_dir_for_spec(self.spec)``
|
|
||||||
to access the spec-specific test stage directory.
|
|
||||||
|
|
||||||
|
Other package properties that provide paths to spec-specific subdirectories
|
||||||
|
and files are described in :ref:`accessing-files`.
|
||||||
|
|
||||||
.. _adding-standalone-tests:
|
.. _adding-standalone-tests:
|
||||||
|
|
||||||
@ -5312,61 +5306,144 @@ Test recipes are defined in the package using methods with names beginning
|
|||||||
Each method has access to the information Spack tracks on the package, such
|
Each method has access to the information Spack tracks on the package, such
|
||||||
as options, compilers, and dependencies, supporting the customization of tests
|
as options, compilers, and dependencies, supporting the customization of tests
|
||||||
to the build. Standard python ``assert`` statements and other error reporting
|
to the build. Standard python ``assert`` statements and other error reporting
|
||||||
mechanisms are available. Such exceptions are automatically caught and reported
|
mechanisms can be used. These exceptions are automatically caught and reported
|
||||||
as test failures.
|
as test failures.
|
||||||
|
|
||||||
Each test method is an implicit test part named by the method and whose
|
Each test method is an *implicit test part* named by the method. Its purpose
|
||||||
purpose is the method's docstring. Providing a purpose gives context for
|
is the method's docstring. Providing a meaningful purpose for the test gives
|
||||||
aiding debugging. A test method may contain embedded test parts. Spack
|
context that can aid debugging. Spack outputs both the name and purpose at the
|
||||||
outputs the test name and purpose prior to running each test method and
|
start of test execution so it's also important that the docstring/purpose be
|
||||||
any embedded test parts. For example, ``MyPackage`` below provides two basic
|
brief.
|
||||||
examples of installation tests: ``test_always_fails`` and ``test_example``.
|
|
||||||
As the name indicates, the first always fails. The second simply runs the
|
.. tip::
|
||||||
installed example.
|
|
||||||
|
We recommend naming test methods so it is clear *what* is being tested.
|
||||||
|
For example, if a test method is building and or running an executable
|
||||||
|
called ``example``, then call the method ``test_example``. This, together
|
||||||
|
with a similarly meaningful test purpose, will aid test comprehension,
|
||||||
|
debugging, and maintainability.
|
||||||
|
|
||||||
|
Stand-alone tests run in an environment that provides access to information
|
||||||
|
on the installed software, such as build options, dependencies, and compilers.
|
||||||
|
Build options and dependencies are accessed using the same spec checks used
|
||||||
|
by build recipes. Examples of checking :ref:`variant settings <variants>` and
|
||||||
|
:ref:`spec constraints <testing-specs>` can be found at the provided links.
|
||||||
|
|
||||||
|
.. admonition:: Spack automatically sets up the test stage directory and environment.
|
||||||
|
|
||||||
|
Spack automatically creates the test stage directory and copies
|
||||||
|
relevant files *prior to* running tests. It can also ensure build
|
||||||
|
dependencies are available **if** necessary.
|
||||||
|
|
||||||
|
The path to the test stage is configurable (see :ref:`configure-test-stage`).
|
||||||
|
|
||||||
|
Files that Spack knows to copy are those saved from the build (see
|
||||||
|
:ref:`cache_extra_test_sources`) and those added to the package repository
|
||||||
|
(see :ref:`cache_custom_files`).
|
||||||
|
|
||||||
|
Spack will use the value of the ``test_requires_compiler`` property to
|
||||||
|
determine whether it needs to also set up build dependencies (see
|
||||||
|
:ref:`test-build-tests`).
|
||||||
|
|
||||||
|
The ``MyPackage`` package below provides two basic test examples:
|
||||||
|
``test_example`` and ``test_example2``. The first runs the installed
|
||||||
|
``example`` and ensures its output contains an expected string. The second
|
||||||
|
runs ``example2`` without checking output so is only concerned with confirming
|
||||||
|
the executable runs successfully. If the installed spec is not expected to have
|
||||||
|
``example2``, then the check at the top of the method will raise a special
|
||||||
|
``SkipTest`` exception, which is captured to facilitate reporting skipped test
|
||||||
|
parts to tools like CDash.
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
class MyPackage(Package):
|
class MyPackage(Package):
|
||||||
...
|
...
|
||||||
|
|
||||||
def test_always_fails(self):
|
|
||||||
"""use assert to always fail"""
|
|
||||||
assert False
|
|
||||||
|
|
||||||
def test_example(self):
|
def test_example(self):
|
||||||
"""run installed example"""
|
"""ensure installed example works"""
|
||||||
|
expected = "Done."
|
||||||
example = which(self.prefix.bin.example)
|
example = which(self.prefix.bin.example)
|
||||||
example()
|
|
||||||
|
# Capture stdout and stderr from running the Executable
|
||||||
|
# and check that the expected output was produced.
|
||||||
|
out = example(output=str.split, error=str.split)
|
||||||
|
assert expected in out, f"Expected '{expected}' in the output"
|
||||||
|
|
||||||
|
def test_example2(self):
|
||||||
|
"""run installed example2"""
|
||||||
|
if self.spec.satisfies("@:1.0"):
|
||||||
|
# Raise SkipTest to ensure flagging the test as skipped for
|
||||||
|
# test reporting purposes.
|
||||||
|
raise SkipTest("Test is only available for v1.1 on")
|
||||||
|
|
||||||
|
example2 = which(self.prefix.bin.example2)
|
||||||
|
example2()
|
||||||
|
|
||||||
Output showing the identification of each test part after running the tests
|
Output showing the identification of each test part after running the tests
|
||||||
is illustrated below.
|
is illustrated below.
|
||||||
|
|
||||||
.. code-block:: console
|
.. code-block:: console
|
||||||
|
|
||||||
$ spack test run --alias mypackage mypackage@1.0
|
$ spack test run --alias mypackage mypackage@2.0
|
||||||
==> Spack test mypackage
|
==> Spack test mypackage
|
||||||
...
|
...
|
||||||
$ spack test results -l mypackage
|
$ spack test results -l mypackage
|
||||||
==> Results for test suite 'mypackage':
|
==> Results for test suite 'mypackage':
|
||||||
...
|
...
|
||||||
==> [2023-03-10-16:03:56.625204] test: test_always_fails: use assert to always fail
|
==> [2024-03-10-16:03:56.625439] test: test_example: ensure installed example works
|
||||||
...
|
...
|
||||||
FAILED
|
PASSED: MyPackage::test_example
|
||||||
==> [2023-03-10-16:03:56.625439] test: test_example: run installed example
|
==> [2024-03-10-16:03:56.625439] test: test_example2: run installed example2
|
||||||
...
|
...
|
||||||
PASSED
|
PASSED: MyPackage::test_example2
|
||||||
|
|
||||||
|
.. admonition:: Do NOT implement tests that must run in the installation prefix.
|
||||||
|
|
||||||
.. note::
|
Use of the package spec's installation prefix for building and running
|
||||||
|
tests is **strongly discouraged**. Doing so causes permission errors for
|
||||||
|
shared spack instances *and* facilities that install the software in
|
||||||
|
read-only file systems or directories.
|
||||||
|
|
||||||
If ``MyPackage`` were a recipe for a library, the tests should build
|
Instead, start these test methods by explicitly copying the needed files
|
||||||
an example or test program that is then executed.
|
from the installation prefix to the test stage directory. Note the test
|
||||||
|
stage directory is the current directory when the test is executed with
|
||||||
|
the ``spack test run`` command.
|
||||||
|
|
||||||
A test method can include test parts using the ``test_part`` context manager.
|
.. admonition:: Test methods for library packages should build test executables.
|
||||||
Each part is treated as an independent check to allow subsequent test parts
|
|
||||||
to execute even after a test part fails.
|
|
||||||
|
|
||||||
.. _test-part:
|
Stand-alone tests for library packages *should* build test executables
|
||||||
|
that utilize the *installed* library. Doing so ensures the tests follow
|
||||||
|
a similar build process that users of the library would follow.
|
||||||
|
|
||||||
|
For more information on how to do this, see :ref:`test-build-tests`.
|
||||||
|
|
||||||
|
.. tip::
|
||||||
|
|
||||||
|
If you want to see more examples from packages with stand-alone tests, run
|
||||||
|
``spack pkg grep "def\stest" | sed "s/\/package.py.*//g" | sort -u``
|
||||||
|
from the command line to get a list of the packages.
|
||||||
|
|
||||||
|
.. _adding-standalone-test-parts:
|
||||||
|
|
||||||
|
"""""""""""""""""""""""""""""
|
||||||
|
Adding stand-alone test parts
|
||||||
|
"""""""""""""""""""""""""""""
|
||||||
|
|
||||||
|
Sometimes dependencies between steps of a test lend themselves to being
|
||||||
|
broken into parts. Tracking the pass/fail status of each part may aid
|
||||||
|
debugging. Spack provides a ``test_part`` context manager for use within
|
||||||
|
test methods.
|
||||||
|
|
||||||
|
Each test part is independently run, tracked, and reported. Test parts are
|
||||||
|
executed in the order they appear. If one fails, subsequent test parts are
|
||||||
|
still performed even if they would also fail. This allows tools like CDash
|
||||||
|
to track and report the status of test parts across runs. The pass/fail status
|
||||||
|
of the enclosing test is derived from the statuses of the embedded test parts.
|
||||||
|
|
||||||
|
.. admonition:: Test method and test part names **must** be unique.
|
||||||
|
|
||||||
|
Test results reporting requires that test methods and embedded test parts
|
||||||
|
within a package have unique names.
|
||||||
|
|
||||||
The signature for ``test_part`` is:
|
The signature for ``test_part`` is:
|
||||||
|
|
||||||
@ -5388,40 +5465,68 @@ where each argument has the following meaning:
|
|||||||
* ``work_dir`` is the path to the directory in which the test will run.
|
* ``work_dir`` is the path to the directory in which the test will run.
|
||||||
|
|
||||||
The default of ``None``, or ``"."``, corresponds to the the spec's test
|
The default of ``None``, or ``"."``, corresponds to the the spec's test
|
||||||
stage (i.e., ``self.test_suite.test_dir_for_spec(self.spec)``.
|
stage (i.e., ``self.test_suite.test_dir_for_spec(self.spec)``).
|
||||||
|
|
||||||
.. admonition:: Tests should **not** run under the installation directory.
|
.. admonition:: Start test part names with the name of the enclosing test.
|
||||||
|
|
||||||
Use of the package spec's installation directory for building and running
|
We **highly recommend** starting the names of test parts with the name
|
||||||
tests is **strongly** discouraged. Doing so causes permission errors for
|
of the enclosing test. Doing so helps with the comprehension, readability
|
||||||
shared spack instances *and* facilities that install the software in
|
and debugging of test results.
|
||||||
read-only file systems or directories.
|
|
||||||
|
|
||||||
Suppose ``MyPackage`` actually installs two examples we want to use for tests.
|
Suppose ``MyPackage`` installs multiple executables that need to run in a
|
||||||
These checks can be implemented as separate checks or, as illustrated below,
|
specific order since the outputs from one are inputs of others. Further suppose
|
||||||
embedded test parts.
|
we want to add an integration test that runs the executables in order. We can
|
||||||
|
accomplish this goal by implementing a stand-alone test method consisting of
|
||||||
|
test parts for each executable as follows:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
class MyPackage(Package):
|
class MyPackage(Package):
|
||||||
...
|
...
|
||||||
|
|
||||||
def test_example(self):
|
def test_series(self):
|
||||||
"""run installed examples"""
|
"""run setup, perform, and report"""
|
||||||
for example in ["ex1", "ex2"]:
|
|
||||||
with test_part(
|
with test_part(self, "test_series_setup", purpose="setup operation"):
|
||||||
self,
|
exe = which(self.prefix.bin.setup))
|
||||||
f"test_example_{example}",
|
|
||||||
purpose=f"run installed {example}",
|
|
||||||
):
|
|
||||||
exe = which(join_path(self.prefix.bin, example))
|
|
||||||
exe()
|
exe()
|
||||||
|
|
||||||
In this case, there will be an implicit test part for ``test_example``
|
with test_part(self, "test_series_run", purpose="perform operation"):
|
||||||
and separate sub-parts for ``ex1`` and ``ex2``. The second sub-part
|
exe = which(self.prefix.bin.run))
|
||||||
will be executed regardless of whether the first passes. The test
|
exe()
|
||||||
log for a run where the first executable fails and the second passes
|
|
||||||
is illustrated below.
|
with test_part(self, "test_series_report", purpose="generate report"):
|
||||||
|
exe = which(self.prefix.bin.report))
|
||||||
|
exe()
|
||||||
|
|
||||||
|
The result is ``test_series`` runs the following executable in order: ``setup``,
|
||||||
|
``run``, and ``report``. In this case no options are passed to any of the
|
||||||
|
executables and no outputs from running them are checked. Consequently, the
|
||||||
|
implementation could be simplified with a for-loop as follows:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
class MyPackage(Package):
|
||||||
|
...
|
||||||
|
|
||||||
|
def test_series(self):
|
||||||
|
"""execute series setup, run, and report"""
|
||||||
|
|
||||||
|
for exe, reason in [
|
||||||
|
("setup", "setup operation"),
|
||||||
|
("run", "perform operation"),
|
||||||
|
("report", "generate report")
|
||||||
|
]:
|
||||||
|
with test_part(self, f"test_series_{exe}", purpose=reason):
|
||||||
|
exe = which(self.prefix.bin.join(exe))
|
||||||
|
exe()
|
||||||
|
|
||||||
|
In both cases, since we're using a context manager, each test part in
|
||||||
|
``test_series`` will execute regardless of the status of the other test
|
||||||
|
parts.
|
||||||
|
|
||||||
|
Now let's look at the output from running the stand-alone tests where
|
||||||
|
the second test part, ``test_series_run``, fails.
|
||||||
|
|
||||||
.. code-block:: console
|
.. code-block:: console
|
||||||
|
|
||||||
@ -5431,50 +5536,67 @@ is illustrated below.
|
|||||||
$ spack test results -l mypackage
|
$ spack test results -l mypackage
|
||||||
==> Results for test suite 'mypackage':
|
==> Results for test suite 'mypackage':
|
||||||
...
|
...
|
||||||
==> [2023-03-10-16:03:56.625204] test: test_example: run installed examples
|
==> [2024-03-10-16:03:56.625204] test: test_series: execute series setup, run, and report
|
||||||
==> [2023-03-10-16:03:56.625439] test: test_example_ex1: run installed ex1
|
==> [2024-03-10-16:03:56.625439] test: test_series_setup: setup operation
|
||||||
...
|
...
|
||||||
FAILED
|
PASSED: MyPackage::test_series_setup
|
||||||
==> [2023-03-10-16:03:56.625555] test: test_example_ex2: run installed ex2
|
==> [2024-03-10-16:03:56.625555] test: test_series_run: perform operation
|
||||||
...
|
...
|
||||||
PASSED
|
FAILED: MyPackage::test_series_run
|
||||||
|
==> [2024-03-10-16:03:57.003456] test: test_series_report: generate report
|
||||||
|
...
|
||||||
|
FAILED: MyPackage::test_series_report
|
||||||
|
FAILED: MyPackage::test_series
|
||||||
...
|
...
|
||||||
|
|
||||||
.. warning::
|
Since test parts depended on the success of previous parts, we see that the
|
||||||
|
failure of one results in the failure of subsequent checks and the overall
|
||||||
|
result of the test method, ``test_series``, is failure.
|
||||||
|
|
||||||
Test results reporting requires that each test method and embedded
|
.. tip::
|
||||||
test part for a package have a unique name.
|
|
||||||
|
|
||||||
Stand-alone tests run in an environment that provides access to information
|
If you want to see more examples from packages using ``test_part``, run
|
||||||
Spack has on how the software was built, such as build options, dependencies,
|
``spack pkg grep "test_part(" | sed "s/\/package.py.*//g" | sort -u``
|
||||||
and compilers. Build options and dependencies are accessed with the normal
|
from the command line to get a list of the packages.
|
||||||
spec checks. Examples of checking :ref:`variant settings <variants>` and
|
|
||||||
:ref:`spec constraints <testing-specs>` can be found at the provided links.
|
|
||||||
Accessing compilers in stand-alone tests that are used by the build requires
|
|
||||||
setting a package property as described :ref:`below <test-compilation>`.
|
|
||||||
|
|
||||||
|
.. _test-build-tests:
|
||||||
|
|
||||||
.. _test-compilation:
|
"""""""""""""""""""""""""""""""""""""
|
||||||
|
Building and running test executables
|
||||||
|
"""""""""""""""""""""""""""""""""""""
|
||||||
|
|
||||||
"""""""""""""""""""""""""
|
.. admonition:: Re-use build-time sources and (small) input data sets when possible.
|
||||||
Enabling test compilation
|
|
||||||
"""""""""""""""""""""""""
|
|
||||||
|
|
||||||
If you want to build and run binaries in tests, then you'll need to tell
|
We **highly recommend** re-using build-time test sources and pared down
|
||||||
Spack to load the package's compiler configuration. This is accomplished
|
input files for testing installed software. These files are easier
|
||||||
by setting the package's ``test_requires_compiler`` property to ``True``.
|
to keep synchronized with software capabilities when they reside
|
||||||
|
within the software's repository. More information on saving files from
|
||||||
|
the installation process can be found at :ref:`cache_extra_test_sources`.
|
||||||
|
|
||||||
Setting the property to ``True`` ensures access to the compiler through
|
If that is not possible, you can add test-related files to the package
|
||||||
canonical environment variables (e.g., ``CC``, ``CXX``, ``FC``, ``F77``).
|
repository (see :ref:`cache_custom_files`). It will be important to
|
||||||
It also gives access to build dependencies like ``cmake`` through their
|
remember to maintain them so they work across listed or supported versions
|
||||||
``spec objects`` (e.g., ``self.spec["cmake"].prefix.bin.cmake``).
|
of the package.
|
||||||
|
|
||||||
.. note::
|
Packages that build libraries are good examples of cases where you'll want
|
||||||
|
to build test executables from the installed software before running them.
|
||||||
|
Doing so requires you to let Spack know it needs to load the package's
|
||||||
|
compiler configuration. This is accomplished by setting the package's
|
||||||
|
``test_requires_compiler`` property to ``True``.
|
||||||
|
|
||||||
The ``test_requires_compiler`` property should be added at the top of
|
.. admonition:: ``test_requires_compiler = True`` is required to build test executables.
|
||||||
the package near other attributes, such as the ``homepage`` and ``url``.
|
|
||||||
|
|
||||||
Below illustrates using this feature to compile an example.
|
Setting the property to ``True`` ensures access to the compiler through
|
||||||
|
canonical environment variables (e.g., ``CC``, ``CXX``, ``FC``, ``F77``).
|
||||||
|
It also gives access to build dependencies like ``cmake`` through their
|
||||||
|
``spec objects`` (e.g., ``self.spec["cmake"].prefix.bin.cmake``).
|
||||||
|
|
||||||
|
Be sure to add the property at the top of the package class under other
|
||||||
|
properties like the ``homepage``.
|
||||||
|
|
||||||
|
The example below, which ignores how ``cxx-example.cpp`` is acquired,
|
||||||
|
illustrates the basic process of compiling a test executable using the
|
||||||
|
installed library before running it.
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
@ -5498,28 +5620,22 @@ Below illustrates using this feature to compile an example.
|
|||||||
cxx_example = which(exe)
|
cxx_example = which(exe)
|
||||||
cxx_example()
|
cxx_example()
|
||||||
|
|
||||||
|
Typically the files used to build and or run test executables are either
|
||||||
|
cached from the installation (see :ref:`cache_extra_test_sources`) or added
|
||||||
|
to the package repository (see :ref:`cache_custom_files`). There is nothing
|
||||||
|
preventing the use of both.
|
||||||
|
|
||||||
.. _cache_extra_test_sources:
|
.. _cache_extra_test_sources:
|
||||||
|
|
||||||
"""""""""""""""""""""""
|
""""""""""""""""""""""""""""""""""""
|
||||||
Saving build-time files
|
Saving build- and install-time files
|
||||||
"""""""""""""""""""""""
|
""""""""""""""""""""""""""""""""""""
|
||||||
|
|
||||||
.. note::
|
You can use the ``cache_extra_test_sources`` helper routine to copy
|
||||||
|
directories and or files from the source build stage directory to the
|
||||||
We highly recommend re-using build-time test sources and pared down
|
package's installation directory. Spack will automatically copy these
|
||||||
input files for testing installed software. These files are easier
|
files for you when it sets up the test stage directory and before it
|
||||||
to keep synchronized with software capabilities since they reside
|
begins running the tests.
|
||||||
within the software's repository.
|
|
||||||
|
|
||||||
If that is not possible, you can add test-related files to the package
|
|
||||||
repository (see :ref:`adding custom files <cache_custom_files>`). It
|
|
||||||
will be important to maintain them so they work across listed or supported
|
|
||||||
versions of the package.
|
|
||||||
|
|
||||||
You can use the ``cache_extra_test_sources`` helper to copy directories
|
|
||||||
and or files from the source build stage directory to the package's
|
|
||||||
installation directory.
|
|
||||||
|
|
||||||
The signature for ``cache_extra_test_sources`` is:
|
The signature for ``cache_extra_test_sources`` is:
|
||||||
|
|
||||||
@ -5534,46 +5650,69 @@ where each argument has the following meaning:
|
|||||||
* ``srcs`` is a string *or* a list of strings corresponding to the
|
* ``srcs`` is a string *or* a list of strings corresponding to the
|
||||||
paths of subdirectories and or files needed for stand-alone testing.
|
paths of subdirectories and or files needed for stand-alone testing.
|
||||||
|
|
||||||
The paths must be relative to the staged source directory. Contents of
|
.. warning::
|
||||||
subdirectories and files are copied to a special test cache subdirectory
|
|
||||||
of the installation prefix. They are automatically copied to the appropriate
|
|
||||||
relative paths under the test stage directory prior to executing stand-alone
|
|
||||||
tests.
|
|
||||||
|
|
||||||
For example, a package method for copying everything in the ``tests``
|
Paths provided in the ``srcs`` argument **must be relative** to the
|
||||||
subdirectory plus the ``foo.c`` and ``bar.c`` files from ``examples``
|
staged source directory. They will be copied to the equivalent relative
|
||||||
and using ``foo.c`` in a test method is illustrated below.
|
location under the test stage directory prior to test execution.
|
||||||
|
|
||||||
|
Contents of subdirectories and files are copied to a special test cache
|
||||||
|
subdirectory of the installation prefix. They are automatically copied to
|
||||||
|
the appropriate relative paths under the test stage directory prior to
|
||||||
|
executing stand-alone tests.
|
||||||
|
|
||||||
|
.. tip::
|
||||||
|
|
||||||
|
*Perform test-related conversions once when copying files.*
|
||||||
|
|
||||||
|
If one or more of the copied files needs to be modified to reference
|
||||||
|
the installed software, it is recommended that those changes be made
|
||||||
|
to the cached files **once** in the post-``install`` copy method
|
||||||
|
**after** the call to ``cache_extra_test_sources``. This will reduce
|
||||||
|
the amount of unnecessary work in the test method **and** avoid problems
|
||||||
|
running stand-alone tests in shared instances and facility deployments.
|
||||||
|
|
||||||
|
The ``filter_file`` function can be quite useful for such changes
|
||||||
|
(see :ref:`file-filtering`).
|
||||||
|
|
||||||
|
Below is a basic example of a test that relies on files from the installation.
|
||||||
|
This package method re-uses the contents of the ``examples`` subdirectory,
|
||||||
|
which is assumed to have all of the files implemented to allow ``make`` to
|
||||||
|
compile and link ``foo.c`` and ``bar.c`` against the package's installed
|
||||||
|
library.
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
class MyLibPackage(Package):
|
class MyLibPackage(MakefilePackage):
|
||||||
...
|
...
|
||||||
|
|
||||||
@run_after("install")
|
@run_after("install")
|
||||||
def copy_test_files(self):
|
def copy_test_files(self):
|
||||||
srcs = ["tests",
|
cache_extra_test_sources(self, "examples")
|
||||||
join_path("examples", "foo.c"),
|
|
||||||
join_path("examples", "bar.c")]
|
|
||||||
cache_extra_test_sources(self, srcs)
|
|
||||||
|
|
||||||
def test_foo(self):
|
def test_example(self):
|
||||||
exe = "foo"
|
"""build and run the examples"""
|
||||||
src_dir = self.test_suite.current_test_cache_dir.examples
|
examples_dir = self.test_suite.current_test_cache_dir.examples
|
||||||
with working_dir(src_dir):
|
with working_dir(examples_dir):
|
||||||
cc = which(os.environ["CC"])
|
make = which("make")
|
||||||
cc(
|
make()
|
||||||
f"-L{self.prefix.lib}",
|
|
||||||
f"-I{self.prefix.include}",
|
|
||||||
f"{exe}.c",
|
|
||||||
"-o", exe
|
|
||||||
)
|
|
||||||
foo = which(exe)
|
|
||||||
foo()
|
|
||||||
|
|
||||||
In this case, the method copies the associated files from the build
|
for program in ["foo", "bar"]:
|
||||||
stage, **after** the software is installed, to the package's test
|
with test_part(
|
||||||
cache directory. Then ``test_foo`` builds ``foo`` using ``foo.c``
|
self,
|
||||||
before running the program.
|
f"test_example_{program}",
|
||||||
|
purpose=f"ensure {program} runs"
|
||||||
|
):
|
||||||
|
exe = Executable(program)
|
||||||
|
exe()
|
||||||
|
|
||||||
|
In this case, ``copy_test_files`` copies the associated files from the
|
||||||
|
build stage to the package's test cache directory under the installation
|
||||||
|
prefix. Running ``spack test run`` for the package results in Spack copying
|
||||||
|
the directory and its contents to the the test stage directory. The
|
||||||
|
``working_dir`` context manager ensures the commands within it are executed
|
||||||
|
from the ``examples_dir``. The test builds the software using ``make`` before
|
||||||
|
running each executable, ``foo`` and ``bar``, as independent test parts.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
@ -5582,43 +5721,18 @@ before running the program.
|
|||||||
|
|
||||||
The key to copying files for stand-alone testing at build time is use
|
The key to copying files for stand-alone testing at build time is use
|
||||||
of the ``run_after`` directive, which ensures the associated files are
|
of the ``run_after`` directive, which ensures the associated files are
|
||||||
copied **after** the provided build stage where the files **and**
|
copied **after** the provided build stage (``install``) when the installation
|
||||||
installation prefix are available.
|
prefix **and** files are available.
|
||||||
|
|
||||||
These paths are **automatically copied** from cache to the test stage
|
The test method uses the path contained in the package's
|
||||||
directory prior to the execution of any stand-alone tests. Tests access
|
``self.test_suite.current_test_cache_dir`` property for the root directory
|
||||||
the files using the ``self.test_suite.current_test_cache_dir`` property.
|
of the copied files. In this case, that's the ``examples`` subdirectory.
|
||||||
In our example above, test methods can use the following paths to reference
|
|
||||||
the copy of each entry listed in ``srcs``, respectively:
|
|
||||||
|
|
||||||
* ``self.test_suite.current_test_cache_dir.tests``
|
.. tip::
|
||||||
* ``join_path(self.test_suite.current_test_cache_dir.examples, "foo.c")``
|
|
||||||
* ``join_path(self.test_suite.current_test_cache_dir.examples, "bar.c")``
|
|
||||||
|
|
||||||
.. admonition:: Library packages should build stand-alone tests
|
|
||||||
|
|
||||||
Library developers will want to build the associated tests
|
|
||||||
against their **installed** libraries before running them.
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
While source and input files are generally recommended, binaries
|
|
||||||
**may** also be cached by the build process. Only you, as the package
|
|
||||||
writer or maintainer, know whether these files would be appropriate
|
|
||||||
for testing the installed software weeks to months later.
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
If one or more of the copied files needs to be modified to reference
|
|
||||||
the installed software, it is recommended that those changes be made
|
|
||||||
to the cached files **once** in the ``copy_test_sources`` method and
|
|
||||||
***after** the call to ``cache_extra_test_sources()``. This will
|
|
||||||
reduce the amount of unnecessary work in the test method **and** avoid
|
|
||||||
problems testing in shared instances and facility deployments.
|
|
||||||
|
|
||||||
The ``filter_file`` function can be quite useful for such changes.
|
|
||||||
See :ref:`file manipulation <file-manipulation>`.
|
|
||||||
|
|
||||||
|
If you want to see more examples from packages that cache build files, run
|
||||||
|
``spack pkg grep cache_extra_test_sources | sed "s/\/package.py.*//g" | sort -u``
|
||||||
|
from the command line to get a list of the packages.
|
||||||
|
|
||||||
.. _cache_custom_files:
|
.. _cache_custom_files:
|
||||||
|
|
||||||
@ -5626,8 +5740,9 @@ the copy of each entry listed in ``srcs``, respectively:
|
|||||||
Adding custom files
|
Adding custom files
|
||||||
"""""""""""""""""""
|
"""""""""""""""""""
|
||||||
|
|
||||||
In some cases it can be useful to have files that can be used to build or
|
Sometimes it is helpful or necessary to include custom files for building and
|
||||||
check the results of tests. Examples include:
|
or checking the results of tests as part of the package. Examples of the types
|
||||||
|
of files that might be useful are:
|
||||||
|
|
||||||
- test source files
|
- test source files
|
||||||
- test input files
|
- test input files
|
||||||
@ -5635,17 +5750,15 @@ check the results of tests. Examples include:
|
|||||||
- expected test outputs
|
- expected test outputs
|
||||||
|
|
||||||
While obtaining such files from the software repository is preferred (see
|
While obtaining such files from the software repository is preferred (see
|
||||||
:ref:`adding build-time files <cache_extra_test_sources>`), there are
|
:ref:`cache_extra_test_sources`), there are circumstances where doing so is not
|
||||||
circumstances where that is not feasible (e.g., the software is not being
|
feasible such as when the software is not being actively maintained. When test
|
||||||
actively maintained). When test files can't be obtained from the repository
|
files cannot be obtained from the repository or there is a need to supplement
|
||||||
or as a supplement to files that can, Spack supports the inclusion of
|
files that can, Spack supports the inclusion of additional files under the
|
||||||
additional files under the ``test`` subdirectory of the package in the
|
``test`` subdirectory of the package in the Spack repository.
|
||||||
Spack repository.
|
|
||||||
|
|
||||||
Spack **automatically copies** the contents of that directory to the
|
The following example assumes a ``custom-example.c`` is saved in ``MyLibary``
|
||||||
test staging directory prior to running stand-alone tests. Test methods
|
package's ``test`` subdirectory. It also assumes the program simply needs to
|
||||||
access those files using the ``self.test_suite.current_test_data_dir``
|
be compiled and linked against the installed ``MyLibrary`` software.
|
||||||
property as shown below.
|
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
@ -5655,17 +5768,29 @@ property as shown below.
|
|||||||
test_requires_compiler = True
|
test_requires_compiler = True
|
||||||
...
|
...
|
||||||
|
|
||||||
def test_example(self):
|
def test_custom_example(self):
|
||||||
"""build and run custom-example"""
|
"""build and run custom-example"""
|
||||||
data_dir = self.test_suite.current_test_data_dir
|
src_dir = self.test_suite.current_test_data_dir
|
||||||
exe = "custom-example"
|
exe = "custom-example"
|
||||||
src = datadir.join(f"{exe}.cpp")
|
|
||||||
...
|
with working_dir(src_dir):
|
||||||
# TODO: Build custom-example using src and exe
|
cc = which(os.environ["CC"])
|
||||||
...
|
cc(
|
||||||
custom_example = which(exe)
|
f"-L{self.prefix.lib}",
|
||||||
|
f"-I{self.prefix.include}",
|
||||||
|
f"{exe}.cpp",
|
||||||
|
"-o", exe
|
||||||
|
)
|
||||||
|
|
||||||
|
custom_example = Executable(exe)
|
||||||
custom_example()
|
custom_example()
|
||||||
|
|
||||||
|
In this case, ``spack test run`` for the package results in Spack copying
|
||||||
|
the contents of the ``test`` subdirectory to the test stage directory path
|
||||||
|
in ``self.test_suite.current_test_data_dir`` before calling
|
||||||
|
``test_custom_example``. Use of the ``working_dir`` context manager
|
||||||
|
ensures the commands to build and run the program are performed from
|
||||||
|
within the appropriate subdirectory of the test stage.
|
||||||
|
|
||||||
.. _expected_test_output_from_file:
|
.. _expected_test_output_from_file:
|
||||||
|
|
||||||
@ -5674,9 +5799,8 @@ Reading expected output from a file
|
|||||||
"""""""""""""""""""""""""""""""""""
|
"""""""""""""""""""""""""""""""""""
|
||||||
|
|
||||||
The helper function ``get_escaped_text_output`` is available for packages
|
The helper function ``get_escaped_text_output`` is available for packages
|
||||||
to retrieve and properly format the text from a file that contains the
|
to retrieve properly formatted text from a file potentially containing
|
||||||
expected output from running an executable that may contain special
|
special characters.
|
||||||
characters.
|
|
||||||
|
|
||||||
The signature for ``get_escaped_text_output`` is:
|
The signature for ``get_escaped_text_output`` is:
|
||||||
|
|
||||||
@ -5686,10 +5810,13 @@ The signature for ``get_escaped_text_output`` is:
|
|||||||
|
|
||||||
where ``filename`` is the path to the file containing the expected output.
|
where ``filename`` is the path to the file containing the expected output.
|
||||||
|
|
||||||
The ``filename`` for a :ref:`custom file <cache_custom_files>` can be
|
The path provided to ``filename`` for one of the copied custom files
|
||||||
accessed by tests using the ``self.test_suite.current_test_data_dir``
|
(:ref:`custom file <cache_custom_files>`) is in the path rooted at
|
||||||
property. The example below illustrates how to read a file that was
|
``self.test_suite.current_test_data_dir``.
|
||||||
added to the package's ``test`` subdirectory.
|
|
||||||
|
The example below shows how to reference both the custom database
|
||||||
|
(``packages.db``) and expected output (``dump.out``) files Spack copies
|
||||||
|
to the test stage:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
@ -5711,8 +5838,9 @@ added to the package's ``test`` subdirectory.
|
|||||||
for exp in expected:
|
for exp in expected:
|
||||||
assert re.search(exp, out), f"Expected '{exp}' in output"
|
assert re.search(exp, out), f"Expected '{exp}' in output"
|
||||||
|
|
||||||
If the file was instead copied from the ``tests`` subdirectory of the staged
|
If the files were instead cached from installing the software, the paths to the
|
||||||
source code, the path would be obtained as shown below.
|
two files would be found under the ``self.test_suite.current_test_cache_dir``
|
||||||
|
directory as shown below:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
@ -5720,17 +5848,24 @@ source code, the path would be obtained as shown below.
|
|||||||
"""check example table dump"""
|
"""check example table dump"""
|
||||||
test_cache_dir = self.test_suite.current_test_cache_dir
|
test_cache_dir = self.test_suite.current_test_cache_dir
|
||||||
db_filename = test_cache_dir.join("packages.db")
|
db_filename = test_cache_dir.join("packages.db")
|
||||||
|
..
|
||||||
|
expected = get_escaped_text_output(test_cache_dir.join("dump.out"))
|
||||||
|
...
|
||||||
|
|
||||||
Alternatively, if the file was copied to the ``share/tests`` subdirectory
|
Alternatively, if both files had been installed by the software into the
|
||||||
as part of the installation process, the test could access the path as
|
``share/tests`` subdirectory of the installation prefix, the paths to the
|
||||||
follows:
|
two files would be referenced as follows:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
def test_example(self):
|
def test_example(self):
|
||||||
"""check example table dump"""
|
"""check example table dump"""
|
||||||
db_filename = join_path(self.prefix.share.tests, "packages.db")
|
db_filename = self.prefix.share.tests.join("packages.db")
|
||||||
|
..
|
||||||
|
expected = get_escaped_text_output(
|
||||||
|
self.prefix.share.tests.join("dump.out")
|
||||||
|
)
|
||||||
|
...
|
||||||
|
|
||||||
.. _check_outputs:
|
.. _check_outputs:
|
||||||
|
|
||||||
@ -5738,9 +5873,9 @@ follows:
|
|||||||
Comparing expected to actual outputs
|
Comparing expected to actual outputs
|
||||||
""""""""""""""""""""""""""""""""""""
|
""""""""""""""""""""""""""""""""""""
|
||||||
|
|
||||||
The helper function ``check_outputs`` is available for packages to ensure
|
The ``check_outputs`` helper routine is available for packages to ensure
|
||||||
the expected outputs from running an executable are contained within the
|
multiple expected outputs from running an executable are contained within
|
||||||
actual outputs.
|
the actual outputs.
|
||||||
|
|
||||||
The signature for ``check_outputs`` is:
|
The signature for ``check_outputs`` is:
|
||||||
|
|
||||||
@ -5766,11 +5901,17 @@ Invoking the method is the equivalent of:
|
|||||||
if errors:
|
if errors:
|
||||||
raise RuntimeError("\n ".join(errors))
|
raise RuntimeError("\n ".join(errors))
|
||||||
|
|
||||||
|
.. tip::
|
||||||
|
|
||||||
|
If you want to see more examples from packages that use this helper, run
|
||||||
|
``spack pkg grep check_outputs | sed "s/\/package.py.*//g" | sort -u``
|
||||||
|
from the command line to get a list of the packages.
|
||||||
|
|
||||||
|
|
||||||
.. _accessing-files:
|
.. _accessing-files:
|
||||||
|
|
||||||
"""""""""""""""""""""""""""""""""""""""""
|
"""""""""""""""""""""""""""""""""""""""""
|
||||||
Accessing package- and test-related files
|
Finding package- and test-related files
|
||||||
"""""""""""""""""""""""""""""""""""""""""
|
"""""""""""""""""""""""""""""""""""""""""
|
||||||
|
|
||||||
You may need to access files from one or more locations when writing
|
You may need to access files from one or more locations when writing
|
||||||
@ -5779,8 +5920,7 @@ include test source files or includes them but has no way to build the
|
|||||||
executables using the installed headers and libraries. In these cases
|
executables using the installed headers and libraries. In these cases
|
||||||
you may need to reference the files relative to one or more root directory.
|
you may need to reference the files relative to one or more root directory.
|
||||||
The table below lists relevant path properties and provides additional
|
The table below lists relevant path properties and provides additional
|
||||||
examples of their use.
|
examples of their use. See :ref:`expected_test_output_from_file` for
|
||||||
:ref:`Reading expected output <expected_test_output_from_file>` provides
|
|
||||||
examples of accessing files saved from the software repository, package
|
examples of accessing files saved from the software repository, package
|
||||||
repository, and installation.
|
repository, and installation.
|
||||||
|
|
||||||
@ -5809,7 +5949,6 @@ repository, and installation.
|
|||||||
- ``self.test_suite.current_test_data_dir``
|
- ``self.test_suite.current_test_data_dir``
|
||||||
- ``join_path(self.test_suite.current_test_data_dir, "hello.f90")``
|
- ``join_path(self.test_suite.current_test_data_dir, "hello.f90")``
|
||||||
|
|
||||||
|
|
||||||
.. _inheriting-tests:
|
.. _inheriting-tests:
|
||||||
|
|
||||||
""""""""""""""""""""""""""""
|
""""""""""""""""""""""""""""
|
||||||
@ -5852,7 +5991,7 @@ maintainers provide additional stand-alone tests customized to the package.
|
|||||||
.. warning::
|
.. warning::
|
||||||
|
|
||||||
Any package that implements a test method with the same name as an
|
Any package that implements a test method with the same name as an
|
||||||
inherited method overrides the inherited method. If that is not the
|
inherited method will override the inherited method. If that is not the
|
||||||
goal and you are not explicitly calling and adding functionality to
|
goal and you are not explicitly calling and adding functionality to
|
||||||
the inherited method for the test, then make sure that all test methods
|
the inherited method for the test, then make sure that all test methods
|
||||||
and embedded test parts have unique test names.
|
and embedded test parts have unique test names.
|
||||||
@ -6017,6 +6156,8 @@ running:
|
|||||||
This is already part of the boilerplate for packages created with
|
This is already part of the boilerplate for packages created with
|
||||||
``spack create``.
|
``spack create``.
|
||||||
|
|
||||||
|
.. _file-filtering:
|
||||||
|
|
||||||
^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^
|
||||||
Filtering functions
|
Filtering functions
|
||||||
^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^
|
||||||
|
Loading…
Reference in New Issue
Block a user