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