test-commands.c 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  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. #define REALLY_NEED_PLAIN_GETOPT 1
  30. #include <zebra.h>
  31. #include <stdio.h>
  32. #include <stdlib.h>
  33. #include <unistd.h>
  34. #include "command.h"
  35. #include "memory.h"
  36. #include "vector.h"
  37. #include "prng.h"
  38. extern vector cmdvec;
  39. extern struct cmd_node vty_node;
  40. extern void test_init_cmd(void); /* provided in test-commands-defun.c */
  41. struct thread_master *master; /* dummy for libzebra*/
  42. static vector test_cmds;
  43. static char test_buf[32768];
  44. static struct cmd_node bgp_node =
  45. {
  46. BGP_NODE,
  47. "%s(config-router)# ",
  48. };
  49. static struct cmd_node rip_node =
  50. {
  51. RIP_NODE,
  52. "%s(config-router)# ",
  53. };
  54. static struct cmd_node isis_node =
  55. {
  56. ISIS_NODE,
  57. "%s(config-router)# ",
  58. };
  59. static struct cmd_node interface_node =
  60. {
  61. INTERFACE_NODE,
  62. "%s(config-if)# ",
  63. };
  64. static struct cmd_node rmap_node =
  65. {
  66. RMAP_NODE,
  67. "%s(config-route-map)# "
  68. };
  69. static struct cmd_node zebra_node =
  70. {
  71. ZEBRA_NODE,
  72. "%s(config-router)# "
  73. };
  74. static struct cmd_node bgp_vpnv4_node =
  75. {
  76. BGP_VPNV4_NODE,
  77. "%s(config-router-af)# "
  78. };
  79. static struct cmd_node bgp_ipv4_node =
  80. {
  81. BGP_IPV4_NODE,
  82. "%s(config-router-af)# "
  83. };
  84. static struct cmd_node bgp_ipv4m_node =
  85. {
  86. BGP_IPV4M_NODE,
  87. "%s(config-router-af)# "
  88. };
  89. static struct cmd_node bgp_ipv6_node =
  90. {
  91. BGP_IPV6_NODE,
  92. "%s(config-router-af)# "
  93. };
  94. static struct cmd_node bgp_ipv6m_node =
  95. {
  96. BGP_IPV6M_NODE,
  97. "%s(config-router-af)# "
  98. };
  99. static struct cmd_node ospf_node =
  100. {
  101. OSPF_NODE,
  102. "%s(config-router)# "
  103. };
  104. static struct cmd_node ripng_node =
  105. {
  106. RIPNG_NODE,
  107. "%s(config-router)# "
  108. };
  109. static struct cmd_node ospf6_node =
  110. {
  111. OSPF6_NODE,
  112. "%s(config-ospf6)# "
  113. };
  114. static struct cmd_node babel_node =
  115. {
  116. BABEL_NODE,
  117. "%s(config-babel)# "
  118. };
  119. static struct cmd_node keychain_node =
  120. {
  121. KEYCHAIN_NODE,
  122. "%s(config-keychain)# "
  123. };
  124. static struct cmd_node keychain_key_node =
  125. {
  126. KEYCHAIN_KEY_NODE,
  127. "%s(config-keychain-key)# "
  128. };
  129. static int
  130. test_callback(struct cmd_element *cmd, struct vty *vty, int argc, const char *argv[])
  131. {
  132. int offset;
  133. int rv;
  134. int i;
  135. offset = 0;
  136. rv = snprintf(test_buf, sizeof(test_buf), "'%s'", cmd->string);
  137. if (rv < 0)
  138. abort();
  139. offset += rv;
  140. for (i = 0; i < argc; i++)
  141. {
  142. rv = snprintf(test_buf + offset, sizeof(test_buf) - offset, "%s'%s'",
  143. (i == 0) ? ": " : ", ", argv[i]);
  144. if (rv < 0)
  145. abort();
  146. offset += rv;
  147. }
  148. return CMD_SUCCESS;
  149. }
  150. static void
  151. test_load(void)
  152. {
  153. char line[4096];
  154. test_cmds = vector_init(VECTOR_MIN_SIZE);
  155. while (fgets(line, sizeof(line), stdin) != NULL)
  156. {
  157. if (strlen(line))
  158. line[strlen(line) - 1] = '\0';
  159. if (line[0] == '#')
  160. continue;
  161. vector_set(test_cmds, XSTRDUP(MTYPE_STRVEC, line));
  162. }
  163. }
  164. static void
  165. test_init(void)
  166. {
  167. unsigned int node;
  168. unsigned int i;
  169. struct cmd_node *cnode;
  170. struct cmd_element *cmd;
  171. cmd_init(1);
  172. install_node (&bgp_node, NULL);
  173. install_node (&rip_node, NULL);
  174. install_node (&interface_node, NULL);
  175. install_node (&rmap_node, NULL);
  176. install_node (&zebra_node, NULL);
  177. install_node (&bgp_vpnv4_node, NULL);
  178. install_node (&bgp_ipv4_node, NULL);
  179. install_node (&bgp_ipv4m_node, NULL);
  180. install_node (&bgp_ipv6_node, NULL);
  181. install_node (&bgp_ipv6m_node, NULL);
  182. install_node (&ospf_node, NULL);
  183. install_node (&ripng_node, NULL);
  184. install_node (&ospf6_node, NULL);
  185. install_node (&babel_node, NULL);
  186. install_node (&keychain_node, NULL);
  187. install_node (&keychain_key_node, NULL);
  188. install_node (&isis_node, NULL);
  189. install_node (&vty_node, NULL);
  190. test_init_cmd();
  191. for (node = 0; node < vector_active(cmdvec); node++)
  192. if ((cnode = vector_slot(cmdvec, node)) != NULL)
  193. for (i = 0; i < vector_active(cnode->cmd_vector); i++)
  194. if ((cmd = vector_slot(cnode->cmd_vector, i)) != NULL)
  195. {
  196. cmd->daemon = 0;
  197. cmd->func = test_callback;
  198. }
  199. test_load();
  200. vty_init_vtysh();
  201. }
  202. static void
  203. test_terminate(void)
  204. {
  205. unsigned int i;
  206. vty_terminate();
  207. for (i = 0; i < vector_active(test_cmds); i++)
  208. XFREE(MTYPE_STRVEC, vector_slot(test_cmds, i));
  209. vector_free(test_cmds);
  210. cmd_terminate();
  211. }
  212. static void
  213. test_run(struct prng *prng, struct vty *vty, const char *cmd, unsigned int edit_dist, unsigned int node_index, int verbose)
  214. {
  215. const char *test_str;
  216. vector vline;
  217. int ret;
  218. unsigned int i;
  219. char **completions;
  220. unsigned int j;
  221. struct cmd_node *cnode;
  222. vector descriptions;
  223. int appended_null;
  224. int no_match;
  225. test_str = prng_fuzz(prng, cmd, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_:. /", edit_dist);
  226. vline = cmd_make_strvec(test_str);
  227. if (vline == NULL)
  228. return;
  229. appended_null = 0;
  230. for (i = 0; i < vector_active(cmdvec); i++)
  231. if ((cnode = vector_slot(cmdvec, i)) != NULL)
  232. {
  233. if (node_index != (unsigned int)-1 && i != node_index)
  234. continue;
  235. if (appended_null)
  236. {
  237. vector_unset(vline, vector_active(vline) - 1);
  238. appended_null = 0;
  239. }
  240. vty->node = cnode->node;
  241. test_buf[0] = '\0';
  242. ret = cmd_execute_command(vline, vty, NULL, 0);
  243. no_match = (ret == CMD_ERR_NO_MATCH);
  244. if (verbose || !no_match)
  245. printf("execute relaxed '%s'@%d: rv==%d%s%s\n",
  246. test_str,
  247. cnode->node,
  248. ret,
  249. (test_buf[0] != '\0') ? ", " : "",
  250. test_buf);
  251. vty->node = cnode->node;
  252. test_buf[0] = '\0';
  253. ret = cmd_execute_command_strict(vline, vty, NULL);
  254. if (verbose || !no_match)
  255. printf("execute strict '%s'@%d: rv==%d%s%s\n",
  256. test_str,
  257. cnode->node,
  258. ret,
  259. (test_buf[0] != '\0') ? ", " : "",
  260. test_buf);
  261. if (isspace((int) test_str[strlen(test_str) - 1]))
  262. {
  263. vector_set (vline, NULL);
  264. appended_null = 1;
  265. }
  266. vty->node = cnode->node;
  267. completions = cmd_complete_command(vline, vty, &ret);
  268. if (verbose || !no_match)
  269. printf("complete '%s'@%d: rv==%d\n",
  270. test_str,
  271. cnode->node,
  272. ret);
  273. if (completions != NULL)
  274. {
  275. for (j = 0; completions[j] != NULL; j++)
  276. {
  277. printf(" '%s'\n", completions[j]);
  278. XFREE(MTYPE_TMP, completions[j]);
  279. }
  280. XFREE(MTYPE_VECTOR_INDEX, completions);
  281. }
  282. vty->node = cnode->node;
  283. descriptions = cmd_describe_command(vline, vty, &ret);
  284. if (verbose || !no_match)
  285. printf("describe '%s'@%d: rv==%d\n",
  286. test_str,
  287. cnode->node,
  288. ret);
  289. if (descriptions != NULL)
  290. {
  291. for (j = 0; j < vector_active(descriptions); j++)
  292. {
  293. struct cmd_token *cmd = vector_slot(descriptions, j);
  294. printf(" '%s' '%s'\n", cmd->cmd, cmd->desc);
  295. }
  296. vector_free(descriptions);
  297. }
  298. }
  299. cmd_free_strvec(vline);
  300. }
  301. int
  302. main(int argc, char **argv)
  303. {
  304. int opt;
  305. struct prng *prng;
  306. struct vty *vty;
  307. unsigned int edit_distance;
  308. unsigned int max_edit_distance;
  309. unsigned int node_index;
  310. int verbose;
  311. unsigned int test_cmd;
  312. unsigned int iteration;
  313. unsigned int num_iterations;
  314. max_edit_distance = 3;
  315. node_index = -1;
  316. verbose = 0;
  317. while ((opt = getopt(argc, argv, "e:n:v")) != -1)
  318. {
  319. switch (opt)
  320. {
  321. case 'e':
  322. max_edit_distance = atoi(optarg);
  323. break;
  324. case 'n':
  325. node_index = atoi(optarg);
  326. break;
  327. case 'v':
  328. verbose++;
  329. break;
  330. default:
  331. fprintf(stderr, "Usage: %s [-e <edit_dist>] [-n <node_idx>] [-v]\n", argv[0]);
  332. exit(1);
  333. break;
  334. }
  335. }
  336. test_init();
  337. prng = prng_new(0);
  338. vty = vty_new();
  339. vty->type = VTY_TERM;
  340. fprintf(stderr, "Progress:\n0/%u", vector_active(test_cmds));
  341. for (test_cmd = 0; test_cmd < vector_active(test_cmds); test_cmd++)
  342. {
  343. for (edit_distance = 0;
  344. edit_distance <= max_edit_distance;
  345. edit_distance++)
  346. {
  347. num_iterations = 1 << edit_distance;
  348. num_iterations *= num_iterations * num_iterations;
  349. for (iteration = 0; iteration < num_iterations; iteration++)
  350. test_run(prng, vty, vector_slot(test_cmds, test_cmd), edit_distance, node_index, verbose);
  351. }
  352. fprintf(stderr, "\r%u/%u", test_cmd + 1, vector_active(test_cmds));
  353. }
  354. fprintf(stderr, "\nDone.\n");
  355. vty_close(vty);
  356. prng_free(prng);
  357. test_terminate();
  358. return 0;
  359. }