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