commit f45e1fbd5b25735c75bed8767d9d50e279c4b63a Author: Nick Mathewson nickm@torproject.org Date: Thu Jul 18 14:38:31 2013 -0400
Start of a unit test for options_validate.
I added this so I could write a unit test for ServerTransportOptions, but it incidentally exercises the succeed-on-defaults case of options_validate too. --- src/or/config.c | 11 ++- src/or/config.h | 12 ++++ src/or/confparse.h | 2 +- src/test/include.am | 1 + src/test/test.c | 2 + src/test/test_options.c | 169 +++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 189 insertions(+), 8 deletions(-)
diff --git a/src/or/config.c b/src/or/config.c index 4ddced8..2218e50 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -9,6 +9,7 @@ * \brief Code to parse and interpret configuration files. **/
+#define CONFIG_PRIVATE #include "or.h" #include "addressmap.h" #include "channel.h" @@ -509,10 +510,6 @@ static const config_var_t testing_tor_network_defaults[] = { #ifdef _WIN32 static char *get_windows_conf_root(void); #endif -static int options_validate(or_options_t *old_options, - or_options_t *options, - or_options_t *default_options, - int from_setconf, char **msg); static int options_act_reversible(const or_options_t *old_options, char **msg); static int options_act(const or_options_t *old_options); static int options_transition_allowed(const or_options_t *old, @@ -556,7 +553,7 @@ static void config_maybe_load_geoip_files_(const or_options_t *options, #define OR_OPTIONS_MAGIC 9090909
/** Configuration format for or_options_t. */ -static config_format_t options_format = { +STATIC config_format_t options_format = { sizeof(or_options_t), OR_OPTIONS_MAGIC, STRUCT_OFFSET(or_options_t, magic_), @@ -712,7 +709,7 @@ get_short_version(void)
/** Release additional memory allocated in options */ -static void +STATIC void or_options_free(or_options_t *options) { if (!options) @@ -2349,7 +2346,7 @@ compute_publishserverdescriptor(or_options_t *options) * Log line should stay empty. If it's 0, then give us a default log * if there are no logs defined. */ -static int +STATIC int options_validate(or_options_t *old_options, or_options_t *options, or_options_t *default_options, int from_setconf, char **msg) { diff --git a/src/or/config.h b/src/or/config.h index 9910f18..16a8a35 100644 --- a/src/or/config.h +++ b/src/or/config.h @@ -116,5 +116,17 @@ smartlist_t *get_options_from_transport_options_line(const char *line, const char *transport); smartlist_t *get_options_for_server_transport(const char *transport);
+#ifdef CONFIG_PRIVATE +#ifdef TOR_UNIT_TESTS +extern struct config_format_t options_format; +#endif + +STATIC void or_options_free(or_options_t *options); +STATIC int options_validate(or_options_t *old_options, + or_options_t *options, + or_options_t *default_options, + int from_setconf, char **msg); +#endif + #endif
diff --git a/src/or/confparse.h b/src/or/confparse.h index d82e109..924ee0d 100644 --- a/src/or/confparse.h +++ b/src/or/confparse.h @@ -76,7 +76,7 @@ typedef int (*validate_fn_t)(void*,void*,int,char**); /** Information on the keys, value types, key-to-struct-member mappings, * variable descriptions, validation functions, and abbreviations for a * configuration or storage format. */ -typedef struct { +typedef struct config_format_t { size_t size; /**< Size of the struct that everything gets parsed into. */ uint32_t magic; /**< Required 'magic value' to make sure we have a struct * of the right type. */ diff --git a/src/test/include.am b/src/test/include.am index d616067..6271909 100644 --- a/src/test/include.am +++ b/src/test/include.am @@ -27,6 +27,7 @@ src_test_test_SOURCES = \ src/test/test_dir.c \ src/test/test_introduce.c \ src/test/test_microdesc.c \ + src/test/test_options.c \ src/test/test_pt.c \ src/test/test_replay.c \ src/test/test_util.c \ diff --git a/src/test/test.c b/src/test/test.c index d1c5b17..9640169 100644 --- a/src/test/test.c +++ b/src/test/test.c @@ -2134,6 +2134,7 @@ extern struct testcase_t replaycache_tests[]; extern struct testcase_t cell_format_tests[]; extern struct testcase_t circuitlist_tests[]; extern struct testcase_t cell_queue_tests[]; +extern struct testcase_t options_tests[];
static struct testgroup_t testgroups[] = { { "", test_array }, @@ -2151,6 +2152,7 @@ static struct testgroup_t testgroups[] = { { "replaycache/", replaycache_tests }, { "introduce/", introduce_tests }, { "circuitlist/", circuitlist_tests }, + { "options/", options_tests }, END_OF_GROUPS };
diff --git a/src/test/test_options.c b/src/test/test_options.c new file mode 100644 index 0000000..6beff25 --- /dev/null +++ b/src/test/test_options.c @@ -0,0 +1,169 @@ +/* Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#define CONFIG_PRIVATE +#include "or.h" +#include "confparse.h" +#include "config.h" +#include "test.h" + +typedef struct { + int severity; + uint32_t domain; + char *msg; +} logmsg_t; + +static smartlist_t *messages = NULL; + +static void +log_cback(int severity, uint32_t domain, const char *msg) +{ + logmsg_t *x = tor_malloc(sizeof(*x)); + x->severity = severity; + x->domain = domain; + x->msg = tor_strdup(msg); + if (!messages) + messages = smartlist_new(); + smartlist_add(messages, x); +} + +static void +setup_log_callback(void) +{ + log_severity_list_t lst; + memset(&lst, 0, sizeof(lst)); + lst.masks[LOG_ERR - LOG_ERR] = ~0; + lst.masks[LOG_WARN - LOG_ERR] = ~0; + lst.masks[LOG_NOTICE - LOG_ERR] = ~0; + add_callback_log(&lst, log_cback); +} + +static char * +dump_logs(void) +{ + smartlist_t *msgs; + char *out; + if (! messages) + return tor_strdup(""); + msgs = smartlist_new(); + SMARTLIST_FOREACH_BEGIN(messages, logmsg_t *, x) { + smartlist_add_asprintf(msgs, "[%s] %s", + log_level_to_string(x->severity), x->msg); + } SMARTLIST_FOREACH_END(x); + out = smartlist_join_strings(msgs, "", 0, NULL); + SMARTLIST_FOREACH(msgs, char *, cp, tor_free(cp)); + smartlist_free(msgs); + return out; +} + +static void +clear_log_messages(void) +{ + if (!messages) + return; + SMARTLIST_FOREACH(messages, logmsg_t *, m, + { tor_free(m->msg); tor_free(m); }); + smartlist_free(messages); + messages = NULL; +} + +static void +test_options_validate_impl(const char *configuration, + const char *expect_errmsg, + int expect_log_severity, + const char *expect_log) +{ + or_options_t *opt = options_new(); + or_options_t *dflt; + config_line_t *cl=NULL; + char *msg=NULL; + int r; + opt->command = CMD_RUN_TOR; + options_init(opt); + + dflt = config_dup(&options_format, opt); + clear_log_messages(); + + r = config_get_lines(configuration, &cl, 1); + tt_int_op(r, ==, 0); + + r = config_assign(&options_format, opt, cl, 0, 0, &msg); + tt_int_op(r, ==, 0); + + r = options_validate(NULL, opt, dflt, 0, &msg); + if (expect_errmsg && !msg) { + TT_DIE(("Expected error message <%s> from <%s>, but got none.", + expect_errmsg, configuration)); + } else if (expect_errmsg && !strstr(msg, expect_errmsg)) { + TT_DIE(("Expected error message <%s> from <%s>, but got <%s>.", + expect_errmsg, configuration, msg)); + } else if (!expect_errmsg && msg) { + TT_DIE(("Expected no error message from <%s> but got <%s>.", + configuration, msg)); + } + tt_int_op((r == 0), ==, (msg == NULL)); + + if (expect_log) { + int found = 0; + if (messages) { + SMARTLIST_FOREACH_BEGIN(messages, logmsg_t *, m) { + if (m->severity == expect_log_severity && + strstr(m->msg, expect_log)) { + found = 1; + break; + } + } SMARTLIST_FOREACH_END(m); + } + if (!found) { + tor_free(msg); + msg = dump_logs(); + TT_DIE(("Expected log message [%s] %s from <%s>, but got <%s>.", + log_level_to_string(expect_log_severity), expect_log, + configuration, msg)); + } + } + + done: + config_free_lines(cl); + or_options_free(opt); + or_options_free(dflt); + tor_free(msg); + clear_log_messages(); +} + +#define WANT_ERR(config, msg) \ + test_options_validate_impl((config), (msg), 0, NULL) +#define WANT_LOG(config, severity, msg) \ + test_options_validate_impl((config), NULL, (severity), (msg)) +#define WANT_ERR_LOG(config, msg, severity, logmsg) \ + test_options_validate_impl((config), (msg), (severity), (logmsg)) +#define OK(config) \ + test_options_validate_impl((config), NULL, 0, NULL) + +static void +test_options_validate(void *arg) +{ + (void)arg; + setup_log_callback(); + + WANT_ERR_LOG("ServerTransportOptions trebuchet", + "ServerTransportOptions did not parse", + LOG_WARN, "Too few arguments"); + OK("ServerTransportOptions trebuchet sling=snappy"); + OK("ServerTransportOptions trebuchet sling="); + WANT_ERR_LOG("ServerTransportOptions trebuchet slingsnappy", + "ServerTransportOptions did not parse", + LOG_WARN, ""slingsnappy" is not a k=v"); + +// done: + clear_log_messages(); + return; +} + +struct testcase_t options_tests[] = { + { "validate", test_options_validate, TT_FORK, NULL, NULL }, + END_OF_TESTCASES +}; +
tor-commits@lists.torproject.org