Commit 7322de15 authored by Nick Mathewson's avatar Nick Mathewson 🎨
Browse files

Split the slow unit tests into their own binary

This can run in parallel with the faster ones and the other tests.
parent 420037dc
......@@ -160,11 +160,13 @@ cscope.*
/src/test/bench
/src/test/bench.exe
/src/test/test
/src/test/test-slow
/src/test/test-bt-cl
/src/test/test-child
/src/test/test-ntor-cl
/src/test/test_workqueue
/src/test/test.exe
/src/test/test-slow.exe
/src/test/test-bt-cl.exe
/src/test/test-child.exe
/src/test/test-ntor-cl.exe
......
o Testing:
- Move the slower unit tests into a new "./src/test/test-slow" binary
that can be run independently of the other tests. Closes ticket 13243.
TESTS += src/test/test
TESTS += src/test/test src/test/test-slow
noinst_PROGRAMS+= src/test/bench
if UNITTESTS_ENABLED
noinst_PROGRAMS+= src/test/test src/test/test-child src/test/test_workqueue
noinst_PROGRAMS+= \
src/test/test \
src/test/test-slow \
src/test/test-child \
src/test/test_workqueue
endif
src_test_AM_CPPFLAGS = -DSHARE_DATADIR="\"$(datadir)\"" \
......@@ -57,8 +61,17 @@ src_test_test_SOURCES = \
src/test/test_status.c \
src/test/test_threads.c \
src/test/test_util.c \
src/test/testing_common.c \
src/ext/tinytest.c
src_test_test_slow_SOURCES = \
src/test/test_slow.c \
src/test/test_crypto_slow.c \
src/test/test_util_slow.c \
src/test/testing_common.c \
src/ext/tinytest.c
src_test_test_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
src_test_test_CPPFLAGS= $(src_test_AM_CPPFLAGS)
......@@ -80,6 +93,11 @@ src_test_test_LDADD = src/or/libtor-testing.a src/common/libor-testing.a \
@TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ \
@TOR_SYSTEMD_LIBS@
src_test_test_slow_CPPFLAGS = $(src_test_test_CPPFLAGS)
src_test_test_slow_CFLAGS = $(src_test_test_CFLAGS)
src_test_test_slow_LDADD = $(src_test_test_LDADD)
src_test_test_slow_LDFLAGS = $(src_test_test_LDFLAGS)
src_test_bench_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \
@TOR_LDFLAGS_libevent@
src_test_bench_LDADD = src/or/libtor.a src/common/libor.a \
......
......@@ -3,10 +3,6 @@
* Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/* Ordinarily defined in tor_main.c; this bit is just here to provide one
* since we're not linking to tor_main.c */
const char tor_git_revision[] = "";
/**
* \file test.c
* \brief Unit tests for many pieces of the lower level Tor modules.
......@@ -67,171 +63,6 @@ double fabs(double x);
#include "crypto_curve25519.h"
#include "onion_ntor.h"
#ifdef USE_DMALLOC
#include <dmalloc.h>
#include <openssl/crypto.h>
#include "main.h"
#endif
/** Set to true if any unit test has failed. Mostly, this is set by the macros
* in test.h */
int have_failed = 0;
/** Temporary directory (set up by setup_directory) under which we store all
* our files during testing. */
static char temp_dir[256];
#ifdef _WIN32
#define pid_t int
#endif
static pid_t temp_dir_setup_in_pid = 0;
/** Select and create the temporary directory we'll use to run our unit tests.
* Store it in <b>temp_dir</b>. Exit immediately if we can't create it.
* idempotent. */
static void
setup_directory(void)
{
static int is_setup = 0;
int r;
char rnd[256], rnd32[256];
if (is_setup) return;
/* Due to base32 limitation needs to be a multiple of 5. */
#define RAND_PATH_BYTES 5
crypto_rand(rnd, RAND_PATH_BYTES);
base32_encode(rnd32, sizeof(rnd32), rnd, RAND_PATH_BYTES);
#ifdef _WIN32
{
char buf[MAX_PATH];
const char *tmp = buf;
const char *extra_backslash = "";
/* If this fails, we're probably screwed anyway */
if (!GetTempPathA(sizeof(buf),buf))
tmp = "c:\\windows\\temp\\";
if (strcmpend(tmp, "\\")) {
/* According to MSDN, it should be impossible for GetTempPath to give us
* an answer that doesn't end with \. But let's make sure. */
extra_backslash = "\\";
}
tor_snprintf(temp_dir, sizeof(temp_dir),
"%s%stor_test_%d_%s", tmp, extra_backslash,
(int)getpid(), rnd32);
r = mkdir(temp_dir);
}
#else
tor_snprintf(temp_dir, sizeof(temp_dir), "/tmp/tor_test_%d_%s",
(int) getpid(), rnd32);
r = mkdir(temp_dir, 0700);
if (!r) {
/* undo sticky bit so tests don't get confused. */
r = chown(temp_dir, getuid(), getgid());
}
#endif
if (r) {
fprintf(stderr, "Can't create directory %s:", temp_dir);
perror("");
exit(1);
}
is_setup = 1;
temp_dir_setup_in_pid = getpid();
}
/** Return a filename relative to our testing temporary directory */
const char *
get_fname(const char *name)
{
static char buf[1024];
setup_directory();
if (!name)
return temp_dir;
tor_snprintf(buf,sizeof(buf),"%s/%s",temp_dir,name);
return buf;
}
/* Remove a directory and all of its subdirectories */
static void
rm_rf(const char *dir)
{
struct stat st;
smartlist_t *elements;
elements = tor_listdir(dir);
if (elements) {
SMARTLIST_FOREACH_BEGIN(elements, const char *, cp) {
char *tmp = NULL;
tor_asprintf(&tmp, "%s"PATH_SEPARATOR"%s", dir, cp);
if (0 == stat(tmp,&st) && (st.st_mode & S_IFDIR)) {
rm_rf(tmp);
} else {
if (unlink(tmp)) {
fprintf(stderr, "Error removing %s: %s\n", tmp, strerror(errno));
}
}
tor_free(tmp);
} SMARTLIST_FOREACH_END(cp);
SMARTLIST_FOREACH(elements, char *, cp, tor_free(cp));
smartlist_free(elements);
}
if (rmdir(dir))
fprintf(stderr, "Error removing directory %s: %s\n", dir, strerror(errno));
}
/** Remove all files stored under the temporary directory, and the directory
* itself. Called by atexit(). */
static void
remove_directory(void)
{
if (getpid() != temp_dir_setup_in_pid) {
/* Only clean out the tempdir when the main process is exiting. */
return;
}
rm_rf(temp_dir);
}
/** Define this if unit tests spend too much time generating public keys*/
#undef CACHE_GENERATED_KEYS
static crypto_pk_t *pregen_keys[5] = {NULL, NULL, NULL, NULL, NULL};
#define N_PREGEN_KEYS ARRAY_LENGTH(pregen_keys)
/** Generate and return a new keypair for use in unit tests. If we're using
* the key cache optimization, we might reuse keys: we only guarantee that
* keys made with distinct values for <b>idx</b> are different. The value of
* <b>idx</b> must be at least 0, and less than N_PREGEN_KEYS. */
crypto_pk_t *
pk_generate(int idx)
{
#ifdef CACHE_GENERATED_KEYS
tor_assert(idx < N_PREGEN_KEYS);
if (! pregen_keys[idx]) {
pregen_keys[idx] = crypto_pk_new();
tor_assert(!crypto_pk_generate_key(pregen_keys[idx]));
}
return crypto_pk_dup_key(pregen_keys[idx]);
#else
crypto_pk_t *result;
(void) idx;
result = crypto_pk_new();
tor_assert(!crypto_pk_generate_key(result));
return result;
#endif
}
/** Free all storage used for the cached key optimization. */
static void
free_pregenerated_keys(void)
{
unsigned idx;
for (idx = 0; idx < N_PREGEN_KEYS; ++idx) {
if (pregen_keys[idx]) {
crypto_pk_free(pregen_keys[idx]);
pregen_keys[idx] = NULL;
}
}
}
/** Run unit tests for the onion handshake code. */
static void
test_onion_handshake(void *arg)
......@@ -1258,23 +1089,6 @@ test_stats(void *arg)
tor_free(s);
}
static void *
passthrough_test_setup(const struct testcase_t *testcase)
{
return testcase->setup_data;
}
static int
passthrough_test_cleanup(const struct testcase_t *testcase, void *ptr)
{
(void)testcase;
(void)ptr;
return 1;
}
const struct testcase_setup_t passthrough_setup = {
passthrough_test_setup, passthrough_test_cleanup
};
#define ENT(name) \
{ #name, test_ ## name , 0, NULL, NULL }
#define FORK(name) \
......@@ -1335,7 +1149,7 @@ extern struct testcase_t status_tests[];
extern struct testcase_t thread_tests[];
extern struct testcase_t util_tests[];
static struct testgroup_t testgroups[] = {
struct testgroup_t testgroups[] = {
{ "", test_array },
{ "accounting/", accounting_tests },
{ "addr/", addr_tests },
......@@ -1379,86 +1193,3 @@ static struct testgroup_t testgroups[] = {
END_OF_GROUPS
};
/** Main entry point for unit test code: parse the command line, and run
* some unit tests. */
int
main(int c, const char **v)
{
or_options_t *options;
char *errmsg = NULL;
int i, i_out;
int loglevel = LOG_ERR;
int accel_crypto = 0;
#ifdef USE_DMALLOC
{
int r = CRYPTO_set_mem_ex_functions(tor_malloc_, tor_realloc_, tor_free_);
tor_assert(r);
}
#endif
update_approx_time(time(NULL));
options = options_new();
tor_threads_init();
init_logging(1);
configure_backtrace_handler(get_version());
for (i_out = i = 1; i < c; ++i) {
if (!strcmp(v[i], "--warn")) {
loglevel = LOG_WARN;
} else if (!strcmp(v[i], "--notice")) {
loglevel = LOG_NOTICE;
} else if (!strcmp(v[i], "--info")) {
loglevel = LOG_INFO;
} else if (!strcmp(v[i], "--debug")) {
loglevel = LOG_DEBUG;
} else if (!strcmp(v[i], "--accel")) {
accel_crypto = 1;
} else {
v[i_out++] = v[i];
}
}
c = i_out;
{
log_severity_list_t s;
memset(&s, 0, sizeof(s));
set_log_severity_config(loglevel, LOG_ERR, &s);
add_stream_log(&s, "", fileno(stdout));
}
options->command = CMD_RUN_UNITTESTS;
if (crypto_global_init(accel_crypto, NULL, NULL)) {
printf("Can't initialize crypto subsystem; exiting.\n");
return 1;
}
crypto_set_tls_dh_prime(NULL);
crypto_seed_rng(1);
rep_hist_init();
network_init();
setup_directory();
options_init(options);
options->DataDirectory = tor_strdup(temp_dir);
options->EntryStatistics = 1;
if (set_options(options, &errmsg) < 0) {
printf("Failed to set initial options: %s\n", errmsg);
tor_free(errmsg);
return 1;
}
atexit(remove_directory);
have_failed = (tinytest_main(c, v, testgroups) != 0);
free_pregenerated_keys();
#ifdef USE_DMALLOC
tor_free_all(0);
dmalloc_log_unfreed();
#endif
if (have_failed)
return 1;
else
return 0;
}
......@@ -5,7 +5,6 @@
#include "orconfig.h"
#define CRYPTO_CURVE25519_PRIVATE
#define CRYPTO_S2K_PRIVATE
#include "or.h"
#include "test.h"
#include "aes.h"
......@@ -14,8 +13,6 @@
#include "crypto_curve25519.h"
#include "crypto_ed25519.h"
#include "ed25519_vectors.inc"
#include "crypto_s2k.h"
#include "crypto_pwbox.h"
extern const char AUTHORITY_SIGNKEY_3[];
extern const char AUTHORITY_SIGNKEY_A_DIGEST[];
......@@ -712,379 +709,6 @@ test_crypto_formats(void *arg)
tor_free(data3);
}
/** Run unit tests for our secret-to-key passphrase hashing functionality. */
static void
test_crypto_s2k_rfc2440(void *arg)
{
char buf[29];
char buf2[29];
char *buf3 = NULL;
int i;
(void)arg;
memset(buf, 0, sizeof(buf));
memset(buf2, 0, sizeof(buf2));
buf3 = tor_malloc(65536);
memset(buf3, 0, 65536);
secret_to_key_rfc2440(buf+9, 20, "", 0, buf);
crypto_digest(buf2+9, buf3, 1024);
tt_mem_op(buf,OP_EQ, buf2, 29);
memcpy(buf,"vrbacrda",8);
memcpy(buf2,"vrbacrda",8);
buf[8] = 96;
buf2[8] = 96;
secret_to_key_rfc2440(buf+9, 20, "12345678", 8, buf);
for (i = 0; i < 65536; i += 16) {
memcpy(buf3+i, "vrbacrda12345678", 16);
}
crypto_digest(buf2+9, buf3, 65536);
tt_mem_op(buf,OP_EQ, buf2, 29);
done:
tor_free(buf3);
}
static void
run_s2k_tests(const unsigned flags, const unsigned type,
int speclen, const int keylen, int legacy)
{
uint8_t buf[S2K_MAXLEN], buf2[S2K_MAXLEN], buf3[S2K_MAXLEN];
int r;
size_t sz;
const char pw1[] = "You can't come in here unless you say swordfish!";
const char pw2[] = "Now, I give you one more guess.";
r = secret_to_key_new(buf, sizeof(buf), &sz,
pw1, strlen(pw1), flags);
tt_int_op(r, OP_EQ, S2K_OKAY);
tt_int_op(buf[0], OP_EQ, type);
tt_int_op(sz, OP_EQ, keylen + speclen);
if (legacy) {
memmove(buf, buf+1, sz-1);
--sz;
--speclen;
}
tt_int_op(S2K_OKAY, OP_EQ,
secret_to_key_check(buf, sz, pw1, strlen(pw1)));
tt_int_op(S2K_BAD_SECRET, OP_EQ,
secret_to_key_check(buf, sz, pw2, strlen(pw2)));
/* Move key to buf2, and clear it. */
memset(buf3, 0, sizeof(buf3));
memcpy(buf2, buf+speclen, keylen);
memset(buf+speclen, 0, sz - speclen);
/* Derivekey should produce the same results. */
tt_int_op(S2K_OKAY, OP_EQ,
secret_to_key_derivekey(buf3, keylen, buf, speclen, pw1, strlen(pw1)));
tt_mem_op(buf2, OP_EQ, buf3, keylen);
/* Derivekey with a longer output should fill the output. */
memset(buf2, 0, sizeof(buf2));
tt_int_op(S2K_OKAY, OP_EQ,
secret_to_key_derivekey(buf2, sizeof(buf2), buf, speclen,
pw1, strlen(pw1)));
tt_mem_op(buf2, OP_NE, buf3, sizeof(buf2));
memset(buf3, 0, sizeof(buf3));
tt_int_op(S2K_OKAY, OP_EQ,
secret_to_key_derivekey(buf3, sizeof(buf3), buf, speclen,
pw1, strlen(pw1)));
tt_mem_op(buf2, OP_EQ, buf3, sizeof(buf3));
tt_assert(!tor_mem_is_zero((char*)buf2+keylen, sizeof(buf2)-keylen));
done:
;
}
static void
test_crypto_s2k_general(void *arg)
{
const char *which = arg;
if (!strcmp(which, "scrypt")) {
run_s2k_tests(0, 2, 19, 32, 0);
} else if (!strcmp(which, "scrypt-low")) {
run_s2k_tests(S2K_FLAG_LOW_MEM, 2, 19, 32, 0);
} else if (!strcmp(which, "pbkdf2")) {
run_s2k_tests(S2K_FLAG_USE_PBKDF2, 1, 18, 20, 0);
} else if (!strcmp(which, "rfc2440")) {
run_s2k_tests(S2K_FLAG_NO_SCRYPT, 0, 10, 20, 0);
} else if (!strcmp(which, "rfc2440-legacy")) {
run_s2k_tests(S2K_FLAG_NO_SCRYPT, 0, 10, 20, 1);
} else {
tt_fail();
}
}
static void
test_crypto_s2k_errors(void *arg)
{
uint8_t buf[S2K_MAXLEN], buf2[S2K_MAXLEN];
size_t sz;
(void)arg;
/* Bogus specifiers: simple */
tt_int_op(S2K_BAD_LEN, OP_EQ,
secret_to_key_derivekey(buf, sizeof(buf),
(const uint8_t*)"", 0, "ABC", 3));
tt_int_op(S2K_BAD_ALGORITHM, OP_EQ,
secret_to_key_derivekey(buf, sizeof(buf),
(const uint8_t*)"\x10", 1, "ABC", 3));
tt_int_op(S2K_BAD_LEN, OP_EQ,
secret_to_key_derivekey(buf, sizeof(buf),
(const uint8_t*)"\x01\x02", 2, "ABC", 3));
tt_int_op(S2K_BAD_LEN, OP_EQ,
secret_to_key_check((const uint8_t*)"", 0, "ABC", 3));
tt_int_op(S2K_BAD_ALGORITHM, OP_EQ,
secret_to_key_check((const uint8_t*)"\x10", 1, "ABC", 3));
tt_int_op(S2K_BAD_LEN, OP_EQ,
secret_to_key_check((const uint8_t*)"\x01\x02", 2, "ABC", 3));
/* too long gets "BAD_LEN" too */
memset(buf, 0, sizeof(buf));
buf[0] = 2;
tt_int_op(S2K_BAD_LEN, OP_EQ,
secret_to_key_derivekey(buf2, sizeof(buf2),
buf, sizeof(buf), "ABC", 3));
/* Truncated output */
#ifdef HAVE_LIBSCRYPT_H
tt_int_op(S2K_TRUNCATED, OP_EQ, secret_to_key_new(buf, 50, &sz,
"ABC", 3, 0));
tt_int_op(S2K_TRUNCATED, OP_EQ, secret_to_key_new(buf, 50, &sz,
"ABC", 3, S2K_FLAG_LOW_MEM));
#endif
tt_int_op(S2K_TRUNCATED, OP_EQ, secret_to_key_new(buf, 37, &sz,
"ABC", 3, S2K_FLAG_USE_PBKDF2));
tt_int_op(S2K_TRUNCATED, OP_EQ, secret_to_key_new(buf, 29, &sz,
"ABC", 3, S2K_FLAG_NO_SCRYPT));
#ifdef HAVE_LIBSCRYPT_H
tt_int_op(S2K_TRUNCATED, OP_EQ, secret_to_key_make_specifier(buf, 18, 0));
tt_int_op(S2K_TRUNCATED, OP_EQ, secret_to_key_make_specifier(buf, 18,
S2K_FLAG_LOW_MEM));
#endif
tt_int_op(S2K_TRUNCATED, OP_EQ, secret_to_key_make_specifier(buf, 17,
S2K_FLAG_USE_PBKDF2));
tt_int_op(S2K_TRUNCATED, OP_EQ, secret_to_key_make_specifier(buf, 9,
S2K_FLAG_NO_SCRYPT));
/* Now try using type-specific bogus specifiers. */
/* It's a bad pbkdf2 buffer if it has an iteration count that would overflow
* int32_t. */
memset(buf, 0, sizeof(buf));
buf[0] = 1; /* pbkdf2 */
buf[17] = 100; /* 1<<100 is much bigger than INT32_MAX */
tt_int_op(S2K_BAD_PARAMS, OP_EQ,
secret_to_key_derivekey(buf2, sizeof(buf2),
buf, 18, "ABC", 3));
#ifdef HAVE_LIBSCRYPT_H
/* It's a bad scrypt buffer if N would overflow uint64 */
memset(buf, 0, sizeof(buf));
buf[0] = 2; /* scrypt */
buf[17] = 100; /* 1<<100 is much bigger than UINT64_MAX */
tt_int_op(S2K_BAD_PARAMS, OP_EQ,
secret_to_key_derivekey(buf2, sizeof(buf2),
buf, 19, "ABC", 3));
#endif
done:
;
}
static void
test_crypto_scrypt_vectors(void *arg)
{
char *mem_op_hex_tmp = NULL;
uint8_t spec[64], out[64];
(void)arg;
#ifndef HAVE_LIBSCRYPT_H
if (1)
tt_skip();
#endif
/* Test vectors from
http://tools.ietf.org/html/draft-josefsson-scrypt-kdf-00 section 11.
Note that the names of 'r' and 'N' are switched in that section. Or
possibly in libscrypt.
*/
base16_decode((char*)spec, sizeof(spec),
"0400", 4);
memset(out, 0x00, sizeof(out));
tt_int_op(64, OP_EQ,
secret_to_key_compute_key(out, 64, spec, 2, "", 0, 2));
test_memeq_hex(out,
"77d6576238657b203b19ca42c18a0497"
"f16b4844e3074ae8dfdffa3fede21442"
"fcd0069ded0948f8326a753a0fc81f17"
"e8d3e0fb2e0d3628cf35e20c38d18906");
base16_decode((char*)spec, sizeof(spec),
"4e61436c" "0A34", 12);
memset(out, 0x00, sizeof(out));
tt_int_op(64, OP_EQ,
secret_to_key_compute_key(out, 64, spec, 6, "password", 8, 2));
test_memeq_hex(out,
"fdbabe1c9d3472007856e7190d01e9fe"
"7c6ad7cbc8237830e77376634b373162"
"2eaf30d92e22a3886ff109279d9830da"
"c727afb94a83ee6d8360cbdfa2cc0640");
base16_decode((char*)spec, sizeof(spec),
"536f6469756d43686c6f72696465" "0e30", 32);
memset(out, 0x00, sizeof(out));
tt_int_op(64, OP_EQ,
secret_to_key_compute_key(out, 64,