1 | /* |
---|
2 | * Test suite for the high-level remctl library API. |
---|
3 | * |
---|
4 | * Written by Russ Allbery <rra@stanford.edu> |
---|
5 | * Copyright 2006, 2007, 2009 |
---|
6 | * Board of Trustees, Leland Stanford Jr. University |
---|
7 | * |
---|
8 | * See LICENSE for licensing terms. |
---|
9 | */ |
---|
10 | |
---|
11 | #include <config.h> |
---|
12 | #include <portable/system.h> |
---|
13 | |
---|
14 | #include <signal.h> |
---|
15 | #ifdef HAVE_SYS_SELECT_H |
---|
16 | # include <sys/select.h> |
---|
17 | #endif |
---|
18 | #include <sys/time.h> |
---|
19 | #include <sys/uio.h> |
---|
20 | #include <sys/wait.h> |
---|
21 | |
---|
22 | #include <client/remctl.h> |
---|
23 | #include <client/internal.h> |
---|
24 | #include <tests/tap/basic.h> |
---|
25 | #include <tests/tap/kerberos.h> |
---|
26 | #include <tests/tap/remctl.h> |
---|
27 | #include <util/util.h> |
---|
28 | |
---|
29 | |
---|
30 | /* |
---|
31 | * Takes the principal and the protocol version and runs a set of tests. Due |
---|
32 | * to the compatibility layer, we should be able to run the same commands |
---|
33 | * regardless of the protocol (we're not testing any of the v2-specific |
---|
34 | * features here). |
---|
35 | */ |
---|
36 | static void |
---|
37 | do_tests(const char *principal, int protocol) |
---|
38 | { |
---|
39 | struct remctl *r; |
---|
40 | struct iovec *command; |
---|
41 | struct remctl_output *output; |
---|
42 | const char *test[] = { "test", "test", NULL }; |
---|
43 | const char *error[] = { "test", "bad-command", NULL }; |
---|
44 | const char *no_service[] = { "all", NULL }; |
---|
45 | |
---|
46 | /* Open the connection. */ |
---|
47 | r = remctl_new(); |
---|
48 | ok(r != NULL, "protocol %d: remctl_new", protocol); |
---|
49 | is_string("no error", remctl_error(r), "remctl_error with no error"); |
---|
50 | r->protocol = protocol; |
---|
51 | ok(remctl_open(r, "localhost", 14373, principal), "remctl_open"); |
---|
52 | is_string("no error", remctl_error(r), "...still no error"); |
---|
53 | |
---|
54 | /* Send a successful command. */ |
---|
55 | ok(remctl_command(r, test), "remctl_command"); |
---|
56 | is_string("no error", remctl_error(r), "...still no error"); |
---|
57 | output = remctl_output(r); |
---|
58 | ok(output != NULL, "first output token is not null"); |
---|
59 | if (output == NULL) |
---|
60 | ok(0, "...and has correct content"); |
---|
61 | else { |
---|
62 | is_int(REMCTL_OUT_OUTPUT, output->type, "...and is right type"); |
---|
63 | is_int(12, output->length, "...and is right length"); |
---|
64 | if (output->data == NULL) |
---|
65 | ok(0, "...and is right data"); |
---|
66 | else |
---|
67 | ok(memcmp("hello world\n", output->data, 11) == 0, |
---|
68 | "...and is right data"); |
---|
69 | is_int(1, output->stream, "...and is right stream"); |
---|
70 | } |
---|
71 | output = remctl_output(r); |
---|
72 | ok(output != NULL, "second output token is not null"); |
---|
73 | is_int(REMCTL_OUT_STATUS, output->type, "...and is right type"); |
---|
74 | is_int(0, output->status, "...and is right status"); |
---|
75 | command = xcalloc(2, sizeof(struct iovec)); |
---|
76 | command[0].iov_base = (char *) "test"; |
---|
77 | command[0].iov_len = 4; |
---|
78 | command[1].iov_base = (char *) "test"; |
---|
79 | command[1].iov_len = 4; |
---|
80 | ok(remctl_commandv(r, command, 2), "remctl_commandv"); |
---|
81 | is_string("no error", remctl_error(r), "...still no error"); |
---|
82 | output = remctl_output(r); |
---|
83 | ok(output != NULL, "first output token is not null"); |
---|
84 | is_int(REMCTL_OUT_OUTPUT, output->type, "...and is right type"); |
---|
85 | is_int(12, output->length, "...and is right length"); |
---|
86 | if (output->data == NULL) |
---|
87 | ok(0, "...and is right data"); |
---|
88 | else |
---|
89 | ok(memcmp("hello world\n", output->data, 11) == 0, |
---|
90 | "...and is right data"); |
---|
91 | is_int(1, output->stream, "...and is right stream"); |
---|
92 | output = remctl_output(r); |
---|
93 | ok(output != NULL, "second output token is not null"); |
---|
94 | is_int(REMCTL_OUT_STATUS, output->type, "...and is right type"); |
---|
95 | is_int(0, output->status, "...and is right status"); |
---|
96 | |
---|
97 | /* Send a failing command. */ |
---|
98 | ok(remctl_command(r, error), "remctl_command of error command"); |
---|
99 | is_string("no error", remctl_error(r), "...no error on send"); |
---|
100 | output = remctl_output(r); |
---|
101 | ok(output != NULL, "first output token is not null"); |
---|
102 | if (protocol == 1) { |
---|
103 | is_int(REMCTL_OUT_OUTPUT, output->type, |
---|
104 | "...and is right protocol 1 type"); |
---|
105 | is_int(16, output->length, "...and is right length"); |
---|
106 | if (output->data == NULL) |
---|
107 | ok(0, "...and has the right error message"); |
---|
108 | else |
---|
109 | ok(memcmp("Unknown command\n", output->data, 16) == 0, |
---|
110 | "...and has the right error message"); |
---|
111 | is_int(1, output->stream, "...and is right stream"); |
---|
112 | output = remctl_output(r); |
---|
113 | ok(output != NULL, "second output token is not null"); |
---|
114 | is_int(REMCTL_OUT_STATUS, output->type, "...and is right type"); |
---|
115 | is_int(-1, output->status, "...and is right status"); |
---|
116 | } else { |
---|
117 | is_int(REMCTL_OUT_ERROR, output->type, |
---|
118 | "...and is right protocol 2 type"); |
---|
119 | is_int(15, output->length, "...and is right length"); |
---|
120 | if (output->data == NULL) |
---|
121 | ok(0, "...and has the right error message"); |
---|
122 | else |
---|
123 | ok(memcmp("Unknown command", output->data, 15) == 0, |
---|
124 | "...and has the right error message"); |
---|
125 | is_int(ERROR_UNKNOWN_COMMAND, output->error, "...and error number"); |
---|
126 | } |
---|
127 | |
---|
128 | /* Send a command with no service. */ |
---|
129 | ok(remctl_command(r, no_service), "remctl_command with no service"); |
---|
130 | is_string("no error", remctl_error(r), "...and no error"); |
---|
131 | output = remctl_output(r); |
---|
132 | ok(output != NULL, "...and non-null output token"); |
---|
133 | is_int(REMCTL_OUT_OUTPUT, output->type, "...of correct type"); |
---|
134 | is_int(12, output->length, "...and length"); |
---|
135 | if (output->data == NULL) |
---|
136 | ok(0, "...and data"); |
---|
137 | else |
---|
138 | ok(memcmp("hello world\n", output->data, 11) == 0, "...and data"); |
---|
139 | is_int(1, output->stream, "...and stream"); |
---|
140 | output = remctl_output(r); |
---|
141 | ok(output != NULL, "...and non-null second token"); |
---|
142 | is_int(REMCTL_OUT_STATUS, output->type, "...of right type"); |
---|
143 | is_int(0, output->status, "...and status"); |
---|
144 | |
---|
145 | /* All done. */ |
---|
146 | remctl_close(r); |
---|
147 | ok(1, "remctl_close didn't explode"); |
---|
148 | } |
---|
149 | |
---|
150 | |
---|
151 | int |
---|
152 | main(void) |
---|
153 | { |
---|
154 | char *principal, *path, *config; |
---|
155 | pid_t remctld; |
---|
156 | struct remctl_result *result; |
---|
157 | const char *test[] = { "test", "test", NULL }; |
---|
158 | const char *error[] = { "test", "bad-command", NULL }; |
---|
159 | |
---|
160 | if (chdir(getenv("SOURCE")) < 0) |
---|
161 | bail("can't chdir to SOURCE"); |
---|
162 | principal = kerberos_setup(); |
---|
163 | if (principal == NULL) |
---|
164 | skip_all("Kerberos tests not configured"); |
---|
165 | plan(98); |
---|
166 | config = concatpath(getenv("SOURCE"), "data/conf-simple"); |
---|
167 | path = concatpath(getenv("BUILD"), "../server/remctld"); |
---|
168 | remctld = remctld_start(path, principal, config); |
---|
169 | |
---|
170 | /* Run the basic protocol tests. */ |
---|
171 | do_tests(principal, 1); |
---|
172 | do_tests(principal, 2); |
---|
173 | |
---|
174 | /* |
---|
175 | * We don't have a way of forcing the simple protocol to use a particular |
---|
176 | * protocol, so we always do it via protocol v2. But if the above worked |
---|
177 | * with protocol v1, and this wrapper works with v2, everything should |
---|
178 | * have gotten tested. |
---|
179 | */ |
---|
180 | result = remctl("localhost", 14373, principal, test); |
---|
181 | ok(result != NULL, "basic remctl API works"); |
---|
182 | is_int(0, result->status, "...with correct status"); |
---|
183 | is_int(0, result->stderr_len, "...and no stderr"); |
---|
184 | is_int(12, result->stdout_len, "...and correct stdout_len"); |
---|
185 | if (result->stdout_buf == NULL) |
---|
186 | ok(0, "...and correct data"); |
---|
187 | else |
---|
188 | ok(memcmp("hello world\n", result->stdout_buf, 11) == 0, |
---|
189 | "...and correct data"); |
---|
190 | ok(result->error == NULL, "...and no error"); |
---|
191 | remctl_result_free(result); |
---|
192 | result = remctl("localhost", 14373, principal, error); |
---|
193 | ok(result != NULL, "remctl API with error works"); |
---|
194 | is_int(0, result->status, "...with correct status"); |
---|
195 | is_int(0, result->stdout_len, "...and no stdout"); |
---|
196 | is_int(0, result->stderr_len, "...and no stderr"); |
---|
197 | if (result->error == NULL) |
---|
198 | ok(0, "...and the right error string"); |
---|
199 | else |
---|
200 | is_string("Unknown command", result->error, |
---|
201 | "...and the right error string"); |
---|
202 | remctl_result_free(result); |
---|
203 | |
---|
204 | remctld_stop(remctld); |
---|
205 | kerberos_cleanup(); |
---|
206 | return 0; |
---|
207 | } |
---|