mb/google: Add OEM product names for various boards
[coreboot.git] / Documentation / tutorial / part3.md
blobdc487182c1125afec04dff08904b5919e919d690
1 # Writing unit tests for coreboot
3 ## Introduction
4 General thoughts about unit testing coreboot can be found in
5 [Unit testing coreboot](../technotes/2020-03-unit-testing-coreboot.md).
6 Additionally, [code coverage](../technotes/2021-05-code-coverage.md) support
7 is available for unit tests.
9 This document aims to guide developers through the process of adding and writing
10 unit tests for coreboot modules.
12 As an example of unit under test, `src/device/i2c.c` (referred hereafter as UUT
13 "Unit Under Test") will be used. This is simple module, thus it should be easy
14 for the reader to focus solely on the testing logic, without the need to spend
15 too much time on digging deeply into the source code details and flow of
16 operations. That being said, a good understanding of what the unit under test is
17 doing is crucial for writing unit tests.
19 This tutorial should also be helpful for developers who want to follow
20 [TDD](https://en.wikipedia.org/wiki/Test-driven_development). Even though TDD
21 has a different work flow of building tests first, followed by the code that
22 satisfies them, the process of writing tests and adding them to the tree is the
23 same.
25 ## Analysis of unit under test
26 First of all, it is necessary to precisely establish what we want to test in a
27 particular module. Usually this will be an externally exposed API, which can be
28 used by other modules.
30 ```eval_rst
31 .. admonition:: i2c-test example
33    In case of our UUT, API consist of two methods:
35    .. code-block:: c
37      int i2c_read_field(unsigned int bus, uint8_t chip, uint8_t reg, uint8_t *data,
38                  uint8_t mask, uint8_t shift)
39      int i2c_write_field(unsigned int bus, uint8_t chip, uint8_t reg, uint8_t data,
40                  uint8_t mask, uint8_t shift)
42    For sake of simplicity, let's focus on `i2c_read_field` in this document.
43 ```
45 Once the API is defined, the next question is __what__ this API is doing (or
46 what it will be doing in case of TDD). In other words, what outputs we are
47 expecting from particular functions, when providing particular input parameters.
49 ```eval_rst
50 .. admonition:: i2c-test example
52    .. code-block:: c
54      int i2c_read_field(unsigned int bus, uint8_t chip, uint8_t reg, uint8_t *data,
55                  uint8_t mask, uint8_t shift)
57    This is a method which means to read content of register `reg` from i2c device
58    on i2c `bus` and slave address `chip`, applying bit `mask` and offset `shift`
59    to it. Returned data should be placed in `data`.
60 ```
62 The next step is to determine all external dependencies of UUT in order to mock
63 them out. Usually we want to isolate the UUT as much as possible, so that the
64 test result depends __only__ on the behavior of UUT and not on the other
65 modules. While some software dependencies may be hard to be mock (for example
66 due to complicated dependencies) and thus should be simply linked into the test
67 binaries, all hardware dependencies need to be mocked out, since in the
68 user-space host environment, targets hardware is not available.
70 ```eval_rst
71 .. admonition:: i2c-test example
73    `i2c_read_field` is calling `i2c_readb`, which eventually invokes
74    `i2c_transfer`. This method simply calls `platform_i2c_transfer`. The last
75    function in the chain is a hardware-touching one, and defined separately for
76    different SOCs. It is responsible for issuing transactions on the i2c bus.
77    For the purpose of writing unit test, we should mock this function.
78 ```
80 ## Adding new tests
81 In order to keep the tree clean, the `tests/` directory should mimic the `src/`
82 directory, so that test harness code is placed in a location corresponding to
83 UUT. Furthermore, the naming convention is to add the suffix `-test` to the UUT
84 name when creating a new test harness file.
86 ```eval_rst
87 .. admonition:: i2c-test example
89    Considering that UUT is `src/device/i2c.c`, test file should be named
90    `tests/device/i2c-test.c`. When adding a new test file, it needs to be
91    registered with the coreboot unit testing infrastructure.
92 ```
94 Every directory under `tests/` should contain a Makefile.inc, similar to what
95 can be seen under the `src/`. Register a new test in Makefile.inc, by
96 __appending__ test name to the `tests-y` variable.
98 ```eval_rst
99 .. admonition:: i2c-test example
101    .. code-block:: c
103      tests-y += i2c-test
106 Next step is to list all source files, which should be linked together in order
107 to create test binary. Usually a tests requires only two files - UUT and test
108 harness code, but sometimes more is needed to provide the test environment.
109 Source files are registered in `<test_name>-srcs` variable.
111 ```eval_rst
112 .. admonition:: i2c-test example
114    .. code-block:: c
116      i2c-test-srcs += tests/device/i2c-test.c
117      i2c-test-srcs += src/device/i2c.c
120 Above minimal configuration is a basis for further work. One can try to build
121 and run test binary either by invoking `make tests/<test_dir>/<test_name>` or by
122 running all unit tests (whole suite) for coreboot `make unit-tests`.
124 ```eval_rst
125 .. admonition:: i2c-test example
127    .. code-block:: c
129      make tests/device/i2c-test
131    or
133    .. code-block:: c
135      make unit-tests
138 When trying to build test binary, one can often see linker complains about
139 `undefined reference` to couple of symbols. This is one of solutions to
140 determine all external dependencies of UUT - iteratively build test and resolve
141 errors one by one. At this step, developer should decide either it's better to
142 add an extra module to provide necessary definitions or rather mock such
143 dependency. Quick guide through adding mocks is provided later in this doc.
145 ## Writing new tests
146 In coreboot, [Cmocka](https://cmocka.org/) is used as unit test framework. The
147 project has exhaustive [API documentation](https://api.cmocka.org/). Let's see
148 how we may incorporate it when writing tests.
150 ### Assertions
151 Testing the UUT consists of calling the functions in the UUT and comparing the
152 returned values to the expected values. Cmocka implements
153 [a set of assert macros](https://api.cmocka.org/group__cmocka__asserts.html) to
154 compare a value with an expected value. If the two values do not match, the test
155 fails with an error message.
157 ```eval_rst
158 .. admonition:: i2c-test example
160    In our example, the simplest test is to call UUT for reading our fake devices
161    registers and do all calculation in the test harness itself. At the end, let's
162    compare integers with `assert_int_equal`.
164    .. code-block:: c
166      #define MASK        0x3
167      #define SHIFT        0x1
169      static void i2c_read_field_test(void **state)
170      {
171              int bus, slave, reg;
172              int i, j;
173              uint8_t buf;
175              mock_expect_params_platform_i2c_transfer();
177              /* Read particular bits in all registers in all devices, then compare
178                 with expected value. */
179              for (i = 0; i < ARRAY_SIZE(i2c_ex_devs); i++)
180                      for (j = 0; j < ARRAY_SIZE(i2c_ex_devs[0].regs); j++) {
181                              i2c_read_field(i2c_ex_devs[i].bus,
182                                      i2c_ex_devs[i].slave,
183                                      i2c_ex_devs[i].regs[j].reg,
184                                      &buf, MASK, SHIFT);
185                              assert_int_equal((i2c_ex_devs[i].regs[j].data &
186                                      (MASK << SHIFT)) >> SHIFT, buf);
187                      };
188      }
191 ### Mocks
193 #### Overview
194 Many coreboot modules are low level software that touch hardware directly.
195 Because of this, one of the most important and challenging part of
196 writing tests is to design and implement mocks. A mock is a software component
197 which implements the API of another component so that the test can verify that
198 certain functions are called (or not called), verify the parameters passed to
199 those functions, and specify the return values from those functions. Mocks are
200 especially useful when the API to be implemented is one that accesses hardware
201 components.
203 When writing a mock, the developer implements the same API as the module being
204 mocked. Such a mock may, for example, register a set of driver methods. Behind
205 this API, there is usually a simulation of real hardware.
207 ```eval_rst
208 .. admonition:: i2c-test example
210    For purpose of our i2c test, we may introduce two i2c devices with set of
211    registers, which simply are structs in memory.
213    .. code-block:: c
215      /* Simulate two i2c devices, both on bus 0, each with three uint8_t regs
216         implemented. */
217      typedef struct {
218              uint8_t reg;
219              uint8_t data;
220      } i2c_ex_regs_t;
222      typedef struct {
223              unsigned int bus;
224              uint8_t slave;
225              i2c_ex_regs_t regs[3];
226      } i2c_ex_devs_t;
228      i2c_ex_devs_t i2c_ex_devs[] = {
229              {.bus = 0, .slave = 0xA, .regs = {
230                      {.reg = 0x0, .data = 0xB},
231                      {.reg = 0x1, .data = 0x6},
232                      {.reg = 0x2, .data = 0xF},
233              } },
234              {.bus = 0, .slave = 0x3, .regs = {
235                      {.reg = 0x0, .data = 0xDE},
236                      {.reg = 0x1, .data = 0xAD},
237                      {.reg = 0x2, .data = 0xBE},
238              } },
239      };
241    These fake devices will be accessed instead of hardware ones:
243    .. code-block:: c
245              reg = tmp->buf[0];
247              /* Find object for requested device */
248              for (i = 0; i < ARRAY_SIZE(i2c_ex_devs); i++, i2c_dev++)
249                      if (i2c_ex_devs[i].slave == tmp->slave) {
250                              i2c_dev = &i2c_ex_devs[i];
251                              break;
252                      }
254              if (i2c_dev == NULL)
255                      return -1;
257              /* Write commands */
258              if (tmp->len > 1) {
259                      i2c_dev->regs[reg].data = tmp->buf[1];
260              };
262              /* Read commands */
263              for (i = 0; i < count; i++, tmp++)
264                      if (tmp->flags & I2C_M_RD) {
265                              *(tmp->buf) = i2c_dev->regs[reg].data;
266                      };
269 Cmocka uses a feature that gcc provides for breaking dependencies at the link
270 time. It is possible to override implementation of some function, with the
271 method from test harness. This allows test harness to take control of execution
272 from binary (during the execution of test), and stimulate UUT as required
273 without changing the source code.
275 coreboot unit test infrastructure supports overriding of functions at link time.
276 This is as simple as adding a `name_of_function` to be mocked into
277 <test_name>-mocks variable in Makefile.inc. The result is that the test's
278 implementation of that function is called instead of coreboot's.
280 ```eval_rst
281 .. admonition:: i2c-test example
283    .. code-block:: c
285      i2c-test-mocks += platform_i2c_transfer
287    Now, dev can write own implementation of `platform_i2c_transfer`. This
288    implementation instead of accessing real i2c bus, will write/read from
289    fake structs.
291    .. code-block:: c
293      int platform_i2c_transfer(unsigned int bus, struct i2c_msg *segments,
294              int count)
295      {
296      }
299 #### Checking mock's arguments
300 A test can verify the parameters provided by the UUT to the mock function. The
301 developer may also verify that number of calls to mock is correct and the order
302 of calls to particular mocks is as expected (See
303 [this](https://api.cmocka.org/group__cmocka__call__order.html)). The Cmocka
304 macros for checking parameters are described
305 [here](https://api.cmocka.org/group__cmocka__param.html). In general, in mock
306 function, one makes a call to `check_expected(<param_name>)` and in the
307 corresponding test function, `expect*()` macro, with description which parameter
308 in which mock should have particular value, or be inside a described range.
310 ```eval_rst
311 .. admonition:: i2c-test example
313    In our example, we may want to check that `platform_i2c_transfer` is fed with
314    number of segments bigger than 0, each segment has flags which are in
315    supported range and each segment has buf which is non-NULL. We are expecting
316    such values for _every_ call, thus the last parameter in `expect*` macros is
317    -1.
319    .. code-block:: c
321      static void mock_expect_params_platform_i2c_transfer(void)
322      {
323              unsigned long int expected_flags[] = {0, I2C_M_RD, I2C_M_TEN,
324                      I2C_M_RECV_LEN, I2C_M_NOSTART};
326              /* Flags should always be only within supported range */
327              expect_in_set_count(platform_i2c_transfer, segments->flags,
328                      expected_flags, -1);
330              expect_not_value_count(platform_i2c_transfer, segments->buf,
331                      NULL, -1);
333              expect_in_range_count(platform_i2c_transfer, count, 1, INT_MAX,
334                      -1);
335      }
337    And the checks below should be added to our mock
339    .. code-block:: c
341              check_expected(count);
343              for (i = 0; i < count; i++, segments++) {
344                      check_expected_ptr(segments->buf);
345                      check_expected(segments->flags);
346              }
349 #### Instrument mocks
350 It is possible for the test function to instrument what the mock will return to
351 the UUT. This can be done by using the `will_return*()` and `mock()` macros.
352 These are described in
353 [the Mock Object section](https://api.cmocka.org/group__cmocka__mock.html) of
354 the Cmocka API documentation.
356 ```eval_rst
357 .. admonition:: Example
359    There is an non-coreboot example for using Cmocka available
360    `here <https://lwn.net/Articles/558106/>`_.
363 ### Test runner
364 Finally, the developer needs to implement the test `main()` function. All tests
365 should be registered there and cmocka test runner invoked. All methods for
366 invoking Cmocka test are described
367 [here](https://api.cmocka.org/group__cmocka__exec.html).
369 ```eval_rst
370 .. admonition:: i2c-test example
372    We don't need any extra setup and teardown functions for i2c-test, so let's
373    simply register test for `i2c_read_field` and return from main value which is
374    output of Cmocka's runner (it returns number of tests that failed).
376    .. code-block:: c
378      int main(void)
379      {
380              const struct CMUnitTest tests[] = {
381                      cmocka_unit_test(i2c_read_field_test),
382              };
384              return cb_run_group_tests(tests, NULL, NULL);
385      }