[tor-commits] [tor/master] Start of a unit test for options_validate.

nickm at torproject.org nickm at torproject.org
Thu Jul 18 18:40:18 UTC 2013


commit f45e1fbd5b25735c75bed8767d9d50e279c4b63a
Author: Nick Mathewson <nickm at 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
+};
+



More information about the tor-commits mailing list