blob: 76e9c15d0bef0c2cd565fd939ecbaa7ad2958eb1 [file] [log] [blame]
Jeremy Kerrc5ce2cb2019-07-26 09:21:35 +08001/**
2 * Copyright © 2019 IBM Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <assert.h>
18#include <stdint.h>
19#include <stdio.h>
20
21#define main __main
22#define read __read
23#include "console-client.c"
24#undef main
25#undef read
26
27struct test {
28 enum esc_type esc_type;
29 union {
30 struct ssh_esc_state ssh;
31 struct str_esc_state str;
32 } esc_state;
33 const char *in[4];
34 int n_in;
35 const char *exp_out;
36 int exp_rc;
37};
38
39struct test_ctx {
40 struct console_client client;
41 struct test *test;
42 uint8_t out[4096];
43 int cur_in;
44 int cur_out;
45};
46
47
48struct test tests[] = {
49 {
50 /* no escape code */
51 .esc_type = ESC_TYPE_SSH,
52 .in = {"a"},
53 .n_in = 1,
54 .exp_out = "a",
55 .exp_rc = PROCESS_EXIT,
56 },
57 {
58 /* no escape code, multiple reads */
59 .esc_type = ESC_TYPE_SSH,
60 .in = {"a", "b"},
61 .n_in = 2,
62 .exp_out = "ab",
63 .exp_rc = PROCESS_EXIT,
64 },
65 {
66 /* ssh escape in one read */
67 .esc_type = ESC_TYPE_SSH,
68 .in = {"a\r~."},
69 .n_in = 1,
70 .exp_out = "a\r",
71 .exp_rc = PROCESS_ESC,
72 },
73 {
74 /* ssh escape, partial ~ is not output. */
75 .esc_type = ESC_TYPE_SSH,
76 .in = {"a\r~"},
77 .n_in = 1,
78 .exp_out = "a\r",
79 .exp_rc = PROCESS_EXIT,
80 },
81 {
82 /* ssh escape split into individual reads */
83 .esc_type = ESC_TYPE_SSH,
84 .in = {"a", "\r", "~", "."},
85 .n_in = 4,
86 .exp_out = "a\r",
87 .exp_rc = PROCESS_ESC,
88 },
89 {
90 /* ssh escape, escaped. */
91 .esc_type = ESC_TYPE_SSH,
92 .in = {"a\r~~."},
93 .n_in = 1,
94 .exp_out = "a\r~.",
95 .exp_rc = PROCESS_EXIT,
96 },
97 {
98 /* ssh escape, escaped ~, and not completed. */
99 .esc_type = ESC_TYPE_SSH,
100 .in = {"a\r~~"},
101 .n_in = 1,
102 .exp_out = "a\r~",
103 .exp_rc = PROCESS_EXIT,
104 },
105 {
106 /* str escape, no match */
107 .esc_type = ESC_TYPE_STR,
108 .esc_state = { .str = { .str = (const uint8_t *)"c" } },
109 .in = {"ab"},
110 .n_in = 1,
111 .exp_out = "ab",
112 .exp_rc = PROCESS_EXIT,
113 },
114 {
115 /* str escape, one byte, as one read */
116 .esc_type = ESC_TYPE_STR,
117 .esc_state = { .str = { .str = (const uint8_t *)"b" } },
118 .in = {"abc"},
119 .n_in = 1,
120 .exp_out = "ab",
121 .exp_rc = PROCESS_ESC,
122 },
123 {
124 /* str escape, multiple bytes, as one read */
125 .esc_type = ESC_TYPE_STR,
126 .esc_state = { .str = { .str = (const uint8_t *)"bc" } },
127 .in = {"abcd"},
128 .n_in = 1,
129 .exp_out = "abc",
130 .exp_rc = PROCESS_ESC,
131 },
132 {
133 /* str escape, multiple bytes, split over reads */
134 .esc_type = ESC_TYPE_STR,
135 .esc_state = { .str = { .str = (const uint8_t *)"bc" } },
136 .in = {"ab", "cd"},
137 .n_in = 2,
138 .exp_out = "abc",
139 .exp_rc = PROCESS_ESC,
140 },
141 {
142 /* str escape, not matched due to intermediate data */
143 .esc_type = ESC_TYPE_STR,
144 .esc_state = { .str = { .str = (const uint8_t *)"ab" } },
145 .in = {"acb"},
146 .n_in = 1,
147 .exp_out = "acb",
148 .exp_rc = PROCESS_EXIT,
149 },
150};
151
152#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
153
154struct test_ctx ctxs[ARRAY_SIZE(tests)];
155
156/* stubs for console socket */
157const char *console_socket_path = "";
158const size_t console_socket_path_len = 1;
159const char *console_socket_path_readable = 0;
160
161int write_buf_to_fd(int fd, const uint8_t *buf, size_t len)
162{
163 struct test_ctx *ctx = &ctxs[fd];
164
165 assert(ctx->cur_out + len <= sizeof(ctx->out));
166 memcpy(ctx->out + ctx->cur_out, buf, len);
167 ctx->cur_out += len;
168
169 return 0;
170}
171
172ssize_t __read(int fd, void *buf, size_t len)
173{
174 struct test_ctx *ctx = &ctxs[fd];
175 const char *inbuf;
176 size_t inlen;
177
178 if (ctx->cur_in >= ctx->test->n_in)
179 return 0;
180
181 inbuf = ctx->test->in[ctx->cur_in];
182 inlen = strlen(inbuf);
183 assert(inlen <= len);
184 memcpy(buf, inbuf, inlen);
185 ctx->cur_in++;
186 return inlen;
187}
188
189void run_one_test(int idx, struct test *test, struct test_ctx *ctx)
190{
191 size_t exp_out_len;
192 int rc;
193
194 /* we store the index into the context array as a FD, so we
195 * can refer to it through the read & write callbacks.
196 */
197 ctx->client.console_sd = idx;
198 ctx->client.fd_in = idx;
199 ctx->client.esc_type = test->esc_type;
200 memcpy(&ctx->client.esc_state, &test->esc_state,
201 sizeof(test->esc_state));
202 ctx->test = test;
203
204 for (;;) {
205 rc = process_tty(&ctx->client);
206 if (rc != PROCESS_OK)
207 break;
208 }
209
210 exp_out_len = strlen(test->exp_out);
211
212#ifdef DEBUG
213 printf("got: rc %d %s(%d), exp: rc %d %s(%ld)\n",
214 rc, ctx->out, ctx->cur_out,
215 test->exp_rc, test->exp_out, exp_out_len);
216 fflush(stdout);
217#endif
218 assert(rc == test->exp_rc);
219 assert(exp_out_len == ctx->cur_out);
220 assert(!memcmp(ctx->out, test->exp_out, exp_out_len));
221}
222
223int main(void)
224{
225 int i;
226
227 for (i = 0; i < ARRAY_SIZE(tests); i++)
228 run_one_test(i, &tests[i], &ctxs[i]);
229
230 return EXIT_SUCCESS;
231}