Make sure passthrough_test_setup doesn't inadvertently fail or skip tests
[tor.git] / src / test / testing_common.c
blob9c6580f78886da674724f59ede38033eb181aba7
1 /* Copyright (c) 2001-2004, Roger Dingledine.
2 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
3 * Copyright (c) 2007-2016, The Tor Project, Inc. */
4 /* See LICENSE for licensing information */
6 extern const char tor_git_revision[];
8 /* Ordinarily defined in tor_main.c; this bit is just here to provide one
9 * since we're not linking to tor_main.c */
10 const char tor_git_revision[] = "";
12 /**
13 * \file test_common.c
14 * \brief Common pieces to implement unit tests.
15 **/
17 #include "orconfig.h"
18 #include "or.h"
19 #include "control.h"
20 #include "config.h"
21 #include "rephist.h"
22 #include "backtrace.h"
23 #include "test.h"
25 #include <stdio.h>
26 #ifdef HAVE_FCNTL_H
27 #include <fcntl.h>
28 #endif
30 #ifdef _WIN32
31 /* For mkdir() */
32 #include <direct.h>
33 #else
34 #include <dirent.h>
35 #endif
37 #include "or.h"
39 #ifdef USE_DMALLOC
40 #include <dmalloc.h>
41 #include <openssl/crypto.h>
42 #include "main.h"
43 #endif
45 /** Temporary directory (set up by setup_directory) under which we store all
46 * our files during testing. */
47 static char temp_dir[256];
48 #ifdef _WIN32
49 #define pid_t int
50 #endif
51 static pid_t temp_dir_setup_in_pid = 0;
53 /** Select and create the temporary directory we'll use to run our unit tests.
54 * Store it in <b>temp_dir</b>. Exit immediately if we can't create it.
55 * idempotent. */
56 static void
57 setup_directory(void)
59 static int is_setup = 0;
60 int r;
61 char rnd[256], rnd32[256];
62 if (is_setup) return;
64 /* Due to base32 limitation needs to be a multiple of 5. */
65 #define RAND_PATH_BYTES 5
66 crypto_rand(rnd, RAND_PATH_BYTES);
67 base32_encode(rnd32, sizeof(rnd32), rnd, RAND_PATH_BYTES);
69 #ifdef _WIN32
71 char buf[MAX_PATH];
72 const char *tmp = buf;
73 const char *extra_backslash = "";
74 /* If this fails, we're probably screwed anyway */
75 if (!GetTempPathA(sizeof(buf),buf))
76 tmp = "c:\\windows\\temp\\";
77 if (strcmpend(tmp, "\\")) {
78 /* According to MSDN, it should be impossible for GetTempPath to give us
79 * an answer that doesn't end with \. But let's make sure. */
80 extra_backslash = "\\";
82 tor_snprintf(temp_dir, sizeof(temp_dir),
83 "%s%stor_test_%d_%s", tmp, extra_backslash,
84 (int)getpid(), rnd32);
85 r = mkdir(temp_dir);
87 #else
88 tor_snprintf(temp_dir, sizeof(temp_dir), "/tmp/tor_test_%d_%s",
89 (int) getpid(), rnd32);
90 r = mkdir(temp_dir, 0700);
91 if (!r) {
92 /* undo sticky bit so tests don't get confused. */
93 r = chown(temp_dir, getuid(), getgid());
95 #endif
96 if (r) {
97 fprintf(stderr, "Can't create directory %s:", temp_dir);
98 perror("");
99 exit(1);
101 is_setup = 1;
102 temp_dir_setup_in_pid = getpid();
105 /** Return a filename relative to our testing temporary directory, based on
106 * name and suffix. If name is NULL, return the name of the testing temporary
107 * directory. */
108 static const char *
109 get_fname_suffix(const char *name, const char *suffix)
111 static char buf[1024];
112 setup_directory();
113 if (!name)
114 return temp_dir;
115 tor_snprintf(buf,sizeof(buf),"%s/%s%s%s",temp_dir,name,suffix ? "_" : "",
116 suffix ? suffix : "");
117 return buf;
120 /** Return a filename relative to our testing temporary directory. If name is
121 * NULL, return the name of the testing temporary directory. */
122 const char *
123 get_fname(const char *name)
125 return get_fname_suffix(name, NULL);
128 /** Return a filename with a random suffix, relative to our testing temporary
129 * directory. If name is NULL, return the name of the testing temporary
130 * directory, without any suffix. */
131 const char *
132 get_fname_rnd(const char *name)
134 char rnd[256], rnd32[256];
135 crypto_rand(rnd, RAND_PATH_BYTES);
136 base32_encode(rnd32, sizeof(rnd32), rnd, RAND_PATH_BYTES);
137 return get_fname_suffix(name, rnd32);
140 /* Remove a directory and all of its subdirectories */
141 static void
142 rm_rf(const char *dir)
144 struct stat st;
145 smartlist_t *elements;
147 elements = tor_listdir(dir);
148 if (elements) {
149 SMARTLIST_FOREACH_BEGIN(elements, const char *, cp) {
150 char *tmp = NULL;
151 tor_asprintf(&tmp, "%s"PATH_SEPARATOR"%s", dir, cp);
152 if (0 == stat(tmp,&st) && (st.st_mode & S_IFDIR)) {
153 rm_rf(tmp);
154 } else {
155 if (unlink(tmp)) {
156 fprintf(stderr, "Error removing %s: %s\n", tmp, strerror(errno));
159 tor_free(tmp);
160 } SMARTLIST_FOREACH_END(cp);
161 SMARTLIST_FOREACH(elements, char *, cp, tor_free(cp));
162 smartlist_free(elements);
164 if (rmdir(dir))
165 fprintf(stderr, "Error removing directory %s: %s\n", dir, strerror(errno));
168 /** Remove all files stored under the temporary directory, and the directory
169 * itself. Called by atexit(). */
170 static void
171 remove_directory(void)
173 if (getpid() != temp_dir_setup_in_pid) {
174 /* Only clean out the tempdir when the main process is exiting. */
175 return;
178 rm_rf(temp_dir);
181 /** Define this if unit tests spend too much time generating public keys*/
182 #define CACHE_GENERATED_KEYS
184 #define N_PREGEN_KEYS 11
185 static crypto_pk_t *pregen_keys[N_PREGEN_KEYS];
186 static int next_key_idx;
188 /** Generate and return a new keypair for use in unit tests. If we're using
189 * the key cache optimization, we might reuse keys. "idx" is ignored.
190 * Our only guarantee is that we won't reuse a key till this function has been
191 * called several times. The order in which keys are returned is slightly
192 * randomized, so that tests that depend on a particular order will not be
193 * reliable. */
194 crypto_pk_t *
195 pk_generate(int idx)
197 (void) idx;
198 #ifdef CACHE_GENERATED_KEYS
199 /* Either skip 1 or 2 keys. */
200 next_key_idx += crypto_rand_int_range(1,3);
201 next_key_idx %= N_PREGEN_KEYS;
202 return crypto_pk_dup_key(pregen_keys[next_key_idx]);
203 #else
204 crypto_pk_t *result;
205 int res;
206 result = crypto_pk_new();
207 res = crypto_pk_generate_key__real(result);
208 tor_assert(!res);
209 return result;
210 #endif
213 #ifdef CACHE_GENERATED_KEYS
214 static int
215 crypto_pk_generate_key_with_bits__get_cached(crypto_pk_t *env, int bits)
217 if (bits != 1024)
218 return crypto_pk_generate_key_with_bits__real(env, bits);
220 crypto_pk_t *newkey = pk_generate(0);
221 crypto_pk_assign_(env, newkey);
222 crypto_pk_free(newkey);
223 return 0;
225 #endif
227 /** Free all storage used for the cached key optimization. */
228 static void
229 free_pregenerated_keys(void)
231 unsigned idx;
232 for (idx = 0; idx < N_PREGEN_KEYS; ++idx) {
233 if (pregen_keys[idx]) {
234 crypto_pk_free(pregen_keys[idx]);
235 pregen_keys[idx] = NULL;
240 static void *
241 passthrough_test_setup(const struct testcase_t *testcase)
243 /* Make sure the passthrough doesn't unintentionally fail or skip tests */
244 tor_assert(testcase->setup_data);
245 tor_assert(testcase->setup_data != (void*)TT_SKIP);
246 return testcase->setup_data;
248 static int
249 passthrough_test_cleanup(const struct testcase_t *testcase, void *ptr)
251 (void)testcase;
252 (void)ptr;
253 return 1;
256 static void *
257 ed25519_testcase_setup(const struct testcase_t *testcase)
259 crypto_ed25519_testing_force_impl(testcase->setup_data);
260 return testcase->setup_data;
262 static int
263 ed25519_testcase_cleanup(const struct testcase_t *testcase, void *ptr)
265 (void)testcase;
266 (void)ptr;
267 crypto_ed25519_testing_restore_impl();
268 return 1;
270 const struct testcase_setup_t ed25519_test_setup = {
271 ed25519_testcase_setup, ed25519_testcase_cleanup
274 const struct testcase_setup_t passthrough_setup = {
275 passthrough_test_setup, passthrough_test_cleanup
278 static void
279 an_assertion_failed(void)
281 tinytest_set_test_failed_();
284 /** Main entry point for unit test code: parse the command line, and run
285 * some unit tests. */
287 main(int c, const char **v)
289 or_options_t *options;
290 char *errmsg = NULL;
291 int i, i_out;
292 int loglevel = LOG_ERR;
293 int accel_crypto = 0;
295 /* We must initialise logs before we call tor_assert() */
296 init_logging(1);
298 #ifdef USE_DMALLOC
300 int r = CRYPTO_set_mem_ex_functions(tor_malloc_, tor_realloc_, tor_free_);
301 tor_assert(r);
303 #endif
305 update_approx_time(time(NULL));
306 options = options_new();
307 tor_threads_init();
309 network_init();
311 monotime_init();
313 struct tor_libevent_cfg cfg;
314 memset(&cfg, 0, sizeof(cfg));
315 tor_libevent_initialize(&cfg);
317 control_initialize_event_queue();
318 configure_backtrace_handler(get_version());
320 for (i_out = i = 1; i < c; ++i) {
321 if (!strcmp(v[i], "--warn")) {
322 loglevel = LOG_WARN;
323 } else if (!strcmp(v[i], "--notice")) {
324 loglevel = LOG_NOTICE;
325 } else if (!strcmp(v[i], "--info")) {
326 loglevel = LOG_INFO;
327 } else if (!strcmp(v[i], "--debug")) {
328 loglevel = LOG_DEBUG;
329 } else if (!strcmp(v[i], "--accel")) {
330 accel_crypto = 1;
331 } else {
332 v[i_out++] = v[i];
335 c = i_out;
338 log_severity_list_t s;
339 memset(&s, 0, sizeof(s));
340 set_log_severity_config(loglevel, LOG_ERR, &s);
341 /* ALWAYS log bug warnings. */
342 s.masks[LOG_WARN-LOG_ERR] |= LD_BUG;
343 add_stream_log(&s, "", fileno(stdout));
346 options->command = CMD_RUN_UNITTESTS;
347 if (crypto_global_init(accel_crypto, NULL, NULL)) {
348 printf("Can't initialize crypto subsystem; exiting.\n");
349 return 1;
351 crypto_set_tls_dh_prime();
352 if (crypto_seed_rng() < 0) {
353 printf("Couldn't seed RNG; exiting.\n");
354 return 1;
356 rep_hist_init();
357 setup_directory();
358 options_init(options);
359 options->DataDirectory = tor_strdup(temp_dir);
360 options->EntryStatistics = 1;
361 if (set_options(options, &errmsg) < 0) {
362 printf("Failed to set initial options: %s\n", errmsg);
363 tor_free(errmsg);
364 return 1;
366 tor_set_failed_assertion_callback(an_assertion_failed);
368 #ifdef CACHE_GENERATED_KEYS
369 for (i = 0; i < N_PREGEN_KEYS; ++i) {
370 pregen_keys[i] = crypto_pk_new();
371 int r = crypto_pk_generate_key(pregen_keys[i]);
372 tor_assert(r == 0);
374 MOCK(crypto_pk_generate_key_with_bits,
375 crypto_pk_generate_key_with_bits__get_cached);
376 #endif
378 atexit(remove_directory);
380 int have_failed = (tinytest_main(c, v, testgroups) != 0);
382 free_pregenerated_keys();
383 #ifdef USE_DMALLOC
384 tor_free_all(0);
385 dmalloc_log_unfreed();
386 #endif
387 crypto_global_cleanup();
389 if (have_failed)
390 return 1;
391 else
392 return 0;