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