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 #define REALLY_NEED_PLAIN_GETOPT 1
44 extern struct cmd_node vty_node
;
45 extern void test_init_cmd(void); /* provided in test-commands-defun.c */
47 struct thread_master
*master
; /* dummy for libfrr*/
49 static vector test_cmds
;
50 static char test_buf
[32768];
52 static struct cmd_node bgp_node
=
55 "%s(config-router)# ",
58 static struct cmd_node rip_node
=
61 "%s(config-router)# ",
64 static struct cmd_node isis_node
=
67 "%s(config-router)# ",
70 static struct cmd_node interface_node
=
76 static struct cmd_node rmap_node
=
79 "%s(config-route-map)# "
82 static struct cmd_node zebra_node
=
88 static struct cmd_node bgp_vpnv4_node
=
91 "%s(config-router-af)# "
94 static struct cmd_node bgp_ipv4_node
=
97 "%s(config-router-af)# "
100 static struct cmd_node bgp_ipv4m_node
=
103 "%s(config-router-af)# "
106 static struct cmd_node bgp_ipv6_node
=
109 "%s(config-router-af)# "
112 static struct cmd_node bgp_ipv6m_node
=
115 "%s(config-router-af)# "
118 static struct cmd_node ospf_node
=
121 "%s(config-router)# "
124 static struct cmd_node ripng_node
=
127 "%s(config-router)# "
130 static struct cmd_node ospf6_node
=
136 static struct cmd_node keychain_node
=
139 "%s(config-keychain)# "
142 static struct cmd_node keychain_key_node
=
145 "%s(config-keychain-key)# "
149 test_callback(const struct cmd_element
*cmd
, struct vty
*vty
, int argc
, struct cmd_token
*argv
[])
156 rv
= snprintf(test_buf
, sizeof(test_buf
), "'%s'", cmd
->string
);
162 for (i
= 0; i
< argc
; i
++)
164 rv
= snprintf(test_buf
+ offset
, sizeof(test_buf
) - offset
, "%s'%s'",
165 (i
== 0) ? ": " : ", ", argv
[i
]->arg
);
179 test_cmds
= vector_init(VECTOR_MIN_SIZE
);
181 while (fgets(line
, sizeof(line
), stdin
) != NULL
)
184 line
[strlen(line
) - 1] = '\0';
187 vector_set(test_cmds
, XSTRDUP(MTYPE_STRVEC
, line
));
196 struct cmd_node
*cnode
;
197 struct cmd_element
*cmd
;
201 install_node (&bgp_node
, NULL
);
202 install_node (&rip_node
, NULL
);
203 install_node (&interface_node
, NULL
);
204 install_node (&rmap_node
, NULL
);
205 install_node (&zebra_node
, NULL
);
206 install_node (&bgp_vpnv4_node
, NULL
);
207 install_node (&bgp_ipv4_node
, NULL
);
208 install_node (&bgp_ipv4m_node
, NULL
);
209 install_node (&bgp_ipv6_node
, NULL
);
210 install_node (&bgp_ipv6m_node
, NULL
);
211 install_node (&ospf_node
, NULL
);
212 install_node (&ripng_node
, NULL
);
213 install_node (&ospf6_node
, NULL
);
214 install_node (&keychain_node
, NULL
);
215 install_node (&keychain_key_node
, NULL
);
216 install_node (&isis_node
, NULL
);
217 install_node (&vty_node
, NULL
);
221 for (node
= 0; node
< vector_active(cmdvec
); node
++)
222 if ((cnode
= vector_slot(cmdvec
, node
)) != NULL
)
223 for (i
= 0; i
< vector_active(cnode
->cmd_vector
); i
++)
224 if ((cmd
= vector_slot(cnode
->cmd_vector
, i
)) != NULL
)
227 cmd
->func
= test_callback
;
239 for (i
= 0; i
< vector_active(test_cmds
); i
++)
240 XFREE(MTYPE_STRVEC
, vector_slot(test_cmds
, i
));
241 vector_free(test_cmds
);
246 test_run(struct prng
*prng
, struct vty
*vty
, const char *cmd
, unsigned int edit_dist
, unsigned int node_index
, int verbose
)
248 const char *test_str
;
254 struct cmd_node
*cnode
;
259 test_str
= prng_fuzz(prng
, cmd
, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_:. /", edit_dist
);
260 vline
= cmd_make_strvec(test_str
);
266 for (i
= 0; i
< vector_active(cmdvec
); i
++)
267 if ((cnode
= vector_slot(cmdvec
, i
)) != NULL
)
269 if (node_index
!= (unsigned int)-1 && i
!= node_index
)
274 vector_unset(vline
, vector_active(vline
) - 1);
277 vty
->node
= cnode
->node
;
279 ret
= cmd_execute_command(vline
, vty
, NULL
, 0);
280 no_match
= (ret
== CMD_ERR_NO_MATCH
);
281 if (verbose
|| !no_match
)
282 printf("execute relaxed '%s'@%d: rv==%d%s%s\n",
286 (test_buf
[0] != '\0') ? ", " : "",
289 vty
->node
= cnode
->node
;
291 ret
= cmd_execute_command_strict(vline
, vty
, NULL
);
292 if (verbose
|| !no_match
)
293 printf("execute strict '%s'@%d: rv==%d%s%s\n",
297 (test_buf
[0] != '\0') ? ", " : "",
300 if (isspace((int) test_str
[strlen(test_str
) - 1]))
302 vector_set (vline
, NULL
);
306 vty
->node
= cnode
->node
;
307 completions
= cmd_complete_command(vline
, vty
, &ret
);
308 if (verbose
|| !no_match
)
309 printf("complete '%s'@%d: rv==%d\n",
313 if (completions
!= NULL
)
315 for (j
= 0; completions
[j
] != NULL
; j
++)
317 printf(" '%s'\n", completions
[j
]);
318 XFREE(MTYPE_TMP
, completions
[j
]);
320 XFREE(MTYPE_TMP
, completions
);
323 vty
->node
= cnode
->node
;
324 descriptions
= cmd_describe_command(vline
, vty
, &ret
);
325 if (verbose
|| !no_match
)
326 printf("describe '%s'@%d: rv==%d\n",
330 if (descriptions
!= NULL
)
332 for (j
= 0; j
< vector_active(descriptions
); j
++)
334 struct cmd_token
*cmd
= vector_slot(descriptions
, j
);
335 printf(" '%s' '%s'\n", cmd
->text
, cmd
->desc
);
337 vector_free(descriptions
);
340 cmd_free_strvec(vline
);
344 main(int argc
, char **argv
)
349 unsigned int edit_distance
;
350 unsigned int max_edit_distance
;
351 unsigned int node_index
;
353 unsigned int test_cmd
;
354 unsigned int iteration
;
355 unsigned int num_iterations
;
357 max_edit_distance
= 3;
361 while ((opt
= getopt(argc
, argv
, "e:n:v")) != -1)
366 max_edit_distance
= atoi(optarg
);
369 node_index
= atoi(optarg
);
375 fprintf(stderr
, "Usage: %s [-e <edit_dist>] [-n <node_idx>] [-v]\n", argv
[0]);
385 vty
->type
= VTY_TERM
;
387 fprintf(stderr
, "Progress:\n0/%u", vector_active(test_cmds
));
388 for (test_cmd
= 0; test_cmd
< vector_active(test_cmds
); test_cmd
++)
390 for (edit_distance
= 0;
391 edit_distance
<= max_edit_distance
;
394 num_iterations
= 1 << edit_distance
;
395 num_iterations
*= num_iterations
* num_iterations
;
397 for (iteration
= 0; iteration
< num_iterations
; iteration
++)
398 test_run(prng
, vty
, vector_slot(test_cmds
, test_cmd
), edit_distance
, node_index
, verbose
);
400 fprintf(stderr
, "\r%u/%u", test_cmd
+ 1, vector_active(test_cmds
));
402 fprintf(stderr
, "\nDone.\n");