2 * Test code for lib/command.c
4 * Copyright (C) 2013 by Open Source Routing.
5 * Copyright (C) 2013 by Internet Systems Consortium, Inc. ("ISC")
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.
11 * The output is currently not validated but only logged. It can
12 * be diffed to find regressions between versions.
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
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.
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
30 /* Example use for testing:
31 * ./testcommands -e 0 < testcommands.in | \
32 * diff -au - testcommands.refout
35 #define REALLY_NEED_PLAIN_GETOPT 1
49 extern struct cmd_node vty_node;
50 extern void test_init_cmd(void); /* provided in test-commands-defun.c */
52 struct thread_master *master; /* dummy for libzebra*/
54 static vector test_cmds;
55 static char test_buf[32768];
57 static struct cmd_node bgp_node =
60 "%s(config-router)# ",
63 static struct cmd_node rip_node =
66 "%s(config-router)# ",
69 static struct cmd_node isis_node =
72 "%s(config-router)# ",
75 static struct cmd_node interface_node =
81 static struct cmd_node rmap_node =
84 "%s(config-route-map)# "
87 static struct cmd_node zebra_node =
93 static struct cmd_node bgp_vpnv4_node =
96 "%s(config-router-af)# "
99 static struct cmd_node bgp_vpnv6_node =
102 "%s(config-router-af-vpnv6)# ",
105 static struct cmd_node bgp_ipv4_node =
108 "%s(config-router-af)# "
111 static struct cmd_node bgp_ipv4m_node =
114 "%s(config-router-af)# "
117 static struct cmd_node bgp_ipv6_node =
120 "%s(config-router-af)# "
123 static struct cmd_node bgp_ipv6m_node =
126 "%s(config-router-af)# "
129 static struct cmd_node bgp_encap_node =
132 "%s(config-router-af-encap)# ",
135 static struct cmd_node bgp_encapv6_node =
138 "%s(config-router-af-encapv6)# ",
141 static struct cmd_node ospf_node =
144 "%s(config-router)# "
147 static struct cmd_node ripng_node =
150 "%s(config-router)# "
153 static struct cmd_node ospf6_node =
159 static struct cmd_node babel_node =
165 static struct cmd_node keychain_node =
168 "%s(config-keychain)# "
171 static struct cmd_node keychain_key_node =
174 "%s(config-keychain-key)# "
177 static struct cmd_node link_params_node =
180 "%s(config-link-params)# ",
186 test_callback(struct cmd_element *cmd, struct vty *vty, int argc, const char *argv[])
193 rv = snprintf(test_buf, sizeof(test_buf), "'%s'", cmd->string);
199 for (i = 0; i < argc; i++)
201 rv = snprintf(test_buf + offset, sizeof(test_buf) - offset, "%s'%s'",
202 (i == 0) ? ": " : ", ", argv[i]);
216 test_cmds = vector_init(VECTOR_MIN_SIZE);
218 while (fgets(line, sizeof(line), stdin) != NULL)
221 line[strlen(line) - 1] = '\0';
224 vector_set(test_cmds, XSTRDUP(MTYPE_STRVEC, line));
233 struct cmd_node *cnode;
234 struct cmd_element *cmd;
238 install_node (&bgp_node, NULL);
239 install_node (&rip_node, NULL);
240 install_node (&interface_node, NULL);
241 install_node (&rmap_node, NULL);
242 install_node (&zebra_node, NULL);
243 install_node (&bgp_vpnv4_node, NULL);
244 install_node (&bgp_vpnv6_node, NULL);
245 install_node (&bgp_ipv4_node, NULL);
246 install_node (&bgp_ipv4m_node, NULL);
247 install_node (&bgp_ipv6_node, NULL);
248 install_node (&bgp_ipv6m_node, NULL);
249 install_node (&bgp_encap_node, NULL);
250 install_node (&bgp_encapv6_node, NULL);
251 install_node (&ospf_node, NULL);
252 install_node (&ripng_node, NULL);
253 install_node (&ospf6_node, NULL);
254 install_node (&babel_node, NULL);
255 install_node (&keychain_node, NULL);
256 install_node (&keychain_key_node, NULL);
257 install_node (&isis_node, NULL);
258 install_node (&vty_node, NULL);
259 install_node (&link_params_node, NULL);
260 //install_node (&zebra_if_defaults_node, NULL);
264 for (node = 0; node < vector_active(cmdvec); node++)
265 if ((cnode = vector_slot(cmdvec, node)) != NULL)
266 for (i = 0; i < vector_active(cnode->cmd_vector); i++)
267 if ((cmd = vector_slot(cnode->cmd_vector, i)) != NULL)
270 cmd->func = test_callback;
282 for (i = 0; i < vector_active(test_cmds); i++)
283 XFREE(MTYPE_STRVEC, vector_slot(test_cmds, i));
284 vector_free(test_cmds);
289 test_run(struct prng *prng, struct vty *vty, const char *cmd, unsigned int edit_dist, unsigned int node_index, int verbose)
291 const char *test_str;
297 struct cmd_node *cnode;
302 test_str = prng_fuzz(prng, cmd, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_:. /", edit_dist);
303 vline = cmd_make_strvec(test_str);
309 for (i = 0; i < vector_active(cmdvec); i++)
310 if ((cnode = vector_slot(cmdvec, i)) != NULL)
312 if (node_index != (unsigned int)-1 && i != node_index)
317 vector_unset(vline, vector_active(vline) - 1);
320 vty->node = cnode->node;
322 ret = cmd_execute_command(vline, vty, NULL, 0);
323 no_match = (ret == CMD_ERR_NO_MATCH);
324 if (verbose || !no_match)
325 printf("execute relaxed '%s'@%d: rv==%d%s%s\n",
329 (test_buf[0] != '\0') ? ", " : "",
332 vty->node = cnode->node;
334 ret = cmd_execute_command_strict(vline, vty, NULL);
335 if (verbose || !no_match)
336 printf("execute strict '%s'@%d: rv==%d%s%s\n",
340 (test_buf[0] != '\0') ? ", " : "",
343 if (isspace((int) test_str[strlen(test_str) - 1]))
345 vector_set (vline, NULL);
349 vty->node = cnode->node;
350 completions = cmd_complete_command(vline, vty, &ret);
351 if (verbose || !no_match)
352 printf("complete '%s'@%d: rv==%d\n",
356 if (completions != NULL)
358 for (j = 0; completions[j] != NULL; j++)
360 printf(" '%s'\n", completions[j]);
361 XFREE(MTYPE_TMP, completions[j]);
363 XFREE(MTYPE_VECTOR_INDEX, completions);
366 vty->node = cnode->node;
367 descriptions = cmd_describe_command(vline, vty, &ret);
368 if (verbose || !no_match)
369 printf("describe '%s'@%d: rv==%d\n",
373 if (descriptions != NULL)
375 for (j = 0; j < vector_active(descriptions); j++)
377 struct cmd_token *cmd = vector_slot(descriptions, j);
378 printf(" '%s' '%s'\n", cmd->cmd, cmd->desc);
380 vector_free(descriptions);
383 cmd_free_strvec(vline);
387 main(int argc, char **argv)
392 unsigned int edit_distance;
393 unsigned int max_edit_distance;
394 unsigned int node_index;
396 unsigned int test_cmd;
397 unsigned int iteration;
398 unsigned int num_iterations;
400 max_edit_distance = 3;
404 while ((opt = getopt(argc, argv, "e:n:v")) != -1)
409 max_edit_distance = atoi(optarg);
412 node_index = atoi(optarg);
418 fprintf(stderr, "Usage: %s [-e <edit_dist>] [-n <node_idx>] [-v]\n", argv[0]);
428 vty->type = VTY_TERM;
430 fprintf(stderr, "Progress:\n0/%u", vector_active(test_cmds));
431 for (test_cmd = 0; test_cmd < vector_active(test_cmds); test_cmd++)
433 for (edit_distance = 0;
434 edit_distance <= max_edit_distance;
437 num_iterations = 1 << edit_distance;
438 num_iterations *= num_iterations * num_iterations;
440 for (iteration = 0; iteration < num_iterations; iteration++)
441 test_run(prng, vty, vector_slot(test_cmds, test_cmd), edit_distance, node_index, verbose);
443 fprintf(stderr, "\r%u/%u", test_cmd + 1, vector_active(test_cmds));
445 fprintf(stderr, "\nDone.\n");