Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
337344ae87544a4acd3541ee2443c53ce38a76d2
[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 \warning this section is outdated. New unit tests should be written
61 using the unit_test_framework component of Boost. There is no such
62 example so far in our codebase, but that's definitely the way to go
63 for the future. STOP USING XBT.
64
65 If you want to test a specific function or set of functions, you need
66 a unit test. Edit the file tools/cmake/UnitTesting.cmake to
67 add your source file to the FILES_CONTAINING_UNITTESTS list. For
68 example, if you want to create unit tests in the file src/xbt/plouf.c,
69 your changes should look like that:
70
71 \verbatim
72 --- a/tools/cmake/UnitTesting.cmake
73 +++ b/tools/cmake/UnitTesting.cmake
74 @@ -11,6 +11,7 @@ set(FILES_CONTAINING_UNITTESTS
75    src/xbt/xbt_strbuff.c
76    src/xbt/xbt_sha.c
77    src/xbt/config.c
78 +  src/xbt/plouf.c
79    )
80
81  if(SIMGRID_HAVE_MC)
82 \endverbatim
83
84 Then, you want to actually add your tests in the source file. All the
85 tests must be protected by "#ifdef SIMGRID_TEST" so that they don't
86 get included in the regular build. The line SIMGRID_TEST must also be
87 written on the endif line for the extraction script to work properly. 
88
89 Tests are subdivided in three levels. The top-level, called <b>test
90 suite</b>, is created with the macro #XBT_TEST_SUITE. There can be
91 only one suite per source file. A suite contains <b>test units</b>
92 that you create with the #XBT_TEST_UNIT macro.  Finally, you start
93 <b>actual tests</b> with #xbt_test_add. There is no closing marker of
94 any sort, and an unit is closed when the next unit starts, or when the
95 end of file is reached. 
96
97 Once a given test is started with #xbt_test_add, you use
98 #xbt_test_assert to specify that it was actually an assert, or
99 #xbt_test_fail to specify that it failed (if your test cannot easily
100 be written as an assert). #xbt_test_exception can be used to report
101 that it failed with an exception. There is nothing to do to report
102 that a given test succeeded, just start the next test without
103 reporting any issue. Finally, #xbt_test_log can be used to report
104 intermediate steps. The messages will be shown only if the
105 corresponding test fails.
106
107 Here is a recaping example, inspired from src/xbt/dynar.h (see that
108 file for details).
109 @code
110 /* The rest of your module implementation */
111
112 #ifdef SIMGRID_TEST
113
114 XBT_TEST_SUITE("dynar", "Dynar data container");
115 XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(xbt_dyn); // Just the regular logging stuff
116
117 XBT_TEST_UNIT("int", test_dynar_int, "Dynars of integers")
118 {
119   int i, cpt;
120   unsigned int cursor;
121
122   xbt_test_add("==== Traverse the empty dynar");
123   xbt_dynar_t d = xbt_dynar_new(sizeof(int), NULL);
124   xbt_dynar_foreach(d, cursor, i) {
125     xbt_test_fail( "Damnit, there is something in the empty dynar");
126   }
127   xbt_dynar_free(&d);
128
129   xbt_test_add("==== Push %d int and re-read them",  NB_ELEM);
130   d = xbt_dynar_new(sizeof(int), NULL);
131   for (cpt = 0; cpt < NB_ELEM; cpt++) {
132     xbt_test_log("Push %d, length=%lu", cpt, xbt_dynar_length(d));
133     xbt_dynar_push_as(d, int, cpt);
134   }
135
136   for (cursor = 0; cursor < NB_ELEM; cursor++) {
137     int *iptr = xbt_dynar_get_ptr(d, cursor);
138     xbt_test_assert(cursor == *iptr,
139        "The retrieved value is not the same than the injected one (%u!=%d)",cursor, cpt);
140   }
141   
142   xbt_test_add("==== Check the size of that %d-long dynar",  NB_ELEM);
143   xbt_test_assert(xbt_dynar_size(d) == NB_ELEM);
144   xbt_dynar_free(&d); 
145 }
146
147 XBT_TEST_UNIT("insert",test_dynar_insert,"Using the xbt_dynar_insert and xbt_dynar_remove functions")
148 {
149   xbt_dynar_t d = xbt_dynar_new(sizeof(unsigned int), NULL);
150   unsigned int cursor;
151   int cpt;
152
153   xbt_test_add("==== Insert %d int, traverse them, remove them",NB_ELEM);
154   // BLA BLA BLA
155 }
156
157 #endif  /* SIMGRID_TEST <-- that string must appear on the endif line */
158 @endcode
159
160 For more details on the macro used to write unit tests, see their
161 reference guide: @ref XBT_cunit.  For details on on how the tests are
162 extracted from the module source, check the tools/sg_unit_extractor.pl
163 script directly.
164
165 Last note: please try to keep your tests fast. We run them very very
166 very often, and you should strive to make it as fast as possible, to
167 not upset the other developers. Do not hesitate to stress test your
168 code with such unit tests, but make sure that it runs reasonably fast,
169 or nobody will run "ctest" before commiting code.
170
171 \section inside_tests_add_integration Adding integration tests
172
173 TESH (the TEsting SHell) is the test runner that we wrote for our
174 integration tests. It is distributed with the SimGrid source file, and
175 even comes with a man page. TESH ensures that the output produced by a
176 command perfectly matches the expected output. This is very precious
177 to ensure that no change modifies the timings computed by the models
178 without notice. 
179
180 To add a new integration test, you thus have 3 things to do:
181
182  - <b>Write the code exercising the feature you target</b>. You should
183    strive to make this code clear, well documented and informative for
184    the users. If you manage to do so, put this somewhere under
185    examples/ and modify the cmake files as explained on this page:
186    \ref inside_cmake_examples. If you feel like you should write a
187    torture test that is not interesting to the users (because nobody
188    would sanely write something similar in user code), then put it under 
189    teshsuite/ somewhere.
190    
191  - <b>Write the tesh file</b>, containing the command to run, the
192    provided input (if any, but almost no SimGrid test provide such an
193    input) and the expected output. Check the tesh man page for more
194    details.\n
195    Tesh is sometimes annoying as you have to ensure that the expected
196    output will always be exactly the same. In particular, your should
197    not output machine dependent informations such as absolute data
198    path, nor memory adresses as they would change on each run. Several
199    steps can be used here, such as the obfucation of the memory
200    adresses unless the verbose logs are displayed (using the
201    #XBT_LOG_ISENABLED() macro), or the modification of the log formats
202    to hide the timings when they depend on the host machine.\n
203    The script located in <project/directory>/tools/tesh/generate_tesh can
204    help you a lot in particular if the output is large (though a smaller output is preferable). 
205    There are also example tesh files in the <project/directory>/tools/tesh/ directory, that can be useful to understand the tesh syntax.
206    
207  - <b>Add your test in the cmake infrastructure</b>. For that, modify
208    the following file:
209    @verbatim
210    <project/directory>/teshsuite/<interface eg msg>/CMakeLists.txt
211    @endverbatim   
212    Make sure to pick a wise name for your test. It is often useful to
213    check a category of tests together. The only way to do so in ctest
214    is to use the -R argument that specifies a regular expression that
215    the test names must match. For example, you can run all MSG test
216    with "ctest -R msg". That explains the importance of the test
217    names.
218
219 Once the name is chosen, create a new test by adding a line similar to
220 the following (assuming that you use tesh as expected).
221
222 \verbatim
223 # Usage: ADD_TEST(test-name ${CMAKE_BINARY_DIR}/bin/tesh <options> <tesh-file>)
224 #  option --setenv bindir set the directory containing the binary
225 #         --setenv srcdir set the directory containing the source file
226 #         --cd set the working directory
227 ADD_TEST(my-test-name ${CMAKE_BINARY_DIR}/bin/tesh 
228          --setenv bindir=${CMAKE_BINARY_DIR}/examples/my-test/
229          --setenv srcdir=${CMAKE_HOME_DIRECTORY}/examples/my-test/
230          --cd ${CMAKE_HOME_DIRECTORY}/examples/my-test/
231          ${CMAKE_HOME_DIRECTORY}/examples/msg/io/io.tesh
232 )
233 \endverbatim             
234
235 As usual, you must run "make distcheck" after modifying the cmake files,
236 to ensure that you did not forget any files in the distributed archive.
237
238 \section inside_tests_ci Continous Integration
239
240 We use several systems to automatically test SimGrid with a large set
241 of parameters, across as many platforms as possible. 
242 We use <a href="https://ci.inria.fr/simgrid/">Jenkins on Inria
243 servers</a> as a workhorse: it runs all of our tests for many
244 configurations. It takes a long time to answer, and it often reports
245 issues but when it's green, then you know that SimGrid is very fit!
246 We use <a href="https://travis-ci.org/simgrid/simgrid">Travis</a> to
247 quickly run some tests on Linux and Mac. It answers quickly but may
248 miss issues. And we use <a href="https://ci.appveyor.com/project/simgrid/simgrid">AppVeyor</a>
249 to build and somehow test SimGrid on windows. 
250
251 \subsection inside_tests_jenkins Jenkins on the Inria CI servers
252
253 You should not have to change the configuration of the Jenkins tool
254 yourself, although you could have to change the slaves' configuration
255 using the <a href="https://ci.inria.fr">CI interface of INRIA</a> --
256 refer to the <a href="https://wiki.inria.fr/ciportal/">CI documentation</a>.
257
258 The result can be seen here: https://ci.inria.fr/simgrid/
259
260 We have 2 interesting projects on Jenkins:
261 \li <a href="https://ci.inria.fr/simgrid/job/SimGrid-Multi/">SimGrid-Multi</a>
262     is the main project, running the tests that we spoke about.\n It is
263     configured (on Jenkins) to run the script <tt>tools/jenkins/build.sh</tt>
264 \li <a href="https://ci.inria.fr/simgrid/job/SimGrid-DynamicAnalysis/">SimGrid-DynamicAnalysis</a>
265     runs the tests both under valgrind to find the memory errors and
266     under gcovr to report the achieved test coverage.\n It is configured
267     (on Jenkins) to run the script <tt>tools/jenkins/DynamicAnalysis.sh</tt>
268
269 In each case, SimGrid gets built in
270 /builds/workspace/$PROJECT/build_mode/$CONFIG/label/$SERVER/build 
271 with $PROJECT being for instance "SimGrid-Multi", $CONFIG "DEBUG" or
272 "ModelChecker" and $SERVER for instance "simgrid-fedora20-64-clang".
273
274 If some configurations are known to fail on some systems (such as
275 model-checking on non-linux systems), go to your Project and click on
276 "Configuration". There, find the field "combination filter" (if your
277 interface language is English) and tick the checkbox; then add a
278 groovy-expression to disable a specific configuration. For example, in
279 order to disable the "ModelChecker" build on host
280 "small-netbsd-64-clang", use:
281
282 \verbatim
283 (label=="small-netbsd-64-clang").implies(build_mode!="ModelChecker")
284 \endverbatim
285
286 \subsection inside_tests_travis Travis
287
288 Travis is a free (as in free beer) Continuous Integration system that
289 open-sourced project can use freely. It is very well integrated in the
290 GitHub ecosystem. There is a plenty of documentation out there. Our
291 configuration is in the file .travis.yml as it should be, and the
292 result is here: https://travis-ci.org/simgrid/simgrid
293
294 The .travis.yml configuration file can be useful if you fail to get
295 SimGrid to compile on modern mac systems. We use the \c brew package
296 manager there, and it works like a charm.
297
298 \subsection inside_tests_appveyor AppVeyor
299
300 AppVeyor aims at becoming the Travis of Windows. It is maybe less
301 mature than Travis, or maybe it is just that I'm less trained in
302 Windows. Our configuration is in the file appveyor.yml as it should
303 be, and the result is here: https://ci.appveyor.com/project/simgrid/simgrid
304
305 We use \c Choco as a package manager on AppVeyor, and it is sufficient
306 for us. In the future, we will probably move to the ubuntu subsystem
307 of Windows 10: SimGrid performs very well under these settings, but
308 unfortunately we have no continuous integration service providing it
309 yet, so we cannot drop AppVeyor yet.
310
311 \subsection inside_tests_debian Debian builders
312
313 Since SimGrid is packaged in Debian, we benefit from their huge
314 testing infrastructure. That's an interesting torture test for our
315 code base. The downside is that it's only for the released versions of
316 SimGrid. That is why the Debian build does not stop when the tests
317 fail: post-releases fixes do not fit well in our workflow and we fix
318 only the most important breakages.
319
320 The build results are here:
321 https://buildd.debian.org/status/package.php?p=simgrid
322
323 \subsection inside_tests_sonarqube SonarQube
324
325 SonarQube is an open-source code quality analysis solution. Their nice
326 code scanners are provided as plugin. The one for C++ is not free, but
327 open-source project can use it at no cost. That is what we are doing.
328
329 Don't miss the great looking dashboard here: 
330 https://nemo.sonarqube.org/overview?id=simgrid
331
332 This tool is enriched by the script @c tools/internal/travis-sonarqube.sh 
333 that is run from @c .travis.yml
334
335 */