WritingTests.txt 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. Writing tests for Tor: an incomplete guide
  2. ==========================================
  3. Tor uses a variety of testing frameworks and methodologies to try to
  4. keep from introducing bugs. The major ones are:
  5. 1. Unit tests written in C and shipped with the Tor distribution.
  6. 2. Integration tests written in Python and shipped with the Tor
  7. distribution.
  8. 3. Integration tests written in Python and shipped with the Stem
  9. library. Some of these use the Tor controller protocol.
  10. 4. System tests written in Python and SH, and shipped with the
  11. Chutney package. These work by running many instances of Tor
  12. locally, and sending traffic through them.
  13. 5. The Shadow network simulator.
  14. How to run these tests
  15. ----------------------
  16. === The easy version
  17. To run all the tests that come bundled with Tor, run "make check"
  18. To run the Stem tests as well, fetch stem from the git repository,
  19. set STEM_SOURCE_DIR to the checkout, and run "make test-stem".
  20. To run the Chutney tests as well, fetch chutney from the git repository,
  21. set CHUTNEY_PATH to the checkout, and run "make test-network".
  22. === Running particular subtests
  23. XXXX WRITEME
  24. === Finding test coverage
  25. When you configure Tor with the --enable-coverage option, it should
  26. build with support for coverage in the unit tests, and in a special
  27. "tor-cov" binary. If you launch
  28. XXXX "make test-network" doesn't know about "tor-cov"; you don't get
  29. XXXX coverage from that yet, unless you do "cp src/or/tor-cov
  30. XXXX src/or/tor" before you run it.
  31. What kinds of test should I write?
  32. ----------------------------------
  33. XXXX writeme.
  34. Unit and regression tests: Does this function do what it's supposed to?
  35. -----------------------------------------------------------------------
  36. Most of Tor's unit tests are made using the "tinytest" testing framework.
  37. You can see a guide to using it in the tinytest manual at
  38. https://github.com/nmathewson/tinytest/blob/master/tinytest-manual.md
  39. To add a new test of this kind, either edit an existing C file in src/test/,
  40. or create a new C file there. Each test is a single function that must
  41. be indexed in the table at the end of the file. We use the label "done:" as
  42. a cleanup point for all test functions.
  43. (Make sure you read tinytest-manual.md before proceeding.)
  44. I use the term "unit test" and "regression tests" very sloppily here.
  45. === A simple example
  46. Here's an example of a test function for a simple function in util.c:
  47. static void
  48. test_util_writepid(void *arg)
  49. {
  50. (void) arg;
  51. char *contents = NULL;
  52. const char *fname = get_fname("tmp_pid");
  53. unsigned long pid;
  54. char c;
  55. write_pidfile(fname);
  56. contents = read_file_to_str(fname, 0, NULL);
  57. tt_assert(contents);
  58. int n = sscanf(contents, "%lu\n%c", &pid, &c);
  59. tt_int_op(n, OP_EQ, 1);
  60. tt_int_op(pid, OP_EQ, getpid());
  61. done:
  62. tor_free(contents);
  63. }
  64. This should look pretty familiar to you if you've read the tinytest
  65. manual. One thing to note here is that we use the testing-specific
  66. function "get_fname" to generate a file with respect to a temporary
  67. directory that the tests use. You don't need to delete the file;
  68. it will get removed when the tests are done.
  69. Also note our use of OP_EQ instead of == in the tt_int_op() calls.
  70. We define OP_* macros to use instead of the binary comparison
  71. operators so that analysis tools can more easily parse our code.
  72. (Coccinelle really hates to see == used as a macro argument.)
  73. Finally, remember that by convention, all *_free() functions that
  74. Tor defines are defined to accept NULL harmlessly. Thus, you don't
  75. need to say "if (contents)" in the cleanup block.
  76. === Exposing static functions for testing
  77. Sometimes you need to test a function, but you don't want to expose
  78. it outside its usual module.
  79. To support this, Tor's build system compiles a testing version of
  80. teach module, with extra identifiers exposed. If you want to
  81. declare a function as static but available for testing, use the
  82. macro "STATIC" instead of "static". Then, make sure there's a
  83. macro-protected declaration of the function in the module's header.
  84. For example, crypto_curve25519.h contains:
  85. #ifdef CRYPTO_CURVE25519_PRIVATE
  86. STATIC int curve25519_impl(uint8_t *output, const uint8_t *secret,
  87. const uint8_t *basepoint);
  88. #endif
  89. The crypto_curve25519.c file and the test_crypto.c file both define
  90. CRYPTO_CURVE25519_PRIVATE, so they can see this declaration.
  91. === Mock functions for testing in isolation
  92. Often we want to test that a function works right, but the function depends
  93. on other functions whose behavior is hard to observe, or whose
  94. XXXX WRITEME
  95. === Advanced techniques: Namespaces
  96. XXXX write this. danah boyd made us some really awesome stuff here.
  97. Integration tests: Calling Tor from the outside
  98. -----------------------------------------------
  99. XXXX WRITEME
  100. Writing integration tests with Stem
  101. -----------------------------------
  102. XXXX WRITEME
  103. System testing with Chutney
  104. ---------------------------
  105. XXXX WRITEME
  106. Who knows what evil lurks in the timings of networks? The Shadow knows!
  107. -----------------------------------------------------------------------
  108. XXXX WRITEME