aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2013-07-18 14:38:31 -0400
committerNick Mathewson <nickm@torproject.org>2013-07-18 14:40:12 -0400
commitf45e1fbd5b25735c75bed8767d9d50e279c4b63a (patch)
treeed755a43790fa2b93ee0f932e00fc81fc82197c4
parentabedd35de08f2a2bd91d9d17e2f3cfd3b42ba52a (diff)
downloadtor-f45e1fbd5b25735c75bed8767d9d50e279c4b63a.tar
tor-f45e1fbd5b25735c75bed8767d9d50e279c4b63a.tar.gz
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.
-rw-r--r--src/or/config.c11
-rw-r--r--src/or/config.h12
-rw-r--r--src/or/confparse.h2
-rw-r--r--src/test/include.am1
-rw-r--r--src/test/test.c2
-rw-r--r--src/test/test_options.c169
6 files changed, 189 insertions, 8 deletions
diff --git a/src/or/config.c b/src/or/config.c
index 4ddced8a6..2218e5078 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 9910f1873..16a8a350d 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 d82e1096c..924ee0d94 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 d616067b8..62719091b 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 d1c5b176b..96401693c 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 000000000..6beff2567
--- /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
+};
+