Merge branch 'maint-0.4.0'
[tor.git] / src / test / testing_common.c
blob1c2a2e8960ac8fa26b1ffdd19e9c6be749fe3389
1 /* Copyright (c) 2001-2004, Roger Dingledine.
2 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
3 * Copyright (c) 2007-2019, The Tor Project, Inc. */
4 /* See LICENSE for licensing information */
6 /**
7 * \file test_common.c
8 * \brief Common pieces to implement unit tests.
9 **/
11 #define MAINLOOP_PRIVATE
12 #include "orconfig.h"
13 #include "core/or/or.h"
14 #include "feature/control/control.h"
15 #include "feature/control/control_events.h"
16 #include "app/config/config.h"
17 #include "lib/crypt_ops/crypto_dh.h"
18 #include "lib/crypt_ops/crypto_ed25519.h"
19 #include "lib/crypt_ops/crypto_rand.h"
20 #include "feature/stats/predict_ports.h"
21 #include "feature/stats/rephist.h"
22 #include "lib/err/backtrace.h"
23 #include "test/test.h"
24 #include "core/or/channelpadding.h"
25 #include "core/mainloop/mainloop.h"
26 #include "lib/compress/compress.h"
27 #include "lib/evloop/compat_libevent.h"
28 #include "lib/crypt_ops/crypto_init.h"
29 #include "lib/version/torversion.h"
30 #include "app/main/subsysmgr.h"
32 #include <stdio.h>
33 #ifdef HAVE_FCNTL_H
34 #include <fcntl.h>
35 #endif
36 #ifdef HAVE_UNISTD_H
37 #include <unistd.h>
38 #endif
39 #ifdef HAVE_SYS_STAT_H
40 #include <sys/stat.h>
41 #endif
43 #ifdef _WIN32
44 /* For mkdir() */
45 #include <direct.h>
46 #else
47 #include <dirent.h>
48 #endif /* defined(_WIN32) */
50 /** Temporary directory (set up by setup_directory) under which we store all
51 * our files during testing. */
52 static char temp_dir[256];
53 #ifdef _WIN32
54 #define pid_t int
55 #endif
56 static pid_t temp_dir_setup_in_pid = 0;
58 /** Select and create the temporary directory we'll use to run our unit tests.
59 * Store it in <b>temp_dir</b>. Exit immediately if we can't create it.
60 * idempotent. */
61 static void
62 setup_directory(void)
64 static int is_setup = 0;
65 int r;
66 char rnd[256], rnd32[256];
67 if (is_setup) return;
69 /* Due to base32 limitation needs to be a multiple of 5. */
70 #define RAND_PATH_BYTES 5
71 crypto_rand(rnd, RAND_PATH_BYTES);
72 base32_encode(rnd32, sizeof(rnd32), rnd, RAND_PATH_BYTES);
74 #ifdef _WIN32
76 char buf[MAX_PATH];
77 const char *tmp = buf;
78 const char *extra_backslash = "";
79 /* If this fails, we're probably screwed anyway */
80 if (!GetTempPathA(sizeof(buf),buf))
81 tmp = "c:\\windows\\temp\\";
82 if (strcmpend(tmp, "\\")) {
83 /* According to MSDN, it should be impossible for GetTempPath to give us
84 * an answer that doesn't end with \. But let's make sure. */
85 extra_backslash = "\\";
87 tor_snprintf(temp_dir, sizeof(temp_dir),
88 "%s%stor_test_%d_%s", tmp, extra_backslash,
89 (int)getpid(), rnd32);
90 r = mkdir(temp_dir);
92 #else /* !(defined(_WIN32)) */
93 tor_snprintf(temp_dir, sizeof(temp_dir), "/tmp/tor_test_%d_%s",
94 (int) getpid(), rnd32);
95 r = mkdir(temp_dir, 0700);
96 if (!r) {
97 /* undo sticky bit so tests don't get confused. */
98 r = chown(temp_dir, getuid(), getgid());
100 #endif /* defined(_WIN32) */
101 if (r) {
102 fprintf(stderr, "Can't create directory %s:", temp_dir);
103 perror("");
104 exit(1);
106 is_setup = 1;
107 temp_dir_setup_in_pid = getpid();
110 /** Return a filename relative to our testing temporary directory, based on
111 * name and suffix. If name is NULL, return the name of the testing temporary
112 * directory. */
113 static const char *
114 get_fname_suffix(const char *name, const char *suffix)
116 static char buf[1024];
117 setup_directory();
118 if (!name)
119 return temp_dir;
120 tor_snprintf(buf,sizeof(buf),"%s%s%s%s%s", temp_dir, PATH_SEPARATOR, name,
121 suffix ? "_" : "", suffix ? suffix : "");
122 return buf;
125 /** Return a filename relative to our testing temporary directory. If name is
126 * NULL, return the name of the testing temporary directory. */
127 const char *
128 get_fname(const char *name)
130 return get_fname_suffix(name, NULL);
133 /** Return a filename with a random suffix, relative to our testing temporary
134 * directory. If name is NULL, return the name of the testing temporary
135 * directory, without any suffix. */
136 const char *
137 get_fname_rnd(const char *name)
139 char rnd[256], rnd32[256];
140 crypto_rand(rnd, RAND_PATH_BYTES);
141 base32_encode(rnd32, sizeof(rnd32), rnd, RAND_PATH_BYTES);
142 return get_fname_suffix(name, rnd32);
145 /* Remove a directory and all of its subdirectories */
146 static void
147 rm_rf(const char *dir)
149 struct stat st;
150 smartlist_t *elements;
152 elements = tor_listdir(dir);
153 if (elements) {
154 SMARTLIST_FOREACH_BEGIN(elements, const char *, cp) {
155 char *tmp = NULL;
156 tor_asprintf(&tmp, "%s"PATH_SEPARATOR"%s", dir, cp);
157 if (0 == stat(tmp,&st) && (st.st_mode & S_IFDIR)) {
158 rm_rf(tmp);
159 } else {
160 if (unlink(tmp)) {
161 fprintf(stderr, "Error removing %s: %s\n", tmp, strerror(errno));
164 tor_free(tmp);
165 } SMARTLIST_FOREACH_END(cp);
166 SMARTLIST_FOREACH(elements, char *, cp, tor_free(cp));
167 smartlist_free(elements);
169 if (rmdir(dir))
170 fprintf(stderr, "Error removing directory %s: %s\n", dir, strerror(errno));
173 /** Remove all files stored under the temporary directory, and the directory
174 * itself. Called by atexit(). */
175 static void
176 remove_directory(void)
178 if (getpid() != temp_dir_setup_in_pid) {
179 /* Only clean out the tempdir when the main process is exiting. */
180 return;
183 rm_rf(temp_dir);
186 static void *
187 passthrough_test_setup(const struct testcase_t *testcase)
189 /* Make sure the passthrough doesn't unintentionally fail or skip tests */
190 tor_assert(testcase->setup_data);
191 tor_assert(testcase->setup_data != (void*)TT_SKIP);
192 return testcase->setup_data;
194 static int
195 passthrough_test_cleanup(const struct testcase_t *testcase, void *ptr)
197 (void)testcase;
198 (void)ptr;
199 return 1;
202 static void *
203 ed25519_testcase_setup(const struct testcase_t *testcase)
205 crypto_ed25519_testing_force_impl(testcase->setup_data);
206 return testcase->setup_data;
208 static int
209 ed25519_testcase_cleanup(const struct testcase_t *testcase, void *ptr)
211 (void)testcase;
212 (void)ptr;
213 crypto_ed25519_testing_restore_impl();
214 return 1;
216 const struct testcase_setup_t ed25519_test_setup = {
217 ed25519_testcase_setup, ed25519_testcase_cleanup
220 const struct testcase_setup_t passthrough_setup = {
221 passthrough_test_setup, passthrough_test_cleanup
224 static void
225 an_assertion_failed(void)
227 tinytest_set_test_failed_();
230 void tinytest_prefork(void);
231 void tinytest_postfork(void);
232 void
233 tinytest_prefork(void)
235 free_pregenerated_keys();
236 subsystems_prefork();
238 void
239 tinytest_postfork(void)
241 subsystems_postfork();
242 init_pregenerated_keys();
245 static void
246 log_callback_failure(int severity, uint32_t domain, const char *msg)
248 (void)msg;
249 if (severity == LOG_ERR || (domain & LD_BUG)) {
250 tinytest_set_test_failed_();
254 /** Main entry point for unit test code: parse the command line, and run
255 * some unit tests. */
257 main(int c, const char **v)
259 or_options_t *options;
260 char *errmsg = NULL;
261 int i, i_out;
262 int loglevel = LOG_ERR;
263 int accel_crypto = 0;
265 subsystems_init_upto(SUBSYS_LEVEL_LIBS);
267 options = options_new();
269 struct tor_libevent_cfg cfg;
270 memset(&cfg, 0, sizeof(cfg));
271 tor_libevent_initialize(&cfg);
273 control_initialize_event_queue();
275 for (i_out = i = 1; i < c; ++i) {
276 if (!strcmp(v[i], "--warn")) {
277 loglevel = LOG_WARN;
278 } else if (!strcmp(v[i], "--notice")) {
279 loglevel = LOG_NOTICE;
280 } else if (!strcmp(v[i], "--info")) {
281 loglevel = LOG_INFO;
282 } else if (!strcmp(v[i], "--debug")) {
283 loglevel = LOG_DEBUG;
284 } else if (!strcmp(v[i], "--accel")) {
285 accel_crypto = 1;
286 } else {
287 v[i_out++] = v[i];
290 c = i_out;
293 /* setup logs to stdout */
294 log_severity_list_t s;
295 memset(&s, 0, sizeof(s));
296 set_log_severity_config(loglevel, LOG_ERR, &s);
297 /* ALWAYS log bug warnings. */
298 s.masks[LOG_WARN-LOG_ERR] |= LD_BUG;
299 add_stream_log(&s, "", fileno(stdout));
302 /* Setup logs that cause failure. */
303 log_severity_list_t s;
304 memset(&s, 0, sizeof(s));
305 set_log_severity_config(LOG_ERR, LOG_ERR, &s);
306 s.masks[LOG_WARN-LOG_ERR] |= LD_BUG;
307 add_callback_log(&s, log_callback_failure);
309 flush_log_messages_from_startup();
310 init_protocol_warning_severity_level();
312 options->command = CMD_RUN_UNITTESTS;
313 if (crypto_global_init(accel_crypto, NULL, NULL)) {
314 printf("Can't initialize crypto subsystem; exiting.\n");
315 return 1;
317 if (crypto_seed_rng() < 0) {
318 printf("Couldn't seed RNG; exiting.\n");
319 return 1;
321 rep_hist_init();
322 setup_directory();
323 initialize_mainloop_events();
324 options_init(options);
325 options->DataDirectory = tor_strdup(temp_dir);
326 tor_asprintf(&options->KeyDirectory, "%s"PATH_SEPARATOR"keys",
327 options->DataDirectory);
328 options->CacheDirectory = tor_strdup(temp_dir);
329 options->EntryStatistics = 1;
330 if (set_options(options, &errmsg) < 0) {
331 printf("Failed to set initial options: %s\n", errmsg);
332 tor_free(errmsg);
333 return 1;
336 tor_set_failed_assertion_callback(an_assertion_failed);
338 init_pregenerated_keys();
340 channelpadding_new_consensus_params(NULL);
342 predicted_ports_init();
344 atexit(remove_directory);
346 int have_failed = (tinytest_main(c, v, testgroups) != 0);
348 free_pregenerated_keys();
350 if (have_failed)
351 return 1;
352 else
353 return 0;