|
Packit Service |
569379 |
= Writing and running tests for OpenSCAP
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
This document should help you with writing and running tests for your pull
|
|
Packit Service |
569379 |
requests. It is recommended to add a new test if a new functionality is added
|
|
Packit Service |
569379 |
or if a code that is not covered by any test is updated. Another recommendation
|
|
Packit Service |
569379 |
is to add your test in a separate commit.
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
All the tests reside in the link:../../tests[tests] directory. It has multiple
|
|
Packit Service |
569379 |
subdirectories which should represent various parts of the OpenSCAP library and
|
|
Packit Service |
569379 |
its utilities. When you contribute to some part of the OpenSCAP project you
|
|
Packit Service |
569379 |
should put a test for your contribution into the corresponding subdirectory
|
|
Packit Service |
569379 |
in the link:../../tests[tests] directory. Use your best judgement when deciding
|
|
Packit Service |
569379 |
where to put the test for your pull request and if you are not sure don't be
|
|
Packit Service |
569379 |
affraid to ask in the pull request, someone will definitely help you with that.
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
NOTE: OpenSCAP project uses the **CMake** buildsystem which has built-in
|
|
Packit Service |
569379 |
testing support through the
|
|
Packit Service |
569379 |
link:https://gitlab.kitware.com/cmake/community/wikis/doc/ctest/Testing-With-CTest[CTest]
|
|
Packit Service |
569379 |
testing tool.
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
== Preparing test environment and running tests
|
|
Packit Service |
569379 |
To run a specific test or all tests you first need to compile the OpenSCAP
|
|
Packit Service |
569379 |
library and then install additional packages required for testing. See the
|
|
Packit Service |
569379 |
*Building OpenSCAP on Linux* section in the link:../developer/developer.adoc[OpenSCAP Developer Manual]
|
|
Packit Service |
569379 |
for more details.
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
== Writing a new test
|
|
Packit Service |
569379 |
In this guide we will use an example to describe the process of writing a test
|
|
Packit Service |
569379 |
for the OpenSCAP project. Let's suppose you want to write a new test for
|
|
Packit Service |
569379 |
the Script Check Engine (SCE) to test its basic functionality. SCE allows you
|
|
Packit Service |
569379 |
to define your own scripts (usually written in Bash or Python) to extend XCCDF
|
|
Packit Service |
569379 |
rule checking capabilities. Custom check scripts can be referenced from
|
|
Packit Service |
569379 |
an XCCDF rule using `<check-content-ref>` element, for example:
|
|
Packit Service |
569379 |
----
|
|
Packit Service |
569379 |
<check system="http://open-scap.org/page/SCE">
|
|
Packit Service |
569379 |
<check-content-ref href="YOUR_BASH_SCRIPT.sh"/>
|
|
Packit Service |
569379 |
</check>
|
|
Packit Service |
569379 |
----
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
=== Deciding where to put a new test
|
|
Packit Service |
569379 |
In our example, we are testing the SCE module, therefore we will look for
|
|
Packit Service |
569379 |
its subdirectory in the link:../../tests[tests] direcotory and we will find it
|
|
Packit Service |
569379 |
at the following link: link:../../tests/sce[tests/sce]. We will add our new test
|
|
Packit Service |
569379 |
into this subdirectory.
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
==== Scenario A: There is a suitable directory for my new test
|
|
Packit Service |
569379 |
This will happen most of the times. As stated above in our example we will place
|
|
Packit Service |
569379 |
our test into the link:../../tests/sce[tests/sce] directory.
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
==== Scenario B: There is no suitable directory for my new test
|
|
Packit Service |
569379 |
This might happen if your test covers a part of the OpenSCAP which has no tests
|
|
Packit Service |
569379 |
at all. In this case you would need to add a new directory with suitable name
|
|
Packit Service |
569379 |
into the link:../../tests[tests] directory structure and create/update
|
|
Packit Service |
569379 |
`CMakeLists.txt` files.
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
To have an example also for this scenario, let's suppose we want to add the
|
|
Packit Service |
569379 |
`foo` subdirectory into the link:../../tests[tests] directory. We need to:
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
. Create the `foo` subdirectory in the link:../../tests[tests] directory.
|
|
Packit Service |
569379 |
. Use the link:https://cmake.org/cmake/help/latest/command/add_subdirectory.html[add_subdirectory]
|
|
Packit Service |
569379 |
command from the link:../../tests/CMakeLists.txt[tests/CMakeLists.txt]
|
|
Packit Service |
569379 |
to add the `foo` subdirectory to the CMake buildsystem.
|
|
Packit Service |
569379 |
. Create `CMakeLists.txt` inside the `tests/foo` directory and use the
|
|
Packit Service |
569379 |
`add_oscap_test` function (defined in the
|
|
Packit Service |
569379 |
link:../../tests/CMakeLists.txt[tests/CMakeLists.txt]) to add all your test
|
|
Packit Service |
569379 |
scripts from the `foo` directory.
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
Please see the
|
|
Packit Service |
569379 |
link:https://gitlab.kitware.com/cmake/community/wikis/doc/ctest/Testing-With-CTest[
|
|
Packit Service |
569379 |
CTest documentation] for more details.
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
=== Common test library
|
|
Packit Service |
569379 |
When writing tests for OpenSCAP you should use the common test library which is
|
|
Packit Service |
569379 |
located at link:../../tests/test_common.sh.in[tests/test_common.sh.in].
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
NOTE: The `cmake` command will generate the `tests/test_common.sh` file from
|
|
Packit Service |
569379 |
the link:../../tests/test_common.sh.in[tests/test_common.sh.in] adding
|
|
Packit Service |
569379 |
configuration specific settings.
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
You will need to source the `tests/test_common.sh` in your test scripts to use
|
|
Packit Service |
569379 |
the functions which it provides:
|
|
Packit Service |
569379 |
[source,bash]
|
|
Packit Service |
569379 |
----
|
|
Packit Service |
569379 |
#!/usr/bin/env bash
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
set -o pipefail
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
. $builddir/tests/test_common.sh
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
test1
|
|
Packit Service |
569379 |
test2
|
|
Packit Service |
569379 |
...
|
|
Packit Service |
569379 |
----
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
NOTE: The `$builddir` variable contains the path to the top level of the build
|
|
Packit Service |
569379 |
tree. It is defined in the link:../../tests/CMakeLists.txt[tests/CMakeLists.txt]
|
|
Packit Service |
569379 |
as `builddir=${CMAKE_BINARY_DIR}`.
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
==== Global variables exported by test library
|
|
Packit Service |
569379 |
Always use `$OSCAP` variable instead of the plain `oscap` in your tests when
|
|
Packit Service |
569379 |
calling the `oscap` command line tool. This is because tests might be run with
|
|
Packit Service |
569379 |
`CUSTOM_OSCAP` variable.
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
You can use `$XMLDIFF` in your tests which will call the
|
|
Packit Service |
569379 |
link:../../tests/xmldiff.pl[tests/xmldiff.pl] script.
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
It is also possible to do XPath queries using `$XPATH` variable, the usage is:
|
|
Packit Service |
569379 |
[source,bash]
|
|
Packit Service |
569379 |
----
|
|
Packit Service |
569379 |
$XPATH FILE 'QUERY'
|
|
Packit Service |
569379 |
----
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
==== Best practices when writing bash tests
|
|
Packit Service |
569379 |
It is always good to set `pipefail` option for all your test scripts so you
|
|
Packit Service |
569379 |
accidentally don't lose non-zero exit statuses of commands in a pipeline:
|
|
Packit Service |
569379 |
[source,bash]
|
|
Packit Service |
569379 |
----
|
|
Packit Service |
569379 |
set -o pipefail
|
|
Packit Service |
569379 |
----
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
The next option you can consider is `errexit` which exits your script
|
|
Packit Service |
569379 |
immediately if a command exits with a non-zero status. You might want to use
|
|
Packit Service |
569379 |
this option if tests are somehow dependent and it doesn't make sense to continue
|
|
Packit Service |
569379 |
testing after one test fails.
|
|
Packit Service |
569379 |
[source,bash]
|
|
Packit Service |
569379 |
----
|
|
Packit Service |
569379 |
set -e
|
|
Packit Service |
569379 |
----
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
Also consider splitting the tests up into several separate bash scripts if
|
|
Packit Service |
569379 |
you test many things at once; long running "all.sh" test should be avoided
|
|
Packit Service |
569379 |
if possible, as when these fail it is harder to debug than having more,
|
|
Packit Service |
569379 |
smaller tests. However, make sure these independent tests don't have hidden
|
|
Packit Service |
569379 |
dependencies: often we'll run the test suite in parallel, meaning in-order
|
|
Packit Service |
569379 |
execution of different test scripts cannot be ensured. (However, order
|
|
Packit Service |
569379 |
order inside the test script is guaranteed per bash's rules).
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
Lastly, make sure your tests are architecture, distribution, and operating
|
|
Packit Service |
569379 |
system independent. Try to make your tests dependent on local file contents,
|
|
Packit Service |
569379 |
not system file contents, and make them independent of listening ports and
|
|
Packit Service |
569379 |
installed software as much as possible.
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
==== test_init function
|
|
Packit Service |
569379 |
This function does nothing. Logging is done by the CTest and the log from
|
|
Packit Service |
569379 |
testing can be found at `build/Testing/Temporary/LastTest.log`.
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
==== test_run function
|
|
Packit Service |
569379 |
The function is responsible for executing a test script file or a function and
|
|
Packit Service |
569379 |
logging its result into the log file.
|
|
Packit Service |
569379 |
[source,bash]
|
|
Packit Service |
569379 |
----
|
|
Packit Service |
569379 |
test_run "DESCRIPTION" TEST_FUNCTION|$srcdir/TEST_SCRIPT_FILE ARG [ARG...]
|
|
Packit Service |
569379 |
----
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
NOTE: The `$srcdir` variable contains the path to the directory with the test
|
|
Packit Service |
569379 |
script. It is defined in the link:../../tests/CMakeLists.txt[tests/CMakeLists.txt]
|
|
Packit Service |
569379 |
as `srcdir=${CMAKE_CURRENT_SOURCE_DIR}`. The reason is backward compatibility
|
|
Packit Service |
569379 |
as originally tests were executed by the GNU automake.
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
The `test_run` function reports the following results into the log file:
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
* *PASS* when script/function returns *0*,
|
|
Packit Service |
569379 |
* *FAIL* when script/function returns *1*,
|
|
Packit Service |
569379 |
* *SKIP* when script/function returns *255*,
|
|
Packit Service |
569379 |
* *WARN* when script/function returns none of the above exit statuses.
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
The result of every test executed by the `test_run` function will be reported
|
|
Packit Service |
569379 |
in the log file in a following way:
|
|
Packit Service |
569379 |
[source,bash]
|
|
Packit Service |
569379 |
----
|
|
Packit Service |
569379 |
TEST: DESCRIPTION
|
|
Packit Service |
569379 |
<test stdout + stderr output>
|
|
Packit Service |
569379 |
RESULT: PASS/FAIL/SKIP/WARN
|
|
Packit Service |
569379 |
----
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
==== test_exit function
|
|
Packit Service |
569379 |
The function is responsible for cleaning-up the testing environment. You can
|
|
Packit Service |
569379 |
call it without arguments or with one argument -- a script/function which will
|
|
Packit Service |
569379 |
do additional clean-up tasks.
|
|
Packit Service |
569379 |
[source,bash]
|
|
Packit Service |
569379 |
----
|
|
Packit Service |
569379 |
test_exit [CLEAN_SCRIPT|CLEAN_FUNCTION]
|
|
Packit Service |
569379 |
----
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
==== require function
|
|
Packit Service |
569379 |
Checks if requirements are in the `$PATH`, use it as follows:
|
|
Packit Service |
569379 |
[source,bash]
|
|
Packit Service |
569379 |
----
|
|
Packit Service |
569379 |
require 'program' || return 255
|
|
Packit Service |
569379 |
----
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
==== probecheck function
|
|
Packit Service |
569379 |
Checks if probe exists, use it as follows:
|
|
Packit Service |
569379 |
[source,bash]
|
|
Packit Service |
569379 |
----
|
|
Packit Service |
569379 |
probecheck 'probe' || return 255
|
|
Packit Service |
569379 |
----
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
==== verify_results function
|
|
Packit Service |
569379 |
Verifies that there is the `COUNT` number of results of selected OVAL `TYPE` in
|
|
Packit Service |
569379 |
a `RESULTS_FILE`:
|
|
Packit Service |
569379 |
[source,bash]
|
|
Packit Service |
569379 |
----
|
|
Packit Service |
569379 |
verify_results TYPE CONTENT_FILE RESULTS_FILE COUNT
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
verify_results "def" test_probe_foo.xml results.xml 13
|
|
Packit Service |
569379 |
----
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
The function extracts the actual test/definition result, and compares it with the respective test/definition comment.
|
|
Packit Service |
569379 |
For example, if the test contains `comment="true"`, the test passes only if result of the respective test is `true`,
|
|
Packit Service |
569379 |
if `comment="false"`, a `false` result is expected.
|
|
Packit Service |
569379 |
If the comment is missing or it has other value, it is assumed that the result should be neither `true` nor `false`.
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
NOTE: This function expects that the OVAL `TYPE` is numbered from `1` to `COUNT`
|
|
Packit Service |
569379 |
in the `RESULTS_FILE`.
|
|
Packit Service |
569379 |
`TYPE` is typically `def` or `tst` for definitions and tests respectively.
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
==== assert_exists function
|
|
Packit Service |
569379 |
Does an XPath query to a file specified in the `$result` variable and checks if
|
|
Packit Service |
569379 |
number of results matches with an expected number specified as an argument:
|
|
Packit Service |
569379 |
[source,bash]
|
|
Packit Service |
569379 |
----
|
|
Packit Service |
569379 |
result="relative_path_to_file"
|
|
Packit Service |
569379 |
assert_exists EXPECTED_NUMBER_OF_RESULTS XPATH_QUERY_STRING
|
|
Packit Service |
569379 |
----
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
For example, let's say you want to check that in the `results.xml` file the
|
|
Packit Service |
569379 |
result of the rule `xccdf_com.example.www_rule_test` is fail:
|
|
Packit Service |
569379 |
[source,bash]
|
|
Packit Service |
569379 |
----
|
|
Packit Service |
569379 |
result="./results.xml"
|
|
Packit Service |
569379 |
my_rule_="xccdf_com.example.www_rule_test"
|
|
Packit Service |
569379 |
assert_exists 1 "//rule-result[@idref=\"$my_rule\"]/result[text()=\"fail\"]"
|
|
Packit Service |
569379 |
----
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
=== Adding test files
|
|
Packit Service |
569379 |
Now, as we know where a new test should go and what functions and capabilities
|
|
Packit Service |
569379 |
are provided by the common test library, we can add test files which will
|
|
Packit Service |
569379 |
contain test scripts and content required for testing.
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
To sum up, we are adding a tests to check the basic functionality of the Script
|
|
Packit Service |
569379 |
Check Engine (SCE) and we have decided that the test will go into the
|
|
Packit Service |
569379 |
link:../../tests/sce[tests/sce] directory.
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
We will add the link:../../tests/sce/test_sce.sh[tests/sce/test_sce.sh]
|
|
Packit Service |
569379 |
script which will contain our test and
|
|
Packit Service |
569379 |
link:../../tests/sce/sce_xccdf.xml[tests/sce/sce_xccdf.xml], an XML file with
|
|
Packit Service |
569379 |
XCCDF rules which are referencing various check scripts (grep the
|
|
Packit Service |
569379 |
`check-content-ref` element to see the referenced files). All the referenced
|
|
Packit Service |
569379 |
check script files are set to always pass and the
|
|
Packit Service |
569379 |
link:../../tests/sce/test_sce.sh[tests/sce/test_sce.sh] script will perform
|
|
Packit Service |
569379 |
evaluation of the link:../../tests/sce/sce_xccdf.xml[tests/sce/sce_xccdf.xml]
|
|
Packit Service |
569379 |
XCCDF document file and it will check that all rule results are `pass`.
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
=== Plugging your new test into the test library
|
|
Packit Service |
569379 |
You need to plug your test into the test library so it will be run automatically
|
|
Packit Service |
569379 |
everytime `make test` is run. To do this, you need to add your test script
|
|
Packit Service |
569379 |
into the `CMakeLists.txt`. The `CMakeLists.txt` which you need to modify is
|
|
Packit Service |
569379 |
located in the same directory as your test script.
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
We will demonstrate this on our example with the SCE test. We have prepared our
|
|
Packit Service |
569379 |
test script, the XML document file with custom rules and various check scripts
|
|
Packit Service |
569379 |
for testing. We placed all our test files into the
|
|
Packit Service |
569379 |
link:../../tests/sce[tests/sce] directory. Now we will modify the
|
|
Packit Service |
569379 |
link:../../tests/sce/CMakeLists.txt[tests/sce/CMakeLists.txt] and we will add
|
|
Packit Service |
569379 |
our test script file using the `add_oscap_test` function which will make sure
|
|
Packit Service |
569379 |
that our test will be executed by the `make test`:
|
|
Packit Service |
569379 |
----
|
|
Packit Service |
569379 |
if(ENABLE_SCE)
|
|
Packit Service |
569379 |
...
|
|
Packit Service |
569379 |
*add_oscap_test("test_sce.sh")*
|
|
Packit Service |
569379 |
...
|
|
Packit Service |
569379 |
endif()
|
|
Packit Service |
569379 |
----
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
=== Running your new test
|
|
Packit Service |
569379 |
To run your new test you first need to compile the OpenSCAP library. See the
|
|
Packit Service |
569379 |
*Building OpenSCAP on Linux* section in the link:../developer/developer.adoc[OpenSCAP Developer Manual]
|
|
Packit Service |
569379 |
for more details.
|
|
Packit Service |
569379 |
Also you don't need to run all the tests using `make test`, you can run only
|
|
Packit Service |
569379 |
the specific test(s). To do so, you need to be in the build directory and
|
|
Packit Service |
569379 |
run `ctest -R` from there, for example:
|
|
Packit Service |
569379 |
[source,bash]
|
|
Packit Service |
569379 |
----
|
|
Packit Service |
569379 |
$ cd build/
|
|
Packit Service |
569379 |
$ ctest -R sce/test_sce.sh
|
|
Packit Service |
569379 |
$ less Testing/Temporary/LastTest.log
|
|
Packit Service |
569379 |
----
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
Results from testing will be printed on the stdout and detailed log file with
|
|
Packit Service |
569379 |
your test results can be found in the `Testing/Temporary/LastTest.log` file.
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
== Running the MITRE tests
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
The MITRE tests (in `tests/mitre`) are functionality tests for several
|
|
Packit Service |
569379 |
key probes.
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
There are several reasons for putting these tests behind an `ENABLE_MITRE`
|
|
Packit Service |
569379 |
CMake flag: they cannot be run in parallel as they race to create and
|
|
Packit Service |
569379 |
delete temporary support files; they require port 25 to be open and
|
|
Packit Service |
569379 |
listening (`mitre/test_mitre_linux_probes.sh`); there are outdated assumptions
|
|
Packit Service |
569379 |
which need to be gated around operating system version checks; and a number of
|
|
Packit Service |
569379 |
probes had to be disabled because they're not supported (e.g., SQL and LDAP
|
|
Packit Service |
569379 |
checks, etc.).
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
To run only the MITRE tests, please make sure you've installed and started a
|
|
Packit Service |
569379 |
SMTP server that is listening on `127.0.0.1:25`, and that you're running on a
|
|
Packit Service |
569379 |
RPM-based distribution. Then:
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
----
|
|
Packit Service |
569379 |
$ cd build/
|
|
Packit Service |
569379 |
$ cmake -DENABLE_MITRE=TRUE ..
|
|
Packit Service |
569379 |
$ make
|
|
Packit Service |
569379 |
$ ctest --output-on-failure -R mitre
|
|
Packit Service |
569379 |
----
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
To run the containerized MITRE tests (which installs a SMTP server and tests
|
|
Packit Service |
569379 |
it):
|
|
Packit Service |
569379 |
|
|
Packit Service |
569379 |
----
|
|
Packit Service |
569379 |
$ cd openscap/
|
|
Packit Service |
569379 |
$ docker build --tag openscap_mitre_tests:latest -f Dockerfiles/mitre_tests .
|
|
Packit Service |
569379 |
$ docker run openscap_mitre_tests:latest
|
|
Packit Service |
569379 |
----
|