]> git.proxmox.com Git - mirror_frr.git/blob - tests/lib/cli/test_commands.c
*: make consistent & update GPLv2 file headers
[mirror_frr.git] / tests / lib / cli / test_commands.c
1 /*
2 * Test code for lib/command.c
3 *
4 * Copyright (C) 2013 by Open Source Routing.
5 * Copyright (C) 2013 by Internet Systems Consortium, Inc. ("ISC")
6 *
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.
10 *
11 * The output is currently not validated but only logged. It can
12 * be diffed to find regressions between versions.
13 *
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
17 * later version.
18 *
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.
23 *
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
27 */
28
29 #define REALLY_NEED_PLAIN_GETOPT 1
30
31 #include <zebra.h>
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <unistd.h>
36
37 #include "command.h"
38 #include "memory.h"
39 #include "vector.h"
40 #include "prng.h"
41
42 extern vector cmdvec;
43 extern struct cmd_node vty_node;
44 extern void test_init_cmd(void); /* provided in test-commands-defun.c */
45
46 struct thread_master *master; /* dummy for libfrr*/
47
48 static vector test_cmds;
49 static char test_buf[32768];
50
51 static struct cmd_node bgp_node =
52 {
53 BGP_NODE,
54 "%s(config-router)# ",
55 };
56
57 static struct cmd_node rip_node =
58 {
59 RIP_NODE,
60 "%s(config-router)# ",
61 };
62
63 static struct cmd_node isis_node =
64 {
65 ISIS_NODE,
66 "%s(config-router)# ",
67 };
68
69 static struct cmd_node interface_node =
70 {
71 INTERFACE_NODE,
72 "%s(config-if)# ",
73 };
74
75 static struct cmd_node rmap_node =
76 {
77 RMAP_NODE,
78 "%s(config-route-map)# "
79 };
80
81 static struct cmd_node zebra_node =
82 {
83 ZEBRA_NODE,
84 "%s(config-router)# "
85 };
86
87 static struct cmd_node bgp_vpnv4_node =
88 {
89 BGP_VPNV4_NODE,
90 "%s(config-router-af)# "
91 };
92
93 static struct cmd_node bgp_ipv4_node =
94 {
95 BGP_IPV4_NODE,
96 "%s(config-router-af)# "
97 };
98
99 static struct cmd_node bgp_ipv4m_node =
100 {
101 BGP_IPV4M_NODE,
102 "%s(config-router-af)# "
103 };
104
105 static struct cmd_node bgp_ipv6_node =
106 {
107 BGP_IPV6_NODE,
108 "%s(config-router-af)# "
109 };
110
111 static struct cmd_node bgp_ipv6m_node =
112 {
113 BGP_IPV6M_NODE,
114 "%s(config-router-af)# "
115 };
116
117 static struct cmd_node ospf_node =
118 {
119 OSPF_NODE,
120 "%s(config-router)# "
121 };
122
123 static struct cmd_node ripng_node =
124 {
125 RIPNG_NODE,
126 "%s(config-router)# "
127 };
128
129 static struct cmd_node ospf6_node =
130 {
131 OSPF6_NODE,
132 "%s(config-ospf6)# "
133 };
134
135 static struct cmd_node keychain_node =
136 {
137 KEYCHAIN_NODE,
138 "%s(config-keychain)# "
139 };
140
141 static struct cmd_node keychain_key_node =
142 {
143 KEYCHAIN_KEY_NODE,
144 "%s(config-keychain-key)# "
145 };
146
147 static int
148 test_callback(const struct cmd_element *cmd, struct vty *vty, int argc, struct cmd_token *argv[])
149 {
150 int offset;
151 int rv;
152 int i;
153
154 offset = 0;
155 rv = snprintf(test_buf, sizeof(test_buf), "'%s'", cmd->string);
156 if (rv < 0)
157 abort();
158
159 offset += rv;
160
161 for (i = 0; i < argc; i++)
162 {
163 rv = snprintf(test_buf + offset, sizeof(test_buf) - offset, "%s'%s'",
164 (i == 0) ? ": " : ", ", argv[i]->arg);
165 if (rv < 0)
166 abort();
167 offset += rv;
168 }
169
170 return CMD_SUCCESS;
171 }
172
173 static void
174 test_load(void)
175 {
176 char line[4096];
177
178 test_cmds = vector_init(VECTOR_MIN_SIZE);
179
180 while (fgets(line, sizeof(line), stdin) != NULL)
181 {
182 if (strlen(line))
183 line[strlen(line) - 1] = '\0';
184 if (line[0] == '#')
185 continue;
186 vector_set(test_cmds, XSTRDUP(MTYPE_STRVEC, line));
187 }
188 }
189
190 static void
191 test_init(void)
192 {
193 unsigned int node;
194 unsigned int i;
195 struct cmd_node *cnode;
196 struct cmd_element *cmd;
197
198 cmd_init(1);
199
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);
217
218 test_init_cmd();
219
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)
224 {
225 cmd->daemon = 0;
226 cmd->func = test_callback;
227 }
228 test_load();
229 vty_init_vtysh();
230 }
231
232 static void
233 test_terminate(void)
234 {
235 unsigned int i;
236
237 vty_terminate();
238 for (i = 0; i < vector_active(test_cmds); i++)
239 XFREE(MTYPE_STRVEC, vector_slot(test_cmds, i));
240 vector_free(test_cmds);
241 cmd_terminate();
242 }
243
244 static void
245 test_run(struct prng *prng, struct vty *vty, const char *cmd, unsigned int edit_dist, unsigned int node_index, int verbose)
246 {
247 const char *test_str;
248 vector vline;
249 int ret;
250 unsigned int i;
251 char **completions;
252 unsigned int j;
253 struct cmd_node *cnode;
254 vector descriptions;
255 int appended_null;
256 int no_match;
257
258 test_str = prng_fuzz(prng, cmd, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_:. /", edit_dist);
259 vline = cmd_make_strvec(test_str);
260
261 if (vline == NULL)
262 return;
263
264 appended_null = 0;
265 for (i = 0; i < vector_active(cmdvec); i++)
266 if ((cnode = vector_slot(cmdvec, i)) != NULL)
267 {
268 if (node_index != (unsigned int)-1 && i != node_index)
269 continue;
270
271 if (appended_null)
272 {
273 vector_unset(vline, vector_active(vline) - 1);
274 appended_null = 0;
275 }
276 vty->node = cnode->node;
277 test_buf[0] = '\0';
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",
282 test_str,
283 cnode->node,
284 ret,
285 (test_buf[0] != '\0') ? ", " : "",
286 test_buf);
287
288 vty->node = cnode->node;
289 test_buf[0] = '\0';
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",
293 test_str,
294 cnode->node,
295 ret,
296 (test_buf[0] != '\0') ? ", " : "",
297 test_buf);
298
299 if (isspace((int) test_str[strlen(test_str) - 1]))
300 {
301 vector_set (vline, NULL);
302 appended_null = 1;
303 }
304
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",
309 test_str,
310 cnode->node,
311 ret);
312 if (completions != NULL)
313 {
314 for (j = 0; completions[j] != NULL; j++)
315 {
316 printf(" '%s'\n", completions[j]);
317 XFREE(MTYPE_TMP, completions[j]);
318 }
319 XFREE(MTYPE_TMP, completions);
320 }
321
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",
326 test_str,
327 cnode->node,
328 ret);
329 if (descriptions != NULL)
330 {
331 for (j = 0; j < vector_active(descriptions); j++)
332 {
333 struct cmd_token *cmd = vector_slot(descriptions, j);
334 printf(" '%s' '%s'\n", cmd->text, cmd->desc);
335 }
336 vector_free(descriptions);
337 }
338 }
339 cmd_free_strvec(vline);
340 }
341
342 int
343 main(int argc, char **argv)
344 {
345 int opt;
346 struct prng *prng;
347 struct vty *vty;
348 unsigned int edit_distance;
349 unsigned int max_edit_distance;
350 unsigned int node_index;
351 int verbose;
352 unsigned int test_cmd;
353 unsigned int iteration;
354 unsigned int num_iterations;
355
356 max_edit_distance = 3;
357 node_index = -1;
358 verbose = 0;
359
360 while ((opt = getopt(argc, argv, "e:n:v")) != -1)
361 {
362 switch (opt)
363 {
364 case 'e':
365 max_edit_distance = atoi(optarg);
366 break;
367 case 'n':
368 node_index = atoi(optarg);
369 break;
370 case 'v':
371 verbose++;
372 break;
373 default:
374 fprintf(stderr, "Usage: %s [-e <edit_dist>] [-n <node_idx>] [-v]\n", argv[0]);
375 exit(1);
376 break;
377 }
378 }
379
380 test_init();
381 prng = prng_new(0);
382
383 vty = vty_new();
384 vty->type = VTY_TERM;
385
386 fprintf(stderr, "Progress:\n0/%u", vector_active(test_cmds));
387 for (test_cmd = 0; test_cmd < vector_active(test_cmds); test_cmd++)
388 {
389 for (edit_distance = 0;
390 edit_distance <= max_edit_distance;
391 edit_distance++)
392 {
393 num_iterations = 1 << edit_distance;
394 num_iterations *= num_iterations * num_iterations;
395
396 for (iteration = 0; iteration < num_iterations; iteration++)
397 test_run(prng, vty, vector_slot(test_cmds, test_cmd), edit_distance, node_index, verbose);
398 }
399 fprintf(stderr, "\r%u/%u", test_cmd + 1, vector_active(test_cmds));
400 }
401 fprintf(stderr, "\nDone.\n");
402
403 vty_close(vty);
404 prng_free(prng);
405 test_terminate();
406 return 0;
407 }