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 along
25 * with this program; see the file COPYING; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
29 #define REALLY_NEED_PLAIN_GETOPT 1
43 extern struct cmd_node vty_node
;
44 extern void test_init_cmd(void); /* provided in test-commands-defun.c */
46 struct thread_master
*master
; /* dummy for libfrr*/
48 static vector test_cmds
;
49 static char test_buf
[32768];
51 static struct cmd_node bgp_node
= {
53 .prompt
= "%s(config-router)# ",
56 static struct cmd_node rip_node
= {
58 .prompt
= "%s(config-router)# ",
61 static struct cmd_node isis_node
= {
63 .prompt
= "%s(config-router)# ",
66 static struct cmd_node interface_node
= {
67 .node
= INTERFACE_NODE
,
68 .prompt
= "%s(config-if)# ",
71 static struct cmd_node rmap_node
= {
73 .prompt
= "%s(config-route-map)# ",
76 static struct cmd_node zebra_node
= {
78 .prompt
= "%s(config-router)# ",
81 static struct cmd_node bgp_vpnv4_node
= {
82 .node
= BGP_VPNV4_NODE
,
83 .prompt
= "%s(config-router-af)# ",
86 static struct cmd_node bgp_ipv4_node
= {
87 .node
= BGP_IPV4_NODE
,
88 .prompt
= "%s(config-router-af)# ",
91 static struct cmd_node bgp_ipv4m_node
= {
92 .node
= BGP_IPV4M_NODE
,
93 .prompt
= "%s(config-router-af)# ",
96 static struct cmd_node bgp_ipv6_node
= {
97 .node
= BGP_IPV6_NODE
,
98 .prompt
= "%s(config-router-af)# ",
101 static struct cmd_node bgp_ipv6m_node
= {
102 .node
= BGP_IPV6M_NODE
,
103 .prompt
= "%s(config-router-af)# ",
106 static struct cmd_node ospf_node
= {
108 .prompt
= "%s(config-router)# ",
111 static struct cmd_node ripng_node
= {
113 .prompt
= "%s(config-router)# ",
116 static struct cmd_node ospf6_node
= {
118 .prompt
= "%s(config-ospf6)# ",
121 static struct cmd_node keychain_node
= {
122 .node
= KEYCHAIN_NODE
,
123 .prompt
= "%s(config-keychain)# ",
126 static struct cmd_node keychain_key_node
= {
127 .node
= KEYCHAIN_KEY_NODE
,
128 .prompt
= "%s(config-keychain-key)# ",
131 static int test_callback(const struct cmd_element
*cmd
, struct vty
*vty
,
132 int argc
, struct cmd_token
*argv
[])
139 rv
= snprintf(test_buf
, sizeof(test_buf
), "'%s'", cmd
->string
);
145 for (i
= 0; i
< argc
; i
++) {
146 rv
= snprintf(test_buf
+ offset
, sizeof(test_buf
) - offset
,
147 "%s'%s'", (i
== 0) ? ": " : ", ", argv
[i
]->arg
);
156 static void test_load(void)
160 test_cmds
= vector_init(VECTOR_MIN_SIZE
);
162 while (fgets(line
, sizeof(line
), stdin
) != NULL
) {
164 line
[strlen(line
) - 1] = '\0';
167 vector_set(test_cmds
, XSTRDUP(MTYPE_TMP
, line
));
171 static void test_init(void)
175 struct cmd_node
*cnode
;
176 struct cmd_element
*cmd
;
180 nb_init(master
, NULL
, 0);
182 install_node(&bgp_node
);
183 install_node(&rip_node
);
184 install_node(&interface_node
);
185 install_node(&rmap_node
);
186 install_node(&zebra_node
);
187 install_node(&bgp_vpnv4_node
);
188 install_node(&bgp_ipv4_node
);
189 install_node(&bgp_ipv4m_node
);
190 install_node(&bgp_ipv6_node
);
191 install_node(&bgp_ipv6m_node
);
192 install_node(&ospf_node
);
193 install_node(&ripng_node
);
194 install_node(&ospf6_node
);
195 install_node(&keychain_node
);
196 install_node(&keychain_key_node
);
197 install_node(&isis_node
);
198 install_node(&vty_node
);
202 for (node
= 0; node
< vector_active(cmdvec
); node
++)
203 if ((cnode
= vector_slot(cmdvec
, node
)) != NULL
)
204 for (i
= 0; i
< vector_active(cnode
->cmd_vector
); i
++)
205 if ((cmd
= vector_slot(cnode
->cmd_vector
, i
))
208 cmd
->func
= test_callback
;
214 static void test_terminate(void)
219 for (i
= 0; i
< vector_active(test_cmds
); i
++)
220 XFREE(MTYPE_TMP
, vector_slot(test_cmds
, i
));
221 vector_free(test_cmds
);
227 static void test_run(struct prng
*prng
, struct vty
*vty
, const char *cmd
,
228 unsigned int edit_dist
, unsigned int node_index
,
231 const char *test_str
;
237 struct cmd_node
*cnode
;
242 test_str
= prng_fuzz(
244 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_:. /",
246 vline
= cmd_make_strvec(test_str
);
252 for (i
= 0; i
< vector_active(cmdvec
); i
++)
253 if ((cnode
= vector_slot(cmdvec
, i
)) != NULL
) {
254 if (node_index
!= (unsigned int)-1 && i
!= node_index
)
258 vector_unset(vline
, vector_active(vline
) - 1);
261 vty
->node
= cnode
->node
;
263 ret
= cmd_execute_command(vline
, vty
, NULL
, 0);
264 no_match
= (ret
== CMD_ERR_NO_MATCH
);
265 if (verbose
|| !no_match
)
266 printf("execute relaxed '%s'@%d: rv==%d%s%s\n",
267 test_str
, cnode
->node
, ret
,
268 (test_buf
[0] != '\0') ? ", " : "",
271 vty
->node
= cnode
->node
;
273 ret
= cmd_execute_command_strict(vline
, vty
, NULL
);
274 if (verbose
|| !no_match
)
275 printf("execute strict '%s'@%d: rv==%d%s%s\n",
276 test_str
, cnode
->node
, ret
,
277 (test_buf
[0] != '\0') ? ", " : "",
280 if (isspace((unsigned char)test_str
[
281 strlen(test_str
) - 1])) {
282 vector_set(vline
, NULL
);
286 vty
->node
= cnode
->node
;
287 completions
= cmd_complete_command(vline
, vty
, &ret
);
288 if (verbose
|| !no_match
)
289 printf("complete '%s'@%d: rv==%d\n", test_str
,
291 if (completions
!= NULL
) {
292 for (j
= 0; completions
[j
] != NULL
; j
++) {
293 printf(" '%s'\n", completions
[j
]);
294 XFREE(MTYPE_TMP
, completions
[j
]);
296 XFREE(MTYPE_TMP
, completions
);
299 vty
->node
= cnode
->node
;
300 descriptions
= cmd_describe_command(vline
, vty
, &ret
);
301 if (verbose
|| !no_match
)
302 printf("describe '%s'@%d: rv==%d\n", test_str
,
304 if (descriptions
!= NULL
) {
305 for (j
= 0; j
< vector_active(descriptions
);
307 struct cmd_token
*ct
=
308 vector_slot(descriptions
, j
);
309 printf(" '%s' '%s'\n", ct
->text
,
312 vector_free(descriptions
);
315 cmd_free_strvec(vline
);
318 int main(int argc
, char **argv
)
323 unsigned int edit_distance
;
324 unsigned int max_edit_distance
;
325 unsigned int node_index
;
327 unsigned int test_cmd
;
328 unsigned int iteration
;
329 unsigned int num_iterations
;
331 max_edit_distance
= 3;
335 while ((opt
= getopt(argc
, argv
, "e:n:v")) != -1) {
338 max_edit_distance
= atoi(optarg
);
341 node_index
= atoi(optarg
);
348 "Usage: %s [-e <edit_dist>] [-n <node_idx>] [-v]\n",
359 vty
->type
= VTY_TERM
;
361 fprintf(stderr
, "Progress:\n0/%u", vector_active(test_cmds
));
362 for (test_cmd
= 0; test_cmd
< vector_active(test_cmds
); test_cmd
++) {
363 for (edit_distance
= 0; edit_distance
<= max_edit_distance
;
365 num_iterations
= 1 << edit_distance
;
366 num_iterations
*= num_iterations
* num_iterations
;
368 for (iteration
= 0; iteration
< num_iterations
;
371 vector_slot(test_cmds
, test_cmd
),
372 edit_distance
, node_index
, verbose
);
374 fprintf(stderr
, "\r%u/%u", test_cmd
+ 1,
375 vector_active(test_cmds
));
377 fprintf(stderr
, "\nDone.\n");