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
=
54 "%s(config-router)# ",
57 static struct cmd_node rip_node
=
60 "%s(config-router)# ",
63 static struct cmd_node isis_node
=
66 "%s(config-router)# ",
69 static struct cmd_node interface_node
=
75 static struct cmd_node rmap_node
=
78 "%s(config-route-map)# "
81 static struct cmd_node zebra_node
=
87 static struct cmd_node bgp_vpnv4_node
=
90 "%s(config-router-af)# "
93 static struct cmd_node bgp_ipv4_node
=
96 "%s(config-router-af)# "
99 static struct cmd_node bgp_ipv4m_node
=
102 "%s(config-router-af)# "
105 static struct cmd_node bgp_ipv6_node
=
108 "%s(config-router-af)# "
111 static struct cmd_node bgp_ipv6m_node
=
114 "%s(config-router-af)# "
117 static struct cmd_node ospf_node
=
120 "%s(config-router)# "
123 static struct cmd_node ripng_node
=
126 "%s(config-router)# "
129 static struct cmd_node ospf6_node
=
135 static struct cmd_node keychain_node
=
138 "%s(config-keychain)# "
141 static struct cmd_node keychain_key_node
=
144 "%s(config-keychain-key)# "
148 test_callback(const struct cmd_element
*cmd
, struct vty
*vty
, int argc
, struct cmd_token
*argv
[])
155 rv
= snprintf(test_buf
, sizeof(test_buf
), "'%s'", cmd
->string
);
161 for (i
= 0; i
< argc
; i
++)
163 rv
= snprintf(test_buf
+ offset
, sizeof(test_buf
) - offset
, "%s'%s'",
164 (i
== 0) ? ": " : ", ", argv
[i
]->arg
);
178 test_cmds
= vector_init(VECTOR_MIN_SIZE
);
180 while (fgets(line
, sizeof(line
), stdin
) != NULL
)
183 line
[strlen(line
) - 1] = '\0';
186 vector_set(test_cmds
, XSTRDUP(MTYPE_STRVEC
, line
));
195 struct cmd_node
*cnode
;
196 struct cmd_element
*cmd
;
200 install_node (&bgp_node
, NULL
);
201 install_node (&rip_node
, NULL
);
202 install_node (&interface_node
, NULL
);
203 install_node (&rmap_node
, NULL
);
204 install_node (&zebra_node
, NULL
);
205 install_node (&bgp_vpnv4_node
, NULL
);
206 install_node (&bgp_ipv4_node
, NULL
);
207 install_node (&bgp_ipv4m_node
, NULL
);
208 install_node (&bgp_ipv6_node
, NULL
);
209 install_node (&bgp_ipv6m_node
, NULL
);
210 install_node (&ospf_node
, NULL
);
211 install_node (&ripng_node
, NULL
);
212 install_node (&ospf6_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
);
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
)
226 cmd
->func
= test_callback
;
238 for (i
= 0; i
< vector_active(test_cmds
); i
++)
239 XFREE(MTYPE_STRVEC
, vector_slot(test_cmds
, i
));
240 vector_free(test_cmds
);
245 test_run(struct prng
*prng
, struct vty
*vty
, const char *cmd
, unsigned int edit_dist
, unsigned int node_index
, int verbose
)
247 const char *test_str
;
253 struct cmd_node
*cnode
;
258 test_str
= prng_fuzz(prng
, cmd
, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_:. /", edit_dist
);
259 vline
= cmd_make_strvec(test_str
);
265 for (i
= 0; i
< vector_active(cmdvec
); i
++)
266 if ((cnode
= vector_slot(cmdvec
, i
)) != NULL
)
268 if (node_index
!= (unsigned int)-1 && i
!= node_index
)
273 vector_unset(vline
, vector_active(vline
) - 1);
276 vty
->node
= cnode
->node
;
278 ret
= cmd_execute_command(vline
, vty
, NULL
, 0);
279 no_match
= (ret
== CMD_ERR_NO_MATCH
);
280 if (verbose
|| !no_match
)
281 printf("execute relaxed '%s'@%d: rv==%d%s%s\n",
285 (test_buf
[0] != '\0') ? ", " : "",
288 vty
->node
= cnode
->node
;
290 ret
= cmd_execute_command_strict(vline
, vty
, NULL
);
291 if (verbose
|| !no_match
)
292 printf("execute strict '%s'@%d: rv==%d%s%s\n",
296 (test_buf
[0] != '\0') ? ", " : "",
299 if (isspace((int) test_str
[strlen(test_str
) - 1]))
301 vector_set (vline
, NULL
);
305 vty
->node
= cnode
->node
;
306 completions
= cmd_complete_command(vline
, vty
, &ret
);
307 if (verbose
|| !no_match
)
308 printf("complete '%s'@%d: rv==%d\n",
312 if (completions
!= NULL
)
314 for (j
= 0; completions
[j
] != NULL
; j
++)
316 printf(" '%s'\n", completions
[j
]);
317 XFREE(MTYPE_TMP
, completions
[j
]);
319 XFREE(MTYPE_TMP
, completions
);
322 vty
->node
= cnode
->node
;
323 descriptions
= cmd_describe_command(vline
, vty
, &ret
);
324 if (verbose
|| !no_match
)
325 printf("describe '%s'@%d: rv==%d\n",
329 if (descriptions
!= NULL
)
331 for (j
= 0; j
< vector_active(descriptions
); j
++)
333 struct cmd_token
*cmd
= vector_slot(descriptions
, j
);
334 printf(" '%s' '%s'\n", cmd
->text
, cmd
->desc
);
336 vector_free(descriptions
);
339 cmd_free_strvec(vline
);
343 main(int argc
, char **argv
)
348 unsigned int edit_distance
;
349 unsigned int max_edit_distance
;
350 unsigned int node_index
;
352 unsigned int test_cmd
;
353 unsigned int iteration
;
354 unsigned int num_iterations
;
356 max_edit_distance
= 3;
360 while ((opt
= getopt(argc
, argv
, "e:n:v")) != -1)
365 max_edit_distance
= atoi(optarg
);
368 node_index
= atoi(optarg
);
374 fprintf(stderr
, "Usage: %s [-e <edit_dist>] [-n <node_idx>] [-v]\n", argv
[0]);
384 vty
->type
= VTY_TERM
;
386 fprintf(stderr
, "Progress:\n0/%u", vector_active(test_cmds
));
387 for (test_cmd
= 0; test_cmd
< vector_active(test_cmds
); test_cmd
++)
389 for (edit_distance
= 0;
390 edit_distance
<= max_edit_distance
;
393 num_iterations
= 1 << edit_distance
;
394 num_iterations
*= num_iterations
* num_iterations
;
396 for (iteration
= 0; iteration
< num_iterations
; iteration
++)
397 test_run(prng
, vty
, vector_slot(test_cmds
, test_cmd
), edit_distance
, node_index
, verbose
);
399 fprintf(stderr
, "\r%u/%u", test_cmd
+ 1, vector_active(test_cmds
));
401 fprintf(stderr
, "\nDone.\n");