test-commands.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  1. /*
  2. * Test code for lib/command.c
  3. *
  4. * Copyright (C) 2013 by Open Source Routing.
  5. * Copyright (C) 2013 by Internet Systems Consortium, Inc. ("ISC")
  6. *
  7. * This program reads in a list of commandlines from stdin
  8. * and calls all the public functions of lib/command.c for
  9. * both the given command lines and fuzzed versions thereof.
  10. *
  11. * The output is currently not validated but only logged. It can
  12. * be diffed to find regressions between versions.
  13. *
  14. * Quagga is free software; you can redistribute it and/or modify it
  15. * under the terms of the GNU General Public License as published by the
  16. * Free Software Foundation; either version 2, or (at your option) any
  17. * later version.
  18. *
  19. * Quagga is distributed in the hope that it will be useful, but
  20. * WITHOUT ANY WARRANTY; without even the implied warranty of
  21. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  22. * General Public License for more details.
  23. *
  24. * You should have received a copy of the GNU General Public License
  25. * along with Quagga; see the file COPYING. If not, write to the Free
  26. * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
  27. * 02111-1307, USA.
  28. */
  29. /* Example use for testing:
  30. * ./testcommands -e 0 < testcommands.in | \
  31. * diff -au - testcommands.refout
  32. */
  33. #define REALLY_NEED_PLAIN_GETOPT 1
  34. #include <zebra.h>
  35. #include <stdio.h>
  36. #include <stdlib.h>
  37. #include <unistd.h>
  38. #include "command.h"
  39. #include "memory.h"
  40. #include "vector.h"
  41. #include "prng.h"
  42. extern vector cmdvec;
  43. extern struct cmd_node vty_node;
  44. extern void test_init_cmd(void); /* provided in test-commands-defun.c */
  45. struct thread_master *master; /* dummy for libzebra*/
  46. static vector test_cmds;
  47. static char test_buf[32768];
  48. static struct cmd_node bgp_node =
  49. {
  50. BGP_NODE,
  51. "%s(config-router)# ",
  52. };
  53. static struct cmd_node rip_node =
  54. {
  55. RIP_NODE,
  56. "%s(config-router)# ",
  57. };
  58. static struct cmd_node isis_node =
  59. {
  60. ISIS_NODE,
  61. "%s(config-router)# ",
  62. };
  63. static struct cmd_node interface_node =
  64. {
  65. INTERFACE_NODE,
  66. "%s(config-if)# ",
  67. };
  68. static struct cmd_node rmap_node =
  69. {
  70. RMAP_NODE,
  71. "%s(config-route-map)# "
  72. };
  73. static struct cmd_node zebra_node =
  74. {
  75. ZEBRA_NODE,
  76. "%s(config-router)# "
  77. };
  78. static struct cmd_node bgp_vpnv4_node =
  79. {
  80. BGP_VPNV4_NODE,
  81. "%s(config-router-af)# "
  82. };
  83. static struct cmd_node bgp_vpnv6_node =
  84. {
  85. BGP_VPNV6_NODE,
  86. "%s(config-router-af-vpnv6)# ",
  87. };
  88. static struct cmd_node bgp_ipv4_node =
  89. {
  90. BGP_IPV4_NODE,
  91. "%s(config-router-af)# "
  92. };
  93. static struct cmd_node bgp_ipv4m_node =
  94. {
  95. BGP_IPV4M_NODE,
  96. "%s(config-router-af)# "
  97. };
  98. static struct cmd_node bgp_ipv6_node =
  99. {
  100. BGP_IPV6_NODE,
  101. "%s(config-router-af)# "
  102. };
  103. static struct cmd_node bgp_ipv6m_node =
  104. {
  105. BGP_IPV6M_NODE,
  106. "%s(config-router-af)# "
  107. };
  108. static struct cmd_node bgp_encap_node =
  109. {
  110. BGP_ENCAP_NODE,
  111. "%s(config-router-af-encap)# ",
  112. };
  113. static struct cmd_node bgp_encapv6_node =
  114. {
  115. BGP_ENCAPV6_NODE,
  116. "%s(config-router-af-encapv6)# ",
  117. };
  118. static struct cmd_node ospf_node =
  119. {
  120. OSPF_NODE,
  121. "%s(config-router)# "
  122. };
  123. static struct cmd_node ripng_node =
  124. {
  125. RIPNG_NODE,
  126. "%s(config-router)# "
  127. };
  128. static struct cmd_node ospf6_node =
  129. {
  130. OSPF6_NODE,
  131. "%s(config-ospf6)# "
  132. };
  133. static struct cmd_node babel_node =
  134. {
  135. BABEL_NODE,
  136. "%s(config-babel)# "
  137. };
  138. static struct cmd_node keychain_node =
  139. {
  140. KEYCHAIN_NODE,
  141. "%s(config-keychain)# "
  142. };
  143. static struct cmd_node keychain_key_node =
  144. {
  145. KEYCHAIN_KEY_NODE,
  146. "%s(config-keychain-key)# "
  147. };
  148. static struct cmd_node link_params_node =
  149. {
  150. LINK_PARAMS_NODE,
  151. "%s(config-link-params)# ",
  152. };
  153. static int
  154. test_callback(struct cmd_element *cmd, struct vty *vty, int argc, const char *argv[])
  155. {
  156. int offset;
  157. int rv;
  158. int i;
  159. offset = 0;
  160. rv = snprintf(test_buf, sizeof(test_buf), "'%s'", cmd->string);
  161. if (rv < 0)
  162. abort();
  163. offset += rv;
  164. for (i = 0; i < argc; i++)
  165. {
  166. rv = snprintf(test_buf + offset, sizeof(test_buf) - offset, "%s'%s'",
  167. (i == 0) ? ": " : ", ", argv[i]);
  168. if (rv < 0)
  169. abort();
  170. offset += rv;
  171. }
  172. return CMD_SUCCESS;
  173. }
  174. static void
  175. test_load(void)
  176. {
  177. char line[4096];
  178. test_cmds = vector_init(VECTOR_MIN_SIZE);
  179. while (fgets(line, sizeof(line), stdin) != NULL)
  180. {
  181. if (strlen(line))
  182. line[strlen(line) - 1] = '\0';
  183. if (line[0] == '#')
  184. continue;
  185. vector_set(test_cmds, XSTRDUP(MTYPE_STRVEC, line));
  186. }
  187. }
  188. static void
  189. test_init(void)
  190. {
  191. unsigned int node;
  192. unsigned int i;
  193. struct cmd_node *cnode;
  194. struct cmd_element *cmd;
  195. cmd_init(1);
  196. install_node (&bgp_node, NULL);
  197. install_node (&rip_node, NULL);
  198. install_node (&interface_node, NULL);
  199. install_node (&rmap_node, NULL);
  200. install_node (&zebra_node, NULL);
  201. install_node (&bgp_vpnv4_node, NULL);
  202. install_node (&bgp_vpnv6_node, NULL);
  203. install_node (&bgp_ipv4_node, NULL);
  204. install_node (&bgp_ipv4m_node, NULL);
  205. install_node (&bgp_ipv6_node, NULL);
  206. install_node (&bgp_ipv6m_node, NULL);
  207. install_node (&bgp_encap_node, NULL);
  208. install_node (&bgp_encapv6_node, NULL);
  209. install_node (&ospf_node, NULL);
  210. install_node (&ripng_node, NULL);
  211. install_node (&ospf6_node, NULL);
  212. install_node (&babel_node, NULL);
  213. install_node (&keychain_node, NULL);
  214. install_node (&keychain_key_node, NULL);
  215. install_node (&isis_node, NULL);
  216. install_node (&vty_node, NULL);
  217. install_node (&link_params_node, NULL);
  218. //install_node (&zebra_if_defaults_node, NULL);
  219. test_init_cmd();
  220. for (node = 0; node < vector_active(cmdvec); node++)
  221. if ((cnode = vector_slot(cmdvec, node)) != NULL)
  222. for (i = 0; i < vector_active(cnode->cmd_vector); i++)
  223. if ((cmd = vector_slot(cnode->cmd_vector, i)) != NULL)
  224. {
  225. cmd->daemon = 0;
  226. cmd->func = test_callback;
  227. }
  228. test_load();
  229. vty_init_vtysh();
  230. }
  231. static void
  232. test_terminate(void)
  233. {
  234. unsigned int i;
  235. vty_terminate();
  236. for (i = 0; i < vector_active(test_cmds); i++)
  237. XFREE(MTYPE_STRVEC, vector_slot(test_cmds, i));
  238. vector_free(test_cmds);
  239. cmd_terminate();
  240. }
  241. static void
  242. test_run(struct prng *prng, struct vty *vty, const char *cmd, unsigned int edit_dist, unsigned int node_index, int verbose)
  243. {
  244. const char *test_str;
  245. vector vline;
  246. int ret;
  247. unsigned int i;
  248. char **completions;
  249. unsigned int j;
  250. struct cmd_node *cnode;
  251. vector descriptions;
  252. int appended_null;
  253. int no_match;
  254. test_str = prng_fuzz(prng, cmd, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_:. /", edit_dist);
  255. vline = cmd_make_strvec(test_str);
  256. if (vline == NULL)
  257. return;
  258. appended_null = 0;
  259. for (i = 0; i < vector_active(cmdvec); i++)
  260. if ((cnode = vector_slot(cmdvec, i)) != NULL)
  261. {
  262. if (node_index != (unsigned int)-1 && i != node_index)
  263. continue;
  264. if (appended_null)
  265. {
  266. vector_unset(vline, vector_active(vline) - 1);
  267. appended_null = 0;
  268. }
  269. vty->node = cnode->node;
  270. test_buf[0] = '\0';
  271. ret = cmd_execute_command(vline, vty, NULL, 0);
  272. no_match = (ret == CMD_ERR_NO_MATCH);
  273. if (verbose || !no_match)
  274. printf("execute relaxed '%s'@%d: rv==%d%s%s\n",
  275. test_str,
  276. cnode->node,
  277. ret,
  278. (test_buf[0] != '\0') ? ", " : "",
  279. test_buf);
  280. vty->node = cnode->node;
  281. test_buf[0] = '\0';
  282. ret = cmd_execute_command_strict(vline, vty, NULL);
  283. if (verbose || !no_match)
  284. printf("execute strict '%s'@%d: rv==%d%s%s\n",
  285. test_str,
  286. cnode->node,
  287. ret,
  288. (test_buf[0] != '\0') ? ", " : "",
  289. test_buf);
  290. if (isspace((int) test_str[strlen(test_str) - 1]))
  291. {
  292. vector_set (vline, NULL);
  293. appended_null = 1;
  294. }
  295. vty->node = cnode->node;
  296. completions = cmd_complete_command(vline, vty, &ret);
  297. if (verbose || !no_match)
  298. printf("complete '%s'@%d: rv==%d\n",
  299. test_str,
  300. cnode->node,
  301. ret);
  302. if (completions != NULL)
  303. {
  304. for (j = 0; completions[j] != NULL; j++)
  305. {
  306. printf(" '%s'\n", completions[j]);
  307. XFREE(MTYPE_TMP, completions[j]);
  308. }
  309. XFREE(MTYPE_VECTOR_INDEX, completions);
  310. }
  311. vty->node = cnode->node;
  312. descriptions = cmd_describe_command(vline, vty, &ret);
  313. if (verbose || !no_match)
  314. printf("describe '%s'@%d: rv==%d\n",
  315. test_str,
  316. cnode->node,
  317. ret);
  318. if (descriptions != NULL)
  319. {
  320. for (j = 0; j < vector_active(descriptions); j++)
  321. {
  322. struct cmd_token *cmd = vector_slot(descriptions, j);
  323. printf(" '%s' '%s'\n", cmd->cmd, cmd->desc);
  324. }
  325. vector_free(descriptions);
  326. }
  327. }
  328. cmd_free_strvec(vline);
  329. }
  330. int
  331. main(int argc, char **argv)
  332. {
  333. int opt;
  334. struct prng *prng;
  335. struct vty *vty;
  336. unsigned int edit_distance;
  337. unsigned int max_edit_distance;
  338. unsigned int node_index;
  339. int verbose;
  340. unsigned int test_cmd;
  341. unsigned int iteration;
  342. unsigned int num_iterations;
  343. max_edit_distance = 3;
  344. node_index = -1;
  345. verbose = 0;
  346. while ((opt = getopt(argc, argv, "e:n:v")) != -1)
  347. {
  348. switch (opt)
  349. {
  350. case 'e':
  351. max_edit_distance = atoi(optarg);
  352. break;
  353. case 'n':
  354. node_index = atoi(optarg);
  355. break;
  356. case 'v':
  357. verbose++;
  358. break;
  359. default:
  360. fprintf(stderr, "Usage: %s [-e <edit_dist>] [-n <node_idx>] [-v]\n", argv[0]);
  361. exit(1);
  362. break;
  363. }
  364. }
  365. test_init();
  366. prng = prng_new(0);
  367. vty = vty_new();
  368. vty->type = VTY_TERM;
  369. fprintf(stderr, "Progress:\n0/%u", vector_active(test_cmds));
  370. for (test_cmd = 0; test_cmd < vector_active(test_cmds); test_cmd++)
  371. {
  372. for (edit_distance = 0;
  373. edit_distance <= max_edit_distance;
  374. edit_distance++)
  375. {
  376. num_iterations = 1 << edit_distance;
  377. num_iterations *= num_iterations * num_iterations;
  378. for (iteration = 0; iteration < num_iterations; iteration++)
  379. test_run(prng, vty, vector_slot(test_cmds, test_cmd), edit_distance, node_index, verbose);
  380. }
  381. fprintf(stderr, "\r%u/%u", test_cmd + 1, vector_active(test_cmds));
  382. }
  383. fprintf(stderr, "\nDone.\n");
  384. vty_close(vty);
  385. prng_free(prng);
  386. test_terminate();
  387. return 0;
  388. }