xref: /openbmc/phosphor-host-ipmid/docs/testing.md (revision 43dda5edb5ddc8da1847a82076ab2167e246269b)
1a3a1cdc2SEmily Shaffer# Running Tests
2a3a1cdc2SEmily Shaffer
3a3a1cdc2SEmily Shaffer## Setting Up Your Environment
4a3a1cdc2SEmily Shaffer
57a4ebde3SEmily ShafferFor the purposes of this tutorial, we'll be setting up an environment in Docker.
67a4ebde3SEmily ShafferDocker is handy because it's fairly portable, and won't interfere with the rest
7a1bd285eSPatrick Williamsof your machine setup. It also offers a strong guarantee that you're testing the
8a1bd285eSPatrick Williamssame way that others working on the project are. Finally, we can get away with
9a1bd285eSPatrick Williamsusing the same Docker image that's run by the OpenBMC continuous integration
10a1bd285eSPatrick Williamsbot, so we have even more confidence that we're running relevant tests the way
11a1bd285eSPatrick Williamsthey'd be run upstream.
12a3a1cdc2SEmily Shaffer
137a4ebde3SEmily Shaffer### Install Docker
147a4ebde3SEmily Shaffer
157a4ebde3SEmily ShafferInstallation of Docker CE (Community Edition) varies by platform, and may differ
167a4ebde3SEmily Shafferin your organization. But the
17a1bd285eSPatrick Williams[Docker Docs](https://docs.docker.com/v17.12/install) are a good place to start
18a1bd285eSPatrick Williamslooking.
197a4ebde3SEmily Shaffer
20a1bd285eSPatrick WilliamsCheck that the installation was successful by running
21a1bd285eSPatrick Williams`sudo docker run hello-world`.
227a4ebde3SEmily Shaffer
237a4ebde3SEmily Shaffer### Download OpenBMC Continuous Integration Image
247a4ebde3SEmily Shaffer
257a4ebde3SEmily ShafferYou'll want a couple of different repositories, so start by making a place for
267a4ebde3SEmily Shafferit all to go, and clone the CI scripts:
277a4ebde3SEmily Shaffer
287a4ebde3SEmily Shaffer```shell
297a4ebde3SEmily Shaffermkdir openbmc-ci-tests
307a4ebde3SEmily Shaffercd openbmc-ci-tests
317a4ebde3SEmily Shaffergit clone https://github.com/openbmc/openbmc-build-scripts.git
327a4ebde3SEmily Shaffer```
337a4ebde3SEmily Shaffer
34*43dda5edSGeorge Liu## Add `phosphor-host-ipmid`
357a4ebde3SEmily Shaffer
367a4ebde3SEmily ShafferWe also need to put a copy of the project you want to test against here. But
37a1bd285eSPatrick Williamsyou've probably got a copy checked out already, so we're going to make a _git
38a1bd285eSPatrick Williamsworktree_. You can read more about those by running `git help worktree`, but the
39a1bd285eSPatrick Williamsbasic idea is that it's like having a second copy of your repo - but the second
40a1bd285eSPatrick Williamscopy is in sync with your main copy, knows about your local branches, and
417a4ebde3SEmily Shafferprotects you from checking out the same branch in two places.
427a4ebde3SEmily Shaffer
437a4ebde3SEmily ShafferYour new worktree doesn't know about any untracked files you have in your main
447a4ebde3SEmily Shafferworktree, so you should get in the habit of committing everything you want to
457a4ebde3SEmily Shafferrun tests against. However, because of the implementation of
467a4ebde3SEmily Shaffer`run-unit-test-docker.sh`, you can't run the CI with untracked changes anyways,
477a4ebde3SEmily Shafferso this isn't the worst thing in the world. (If you make untracked changes in
487a4ebde3SEmily Shafferyour testing worktree, it's easy to update a commit with those.)
497a4ebde3SEmily Shaffer
507a4ebde3SEmily ShafferNote the placeholders in the following steps; modify the commands to match your
517a4ebde3SEmily Shafferdirectory layout.
527a4ebde3SEmily Shaffer
537a4ebde3SEmily Shaffer```shell
547a4ebde3SEmily Shaffercd /my/dir/for/phosphor-host-ipmid
557a4ebde3SEmily Shaffergit worktree add /path/to/openbmc-ci-tests/phosphor-host-ipmid
567a4ebde3SEmily Shaffer```
577a4ebde3SEmily Shaffer
587a4ebde3SEmily ShafferNow, if you `cd /path/to/openbmc-ci-tests`, you should see a directory
597a4ebde3SEmily Shaffer`phosphor-host-ipmid/`, and if you enter it and run `git status` you will see
607a4ebde3SEmily Shafferthat you're likely on a new branch named `phosphor-host-ipmid`. This is just for
617a4ebde3SEmily Shafferconvenience, since you can't check out a branch in your worktree that's already
627a4ebde3SEmily Shafferchecked out somewhere else; you can safely ignore or delete that branch later.
637a4ebde3SEmily Shaffer
647a4ebde3SEmily ShafferHowever, Git won't be able to figure out how to get to your main worktree
657a4ebde3SEmily Shaffer(`/my/dir/for/phosphor-host-ipmid`), so we'll need to mount it when we run. Open
667a4ebde3SEmily Shafferup `/path/to/openbmc-ci-tests/openbmc-build-scripts/run-unit-test-docker.sh` and
677a4ebde3SEmily Shafferfind where we call `docker run`, way down at the bottom. Add an additional
687a4ebde3SEmily Shafferargument, remembering to escape the newline ('\'):
697a4ebde3SEmily Shaffer
707a4ebde3SEmily Shaffer```shell
717a4ebde3SEmily ShafferPHOSPHOR_IPMI_HOST_PATH="/my/dir/for/phosphor-host-ipmid"
727a4ebde3SEmily Shaffer
737a4ebde3SEmily Shafferdocker run --blah-blah-existing-flags \
747a4ebde3SEmily Shaffer  -v ${PHOSPHOR_IPMI_HOST_PATH}:${PHOSPHOR_IPMI_HOST_PATH} \
757a4ebde3SEmily Shaffer  -other \
767a4ebde3SEmily Shaffer  -args
777a4ebde3SEmily Shaffer```
787a4ebde3SEmily Shaffer
797a4ebde3SEmily ShafferThen commit this, so you can make sure not to lose it if you update the scripts
807a4ebde3SEmily Shafferrepo:
817a4ebde3SEmily Shaffer
827a4ebde3SEmily Shaffer```shell
837a4ebde3SEmily Shaffercd openbmc-build-scripts
847a4ebde3SEmily Shaffergit add run-unit-test-docker.sh
857a4ebde3SEmily Shaffergit commit -m "mount phosphor-host-ipmid"
867a4ebde3SEmily Shaffer```
877a4ebde3SEmily Shaffer
88a1bd285eSPatrick WilliamsNOTE: There are other ways to do this besides a worktree; other approaches trade
89a1bd285eSPatrick Williamsthe cruft of mounting extra paths to the Docker container for different cruft:
907a4ebde3SEmily Shaffer
917a4ebde3SEmily ShafferYou can create a local upstream:
92a1bd285eSPatrick Williams
937a4ebde3SEmily Shaffer```shell
947a4ebde3SEmily Shaffercd openbmc-ci-tests
957a4ebde3SEmily Shaffermkdir phosphor-host-ipmid
967a4ebde3SEmily Shaffercd phosphor-host-ipmid
977a4ebde3SEmily Shaffergit init
987a4ebde3SEmily Shaffercd /my/dir/for/phosphor-host-ipmid
997a4ebde3SEmily Shaffergit remote add /path/to/openbmc-ci-tests/phosphor-host-ipmid ci
1007a4ebde3SEmily Shaffergit push ci
1017a4ebde3SEmily Shaffer```
102a1bd285eSPatrick Williams
103a1bd285eSPatrick WilliamsThis method would require you to push your topic branch to `ci` and then
104a1bd285eSPatrick Williams`git checkout` the appropriate branch every time you switched topics:
105a1bd285eSPatrick Williams
1067a4ebde3SEmily Shaffer```shell
1077a4ebde3SEmily Shaffercd /my/dir/for/phosphor-host-ipmid
1087a4ebde3SEmily Shaffergit commit -m "my changes to be tested"
1097a4ebde3SEmily Shaffergit push ci
1107a4ebde3SEmily Shaffercd /path/to/openbmc-ci-tests/phosphor-host-ipmid
1117a4ebde3SEmily Shaffergit checkout topic-branch
1127a4ebde3SEmily Shaffer```
1137a4ebde3SEmily Shaffer
1147a4ebde3SEmily ShafferYou can also create a symlink from your Git workspace into `openbmc-ci-tests/`.
1157a4ebde3SEmily ShafferThis is especially not recommended, since you won't be able to work on your code
1167a4ebde3SEmily Shafferin parallel while the tests run, and since the CI scripts are unhappy when you
1177a4ebde3SEmily Shafferhave untracked changes - which you're likely to have during active development.
1187a4ebde3SEmily Shaffer
119*43dda5edSGeorge Liu### Building and Running
1207a4ebde3SEmily Shaffer
1217a4ebde3SEmily ShafferThe OpenBMC CI scripts take care of the build for you, and run the test suite.
1227a4ebde3SEmily ShafferBuild and run like so:
1237a4ebde3SEmily Shaffer
1247a4ebde3SEmily Shaffer```shell
1257a4ebde3SEmily Shaffersudo WORKSPACE=$(pwd) UNIT_TEST_PKG=phosphor-host-ipmid \
1267a4ebde3SEmily Shaffer  ./openbmc-build-scripts/run-unit-test-docker.sh
1277a4ebde3SEmily Shaffer```
1287a4ebde3SEmily Shaffer
1297a4ebde3SEmily ShafferThe first run will take a long time! But afterwards it shouldn't be so bad, as
1307a4ebde3SEmily Shaffermany parts of the Docker container are already downloaded and configured.
131a3a1cdc2SEmily Shaffer
132*43dda5edSGeorge Liu### Reading Output
133a3a1cdc2SEmily Shaffer
1347a4ebde3SEmily ShafferYour results will appear in
1357a4ebde3SEmily Shaffer`openbmc-ci-tests/phosphor-host-ipmid/test/test-suite.log`, as well as being
1367a4ebde3SEmily Shafferprinted to `stdout`. You will also see other `.log` files generated for each
1377a4ebde3SEmily Shaffertest file, for example `sample_unittest.log`. All these `*.log` files are
1387a4ebde3SEmily Shafferhuman-readable and can be examined to determine why something failed
1397a4ebde3SEmily Shaffer
140*43dda5edSGeorge Liu### Writing Tests
141a3a1cdc2SEmily Shaffer
14200a553dfSEmily ShafferNow that you've got an easy working environment for running tests, let's write
14300a553dfSEmily Shaffersome new ones.
14400a553dfSEmily Shaffer
145*43dda5edSGeorge Liu### Setting Up Your Environment
146a3a1cdc2SEmily Shaffer
14700a553dfSEmily ShafferIn `/my/dir/for/phosphor-host-ipmid`, create a new branch based on `master` (or
14800a553dfSEmily Shafferyour current patchset). For this tutorial, let's call it `sensorhandler-tests`.
14900a553dfSEmily Shaffer
15000a553dfSEmily Shaffer```shell
15100a553dfSEmily Shaffergit checkout -b sensorhandler-tests master
15200a553dfSEmily Shaffer```
15300a553dfSEmily Shaffer
15400a553dfSEmily ShafferThis creates a new branch `sensorhandler-tests` which is based on `master`, then
15500a553dfSEmily Shafferchecks out that branch for you to start hacking.
15600a553dfSEmily Shaffer
157*43dda5edSGeorge Liu### Write Some Tests
15800a553dfSEmily Shaffer
15900a553dfSEmily ShafferFor this tutorial, we'll be adding some basic unit testing of the struct
16000a553dfSEmily Shafferaccessors for `get_sdr::GetSdrReq`, just because they're fairly simple. The text
16100a553dfSEmily Shafferof the struct and accessors is recreated here:
16200a553dfSEmily Shaffer
16300a553dfSEmily Shaffer```c++
16400a553dfSEmily Shaffer/**
16500a553dfSEmily Shaffer * Get SDR
16600a553dfSEmily Shaffer */
16700a553dfSEmily Shaffernamespace get_sdr
16800a553dfSEmily Shaffer{
16900a553dfSEmily Shaffer
17000a553dfSEmily Shafferstruct GetSdrReq
17100a553dfSEmily Shaffer{
17200a553dfSEmily Shaffer    uint8_t reservation_id_lsb;
17300a553dfSEmily Shaffer    uint8_t reservation_id_msb;
17400a553dfSEmily Shaffer    uint8_t record_id_lsb;
17500a553dfSEmily Shaffer    uint8_t record_id_msb;
17600a553dfSEmily Shaffer    uint8_t offset;
17700a553dfSEmily Shaffer    uint8_t bytes_to_read;
17800a553dfSEmily Shaffer} __attribute__((packed));
17900a553dfSEmily Shaffer
18000a553dfSEmily Shaffernamespace request
18100a553dfSEmily Shaffer{
18200a553dfSEmily Shaffer
18300a553dfSEmily Shafferinline uint8_t get_reservation_id(GetSdrReq* req)
18400a553dfSEmily Shaffer{
18500a553dfSEmily Shaffer    return (req->reservation_id_lsb + (req->reservation_id_msb << 8));
18600a553dfSEmily Shaffer};
18700a553dfSEmily Shaffer
18800a553dfSEmily Shafferinline uint16_t get_record_id(GetSdrReq* req)
18900a553dfSEmily Shaffer{
19000a553dfSEmily Shaffer    return (req->record_id_lsb + (req->record_id_msb << 8));
19100a553dfSEmily Shaffer};
19200a553dfSEmily Shaffer
19300a553dfSEmily Shaffer} // namespace request
19400a553dfSEmily Shaffer
19500a553dfSEmily Shaffer...
19600a553dfSEmily Shaffer} // namespace get_sdr
19700a553dfSEmily Shaffer```
19800a553dfSEmily Shaffer
19900a553dfSEmily ShafferWe'll create the tests in `test/sensorhandler_unittest.cpp`; go ahead and start
20000a553dfSEmily Shafferthat file with your editor.
20100a553dfSEmily Shaffer
20200a553dfSEmily ShafferFirst, include the header you want to test, as well as the GTest header:
20300a553dfSEmily Shaffer
20400a553dfSEmily Shaffer```c++
20500a553dfSEmily Shaffer#include <sensorhandler.hpp>
20600a553dfSEmily Shaffer
20700a553dfSEmily Shaffer#include <gtest/gtest.h>
20800a553dfSEmily Shaffer```
20900a553dfSEmily Shaffer
21000a553dfSEmily ShafferLet's plan the test cases we care about before we build any additional
21100a553dfSEmily Shafferscaffolding. We've only got two functions - `get_reservation_id()` and
21200a553dfSEmily Shaffer`get_record_id()`. We want to test:
21300a553dfSEmily Shaffer
21400a553dfSEmily Shaffer- "Happy path" - in an ideal case, everything works correctly
21500a553dfSEmily Shaffer- Error handling - when given bad input, things break as expected
21600a553dfSEmily Shaffer- Edge cases - when given extremes (e.g. very large or very small numbers),
21700a553dfSEmily Shaffer  things work correctly or break as expected
21800a553dfSEmily Shaffer
21900a553dfSEmily ShafferFor `get_reservation_id()`:
22000a553dfSEmily Shaffer
22100a553dfSEmily Shaffer```c++
22200a553dfSEmily ShafferTEST(SensorHandlerTest, GetSdrReq_get_reservation_id_HappyPath)
22300a553dfSEmily Shaffer{
22400a553dfSEmily Shaffer}
22500a553dfSEmily Shaffer
22600a553dfSEmily ShafferTEST(SensorHandlerTest, GetSdrReq_get_reservation_id_NullInputDies)
22700a553dfSEmily Shaffer{
22800a553dfSEmily Shaffer}
22900a553dfSEmily Shaffer
23000a553dfSEmily ShafferTEST(SensorHandlerTest, GetSdrReq_get_reservation_id_Uint16MaxWorksCorrectly)
23100a553dfSEmily Shaffer{
23200a553dfSEmily Shaffer}
23300a553dfSEmily Shaffer```
23400a553dfSEmily Shaffer
23500a553dfSEmily ShafferFor `get_record_id()`, we have pretty much the same set of tests:
23600a553dfSEmily Shaffer
23700a553dfSEmily Shaffer```c++
23800a553dfSEmily ShafferTEST(SensorHandlerTest, GetSdrReq_get_record_id_HappyPath)
23900a553dfSEmily Shaffer{
24000a553dfSEmily Shaffer}
24100a553dfSEmily Shaffer
24200a553dfSEmily ShafferTEST(SensorHandlerTest, GetSdrReq_get_record_id_NullInputDies)
24300a553dfSEmily Shaffer{
24400a553dfSEmily Shaffer}
24500a553dfSEmily Shaffer
24600a553dfSEmily ShafferTEST(SensorHandlerTest, GetSdrReq_get_record_id_Uint16MaxWorksCorrectly)
24700a553dfSEmily Shaffer{
24800a553dfSEmily Shaffer}
24900a553dfSEmily Shaffer```
25000a553dfSEmily Shaffer
25100a553dfSEmily ShafferIn the case of these two methods, there's really not much else to test. Some
25200a553dfSEmily Shaffertypes of edge cases - like overflow/underflow - are prevented by C++'s strong
25300a553dfSEmily Shaffertyping; other types - like passing the incorrect type - are impossible to
25400a553dfSEmily Shafferinsulate against because it's possible to cast anything to a `GetSdrReq*` if we
25500a553dfSEmily Shafferwant. Since these are particularly boring, they make a good example for a
25600a553dfSEmily Shaffertutorial like this; in practice, tests you write will likely be for more
25700a553dfSEmily Shaffercomplicated code! We'll talk more about this in the Best Practices section
25800a553dfSEmily Shafferbelow.
25900a553dfSEmily Shaffer
26000a553dfSEmily ShafferLet's implement the `get_reservation_id()` items first. The implementations for
26100a553dfSEmily Shaffer`get_record_id()` will be identical, so we won't cover them here.
26200a553dfSEmily Shaffer
26300a553dfSEmily ShafferFor the happy path, we want to make it very clear that the test value we're
26400a553dfSEmily Shafferusing is within range, so we express it in binary. We also want to be able to
26500a553dfSEmily Shafferensure that the MSB and LSB are being combined in the correct order, so we make
26600a553dfSEmily Shaffersure that the MSB and LSB values are different (don't use `0x3333` as the
26700a553dfSEmily Shafferexpected ID here). Finally, we want it to be obvious to the reader if we have
26800a553dfSEmily Shafferpopulated the `GetSdrReq` incorrectly, so we've labeled all the fields. Since we
26900a553dfSEmily Shafferare only testing one operation, it's okay to use either `ASSERT_EQ` or
27000a553dfSEmily Shaffer`EXPECT_EQ`; more on that in the Best Practices section.
27100a553dfSEmily Shaffer
27200a553dfSEmily Shaffer```c++
27300a553dfSEmily ShafferTEST(SensorHandlerTest, GetSdrReq_get_reservation_id_HappyPath)
27400a553dfSEmily Shaffer{
27500a553dfSEmily Shaffer    uint16_t expected_id = 0x1234; // Expected ID spans both bytes.
27600a553dfSEmily Shaffer    GetSdrReq input = {0x34,  // Reservation ID LSB
27700a553dfSEmily Shaffer                       0x12,  // Reservation ID MSB
27800a553dfSEmily Shaffer                       0x00,  // Record ID LSB
27900a553dfSEmily Shaffer                       0x00,  // Record ID MSB
28000a553dfSEmily Shaffer                       0x00,  // Offset
28100a553dfSEmily Shaffer                       0x00}; // Bytes to Read
28200a553dfSEmily Shaffer
28300a553dfSEmily Shaffer    uint16_t actual = get_sdr::request::get_reservation_id(&input);
28400a553dfSEmily Shaffer    ASSERT_EQ(actual, expected_id);
28500a553dfSEmily Shaffer}
28600a553dfSEmily Shaffer```
28700a553dfSEmily Shaffer
28800a553dfSEmily ShafferWe don't expect that our `GetSdrReq` pointer will ever be null; in this case,
28900a553dfSEmily Shafferthe null pointer validation is done much, much earlier. So it's okay for us to
29000a553dfSEmily Shafferspecify that in the unlikely case we're given a null pointer, we die. We don't
29100a553dfSEmily Shafferreally care what the output message is.
29200a553dfSEmily Shaffer
29300a553dfSEmily Shaffer```c++
29400a553dfSEmily ShafferTEST(SensorHandlerTest, GetSdrReq_get_reservation_id_NullInputDies)
29500a553dfSEmily Shaffer{
29600a553dfSEmily Shaffer    ASSERT_DEATH(get_sdr::request::get_reservation_id(nullptr), ".*");
29700a553dfSEmily Shaffer}
29800a553dfSEmily Shaffer```
29900a553dfSEmily Shaffer
30000a553dfSEmily ShafferFinally, while negative values are taken care of by C++'s type system, we can at
30100a553dfSEmily Shafferleast check that our code still works happily with `UINT16_MAX`. This test is
30200a553dfSEmily Shaffersimilar to the happy path test, but uses an edge value instead.
30300a553dfSEmily Shaffer
30400a553dfSEmily Shaffer```c++
30500a553dfSEmily ShafferTEST(SensorHandlerTest, GetSdrReq_get_reservation_id_Uint16MaxWorksCorrectly)
30600a553dfSEmily Shaffer{
30700a553dfSEmily Shaffer    uint16_t expected_id = 0xFFFF; // Expected ID spans both bytes.
30800a553dfSEmily Shaffer    GetSdrReq input = {0xFF,  // Reservation ID LSB
30900a553dfSEmily Shaffer                       0xFF,  // Reservation ID MSB
31000a553dfSEmily Shaffer                       0x00,  // Record ID LSB
31100a553dfSEmily Shaffer                       0x00,  // Record ID MSB
31200a553dfSEmily Shaffer                       0x00,  // Offset
31300a553dfSEmily Shaffer                       0x00}; // Bytes to Read
31400a553dfSEmily Shaffer
31500a553dfSEmily Shaffer    uint16_t actual = get_sdr::request::get_reservation_id(&input);
31600a553dfSEmily Shaffer    ASSERT_EQ(actual, expected_id);
31700a553dfSEmily Shaffer}
31800a553dfSEmily Shaffer```
31900a553dfSEmily Shaffer
32000a553dfSEmily ShafferThe `get_record_id()` tests are identical, except that they are testing the
32100a553dfSEmily ShafferRecord ID field. They will not be duplicated here.
32200a553dfSEmily Shaffer
323a1bd285eSPatrick WilliamsFinally, we'll need to add the new tests to `test/Makefile.am`. You can mimic
324a1bd285eSPatrick Williamsother existing test setups:
32500a553dfSEmily Shaffer
32600a553dfSEmily Shaffer```make
32700a553dfSEmily Shaffer# Build/add sensorhandler_unittest to test suite
32800a553dfSEmily Shaffersensorhandler_unittest_CPPFLAGS = \
32900a553dfSEmily Shaffer    -Igtest \
33000a553dfSEmily Shaffer    $(GTEST_CPPFLAGS) \
33100a553dfSEmily Shaffer    $(AM_CPPFLAGS)
33200a553dfSEmily Shaffersensorhandler_unittest_CXXFLAGS = \
33300a553dfSEmily Shaffer    $(PTHREAD_CFLAGS) \
33400a553dfSEmily Shaffer    $(CODE_COVERAGE_CXXFLAGS) \
33500a553dfSEmily Shaffer    $(CODE_COVERAGE_CFLAGS) \
33600a553dfSEmily Shaffer    -DBOOST_COROUTINES_NO_DEPRECATION_WARNING
33700a553dfSEmily Shaffersensorhandler_unittest_LDFLAGS = \
33800a553dfSEmily Shaffer    -lgtest_main \
33900a553dfSEmily Shaffer    -lgtest \
34000a553dfSEmily Shaffer    -pthread \
34100a553dfSEmily Shaffer    $(OESDK_TESTCASE_FLAGS) \
34200a553dfSEmily Shaffer    $(CODE_COVERAGE_LDFLAGS)
34300a553dfSEmily Shaffersensorhandler_unittest_SOURCES = \
34400a553dfSEmily Shaffer    %reldir%/sensorhandler_unittest.cpp
34500a553dfSEmily Shaffercheck_PROGRAMS += %reldir%/sensorhandler_unittest
34600a553dfSEmily Shaffer```
34700a553dfSEmily Shaffer
348*43dda5edSGeorge Liu### Run the New Tests
34900a553dfSEmily Shaffer
35000a553dfSEmily ShafferCommit your test changes. Then, you'll want to checkout the
35100a553dfSEmily Shaffer`sensorhandler-tests` branch in your CI worktree, which will involve releasing
35200a553dfSEmily Shafferit from your main worktree:
35300a553dfSEmily Shaffer
35400a553dfSEmily Shaffer```shell
35500a553dfSEmily Shaffercd /my/dir/for/phosphor-host-ipmid
35600a553dfSEmily Shaffergit add test/sensorhandler_unittest.cpp
35700a553dfSEmily Shaffergit commit -s
35800a553dfSEmily Shaffergit checkout master   # Here you can use any branch except sensorhandler-tests
35900a553dfSEmily Shaffercd /path/to/openbmc-ci-tests/phosphor-host-ipmid
36000a553dfSEmily Shaffergit checkout sensorhandler-tests
36100a553dfSEmily Shaffer```
36200a553dfSEmily Shaffer
36300a553dfSEmily ShafferNow you can run the test suite as described earlier in the document. If you see
36400a553dfSEmily Shaffera linter error when you run, you can actually apply the cleaned-up code easily:
36500a553dfSEmily Shaffer
36600a553dfSEmily Shaffer```shell
36700a553dfSEmily Shaffercd ./phosphor-host-ipmid
36800a553dfSEmily Shaffergit diff    # Examine the proposed changes
36900a553dfSEmily Shaffergit add -u  # Apply the proposed changes
37000a553dfSEmily Shaffergit commit --amend
37100a553dfSEmily Shaffer```
37200a553dfSEmily Shaffer
37300a553dfSEmily Shaffer(If you will need to apply the proposed changes to multiple commits, you can do
37400a553dfSEmily Shafferthis with interactive rebase, which won't be described here.)
37500a553dfSEmily Shaffer
376*43dda5edSGeorge Liu### Best Practices
377a3a1cdc2SEmily Shaffer
37800a553dfSEmily ShafferWhile a good unit test can ensure your code's stability, a flaky or
37900a553dfSEmily Shafferpoorly-written unit test can make life harder for contributors down the road.
38000a553dfSEmily ShafferSome things to remember:
38100a553dfSEmily Shaffer
38200a553dfSEmily ShafferInclude both positive (happy-path) and negative (error) testing in your
38300a553dfSEmily Shaffertestbench. It's not enough to know that the code works when it's supposed to; we
38400a553dfSEmily Shafferalso need to know that it fails gracefully when something goes wrong. Applying
38500a553dfSEmily Shafferedge-case testing helps us find bugs that may take years to occur (and
38600a553dfSEmily Shafferreproduce!) in the field.
38700a553dfSEmily Shaffer
38800a553dfSEmily ShafferKeep your tests small. Avoid branching - if you feel a desire to, instead
38900a553dfSEmily Shafferexplore that codepath in another test. The best tests are easy to read and
39000a553dfSEmily Shafferunderstand.
39100a553dfSEmily Shaffer
39200a553dfSEmily ShafferWhen a test fails, it's useful if the test is named in such a way that you can
39300a553dfSEmily Shaffertell _what it's supposed to do_ and _when_. That way you can be certain whether
39400a553dfSEmily Shafferthe change you made really broke it or not. A good pattern is
39500a553dfSEmily Shaffer`Object_NameCircumstanceResult` - for example,
39600a553dfSEmily Shaffer`FooFactory_OutOfBoundsNameThrowsException`. From the name, it's very clear that
39700a553dfSEmily Shafferwhen some "name" is out of bounds, an exception should be thrown. (What "name"
39800a553dfSEmily Shafferis should be clear from the context of the function in `FooFactory`.)
39900a553dfSEmily Shaffer
40000a553dfSEmily ShafferDon't test other people's code. Make sure to limit the test assertions to the
40100a553dfSEmily Shaffercode under test. For example, don't test what happens if you give a bad input to
40200a553dfSEmily Shaffer`sdbusplus` when you're supposed to be testing `phosphor-host-ipmid`.
40300a553dfSEmily Shaffer
40400a553dfSEmily ShafferHowever, don't trust other people's code, either! Try to test _how you respond_
40500a553dfSEmily Shafferwhen a service fails unexpectedly. Rather than checking if `sdbusplus` fails on
40600a553dfSEmily Shafferbad inputs, check whether you handle an `sdbusplus` failure gracefully. You can
40700a553dfSEmily Shafferuse GMock for this kind of testing.
40800a553dfSEmily Shaffer
40900a553dfSEmily ShafferThink about testing when you write your business logic code. Concepts like
41000a553dfSEmily Shafferdependency injection and small functions make your code more testable - you'll
41100a553dfSEmily Shafferbe thanking yourself later when you're writing tests.
41200a553dfSEmily Shaffer
41300a553dfSEmily ShafferFinally, you're very likely to find bugs while writing tests, especially if it's
41400a553dfSEmily Shafferfor code that wasn't previously unit-tested. It's okay to check in a bugfix
41500a553dfSEmily Shafferalong with a test that verifies the fix worked, if you're only doing one test
41600a553dfSEmily Shafferand one bugfix. If you're checking in a large suite of tests, do the bugfixes in
41700a553dfSEmily Shafferindependent commits which your test suite commit is based on:
41800a553dfSEmily Shaffer
41900a553dfSEmily Shaffermaster -> fix Foo.Abc() -> fix Foo.Def() -> Fix Foo.Ghi() -> test Foo class
42000a553dfSEmily Shaffer
421*43dda5edSGeorge Liu### Sending for Review
422a3a1cdc2SEmily Shaffer
42300a553dfSEmily ShafferYou can send your test update and any associated bugfixes for review to Gerrit
42400a553dfSEmily Shafferas you would send any other change. For the `Tested:` field in the commit
42500a553dfSEmily Shaffermessage, you can state that you ran the new unit tests written.
42600a553dfSEmily Shaffer
427*43dda5edSGeorge Liu### Reviewing Tests
428a3a1cdc2SEmily Shaffer
429455ee0b9SEmily ShafferTests are written primarily to be read. So when you review a test, you're the
430455ee0b9SEmily Shafferfirst customer of that test!
431455ee0b9SEmily Shaffer
432a3a1cdc2SEmily Shaffer## Best Practices
433a3a1cdc2SEmily Shaffer
434455ee0b9SEmily ShafferFirst, all the best practices listed above for writing tests are things you
435455ee0b9SEmily Shaffershould check for and encourage when you're reading tests.
436455ee0b9SEmily Shaffer
437455ee0b9SEmily ShafferNext, you should ensure that you can tell what's going on when you read the
438455ee0b9SEmily Shaffertest. If it's not clear to you, it's not going to be clear to someone else, and
439455ee0b9SEmily Shafferthe test is more prone to error - ask!
440455ee0b9SEmily Shaffer
441455ee0b9SEmily ShafferFinally, think about what's _not_ being tested. If there's a case you're curious
442455ee0b9SEmily Shafferabout and it isn't covered, you should mention it to the committer.
443455ee0b9SEmily Shaffer
444a3a1cdc2SEmily Shaffer## Quickly Running At Home
4457a4ebde3SEmily Shaffer
446455ee0b9SEmily ShafferNow that you've got a handy setup as described earlier in this document, you can
447455ee0b9SEmily Shafferquickly download and run the tests yourself. Within the Gerrit change, you
448455ee0b9SEmily Shaffershould be able to find a button that says "Download", which will give you
449455ee0b9SEmily Shaffercommands for various types of downloads into an existing Git repo. Use
450455ee0b9SEmily Shaffer"Checkout", for example:
451455ee0b9SEmily Shaffer
452455ee0b9SEmily Shaffer```shell
453455ee0b9SEmily Shaffercd openbmc-ci-tests/phosphor-host-ipmid
454455ee0b9SEmily Shaffergit fetch "https://gerrit.openbmc-project.xyz/openbmc/phosphor-host-ipmid" \
455455ee0b9SEmily Shaffer  refs/changes/43/23043/1 && git checkout FETCH_HEAD
456455ee0b9SEmily Shaffer```
457455ee0b9SEmily Shaffer
458455ee0b9SEmily ShafferThis won't disturb the rest of your Git repo state, and will put your CI
459455ee0b9SEmily Shafferworktree into detached-HEAD mode pointing to the commit that's under review. You
460455ee0b9SEmily Shaffercan then run your tests normally, and even make changes and push again if the
461455ee0b9SEmily Shaffercommit was abandoned or otherwise left to rot by its author.
462455ee0b9SEmily Shaffer
463455ee0b9SEmily ShafferDoing so can be handy in a number of scenarios:
464455ee0b9SEmily Shaffer
465455ee0b9SEmily Shaffer- Jenkins isn't responding
466455ee0b9SEmily Shaffer- The Jenkins build is broken for a reason beyond the committer's control
467455ee0b9SEmily Shaffer- The committer doesn't have "Ok-To-Test" permission, and you don't have
468455ee0b9SEmily Shaffer  permission to grant it to them
469455ee0b9SEmily Shaffer
470*43dda5edSGeorge Liu## Credits
4717a4ebde3SEmily Shaffer
4727a4ebde3SEmily ShafferThanks very much to Patrick Venture for his prior work putting together
4737a4ebde3SEmily Shafferdocumentation on this topic internal to Google.
474