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 .parent_node
= CONFIG_NODE
,
55 .prompt
= "%s(config-router)# ",
58 static struct cmd_node rip_node
= {
61 .parent_node
= CONFIG_NODE
,
62 .prompt
= "%s(config-router)# ",
65 static struct cmd_node isis_node
= {
68 .parent_node
= CONFIG_NODE
,
69 .prompt
= "%s(config-router)# ",
72 static struct cmd_node interface_node
= {
74 .node
= INTERFACE_NODE
,
75 .parent_node
= CONFIG_NODE
,
76 .prompt
= "%s(config-if)# ",
79 static struct cmd_node rmap_node
= {
82 .parent_node
= CONFIG_NODE
,
83 .prompt
= "%s(config-route-map)# ",
86 static struct cmd_node zebra_node
= {
89 .parent_node
= CONFIG_NODE
,
90 .prompt
= "%s(config-router)# ",
93 static struct cmd_node bgp_vpnv4_node
= {
95 .node
= BGP_VPNV4_NODE
,
96 .parent_node
= BGP_NODE
,
97 .prompt
= "%s(config-router-af)# ",
100 static struct cmd_node bgp_ipv4_node
= {
101 .name
= "bgp ipv4 unicast",
102 .node
= BGP_IPV4_NODE
,
103 .parent_node
= BGP_NODE
,
104 .prompt
= "%s(config-router-af)# ",
107 static struct cmd_node bgp_ipv4m_node
= {
108 .name
= "bgp ipv4 multicast",
109 .node
= BGP_IPV4M_NODE
,
110 .parent_node
= BGP_NODE
,
111 .prompt
= "%s(config-router-af)# ",
114 static struct cmd_node bgp_ipv6_node
= {
116 .node
= BGP_IPV6_NODE
,
117 .parent_node
= BGP_NODE
,
118 .prompt
= "%s(config-router-af)# ",
121 static struct cmd_node bgp_ipv6m_node
= {
122 .name
= "bgp ipv6 multicast",
123 .node
= BGP_IPV6M_NODE
,
124 .parent_node
= BGP_NODE
,
125 .prompt
= "%s(config-router-af)# ",
128 static struct cmd_node ospf_node
= {
131 .parent_node
= CONFIG_NODE
,
132 .prompt
= "%s(config-router)# ",
135 static struct cmd_node ripng_node
= {
138 .parent_node
= CONFIG_NODE
,
139 .prompt
= "%s(config-router)# ",
142 static struct cmd_node ospf6_node
= {
145 .parent_node
= CONFIG_NODE
,
146 .prompt
= "%s(config-ospf6)# ",
149 static struct cmd_node keychain_node
= {
151 .node
= KEYCHAIN_NODE
,
152 .parent_node
= CONFIG_NODE
,
153 .prompt
= "%s(config-keychain)# ",
156 static struct cmd_node keychain_key_node
= {
157 .name
= "keychain key",
158 .node
= KEYCHAIN_KEY_NODE
,
159 .parent_node
= KEYCHAIN_NODE
,
160 .prompt
= "%s(config-keychain-key)# ",
163 static int test_callback(const struct cmd_element
*cmd
, struct vty
*vty
,
164 int argc
, struct cmd_token
*argv
[])
171 rv
= snprintf(test_buf
, sizeof(test_buf
), "'%s'", cmd
->string
);
177 for (i
= 0; i
< argc
; i
++) {
178 rv
= snprintf(test_buf
+ offset
, sizeof(test_buf
) - offset
,
179 "%s'%s'", (i
== 0) ? ": " : ", ", argv
[i
]->arg
);
188 static void test_load(void)
192 test_cmds
= vector_init(VECTOR_MIN_SIZE
);
194 while (fgets(line
, sizeof(line
), stdin
) != NULL
) {
196 line
[strlen(line
) - 1] = '\0';
199 vector_set(test_cmds
, XSTRDUP(MTYPE_TMP
, line
));
203 static void test_init(void)
207 struct cmd_node
*cnode
;
208 struct cmd_element
*cmd
;
211 nb_init(master
, NULL
, 0, false);
213 install_node(&bgp_node
);
214 install_node(&rip_node
);
215 install_node(&interface_node
);
216 install_node(&rmap_node
);
217 install_node(&zebra_node
);
218 install_node(&bgp_vpnv4_node
);
219 install_node(&bgp_ipv4_node
);
220 install_node(&bgp_ipv4m_node
);
221 install_node(&bgp_ipv6_node
);
222 install_node(&bgp_ipv6m_node
);
223 install_node(&ospf_node
);
224 install_node(&ripng_node
);
225 install_node(&ospf6_node
);
226 install_node(&keychain_node
);
227 install_node(&keychain_key_node
);
228 install_node(&isis_node
);
229 install_node(&vty_node
);
233 for (node
= 0; node
< vector_active(cmdvec
); node
++)
234 if ((cnode
= vector_slot(cmdvec
, node
)) != NULL
)
235 for (i
= 0; i
< vector_active(cnode
->cmd_vector
); i
++)
236 if ((cmd
= vector_slot(cnode
->cmd_vector
, i
))
239 cmd
->func
= test_callback
;
245 static void test_terminate(void)
250 for (i
= 0; i
< vector_active(test_cmds
); i
++)
251 XFREE(MTYPE_TMP
, vector_slot(test_cmds
, i
));
252 vector_free(test_cmds
);
258 static void test_run(struct prng
*prng
, struct vty
*vty
, const char *cmd
,
259 unsigned int edit_dist
, unsigned int node_index
,
262 const char *test_str
;
268 struct cmd_node
*cnode
;
273 test_str
= prng_fuzz(
275 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_:. /",
277 vline
= cmd_make_strvec(test_str
);
283 for (i
= 0; i
< vector_active(cmdvec
); i
++)
284 if ((cnode
= vector_slot(cmdvec
, i
)) != NULL
) {
285 if (node_index
!= (unsigned int)-1 && i
!= node_index
)
289 vector_unset(vline
, vector_active(vline
) - 1);
292 vty
->node
= cnode
->node
;
294 ret
= cmd_execute_command(vline
, vty
, NULL
, 0);
295 no_match
= (ret
== CMD_ERR_NO_MATCH
);
296 if (verbose
|| !no_match
)
297 printf("execute relaxed '%s'@%d: rv==%d%s%s\n",
298 test_str
, cnode
->node
, ret
,
299 (test_buf
[0] != '\0') ? ", " : "",
302 vty
->node
= cnode
->node
;
304 ret
= cmd_execute_command_strict(vline
, vty
, NULL
);
305 if (verbose
|| !no_match
)
306 printf("execute strict '%s'@%d: rv==%d%s%s\n",
307 test_str
, cnode
->node
, ret
,
308 (test_buf
[0] != '\0') ? ", " : "",
311 if (isspace((unsigned char)test_str
[
312 strlen(test_str
) - 1])) {
313 vector_set(vline
, NULL
);
317 vty
->node
= cnode
->node
;
318 completions
= cmd_complete_command(vline
, vty
, &ret
);
319 if (verbose
|| !no_match
)
320 printf("complete '%s'@%d: rv==%d\n", test_str
,
322 if (completions
!= NULL
) {
323 for (j
= 0; completions
[j
] != NULL
; j
++) {
324 printf(" '%s'\n", completions
[j
]);
325 XFREE(MTYPE_TMP
, completions
[j
]);
327 XFREE(MTYPE_TMP
, completions
);
330 vty
->node
= cnode
->node
;
331 descriptions
= cmd_describe_command(vline
, vty
, &ret
);
332 if (verbose
|| !no_match
)
333 printf("describe '%s'@%d: rv==%d\n", test_str
,
335 if (descriptions
!= NULL
) {
336 for (j
= 0; j
< vector_active(descriptions
);
338 struct cmd_token
*ct
=
339 vector_slot(descriptions
, j
);
340 printf(" '%s' '%s'\n", ct
->text
,
343 vector_free(descriptions
);
346 cmd_free_strvec(vline
);
349 int main(int argc
, char **argv
)
354 unsigned int edit_distance
;
355 unsigned int max_edit_distance
;
356 unsigned int node_index
;
358 unsigned int test_cmd
;
359 unsigned int iteration
;
360 unsigned int num_iterations
;
362 max_edit_distance
= 3;
366 while ((opt
= getopt(argc
, argv
, "e:n:v")) != -1) {
369 max_edit_distance
= atoi(optarg
);
372 node_index
= atoi(optarg
);
379 "Usage: %s [-e <edit_dist>] [-n <node_idx>] [-v]\n",
390 vty
->type
= VTY_TERM
;
392 fprintf(stderr
, "Progress:\n0/%u", vector_active(test_cmds
));
393 for (test_cmd
= 0; test_cmd
< vector_active(test_cmds
); test_cmd
++) {
394 for (edit_distance
= 0; edit_distance
<= max_edit_distance
;
396 num_iterations
= 1 << edit_distance
;
397 num_iterations
*= num_iterations
* num_iterations
;
399 for (iteration
= 0; iteration
< num_iterations
;
402 vector_slot(test_cmds
, test_cmd
),
403 edit_distance
, node_index
, verbose
);
405 fprintf(stderr
, "\r%u/%u", test_cmd
+ 1,
406 vector_active(test_cmds
));
408 fprintf(stderr
, "\nDone.\n");