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
= {
52 BGP_NODE
, "%s(config-router)# ",
55 static struct cmd_node rip_node
= {
56 RIP_NODE
, "%s(config-router)# ",
59 static struct cmd_node isis_node
= {
60 ISIS_NODE
, "%s(config-router)# ",
63 static struct cmd_node interface_node
= {
64 INTERFACE_NODE
, "%s(config-if)# ",
67 static struct cmd_node rmap_node
= {RMAP_NODE
, "%s(config-route-map)# "};
69 static struct cmd_node zebra_node
= {ZEBRA_NODE
, "%s(config-router)# "};
71 static struct cmd_node bgp_vpnv4_node
= {BGP_VPNV4_NODE
,
72 "%s(config-router-af)# "};
74 static struct cmd_node bgp_ipv4_node
= {BGP_IPV4_NODE
,
75 "%s(config-router-af)# "};
77 static struct cmd_node bgp_ipv4m_node
= {BGP_IPV4M_NODE
,
78 "%s(config-router-af)# "};
80 static struct cmd_node bgp_ipv6_node
= {BGP_IPV6_NODE
,
81 "%s(config-router-af)# "};
83 static struct cmd_node bgp_ipv6m_node
= {BGP_IPV6M_NODE
,
84 "%s(config-router-af)# "};
86 static struct cmd_node ospf_node
= {OSPF_NODE
, "%s(config-router)# "};
88 static struct cmd_node ripng_node
= {RIPNG_NODE
, "%s(config-router)# "};
90 static struct cmd_node ospf6_node
= {OSPF6_NODE
, "%s(config-ospf6)# "};
92 static struct cmd_node keychain_node
= {KEYCHAIN_NODE
, "%s(config-keychain)# "};
94 static struct cmd_node keychain_key_node
= {KEYCHAIN_KEY_NODE
,
95 "%s(config-keychain-key)# "};
97 static int test_callback(const struct cmd_element
*cmd
, struct vty
*vty
,
98 int argc
, struct cmd_token
*argv
[])
105 rv
= snprintf(test_buf
, sizeof(test_buf
), "'%s'", cmd
->string
);
111 for (i
= 0; i
< argc
; i
++) {
112 rv
= snprintf(test_buf
+ offset
, sizeof(test_buf
) - offset
,
113 "%s'%s'", (i
== 0) ? ": " : ", ", argv
[i
]->arg
);
122 static void test_load(void)
126 test_cmds
= vector_init(VECTOR_MIN_SIZE
);
128 while (fgets(line
, sizeof(line
), stdin
) != NULL
) {
130 line
[strlen(line
) - 1] = '\0';
133 vector_set(test_cmds
, XSTRDUP(MTYPE_TMP
, line
));
137 static void test_init(void)
141 struct cmd_node
*cnode
;
142 struct cmd_element
*cmd
;
146 install_node(&bgp_node
, NULL
);
147 install_node(&rip_node
, NULL
);
148 install_node(&interface_node
, NULL
);
149 install_node(&rmap_node
, NULL
);
150 install_node(&zebra_node
, NULL
);
151 install_node(&bgp_vpnv4_node
, NULL
);
152 install_node(&bgp_ipv4_node
, NULL
);
153 install_node(&bgp_ipv4m_node
, NULL
);
154 install_node(&bgp_ipv6_node
, NULL
);
155 install_node(&bgp_ipv6m_node
, NULL
);
156 install_node(&ospf_node
, NULL
);
157 install_node(&ripng_node
, NULL
);
158 install_node(&ospf6_node
, NULL
);
159 install_node(&keychain_node
, NULL
);
160 install_node(&keychain_key_node
, NULL
);
161 install_node(&isis_node
, NULL
);
162 install_node(&vty_node
, NULL
);
166 for (node
= 0; node
< vector_active(cmdvec
); node
++)
167 if ((cnode
= vector_slot(cmdvec
, node
)) != NULL
)
168 for (i
= 0; i
< vector_active(cnode
->cmd_vector
); i
++)
169 if ((cmd
= vector_slot(cnode
->cmd_vector
, i
))
172 cmd
->func
= test_callback
;
178 static void test_terminate(void)
183 for (i
= 0; i
< vector_active(test_cmds
); i
++)
184 XFREE(MTYPE_TMP
, vector_slot(test_cmds
, i
));
185 vector_free(test_cmds
);
189 static void test_run(struct prng
*prng
, struct vty
*vty
, const char *cmd
,
190 unsigned int edit_dist
, unsigned int node_index
,
193 const char *test_str
;
199 struct cmd_node
*cnode
;
204 test_str
= prng_fuzz(
206 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_:. /",
208 vline
= cmd_make_strvec(test_str
);
214 for (i
= 0; i
< vector_active(cmdvec
); i
++)
215 if ((cnode
= vector_slot(cmdvec
, i
)) != NULL
) {
216 if (node_index
!= (unsigned int)-1 && i
!= node_index
)
220 vector_unset(vline
, vector_active(vline
) - 1);
223 vty
->node
= cnode
->node
;
225 ret
= cmd_execute_command(vline
, vty
, NULL
, 0);
226 no_match
= (ret
== CMD_ERR_NO_MATCH
);
227 if (verbose
|| !no_match
)
228 printf("execute relaxed '%s'@%d: rv==%d%s%s\n",
229 test_str
, cnode
->node
, ret
,
230 (test_buf
[0] != '\0') ? ", " : "",
233 vty
->node
= cnode
->node
;
235 ret
= cmd_execute_command_strict(vline
, vty
, NULL
);
236 if (verbose
|| !no_match
)
237 printf("execute strict '%s'@%d: rv==%d%s%s\n",
238 test_str
, cnode
->node
, ret
,
239 (test_buf
[0] != '\0') ? ", " : "",
242 if (isspace((int)test_str
[strlen(test_str
) - 1])) {
243 vector_set(vline
, NULL
);
247 vty
->node
= cnode
->node
;
248 completions
= cmd_complete_command(vline
, vty
, &ret
);
249 if (verbose
|| !no_match
)
250 printf("complete '%s'@%d: rv==%d\n", test_str
,
252 if (completions
!= NULL
) {
253 for (j
= 0; completions
[j
] != NULL
; j
++) {
254 printf(" '%s'\n", completions
[j
]);
255 XFREE(MTYPE_TMP
, completions
[j
]);
257 XFREE(MTYPE_TMP
, completions
);
260 vty
->node
= cnode
->node
;
261 descriptions
= cmd_describe_command(vline
, vty
, &ret
);
262 if (verbose
|| !no_match
)
263 printf("describe '%s'@%d: rv==%d\n", test_str
,
265 if (descriptions
!= NULL
) {
266 for (j
= 0; j
< vector_active(descriptions
);
268 struct cmd_token
*cmd
=
269 vector_slot(descriptions
, j
);
270 printf(" '%s' '%s'\n", cmd
->text
,
273 vector_free(descriptions
);
276 cmd_free_strvec(vline
);
279 int main(int argc
, char **argv
)
284 unsigned int edit_distance
;
285 unsigned int max_edit_distance
;
286 unsigned int node_index
;
288 unsigned int test_cmd
;
289 unsigned int iteration
;
290 unsigned int num_iterations
;
292 max_edit_distance
= 3;
296 while ((opt
= getopt(argc
, argv
, "e:n:v")) != -1) {
299 max_edit_distance
= atoi(optarg
);
302 node_index
= atoi(optarg
);
309 "Usage: %s [-e <edit_dist>] [-n <node_idx>] [-v]\n",
320 vty
->type
= VTY_TERM
;
322 fprintf(stderr
, "Progress:\n0/%u", vector_active(test_cmds
));
323 for (test_cmd
= 0; test_cmd
< vector_active(test_cmds
); test_cmd
++) {
324 for (edit_distance
= 0; edit_distance
<= max_edit_distance
;
326 num_iterations
= 1 << edit_distance
;
327 num_iterations
*= num_iterations
* num_iterations
;
329 for (iteration
= 0; iteration
< num_iterations
;
332 vector_slot(test_cmds
, test_cmd
),
333 edit_distance
, node_index
, verbose
);
335 fprintf(stderr
, "\r%u/%u", test_cmd
+ 1,
336 vector_active(test_cmds
));
338 fprintf(stderr
, "\nDone.\n");