Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
d99b23762ea5431b7cfc4ce0c481a0c92bf057ec
[simgrid.git] / doc / doxygen / inside_tests.doc
1 /*! 
2 @page inside_tests Testing SimGrid
3
4 This page will teach you how to run the tests, selecting the ones you
5 want, and how to add new tests to the archive.
6
7 \tableofcontents
8
9 SimGrid code coverage is usually between 70% and 80%, which is much
10 more than most projects out there. This is because we consider SimGrid
11 to be a rather complex project, and we want to modify it with less fear.
12
13 We have two sets of tests in SimGrid: Each of the 10,000+ unit tests
14 check one specific case for one specific function, while the 500+
15 integration tests run a given simulation specifically intended to
16 exercise a larger amount of functions together. Every example provided
17 in examples/ is used as an integration test, while some other torture
18 tests and corner cases integration tests are located in teshsuite/.
19 For each integration test, we ensure that the output exactly matches
20 the defined expectations. Since SimGrid displays the timestamp of
21 every logged line, this ensures that every change of the models'
22 prediction will be noticed. All these tests should ensure that SimGrid
23 is safe to use and to depend on.
24
25 \section inside_tests_runintegration Running the tests
26
27 Running the tests is done using the ctest binary that comes with
28 cmake. These tests are run for every commit and the result is publicly
29 <a href="https://ci.inria.fr/simgrid/">available</a>.
30
31 \verbatim
32 ctest                     # Launch all tests
33 ctest -R msg              # Launch only the tests which name match the string "msg"
34 ctest -j4                 # Launch all tests in parallel, at most 4 at the same time
35 ctest --verbose           # Display all details on what's going on
36 ctest --output-on-failure # Only get verbose for the tests that fail
37
38 ctest -R msg- -j5 --output-on-failure # You changed MSG and want to check that you didn't break anything, huh?
39                                       # That's fine, I do so all the time myself.
40 \endverbatim
41
42 \section inside_tests_rununit Running the unit tests
43
44 All unit tests are packed into the testall binary, that lives at the
45 source root. These tests are run when you launch ctest, don't worry.
46
47 \verbatim
48 make testall                    # Rebuild the test runner on need
49 ./testall                       # Launch all tests
50 ./testall --help                # revise how it goes if you forgot
51 ./testall --tests=-all          # run no test at all (yeah, that's useless)
52 ./testall --dump-only           # Display all existing test suites
53 ./testall --tests=-all,+dict    # Only launch the tests from the dict test suite
54 ./testall --tests=-all,+foo:bar # run only the bar test from the foo suite.
55 \endverbatim
56
57
58 \section inside_tests_add_units Adding unit tests
59
60 If you want to test a specific function or set of functions, you need
61 a unit test. Edit the file tools/cmake/UnitTesting.cmake to
62 add your source file to the FILES_CONTAINING_UNITTESTS list. For
63 example, if you want to create unit tests in the file src/xbt/plouf.c,
64 your changes should look like that:
65
66 \verbatim
67 --- a/tools/cmake/UnitTesting.cmake
68 +++ b/tools/cmake/UnitTesting.cmake
69 @@ -11,6 +11,7 @@ set(FILES_CONTAINING_UNITTESTS
70    src/xbt/xbt_strbuff.c
71    src/xbt/xbt_sha.c
72    src/xbt/config.c
73 +  src/xbt/plouf.c
74    )
75
76  if(HAVE_MC)
77 \endverbatim
78
79 Then, you want to actually add your tests in the source file. All the
80 tests must be protected by "#ifdef SIMGRID_TEST" so that they don't
81 get included in the regular build. The line SIMGRID_TEST must also be
82 written on the endif line for the extraction script to work properly. 
83
84 Tests are subdivided in three levels. The top-level, called <b>test
85 suite</b>, is created with the macro #XBT_TEST_SUITE. There can be
86 only one suite per source file. A suite contains <b>test units</b>
87 that you create with the #XBT_TEST_UNIT macro.  Finally, you start
88 <b>actual tests</b> with #xbt_test_add. There is no closing marker of
89 any sort, and an unit is closed when the next unit starts, or when the
90 end of file is reached. 
91
92 Once a given test is started with #xbt_test_add, you use
93 #xbt_test_assert to specify that it was actually an assert, or
94 #xbt_test_fail to specify that it failed (if your test cannot easily
95 be written as an assert). #xbt_test_exception can be used to report
96 that it failed with an exception. There is nothing to do to report
97 that a given test succeeded, just start the next test without
98 reporting any issue. Finally, #xbt_test_log can be used to report
99 intermediate steps. The messages will be shown only if the
100 corresponding test fails.
101
102 Here is a recaping example, inspired from src/xbt/dynar.h (see that
103 file for details).
104 @code
105 /* The rest of your module implementation */
106
107 #ifdef SIMGRID_TEST
108
109 XBT_TEST_SUITE("dynar", "Dynar data container");
110 XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(xbt_dyn); // Just the regular logging stuff
111
112 XBT_TEST_UNIT("int", test_dynar_int, "Dynars of integers")
113 {
114   int i, cpt;
115   unsigned int cursor;
116
117   xbt_test_add("==== Traverse the empty dynar");
118   xbt_dynar_t d = xbt_dynar_new(sizeof(int), NULL);
119   xbt_dynar_foreach(d, cursor, i) {
120     xbt_test_fail( "Damnit, there is something in the empty dynar");
121   }
122   xbt_dynar_free(&d);
123
124   xbt_test_add("==== Push %d int and re-read them",  NB_ELEM);
125   d = xbt_dynar_new(sizeof(int), NULL);
126   for (cpt = 0; cpt < NB_ELEM; cpt++) {
127     xbt_test_log("Push %d, length=%lu", cpt, xbt_dynar_length(d));
128     xbt_dynar_push_as(d, int, cpt);
129   }
130
131   for (cursor = 0; cursor < NB_ELEM; cursor++) {
132     int *iptr = xbt_dynar_get_ptr(d, cursor);
133     xbt_test_assert(cursor == *iptr,
134        "The retrieved value is not the same than the injected one (%u!=%d)",cursor, cpt);
135   }
136   
137   xbt_test_add("==== Check the size of that %d-long dynar",  NB_ELEM);
138   xbt_test_assert(xbt_dynar_size(d) == NB_ELEM);
139   xbt_dynar_free(&d); 
140 }
141
142 XBT_TEST_UNIT("insert",test_dynar_insert,"Using the xbt_dynar_insert and xbt_dynar_remove functions")
143 {
144   xbt_dynar_t d = xbt_dynar_new(sizeof(unsigned int), NULL);
145   unsigned int cursor;
146   int cpt;
147
148   xbt_test_add("==== Insert %d int, traverse them, remove them",NB_ELEM);
149   // BLA BLA BLA
150 }
151
152 #endif  /* SIMGRID_TEST <-- that string must appear on the endif line */
153 @endcode
154
155 For more details on the macro used to write unit tests, see their
156 reference guide: @ref XBT_cunit.  For details on on how the tests are
157 extracted from the module source, check the tools/sg_unit_extractor.pl
158 script directly.
159
160 Last note: please try to keep your tests fast. We run them very very
161 very often, and you should strive to make it as fast as possible, to
162 not upset the other developers. Do not hesitate to stress test your
163 code with such unit tests, but make sure that it runs reasonably fast,
164 or nobody will run "ctest" before commiting code.
165
166 \section inside_tests_add_integration Adding integration tests
167
168 TESH (the TEsting SHell) is the test runner that we wrote for our
169 integration tests. It is distributed with the SimGrid source file, and
170 even comes with a man page. TESH ensures that the output produced by a
171 command perfectly matches the expected output. This is very precious
172 to ensure that no change modifies the timings computed by the models
173 without notice. 
174
175 To add a new integration test, you thus have 3 things to do:
176
177  - <b>Write the code exercising the feature you target</b>. You should
178    strive to make this code clear, well documented and informative for
179    the users. If you manage to do so, put this somewhere under
180    examples/ and modify the cmake files as explained on this page:
181    \ref inside_cmake_examples. If you feel like you should write a
182    torture test that is not interesting to the users (because nobody
183    would sanely write something similar in user code), then put it under 
184    teshsuite/ somewhere.
185    
186  - <b>Write the tesh file</b>, containing the command to run, the
187    provided input (if any, but almost no SimGrid test provide such an
188    input) and the expected output. Check the tesh man page for more
189    details.\n
190    Tesh is sometimes annoying as you have to ensure that the expected
191    output will always be exactly the same. In particular, your should
192    not output machine dependent informations such as absolute data path, nor memory adresses as
193    they would change on each run. Several steps can be used here, such
194    as the obfucation of the memory adresses unless the verbose logs
195    are displayed (using the #XBT_LOG_ISENABLED() macro), or the
196    modification of the log formats to hide the timings when they
197    depend on the host machine.\n
198    The script located in <project/directory>/tools/tesh/generate_tesh can
199    help you a lot in particular if the output is large (though a smaller output is preferable). 
200    There are also example tesh files in the <project/directory>/tools/tesh/ directory, that can be useful to understand the tesh syntax.
201    
202  - <b>Add your test in the cmake infrastructure</b>. For that, modify
203    the file <project/directory>/tools/cmake/Tests.cmake. Make sure to
204    pick a wise name for your test. It is often useful to check a
205    category of tests together. The only way to do so in ctest is to
206    use the -R argument that specifies a regular expression that the
207    test names must match. For example, you can run all MSG test with
208    "ctest -R msg". That explains the importance of the test names.
209
210 Once the name is chosen, create a new test by adding a line similar to
211 the following (assuming that you use tesh as expected).
212
213 \verbatim
214 # Usage: ADD_TEST(test-name ${CMAKE_BINARY_DIR}/bin/tesh <options> <tesh-file>)
215 #  option --setenv bindir set the directory containing the binary
216 #         --setenv srcdir set the directory containing the source file
217 #         --cd set the working directory
218 ADD_TEST(my-test-name ${CMAKE_BINARY_DIR}/bin/tesh 
219          --setenv bindir=${CMAKE_BINARY_DIR}/examples/my-test/
220          --setenv srcdir=${CMAKE_HOME_DIRECTORY}/examples/my-test/
221          --cd ${CMAKE_HOME_DIRECTORY}/examples/my-test/
222          ${CMAKE_HOME_DIRECTORY}/examples/msg/io/io.tesh
223 )
224 \endverbatim             
225
226 As usual, you must run "make distcheck" after modifying the cmake files,
227 to ensure that you did not forget any files in the distributed archive.
228
229 \section inside_tests_ci Continous Integration
230
231 We use several systems to automatically test SimGrid with a large set
232 of parameters, across as many platforms as possible. 
233 We use <a href="https://ci.inria.fr/simgrid/">Jenkins on Inria
234 servers</a> as a workhorse: it runs all of our tests for many
235 configurations. It takes a long time to answer, and it often reports
236 issues but when it's green, then you know that SimGrid is very fit!
237 We use <a href="https://travis-ci.org/simgrid/simgrid">Travis</a> to
238 quickly run some tests on Linux and Mac. It answers quickly but may
239 miss issues. And we use <a href="https://ci.appveyor.com/project/simgrid/simgrid">AppVeyor</a>
240 to build and somehow test SimGrid on windows. 
241
242 \subsection inside_tests_jenkins Jenkins on the Inria CI servers
243
244 You should not have to change the configuration of the Jenkins tool
245 yourself, although you could have to change the slaves' configuration
246 using the <a href="https://ci.inria.fr">CI interface of INRIA</a> --
247 refer to the <a href="https://wiki.inria.fr/ciportal/">CI documentation</a>.
248
249 The result can be seen here: https://ci.inria.fr/simgrid/
250
251 We have 3 projects on Jenkins:
252 \li <a href="https://ci.inria.fr/simgrid/job/SimGrid-Multi/">SimGrid-Multi</a>
253     is the main project, running the tests that we spoke about.\n It is
254     configured (on Jenkins) to run the script <tt>tools/jenkins/build.sh</tt>
255 \li <a href="https://ci.inria.fr/simgrid/job/SimGrid-DynamicAnalysis/">SimGrid-DynamicAnalysis</a>
256     runs the tests both under valgrind to find the memory errors and
257     under gcovr to report the achieved test coverage.\n It is configured
258     (on Jenkins) to run the script <tt>tools/jenkins/DynamicAnalysis.sh</tt>
259 \li <a href="https://ci.inria.fr/simgrid/job/SimGrid-Windows/">SimGrid-Windows</a>
260     is an ongoing attempt to get Windows tested on Jenkins too.
261
262 In each case, SimGrid gets built in
263 /builds/workspace/$PROJECT/build_mode/$CONFIG/label/$SERVER/build 
264 with $PROJECT being for instance "SimGrid-Multi", $CONFIG "DEBUG" or
265 "ModelChecker" and $SERVER for instance "simgrid-fedora20-64-clang".
266
267 If some configurations are known to fail on some systems (such as
268 model-checking on non-linux systems), go to your Project and click on
269 "Configuration". There, find the field "combination filter" (if your
270 interface language is English) and tick the checkbox; then add a
271 groovy-expression to disable a specific configuration. For example, in
272 order to disable the "ModelChecker" build on host
273 "small-freebsd-64-clang", use:
274
275 \verbatim
276 (label=="small-freebsd-64-clang").implies(build_mode!="ModelChecker")
277 \endverbatim
278
279 \subsection inside_tests_travis Travis
280
281 Travis is a free (as in free beer) Continuous Integration system that
282 open-sourced project can use freely. It is very well integrated in the
283 GitHub ecosystem. There is a plenty of documentation out there. Our
284 configuration is in the file .travis.yml as it should be, and the
285 result is here: https://travis-ci.org/simgrid/simgrid
286
287 \subsection inside_tests_appveyor AppVeyor
288
289 AppVeyor aims at becoming the Travis of Windows. It is maybe less
290 mature than Travis, or maybe it is just that I'm less trained in
291 Windows. Our configuration is in the file appveyor.yml as it should
292 be, and the result is here: https://ci.appveyor.com/project/simgrid/simgrid
293
294 It should be noted that I miserably failed to use the environment
295 provided by AppVeyor, since SimGrid does not build with Microsoft
296 Visual Studio. Instead, we download a whole development environment
297 from the internet at each build. That's an archive of already compiled
298 binaries that are unpacked on the appveyor systems each time we start.
299 We re-use the ones from the 
300 <a href="https://github.com/symengine/symengine">symengine</a>
301 project. Thanks to them for compiling sane tools and constituting that
302 archive, it saved my mind! 
303
304 \subsection inside_tests_debian Debian builders
305
306 Since SimGrid is packaged in Debian, we benefit from their huge
307 testing infrastructure. That's an interesting torture test for our
308 code base. The downside is that it's only for the released versions of
309 SimGrid. That is why the Debian build does not stop when the tests
310 fail: post-releases fixes do not fit well in our workflow and we fix
311 only the most important breakages.
312
313 The build results are here:
314 https://buildd.debian.org/status/package.php?p=simgrid
315
316 */