test_confmgr.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. /* Copyright (c) 2001-2004, Roger Dingledine.
  2. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
  3. * Copyright (c) 2007-2019, The Tor Project, Inc. */
  4. /* See LICENSE for licensing information */
  5. /*
  6. * Tests for confparse.c's features that support multiple configuration
  7. * formats and configuration objects.
  8. */
  9. #define CONFPARSE_PRIVATE
  10. #include "orconfig.h"
  11. #include "core/or/or.h"
  12. #include "lib/encoding/confline.h"
  13. #include "lib/confmgt/confparse.h"
  14. #include "test/test.h"
  15. #include "test/log_test_helpers.h"
  16. /*
  17. * Set up a few objects: a pasture_cfg is toplevel; it has a llama_cfg and an
  18. * alpaca_cfg.
  19. */
  20. typedef struct {
  21. uint32_t magic;
  22. char *address;
  23. int opentopublic;
  24. config_suite_t *subobjs;
  25. } pasture_cfg_t;
  26. typedef struct {
  27. char *llamaname;
  28. int cuteness;
  29. uint32_t magic;
  30. int eats_meat; /* deprecated; llamas are never carnivorous. */
  31. char *description; // derived from other fields.
  32. } llama_cfg_t;
  33. typedef struct {
  34. uint32_t magic;
  35. int fuzziness;
  36. char *alpacaname;
  37. int n_wings; /* deprecated; alpacas don't have wings. */
  38. } alpaca_cfg_t;
  39. /*
  40. * Make the above into configuration objects.
  41. */
  42. static pasture_cfg_t pasture_cfg_t_dummy;
  43. static llama_cfg_t llama_cfg_t_dummy;
  44. static alpaca_cfg_t alpaca_cfg_t_dummy;
  45. #define PV(name, type, dflt) \
  46. CONFIG_VAR_ETYPE(pasture_cfg_t, #name, type, name, 0, dflt)
  47. #define LV(name, type, dflt) \
  48. CONFIG_VAR_ETYPE(llama_cfg_t, #name, type, name, 0, dflt)
  49. #define AV(name, type, dflt) \
  50. CONFIG_VAR_ETYPE(alpaca_cfg_t, #name, type, name, 0, dflt)
  51. static const config_var_t pasture_vars[] = {
  52. PV(address, STRING, NULL),
  53. PV(opentopublic, BOOL, "1"),
  54. END_OF_CONFIG_VARS
  55. };
  56. static const config_var_t llama_vars[] =
  57. {
  58. LV(llamaname, STRING, NULL),
  59. LV(eats_meat, BOOL, NULL),
  60. LV(cuteness, POSINT, "100"),
  61. END_OF_CONFIG_VARS
  62. };
  63. static const config_var_t alpaca_vars[] =
  64. {
  65. AV(alpacaname, STRING, NULL),
  66. AV(fuzziness, POSINT, "50"),
  67. AV(n_wings, POSINT, "0"),
  68. END_OF_CONFIG_VARS
  69. };
  70. static config_deprecation_t llama_deprecations[] = {
  71. { "eats_meat", "Llamas are herbivores." },
  72. {NULL,NULL}
  73. };
  74. static config_deprecation_t alpaca_deprecations[] = {
  75. { "n_wings", "Alpacas are quadrupeds." },
  76. {NULL,NULL}
  77. };
  78. static int clear_llama_cfg_called = 0;
  79. static void
  80. clear_llama_cfg(const config_mgr_t *mgr, void *llamacfg)
  81. {
  82. (void)mgr;
  83. llama_cfg_t *lc = llamacfg;
  84. tor_free(lc->description);
  85. ++clear_llama_cfg_called;
  86. }
  87. static config_abbrev_t llama_abbrevs[] = {
  88. { "gracia", "cuteness", 0, 0 },
  89. { "gentillesse", "cuteness", 0, 0 },
  90. { NULL, NULL, 0, 0 },
  91. };
  92. static const config_format_t pasture_fmt = {
  93. sizeof(pasture_cfg_t),
  94. {
  95. "pasture_cfg_t",
  96. 8989,
  97. offsetof(pasture_cfg_t, magic)
  98. },
  99. .vars = pasture_vars,
  100. .config_suite_offset = offsetof(pasture_cfg_t, subobjs),
  101. };
  102. static const config_format_t llama_fmt = {
  103. sizeof(llama_cfg_t),
  104. {
  105. "llama_cfg_t",
  106. 0x11aa11,
  107. offsetof(llama_cfg_t, magic)
  108. },
  109. .vars = llama_vars,
  110. .config_suite_offset = -1,
  111. .deprecations = llama_deprecations,
  112. .abbrevs = llama_abbrevs,
  113. .clear_fn = clear_llama_cfg,
  114. };
  115. static const config_format_t alpaca_fmt = {
  116. sizeof(alpaca_cfg_t),
  117. {
  118. "alpaca_cfg_t",
  119. 0xa15aca,
  120. offsetof(alpaca_cfg_t, magic)
  121. },
  122. .vars = alpaca_vars,
  123. .config_suite_offset = -1,
  124. .deprecations = alpaca_deprecations,
  125. };
  126. #define LLAMA_IDX 0
  127. #define ALPACA_IDX 1
  128. static config_mgr_t *
  129. get_mgr(bool freeze)
  130. {
  131. config_mgr_t *mgr = config_mgr_new(&pasture_fmt);
  132. tt_int_op(LLAMA_IDX, OP_EQ, config_mgr_add_format(mgr, &llama_fmt));
  133. tt_int_op(ALPACA_IDX, OP_EQ, config_mgr_add_format(mgr, &alpaca_fmt));
  134. if (freeze)
  135. config_mgr_freeze(mgr);
  136. return mgr;
  137. done:
  138. config_mgr_free(mgr);
  139. return NULL;
  140. }
  141. static void
  142. test_confmgr_init(void *arg)
  143. {
  144. (void)arg;
  145. config_mgr_t *mgr = get_mgr(true);
  146. smartlist_t *vars = NULL;
  147. tt_ptr_op(mgr, OP_NE, NULL);
  148. vars = config_mgr_list_vars(mgr);
  149. tt_int_op(smartlist_len(vars), OP_EQ, 8); // 8 vars total.
  150. tt_str_op("cuteness", OP_EQ, config_find_option_name(mgr, "CUTENESS"));
  151. tt_str_op("cuteness", OP_EQ, config_find_option_name(mgr, "GRACIA"));
  152. smartlist_free(vars);
  153. vars = config_mgr_list_deprecated_vars(mgr); // 2 deprecated vars.
  154. tt_int_op(smartlist_len(vars), OP_EQ, 2);
  155. tt_assert(smartlist_contains_string(vars, "eats_meat"));
  156. tt_assert(smartlist_contains_string(vars, "n_wings"));
  157. tt_str_op("Llamas are herbivores.", OP_EQ,
  158. config_find_deprecation(mgr, "EATS_MEAT"));
  159. tt_str_op("Alpacas are quadrupeds.", OP_EQ,
  160. config_find_deprecation(mgr, "N_WINGS"));
  161. done:
  162. smartlist_free(vars);
  163. config_mgr_free(mgr);
  164. }
  165. static void
  166. test_confmgr_magic(void *args)
  167. {
  168. (void)args;
  169. // Every time we build a manager, it is supposed to get a different magic
  170. // number. Let's test that.
  171. config_mgr_t *mgr1 = get_mgr(true);
  172. config_mgr_t *mgr2 = get_mgr(true);
  173. config_mgr_t *mgr3 = get_mgr(true);
  174. pasture_cfg_t *p1 = NULL, *p2 = NULL, *p3 = NULL;
  175. tt_assert(mgr1);
  176. tt_assert(mgr2);
  177. tt_assert(mgr3);
  178. p1 = config_new(mgr1);
  179. p2 = config_new(mgr2);
  180. p3 = config_new(mgr3);
  181. tt_assert(p1);
  182. tt_assert(p2);
  183. tt_assert(p3);
  184. // By chance, two managers get the same magic with P=2^-32. Let's
  185. // make sure that at least two of them are different, so that our
  186. // odds of a false positive are 1/2^-64.
  187. tt_assert((p1->magic != p2->magic) || (p2->magic != p3->magic));
  188. done:
  189. config_free(mgr1, p1);
  190. config_free(mgr2, p2);
  191. config_free(mgr3, p3);
  192. config_mgr_free(mgr1);
  193. config_mgr_free(mgr2);
  194. config_mgr_free(mgr3);
  195. }
  196. static const char *simple_pasture =
  197. "LLamaname hugo\n"
  198. "Alpacaname daphne\n"
  199. "gentillesse 42\n"
  200. "address 123 Camelid ave\n";
  201. static void
  202. test_confmgr_parse(void *arg)
  203. {
  204. (void)arg;
  205. config_mgr_t *mgr = get_mgr(true);
  206. pasture_cfg_t *p = config_new(mgr);
  207. config_line_t *lines = NULL;
  208. char *msg = NULL;
  209. config_init(mgr, p); // set defaults.
  210. int r = config_get_lines(simple_pasture, &lines, 0);
  211. tt_int_op(r, OP_EQ, 0);
  212. r = config_assign(mgr, p, lines, 0, &msg);
  213. tt_int_op(r, OP_EQ, 0);
  214. tt_int_op(p->opentopublic, OP_EQ, 1);
  215. tt_str_op(p->address, OP_EQ, "123 Camelid ave");
  216. // We are using this API directly; modules outside confparse will, in the
  217. // future, not.
  218. const alpaca_cfg_t *ac = config_mgr_get_obj(mgr, p, ALPACA_IDX);
  219. const llama_cfg_t *lc = config_mgr_get_obj(mgr, p, LLAMA_IDX);
  220. tt_str_op(lc->llamaname, OP_EQ, "hugo");
  221. tt_str_op(ac->alpacaname, OP_EQ, "daphne");
  222. tt_int_op(lc->cuteness, OP_EQ, 42);
  223. tt_int_op(ac->fuzziness, OP_EQ, 50);
  224. // We set the description for the llama here, so that the clear function
  225. // can clear it. (Later we can do this in a verification function.)
  226. clear_llama_cfg_called = 0;
  227. llama_cfg_t *mut_lc = config_mgr_get_obj_mutable(mgr, p, LLAMA_IDX);
  228. mut_lc->description = tor_strdup("A llama named Hugo.");
  229. config_free(mgr, p);
  230. tt_int_op(clear_llama_cfg_called, OP_EQ, 1);
  231. done:
  232. config_free_lines(lines);
  233. config_free(mgr, p);
  234. config_mgr_free(mgr);
  235. tor_free(msg);
  236. }
  237. static void
  238. test_confmgr_dump(void *arg)
  239. {
  240. (void)arg;
  241. config_mgr_t *mgr = get_mgr(true);
  242. pasture_cfg_t *p = config_new(mgr);
  243. pasture_cfg_t *defaults = config_new(mgr);
  244. config_line_t *lines = NULL;
  245. char *msg = NULL;
  246. char *s = NULL;
  247. config_init(mgr, p); // set defaults.
  248. config_init(mgr, defaults); // set defaults.
  249. int r = config_get_lines(simple_pasture, &lines, 0);
  250. tt_int_op(r, OP_EQ, 0);
  251. r = config_assign(mgr, p, lines, 0, &msg);
  252. tt_int_op(r, OP_EQ, 0);
  253. s = config_dump(mgr, defaults, p, 1, 0);
  254. tt_str_op("address 123 Camelid ave\n"
  255. "alpacaname daphne\n"
  256. "cuteness 42\n"
  257. "llamaname hugo\n", OP_EQ, s);
  258. done:
  259. config_free_lines(lines);
  260. config_free(mgr, p);
  261. config_free(mgr, defaults);
  262. config_mgr_free(mgr);
  263. tor_free(msg);
  264. tor_free(s);
  265. }
  266. #define CONFMGR_TEST(name, flags) \
  267. { #name, test_confmgr_ ## name, flags, NULL, NULL }
  268. struct testcase_t confmgr_tests[] = {
  269. CONFMGR_TEST(init, 0),
  270. CONFMGR_TEST(magic, 0),
  271. CONFMGR_TEST(parse, 0),
  272. CONFMGR_TEST(dump, 0),
  273. END_OF_TESTCASES
  274. };