]>
Commit | Line | Data |
---|---|---|
8f399b0e CF |
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 | * | |
896014f4 DL |
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 | |
8f399b0e CF |
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 | ||
55c72803 | 46 | struct thread_master *master; /* dummy for libfrr*/ |
8f399b0e CF |
47 | |
48 | static vector test_cmds; | |
49 | static char test_buf[32768]; | |
50 | ||
d62a17ae | 51 | static struct cmd_node bgp_node = { |
9d303b37 | 52 | BGP_NODE, "%s(config-router)# ", |
8f399b0e CF |
53 | }; |
54 | ||
d62a17ae | 55 | static struct cmd_node rip_node = { |
9d303b37 | 56 | RIP_NODE, "%s(config-router)# ", |
8f399b0e CF |
57 | }; |
58 | ||
d62a17ae | 59 | static struct cmd_node isis_node = { |
9d303b37 | 60 | ISIS_NODE, "%s(config-router)# ", |
8f399b0e CF |
61 | }; |
62 | ||
d62a17ae | 63 | static struct cmd_node interface_node = { |
9d303b37 | 64 | INTERFACE_NODE, "%s(config-if)# ", |
8f399b0e CF |
65 | }; |
66 | ||
d62a17ae | 67 | static struct cmd_node rmap_node = {RMAP_NODE, "%s(config-route-map)# "}; |
8f399b0e | 68 | |
d62a17ae | 69 | static struct cmd_node zebra_node = {ZEBRA_NODE, "%s(config-router)# "}; |
8f399b0e | 70 | |
d62a17ae | 71 | static struct cmd_node bgp_vpnv4_node = {BGP_VPNV4_NODE, |
72 | "%s(config-router-af)# "}; | |
8f399b0e | 73 | |
d62a17ae | 74 | static struct cmd_node bgp_ipv4_node = {BGP_IPV4_NODE, |
75 | "%s(config-router-af)# "}; | |
8f399b0e | 76 | |
d62a17ae | 77 | static struct cmd_node bgp_ipv4m_node = {BGP_IPV4M_NODE, |
78 | "%s(config-router-af)# "}; | |
8f399b0e | 79 | |
d62a17ae | 80 | static struct cmd_node bgp_ipv6_node = {BGP_IPV6_NODE, |
81 | "%s(config-router-af)# "}; | |
8f399b0e | 82 | |
d62a17ae | 83 | static struct cmd_node bgp_ipv6m_node = {BGP_IPV6M_NODE, |
84 | "%s(config-router-af)# "}; | |
8f399b0e | 85 | |
d62a17ae | 86 | static struct cmd_node ospf_node = {OSPF_NODE, "%s(config-router)# "}; |
8f399b0e | 87 | |
d62a17ae | 88 | static struct cmd_node ripng_node = {RIPNG_NODE, "%s(config-router)# "}; |
8f399b0e | 89 | |
d62a17ae | 90 | static struct cmd_node ospf6_node = {OSPF6_NODE, "%s(config-ospf6)# "}; |
8f399b0e | 91 | |
d62a17ae | 92 | static struct cmd_node keychain_node = {KEYCHAIN_NODE, "%s(config-keychain)# "}; |
8f399b0e | 93 | |
d62a17ae | 94 | static struct cmd_node keychain_key_node = {KEYCHAIN_KEY_NODE, |
95 | "%s(config-keychain-key)# "}; | |
8f399b0e | 96 | |
d62a17ae | 97 | static int test_callback(const struct cmd_element *cmd, struct vty *vty, |
98 | int argc, struct cmd_token *argv[]) | |
8f399b0e | 99 | { |
d62a17ae | 100 | int offset; |
101 | int rv; | |
102 | int i; | |
103 | ||
104 | offset = 0; | |
105 | rv = snprintf(test_buf, sizeof(test_buf), "'%s'", cmd->string); | |
106 | if (rv < 0) | |
107 | abort(); | |
108 | ||
109 | offset += rv; | |
110 | ||
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); | |
114 | if (rv < 0) | |
115 | abort(); | |
116 | offset += rv; | |
117 | } | |
118 | ||
119 | return CMD_SUCCESS; | |
8f399b0e CF |
120 | } |
121 | ||
d62a17ae | 122 | static void test_load(void) |
8f399b0e | 123 | { |
d62a17ae | 124 | char line[4096]; |
125 | ||
126 | test_cmds = vector_init(VECTOR_MIN_SIZE); | |
127 | ||
128 | while (fgets(line, sizeof(line), stdin) != NULL) { | |
129 | if (strlen(line)) | |
130 | line[strlen(line) - 1] = '\0'; | |
131 | if (line[0] == '#') | |
132 | continue; | |
fe011935 | 133 | vector_set(test_cmds, XSTRDUP(MTYPE_TMP, line)); |
d62a17ae | 134 | } |
8f399b0e CF |
135 | } |
136 | ||
d62a17ae | 137 | static void test_init(void) |
8f399b0e | 138 | { |
d62a17ae | 139 | unsigned int node; |
140 | unsigned int i; | |
141 | struct cmd_node *cnode; | |
142 | struct cmd_element *cmd; | |
143 | ||
144 | cmd_init(1); | |
1c2facd1 | 145 | yang_init(); |
fbdc1c0a | 146 | nb_init(master, NULL, 0); |
d62a17ae | 147 | |
148 | install_node(&bgp_node, NULL); | |
149 | install_node(&rip_node, NULL); | |
150 | install_node(&interface_node, NULL); | |
151 | install_node(&rmap_node, NULL); | |
152 | install_node(&zebra_node, NULL); | |
153 | install_node(&bgp_vpnv4_node, NULL); | |
154 | install_node(&bgp_ipv4_node, NULL); | |
155 | install_node(&bgp_ipv4m_node, NULL); | |
156 | install_node(&bgp_ipv6_node, NULL); | |
157 | install_node(&bgp_ipv6m_node, NULL); | |
158 | install_node(&ospf_node, NULL); | |
159 | install_node(&ripng_node, NULL); | |
160 | install_node(&ospf6_node, NULL); | |
161 | install_node(&keychain_node, NULL); | |
162 | install_node(&keychain_key_node, NULL); | |
163 | install_node(&isis_node, NULL); | |
164 | install_node(&vty_node, NULL); | |
165 | ||
166 | test_init_cmd(); | |
167 | ||
168 | for (node = 0; node < vector_active(cmdvec); node++) | |
169 | if ((cnode = vector_slot(cmdvec, node)) != NULL) | |
170 | for (i = 0; i < vector_active(cnode->cmd_vector); i++) | |
171 | if ((cmd = vector_slot(cnode->cmd_vector, i)) | |
172 | != NULL) { | |
173 | cmd->daemon = 0; | |
174 | cmd->func = test_callback; | |
175 | } | |
176 | test_load(); | |
177 | vty_init_vtysh(); | |
8f399b0e CF |
178 | } |
179 | ||
d62a17ae | 180 | static void test_terminate(void) |
8f399b0e | 181 | { |
d62a17ae | 182 | unsigned int i; |
8f399b0e | 183 | |
d62a17ae | 184 | vty_terminate(); |
185 | for (i = 0; i < vector_active(test_cmds); i++) | |
fe011935 | 186 | XFREE(MTYPE_TMP, vector_slot(test_cmds, i)); |
d62a17ae | 187 | vector_free(test_cmds); |
188 | cmd_terminate(); | |
1c2facd1 RW |
189 | nb_terminate(); |
190 | yang_terminate(); | |
8f399b0e CF |
191 | } |
192 | ||
d62a17ae | 193 | static void test_run(struct prng *prng, struct vty *vty, const char *cmd, |
194 | unsigned int edit_dist, unsigned int node_index, | |
195 | int verbose) | |
8f399b0e | 196 | { |
d62a17ae | 197 | const char *test_str; |
198 | vector vline; | |
199 | int ret; | |
200 | unsigned int i; | |
201 | char **completions; | |
202 | unsigned int j; | |
203 | struct cmd_node *cnode; | |
204 | vector descriptions; | |
205 | int appended_null; | |
206 | int no_match; | |
207 | ||
208 | test_str = prng_fuzz( | |
209 | prng, cmd, | |
210 | "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_:. /", | |
211 | edit_dist); | |
212 | vline = cmd_make_strvec(test_str); | |
213 | ||
214 | if (vline == NULL) | |
215 | return; | |
216 | ||
217 | appended_null = 0; | |
218 | for (i = 0; i < vector_active(cmdvec); i++) | |
219 | if ((cnode = vector_slot(cmdvec, i)) != NULL) { | |
220 | if (node_index != (unsigned int)-1 && i != node_index) | |
221 | continue; | |
222 | ||
223 | if (appended_null) { | |
224 | vector_unset(vline, vector_active(vline) - 1); | |
225 | appended_null = 0; | |
226 | } | |
227 | vty->node = cnode->node; | |
228 | test_buf[0] = '\0'; | |
229 | ret = cmd_execute_command(vline, vty, NULL, 0); | |
230 | no_match = (ret == CMD_ERR_NO_MATCH); | |
231 | if (verbose || !no_match) | |
232 | printf("execute relaxed '%s'@%d: rv==%d%s%s\n", | |
233 | test_str, cnode->node, ret, | |
234 | (test_buf[0] != '\0') ? ", " : "", | |
235 | test_buf); | |
236 | ||
237 | vty->node = cnode->node; | |
238 | test_buf[0] = '\0'; | |
239 | ret = cmd_execute_command_strict(vline, vty, NULL); | |
240 | if (verbose || !no_match) | |
241 | printf("execute strict '%s'@%d: rv==%d%s%s\n", | |
242 | test_str, cnode->node, ret, | |
243 | (test_buf[0] != '\0') ? ", " : "", | |
244 | test_buf); | |
245 | ||
246 | if (isspace((int)test_str[strlen(test_str) - 1])) { | |
247 | vector_set(vline, NULL); | |
248 | appended_null = 1; | |
249 | } | |
250 | ||
251 | vty->node = cnode->node; | |
252 | completions = cmd_complete_command(vline, vty, &ret); | |
253 | if (verbose || !no_match) | |
254 | printf("complete '%s'@%d: rv==%d\n", test_str, | |
255 | cnode->node, ret); | |
256 | if (completions != NULL) { | |
257 | for (j = 0; completions[j] != NULL; j++) { | |
258 | printf(" '%s'\n", completions[j]); | |
259 | XFREE(MTYPE_TMP, completions[j]); | |
260 | } | |
261 | XFREE(MTYPE_TMP, completions); | |
262 | } | |
263 | ||
264 | vty->node = cnode->node; | |
265 | descriptions = cmd_describe_command(vline, vty, &ret); | |
266 | if (verbose || !no_match) | |
267 | printf("describe '%s'@%d: rv==%d\n", test_str, | |
268 | cnode->node, ret); | |
269 | if (descriptions != NULL) { | |
270 | for (j = 0; j < vector_active(descriptions); | |
271 | j++) { | |
7fe96307 | 272 | struct cmd_token *ct = |
d62a17ae | 273 | vector_slot(descriptions, j); |
7fe96307 A |
274 | printf(" '%s' '%s'\n", ct->text, |
275 | ct->desc); | |
d62a17ae | 276 | } |
277 | vector_free(descriptions); | |
278 | } | |
279 | } | |
280 | cmd_free_strvec(vline); | |
8f399b0e CF |
281 | } |
282 | ||
d62a17ae | 283 | int main(int argc, char **argv) |
8f399b0e | 284 | { |
d62a17ae | 285 | int opt; |
286 | struct prng *prng; | |
287 | struct vty *vty; | |
288 | unsigned int edit_distance; | |
289 | unsigned int max_edit_distance; | |
290 | unsigned int node_index; | |
291 | int verbose; | |
292 | unsigned int test_cmd; | |
293 | unsigned int iteration; | |
294 | unsigned int num_iterations; | |
295 | ||
296 | max_edit_distance = 3; | |
297 | node_index = -1; | |
298 | verbose = 0; | |
299 | ||
300 | while ((opt = getopt(argc, argv, "e:n:v")) != -1) { | |
301 | switch (opt) { | |
302 | case 'e': | |
303 | max_edit_distance = atoi(optarg); | |
304 | break; | |
305 | case 'n': | |
306 | node_index = atoi(optarg); | |
307 | break; | |
308 | case 'v': | |
309 | verbose++; | |
310 | break; | |
311 | default: | |
312 | fprintf(stderr, | |
313 | "Usage: %s [-e <edit_dist>] [-n <node_idx>] [-v]\n", | |
314 | argv[0]); | |
315 | exit(1); | |
316 | break; | |
317 | } | |
318 | } | |
319 | ||
320 | test_init(); | |
321 | prng = prng_new(0); | |
322 | ||
323 | vty = vty_new(); | |
324 | vty->type = VTY_TERM; | |
325 | ||
326 | fprintf(stderr, "Progress:\n0/%u", vector_active(test_cmds)); | |
327 | for (test_cmd = 0; test_cmd < vector_active(test_cmds); test_cmd++) { | |
328 | for (edit_distance = 0; edit_distance <= max_edit_distance; | |
329 | edit_distance++) { | |
330 | num_iterations = 1 << edit_distance; | |
331 | num_iterations *= num_iterations * num_iterations; | |
332 | ||
333 | for (iteration = 0; iteration < num_iterations; | |
334 | iteration++) | |
335 | test_run(prng, vty, | |
336 | vector_slot(test_cmds, test_cmd), | |
337 | edit_distance, node_index, verbose); | |
338 | } | |
339 | fprintf(stderr, "\r%u/%u", test_cmd + 1, | |
340 | vector_active(test_cmds)); | |
341 | } | |
342 | fprintf(stderr, "\nDone.\n"); | |
343 | ||
344 | vty_close(vty); | |
345 | prng_free(prng); | |
346 | test_terminate(); | |
347 | return 0; | |
8f399b0e | 348 | } |