aboutsummaryrefslogtreecommitdiff
path: root/docs/implementing-tests.rst
blob: f7be28433ee44984bf8ab64402ced37930e910bc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
How to implement tests
======================

.. section-numbering::
    :suffix: .

.. contents::

This document aims at providing some pointers to help implementing new tests in
the TFTF image.

Structure of a test
-------------------

A test might be divided into 3 logical parts, detailed in the following
sections.

Prologue
''''''''

A test has a main entry point function, whose type is:

::

    typedef test_result_t (*test_function_t)(void);

See `tftf/framework/include/tftf.h`_.

Only the primary CPU enters this function, while other CPUs are powered down.

First of all, the test function should check whether this test is applicable to
this platform and environment. Some tests rely on specific hardware features or
firmware capabilities to be present. If these are not available, the test should
be skipped.  For example, a multi-core test requires at least 2 CPUs to
run. Macros and functions are provided in `include/common/test_helpers.h`_ to
help test code verify that their requirements are met.

Core
''''

This is completely dependent on the purpose of the test. The paragraphs below
just provide some useful, general information.

The primary CPU may power on other CPUs by calling the function
``tftf_cpu_on()``.  It provides an address to which secondary CPUs should jump
to once they have been initialized by the test framework. This address should be
different from the primary CPU test function.

Synchronization primitives are provided in `include/lib/events.h`_ in case CPUs'
execution threads need to be synchronized. Most multi-processing tests will need
some synchronisation points that all/some CPUs need to reach before test
execution may continue.

Any CPU that is involved in a test must return from its test function. Failure
to do so will put the framework in an unrecoverable state, see the `TFTF known
limitations`_. The return code indicates the test result from the point of view
of this CPU. At the end of the test, individual CPU results are aggregated and
the overall test result is derived from that. A test is considered as passed if
all involved CPUs reported a success status code.

Epilogue
''''''''

Each test is responsible for releasing any allocated resources and putting the
system back in a clean state when it finishes. Any change to the system
configuration (e.g. MMU setup, GIC configuration, system registers, ...) must be
undone and the original configuration must be restored. This guarantees that the
next test is not affected by the actions of the previous one.

One exception to this rule is that CPUs powered on as part of a test must not be
powered down. As already stated above, as soon as a CPU enters the test, the
framework expects it to return from the test.

Template test code
------------------

Some template test code is provided in `tftf/tests/template_tests`_. It can be
used as a starting point for developing new tests. Template code for both
single-core and multi-core tests is provided.

Plugging the test into the build system
---------------------------------------

All test code is located under the `tftf/tests`_ directory. Tests are usually
divided into categories represented as sub-directories under ``tftf/tests/``.

The source file implementing the new test code should be added to the
appropriate tests makefile, see `.*mk` files under `tftf/tests`_.

The new test code should also appear in a tests manifest, see ``*.xml`` files
under `tftf/tests`_. A unique name and test function must be provided. An
optional description may be provided as well.

For example, to create a test case named "``Foo test case``", whose test
function is ``foo()``, add the following line in the tests manifest:

::

    <testcase name="Foo test case" function="foo" />

A testcase must be part of a testsuite. The ``testcase`` XML node above must be
inside a ``testsuite`` XML node. A unique name and a description must be
provided for the testsuite.

For example, to create a test suite named "``Bar test suite``", whose
description is: "``An example test suite``", add the following 2 lines:

::

    <testsuite name="Bar test suite" description="An example test suite">
    </testsuite>

See the template test manifest for reference: `tftf/tests/tests-template.xml`_.

--------------

*Copyright (c) 2018, Arm Limited. All rights reserved.*

.. _SMC Calling Convention: SMCCC_
.. _SMCCC: http://infocenter.arm.com/help/topic/com.arm.doc.den0028b/ARM_DEN0028B_SMC_Calling_Convention.pdf

.. _TFTF known limitations: change-log.rst#test-framework
.. _tftf/framework/include/tftf.h: ../tftf/framework/include/tftf.h
.. _tftf/tests: ../tftf/tests
.. _tftf/tests/template_tests: ../tftf/tests/template_tests
.. _tftf/tests/tests-template.xml: ../tftf/tests/tests-template.xml
.. _include/common/test_helpers.h: ../include/common/test_helpers.h
.. _include/lib/events.h: ../include/lib/events.h