blob: eeae0159c80e44068cabeceac88b19b61908f032 [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
Jeremy Kerrc5ce2cb2019-07-26 09:21:35 +080021#define read __read
Andrew Jeffery5e7c0782020-02-10 12:12:36 +103022#include "console-socket.c"
23#define main __main
Jeremy Kerrc5ce2cb2019-07-26 09:21:35 +080024#include "console-client.c"
Jeremy Kerrc5ce2cb2019-07-26 09:21:35 +080025#undef read
Andrew Jeffery5e7c0782020-02-10 12:12:36 +103026#undef main
Jeremy Kerrc5ce2cb2019-07-26 09:21:35 +080027
28struct test {
29 enum esc_type esc_type;
30 union {
31 struct ssh_esc_state ssh;
32 struct str_esc_state str;
33 } esc_state;
34 const char *in[4];
35 int n_in;
36 const char *exp_out;
37 int exp_rc;
38};
39
40struct test_ctx {
41 struct console_client client;
42 struct test *test;
43 uint8_t out[4096];
44 int cur_in;
45 int cur_out;
46};
47
48
49struct test tests[] = {
50 {
51 /* no escape code */
52 .esc_type = ESC_TYPE_SSH,
53 .in = {"a"},
54 .n_in = 1,
55 .exp_out = "a",
56 .exp_rc = PROCESS_EXIT,
57 },
58 {
59 /* no escape code, multiple reads */
60 .esc_type = ESC_TYPE_SSH,
61 .in = {"a", "b"},
62 .n_in = 2,
63 .exp_out = "ab",
64 .exp_rc = PROCESS_EXIT,
65 },
66 {
67 /* ssh escape in one read */
68 .esc_type = ESC_TYPE_SSH,
69 .in = {"a\r~."},
70 .n_in = 1,
71 .exp_out = "a\r",
72 .exp_rc = PROCESS_ESC,
73 },
74 {
75 /* ssh escape, partial ~ is not output. */
76 .esc_type = ESC_TYPE_SSH,
77 .in = {"a\r~"},
78 .n_in = 1,
79 .exp_out = "a\r",
80 .exp_rc = PROCESS_EXIT,
81 },
82 {
83 /* ssh escape split into individual reads */
84 .esc_type = ESC_TYPE_SSH,
85 .in = {"a", "\r", "~", "."},
86 .n_in = 4,
87 .exp_out = "a\r",
88 .exp_rc = PROCESS_ESC,
89 },
90 {
91 /* ssh escape, escaped. */
92 .esc_type = ESC_TYPE_SSH,
93 .in = {"a\r~~."},
94 .n_in = 1,
95 .exp_out = "a\r~.",
96 .exp_rc = PROCESS_EXIT,
97 },
98 {
99 /* ssh escape, escaped ~, and not completed. */
100 .esc_type = ESC_TYPE_SSH,
101 .in = {"a\r~~"},
102 .n_in = 1,
103 .exp_out = "a\r~",
104 .exp_rc = PROCESS_EXIT,
105 },
106 {
107 /* str escape, no match */
108 .esc_type = ESC_TYPE_STR,
109 .esc_state = { .str = { .str = (const uint8_t *)"c" } },
110 .in = {"ab"},
111 .n_in = 1,
112 .exp_out = "ab",
113 .exp_rc = PROCESS_EXIT,
114 },
115 {
116 /* str escape, one byte, as one read */
117 .esc_type = ESC_TYPE_STR,
118 .esc_state = { .str = { .str = (const uint8_t *)"b" } },
119 .in = {"abc"},
120 .n_in = 1,
121 .exp_out = "ab",
122 .exp_rc = PROCESS_ESC,
123 },
124 {
125 /* str escape, multiple bytes, as one read */
126 .esc_type = ESC_TYPE_STR,
127 .esc_state = { .str = { .str = (const uint8_t *)"bc" } },
128 .in = {"abcd"},
129 .n_in = 1,
130 .exp_out = "abc",
131 .exp_rc = PROCESS_ESC,
132 },
133 {
134 /* str escape, multiple bytes, split over reads */
135 .esc_type = ESC_TYPE_STR,
136 .esc_state = { .str = { .str = (const uint8_t *)"bc" } },
137 .in = {"ab", "cd"},
138 .n_in = 2,
139 .exp_out = "abc",
140 .exp_rc = PROCESS_ESC,
141 },
142 {
143 /* str escape, not matched due to intermediate data */
144 .esc_type = ESC_TYPE_STR,
145 .esc_state = { .str = { .str = (const uint8_t *)"ab" } },
146 .in = {"acb"},
147 .n_in = 1,
148 .exp_out = "acb",
149 .exp_rc = PROCESS_EXIT,
150 },
151};
152
153#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
154
155struct test_ctx ctxs[ARRAY_SIZE(tests)];
156
Jeremy Kerrc5ce2cb2019-07-26 09:21:35 +0800157int write_buf_to_fd(int fd, const uint8_t *buf, size_t len)
158{
159 struct test_ctx *ctx = &ctxs[fd];
160
161 assert(ctx->cur_out + len <= sizeof(ctx->out));
162 memcpy(ctx->out + ctx->cur_out, buf, len);
163 ctx->cur_out += len;
164
165 return 0;
166}
167
168ssize_t __read(int fd, void *buf, size_t len)
169{
170 struct test_ctx *ctx = &ctxs[fd];
171 const char *inbuf;
172 size_t inlen;
173
174 if (ctx->cur_in >= ctx->test->n_in)
175 return 0;
176
177 inbuf = ctx->test->in[ctx->cur_in];
178 inlen = strlen(inbuf);
179 assert(inlen <= len);
180 memcpy(buf, inbuf, inlen);
181 ctx->cur_in++;
182 return inlen;
183}
184
185void run_one_test(int idx, struct test *test, struct test_ctx *ctx)
186{
187 size_t exp_out_len;
188 int rc;
189
190 /* we store the index into the context array as a FD, so we
191 * can refer to it through the read & write callbacks.
192 */
193 ctx->client.console_sd = idx;
194 ctx->client.fd_in = idx;
195 ctx->client.esc_type = test->esc_type;
196 memcpy(&ctx->client.esc_state, &test->esc_state,
197 sizeof(test->esc_state));
198 ctx->test = test;
199
200 for (;;) {
201 rc = process_tty(&ctx->client);
202 if (rc != PROCESS_OK)
203 break;
204 }
205
206 exp_out_len = strlen(test->exp_out);
207
208#ifdef DEBUG
209 printf("got: rc %d %s(%d), exp: rc %d %s(%ld)\n",
210 rc, ctx->out, ctx->cur_out,
211 test->exp_rc, test->exp_out, exp_out_len);
212 fflush(stdout);
213#endif
214 assert(rc == test->exp_rc);
215 assert(exp_out_len == ctx->cur_out);
216 assert(!memcmp(ctx->out, test->exp_out, exp_out_len));
217}
218
219int main(void)
220{
221 int i;
222
223 for (i = 0; i < ARRAY_SIZE(tests); i++)
224 run_one_test(i, &tests[i], &ctxs[i]);
225
226 return EXIT_SUCCESS;
227}