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