| LTP Style Guide |
| =============== |
| |
| ********************************************************************** |
| Welcome to the *LTP Project Coding Guideline* document! This document is |
| designed to guide committers and contributors in producing consistent, quality |
| deterministic testcases and port testcases from other sources to LTP so that |
| they can be easily maintained by project members and external contributors. |
| |
| Please refer to the *Linux Kernel Coding Guidelines* unless stated otherwise |
| in this document. |
| |
| Changelog: |
| |
| * Initial version: Ngie Cooper <yaneurabeya@gmail.com> |
| * Reformatted for asciidoc: Cyril Hrubis <chrubis@suse.cz> |
| ********************************************************************** |
| |
| Using libltp |
| ------------ |
| |
| Of course the manpages should be the primary source of information in |
| terms of how you should use libltp, but this section provides a quick |
| set of guidelines to hit the ground running with libltp. |
| |
| When you can use libltp please observe the following guidelines: |
| |
| 1. Should I use tst_*() interface in forked processes? |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| |
| No, only use libltp in non-forked processes and functions +perror(3)+ / |
| +exit(3)+ otherwise. Reason being: |
| |
| * Calling +tst_resm()+ from multiple processes is messy. |
| * Calling cleanup can break test execution. |
| * Establishing a complicated scheme of tracking the testcase state |
| for teardown is undesirable. |
| |
| 2. Use SAFE_* macros |
| ~~~~~~~~~~~~~~~~~~~~ |
| |
| Use +SAFE_*+ macros (see +safe_macros.h+) instead of bare calls to libcalls and |
| syscalls. This will: |
| |
| * Reduce number of lines wasted on repeated in multiple files with |
| error catching logic. |
| * Ensure that error catching is consistent and informative; all |
| +SAFE_*+ macros contain the line number of the failure as well as |
| the file where the failure occurred by design. So unless the |
| stack gets stomped on, you will be able to determine where |
| the failures occurred if and when they do occur with absolute |
| determinism. |
| * Mute some unchecked return code warnings. |
| |
| 3. Don't call cleanup() from within setup() |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| |
| Unless you need to clean up or reset system state that wouldn't otherwise be |
| handled by a proper release of all OS resources. |
| |
| This includes (but is not limited to): |
| |
| * Memory mapped pages. |
| * Mounted filesystems. |
| * File descriptors (if they're in temporary directories, etc). |
| * Temporary files / directories. |
| * Waiting for child processes. |
| * +/proc+ & +/sysfs+ tunable states. |
| |
| You don't need to clean up the following: |
| |
| * +malloc(3)+'ed memory. |
| * Read-only file descriptors in persistent paths (i.e. not |
| temporary directories). |
| |
| Please be aware of some of the caveats surrounding forking, |
| exec'ing and descriptor inheritance, etc. |
| |
| 4. Call APIs that don't require freeing up resources on failure first |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| |
| * +tst_require_root()+ |
| * +tst_sig(...)+ |
| * +malloc(3)+ |
| * +tst_tmpdir()+ |
| |
| That way you can simplify your setup and avoid calling cleanup whenever |
| possible! |
| |
| 5. If the test needs to run as root |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| |
| If the test need to run as root, check to make sure that you're root |
| *before doing any other setup* via +tst_require_root()+. |
| |
| 6. No custom reporting APIs |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| |
| Don't roll your own reporting APIs unless you're porting testcases or are |
| concerned about portability. |
| |
| 7. Handle TBROK and TFAIL correctly |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| |
| Use +TBROK+ when an unexpected failure unrelated to the goal of the testcase |
| occurred, and use +TFAIL+ when an unexpected failure related to the goal of |
| the testcase occurred. |
| |
| 8. Don't roll your own syscall numbers |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| |
| Header +lapi/syscalls.h+ exists for this purpose and does a pretty |
| dang good job. |
| |
| 9. Keep errors as short and sweet as possible |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| |
| For example: |
| [source,c] |
| ---------------------------------------------------- |
| if (fork() == -1) |
| tst_brkm(TBROK, cleanup, "fork failed"); |
| |
| /* or */ |
| |
| if (fork() == -1) |
| tst_brkm(TBROK, cleanup, "fork # 1 failed"); |
| |
| if (fork() == -1) |
| tst_brkm(TBROK, cleanup, "fork # 2 failed"); |
| ---------------------------------------------------- |
| |
| If you can't determine where the failure has occurred in a testcase based on |
| the entire content of the failure messages, then determining the cause of |
| failure may be impossible. |
| |
| 10. Reporting errno and the TEST() macro |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| |
| Don't roll your own +errno+ / +strerror()+ printout when you use +tst_resm()+ |
| calls. Use either +TERRNO+ or +TTERRNO+. Similarly, if a testcase passed and |
| it's obvious why it passed (for example a function call returns +0+ or |
| +TEST_RETURN == 0+). |
| |
| [source,c] |
| ------------------------------------------------------------------------------- |
| /* Example without TEST(...) macro */ |
| |
| exp_errno = ENOENT; |
| |
| if (fn() == -1) { |
| /* |
| * Using TERRNO here is valid because the error case |
| * isn't static. |
| */ |
| if (exp_errno == ENOENT) |
| tst_resm(TPASS|TERRNO, |
| "fn failed as expected"); |
| /* |
| * Using strerror(TEST_ERRNO) here is valid because |
| * the error case isn't static. |
| */ |
| else |
| tst_resm(TFAIL|TERRNO, |
| "fn failed unexpectedly; expected " |
| "%d - %s", |
| exp_errno, strerror(exp_errno)); |
| } else |
| tst_resm(TBROK, "fn passed unexpectedly"); |
| |
| /* Example using TEST(...) macro */ |
| |
| TEST(fn()); |
| if (TEST_RETURN == 0) |
| tst_resm(TPASS, "fn passed as expected"); |
| else |
| tst_resm(TFAIL|TTERRNO, "fn failed"); |
| ------------------------------------------------------------------------------- |
| |
| [NOTE] |
| The +TEST()+ macro is not thread-safe as it saves return value and errno into |
| global variable. |
| |
| 12. Use tst_brkm() when possible |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| |
| Use... |
| [source,c] |
| ------------------------------ |
| tst_brkm(TBROK, cleanup, ...); |
| ------------------------------ |
| ...instead of... |
| [source,c] |
| ------------------------------ |
| tst_resm(TBROK, ...); |
| cleanup(); |
| tst_exit(); |
| ------------------------------ |
| |
| [NOTE] |
| As you see the +tst_brkm()+ no longer requires non +NULL+ cleanup_fn argument |
| in order to call +tst_exit()+. |
| |
| 13. Indentation |
| ~~~~~~~~~~~~~~~ |
| |
| Use hard tabs for first-level indentation, and 4 spaces for every line longer |
| than 80 columns. Use a linebreak with string constants in format functions |
| like +*printf()+, the +tst_resm()+ APIs, etc. |
| |
| Example: |
| [source,c] |
| ------------------------------------------------------------------------------- |
| if ((this_is_a_poorly_formed_really_long_variable = function_call()) == NULL && |
| statement1() && i < j && l != 5) { |
| /* Use tabs here */ |
| printf("The rain in Spain falls mainly in the plain.\nThe quick brown " |
| "fox jumped over the lazy yellow dog\n"); |
| tst_resm(TPASS, |
| "Half would turn and fight. The other half would try to swim " |
| "across. But my uncle told me about a few that... they'd swim " |
| "halfway out, turn with the current, and ride it all the way out " |
| "to sea. Fisherman would find them a mile offshore, swimming."); |
| } |
| ------------------------------------------------------------------------------- |
| |
| 14. System headers |
| ~~~~~~~~~~~~~~~~~~ |
| |
| Don't use +linux/+ headers if at all possible. Usually they are replaced with |
| +sys/+ headers as things work their way into glibc. Furthermore, +linux/+ |
| headers get shuffled around a lot more than their +sys/+ counterparts it |
| seems. |
| |
| 15. Signal handlers |
| ~~~~~~~~~~~~~~~~~~~~ |
| |
| Avoid doing tricky things in signal handlers. Calling most of the libc |
| functions from signal handler may lead to deadlocks or memory corruption. If |
| you really need to do anything more complicated that +should_run = 0;+ in your |
| signal handler consult +man 7 signal+ for async-signal-safe functions. |
| |
| Porting Testcases |
| ----------------- |
| |
| If one of the following is true... |
| |
| 1. You are porting a testcase directly to LTP which doesn't need to |
| be ported outside of Linux. |
| 2. The beforementioned project or source is no longer contributing |
| changes to the testcases. |
| |
| Then please fully port the testcase(s) to LTP. Otherwise, add robust porting |
| shims around the testcases using libltp APIs to reduce longterm maintenance |
| and leave the sources alone so it's easier to sync the testcases from the |
| upstream source. |
| |
| New Testcases |
| ------------- |
| |
| 1. Always use libltp for Linux centric tests. No ifs, ands, or buts |
| about it. |
| 2. Sort headers, like: |
| |
| [source,c] |
| --------------------------------------------------------------------------- |
| /* |
| * sys/types.h is usually (but not always) required by POSIX |
| * APIs. |
| */ |
| #include <sys/types.h> |
| /* sys headers, alphabetical order. */ |
| /* directory prefixed libc headers. */ |
| /* non-directory prefixed libc headers. */ |
| /* directory prefixed non-libc (third-party) headers. */ |
| /* non-directory prefixed non-libc (third-party) headers. */ |
| /* Sourcebase relative includes. */ |
| |
| /* e.g. */ |
| |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <netinet/icmp.h> |
| #include <stdio.h> |
| #include <dbus-1.0/dbus/dbus.h> |
| #include <archive.h> |
| #include "foo/bar.h" |
| #include "test.h" |
| --------------------------------------------------------------------------- |
| |
| 3. Comments |
| ~~~~~~~~~~~ |
| |
| Do not use obvious comments ("child process", "parse options", etc). This |
| leads to visual comment noise pollution. |
| |
| 4. Inline assignments |
| ~~~~~~~~~~~~~~~~~~~~ |
| |
| Don't do inline assignment, i.e. |
| |
| [source,c] |
| --------------------------------------------------------------------------- |
| int foo = 0; |
| |
| Use separate statements: |
| |
| int foo; |
| |
| foo = 0; |
| --------------------------------------------------------------------------- |
| |
| The only exception to this is when you define global variables. |
| |
| 5. How to assert test is running as root? |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| |
| Your testcase should be runnable as root and non-root. What does that mean? It |
| should fail gracefully as non-root if it has insufficient privileges, or use |
| +tst_require_root()+ if root access is absolutely required. |
| |
| A lot of newer testcases don't honor this fact and it causes random |
| unnecessary errors when run as non-privileged users. |
| |
| 6. Do I need to create temporary directory? |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| |
| Use +tst_tmpdir()+ if your testcase will: |
| |
| * Create temporary files. |
| * Dump core. |
| * Etc. Otherwise, don't bother with the API. |
| |
| [NOTE] |
| If you created temporary directory with +tst_tmpdir()+ don't forget to call |
| +tst_rmdir()+ when the test is cleaning up. This is *NOT* done automatically. |
| |
| 7. Setting up signal handlers |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| |
| Use +tst_sig()+ instead of bothering with sigaction / signal. This reduces |
| potential of leaving a mess around if your test doesn't exit cleanly (now, |
| there are some signals that can't be blocked, i.e. +SIGKILL+ and +SIGSTOP+, |
| but the rest can be caught). |
| |
| 8. Basic template |
| ~~~~~~~~~~~~~~~~~ |
| |
| The following is a basic testcase template: |
| [source,c] |
| --------------------------------------------------------------------------- |
| #include "test.h" |
| |
| char *TCID = "testname"; |
| int TST_TOTAL = /* ... */ |
| |
| static void setup(void) |
| { |
| /* ... */ |
| |
| tst_require_root(); |
| |
| tst_tmpdir(); |
| |
| /* ... */ |
| |
| TEST_PAUSE; |
| } |
| |
| static void cleanup(void) |
| { |
| |
| TEST_CLEANUP; |
| |
| /* ... */ |
| |
| tst_rmdir(); |
| } |
| |
| int main(void) |
| { |
| /* ... */ |
| |
| setup(); /* Optional */ |
| |
| cleanup(); /* Optional */ |
| tst_exit(); /* DON'T FORGET THIS -- this must be last! */ |
| } |
| --------------------------------------------------------------------------- |
| |
| Fixing Legacy Testcases |
| ----------------------- |
| |
| Unless you interested in exercising self-masochism, do minimal changes |
| to testcases when fixing them so it's easier to track potential |
| breakage in testcases after a commit is made (mistakes happen and no |
| one is perfect). If it works after you fix it -- great -- move on. |
| It's more the job of the committers / maintainers to do things like |
| style commits. |
| |
| It's better to focus on adding more content to LTP as a contributor |
| and fixing functional issues with existing tests than it is worrying |
| about whitespace, unnecessary pedanticness of function calls, etc. |
| |
| As ugly as the style is in the surrounding code may be, stick to it. |
| Otherwise anyone reading the code will cringe at the chaos and |
| non-uniform `style', and it will be more difficult to fix later. |
| |
| |
| Fixing Open Posix Testsuite |
| --------------------------- |
| |
| The *Open Posix Testsuite* does not use libltp interface and moreover aims to |
| be usable on any *POSIX* compatible operating system. |
| |
| So *NO* Linux, BSD specific syscalls there. |
| |
| Contribution to the project |
| --------------------------- |
| |
| Since CVS is effectively dead for LTP proper, we ask that you submit |
| patches that are git friendly and patchable. |
| |
| Guidelines for submitting patches are as follows: |
| |
| 1. Use +git commit -s+ . You know you want to ;) .. (you may need to |
| submit a correct signed-off-by line, e.g. use git config first). |
| 2. Provide a short (<= 50 character) description of the commit. |
| 3. Provide a little more terse (1-2 paragraph maximum, <= 72 character |
| lines) description of what the commit does. |
| 4. Format the email with +git format-patch --attach+ command . |
| |
| Example of a commit message: |
| |
| ------------------------------------------------------------------- |
| Short description of my commit. |
| |
| This is a much longer description of my commit. Blah blah blah blah |
| blah blah blah blah blah. |
| |
| Signed-off-by: John Smith <dev@null> |
| ------------------------------------------------------------------- |