1d4afb5ceSopenharmony_ci /*
2d4afb5ceSopenharmony_ci * libwebsockets - small server side websockets and web server implementation
3d4afb5ceSopenharmony_ci *
4d4afb5ceSopenharmony_ci * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
5d4afb5ceSopenharmony_ci *
6d4afb5ceSopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy
7d4afb5ceSopenharmony_ci * of this software and associated documentation files (the "Software"), to
8d4afb5ceSopenharmony_ci * deal in the Software without restriction, including without limitation the
9d4afb5ceSopenharmony_ci * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10d4afb5ceSopenharmony_ci * sell copies of the Software, and to permit persons to whom the Software is
11d4afb5ceSopenharmony_ci * furnished to do so, subject to the following conditions:
12d4afb5ceSopenharmony_ci *
13d4afb5ceSopenharmony_ci * The above copyright notice and this permission notice shall be included in
14d4afb5ceSopenharmony_ci * all copies or substantial portions of the Software.
15d4afb5ceSopenharmony_ci *
16d4afb5ceSopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17d4afb5ceSopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18d4afb5ceSopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19d4afb5ceSopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20d4afb5ceSopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21d4afb5ceSopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22d4afb5ceSopenharmony_ci * IN THE SOFTWARE.
23d4afb5ceSopenharmony_ci *
24d4afb5ceSopenharmony_ci * An abstract transport that is useful for unit testing an abstract protocol.
25d4afb5ceSopenharmony_ci * It doesn't actually connect to anything, but checks the protocol's response
26d4afb5ceSopenharmony_ci * to provided canned packets from an array of test vectors.
27d4afb5ceSopenharmony_ci */
28d4afb5ceSopenharmony_ci
29d4afb5ceSopenharmony_ci#include "private-lib-core.h"
30d4afb5ceSopenharmony_ci#include "private-lib-abstract.h"
31d4afb5ceSopenharmony_ci
32d4afb5ceSopenharmony_ci/* this is the transport priv instantiated at abs->ati */
33d4afb5ceSopenharmony_ci
34d4afb5ceSopenharmony_citypedef struct lws_abstxp_unit_test_priv {
35d4afb5ceSopenharmony_ci	char					note[128];
36d4afb5ceSopenharmony_ci	struct lws_abs				*abs;
37d4afb5ceSopenharmony_ci
38d4afb5ceSopenharmony_ci	struct lws_sequencer			*seq;
39d4afb5ceSopenharmony_ci	lws_unit_test_t				*current_test;
40d4afb5ceSopenharmony_ci	lws_unit_test_packet_t			*expect;
41d4afb5ceSopenharmony_ci	lws_unit_test_packet_test_cb		result_cb;
42d4afb5ceSopenharmony_ci	const void				*result_cb_arg;
43d4afb5ceSopenharmony_ci
44d4afb5ceSopenharmony_ci	lws_unit_test_packet_disposition	disposition;
45d4afb5ceSopenharmony_ci	/* synthesized protocol timeout */
46d4afb5ceSopenharmony_ci	time_t					timeout;
47d4afb5ceSopenharmony_ci
48d4afb5ceSopenharmony_ci	uint8_t					established:1;
49d4afb5ceSopenharmony_ci	uint8_t					connecting:1;
50d4afb5ceSopenharmony_ci} abs_unit_test_priv_t;
51d4afb5ceSopenharmony_ci
52d4afb5ceSopenharmony_citypedef struct seq_priv {
53d4afb5ceSopenharmony_ci	lws_abs_t *ai;
54d4afb5ceSopenharmony_ci} seq_priv_t;
55d4afb5ceSopenharmony_ci
56d4afb5ceSopenharmony_cienum {
57d4afb5ceSopenharmony_ci	UTSEQ_MSG_WRITEABLE = LWSSEQ_USER_BASE,
58d4afb5ceSopenharmony_ci	UTSEQ_MSG_CLOSING,
59d4afb5ceSopenharmony_ci	UTSEQ_MSG_TIMEOUT,
60d4afb5ceSopenharmony_ci	UTSEQ_MSG_CONNECTING,
61d4afb5ceSopenharmony_ci	UTSEQ_MSG_POST_TX_KICK,
62d4afb5ceSopenharmony_ci	UTSEQ_MSG_DISPOSITION_KNOWN
63d4afb5ceSopenharmony_ci};
64d4afb5ceSopenharmony_ci
65d4afb5ceSopenharmony_ci/*
66d4afb5ceSopenharmony_ci * A definitive result has appeared for the current test
67d4afb5ceSopenharmony_ci */
68d4afb5ceSopenharmony_ci
69d4afb5ceSopenharmony_cistatic lws_unit_test_packet_disposition
70d4afb5ceSopenharmony_cilws_unit_test_packet_dispose(abs_unit_test_priv_t *priv,
71d4afb5ceSopenharmony_ci			    lws_unit_test_packet_disposition disp,
72d4afb5ceSopenharmony_ci			    const char *note)
73d4afb5ceSopenharmony_ci{
74d4afb5ceSopenharmony_ci	assert(priv->disposition == LPE_CONTINUE);
75d4afb5ceSopenharmony_ci
76d4afb5ceSopenharmony_ci	lwsl_info("%s: %d\n", __func__, disp);
77d4afb5ceSopenharmony_ci
78d4afb5ceSopenharmony_ci	if (note)
79d4afb5ceSopenharmony_ci		lws_strncpy(priv->note, note, sizeof(priv->note));
80d4afb5ceSopenharmony_ci
81d4afb5ceSopenharmony_ci	priv->disposition = disp;
82d4afb5ceSopenharmony_ci
83d4afb5ceSopenharmony_ci	lws_seq_queue_event(priv->seq, UTSEQ_MSG_DISPOSITION_KNOWN,
84d4afb5ceSopenharmony_ci				  NULL, NULL);
85d4afb5ceSopenharmony_ci
86d4afb5ceSopenharmony_ci	return disp;
87d4afb5ceSopenharmony_ci}
88d4afb5ceSopenharmony_ci
89d4afb5ceSopenharmony_ci/*
90d4afb5ceSopenharmony_ci * start on the next step of the test
91d4afb5ceSopenharmony_ci */
92d4afb5ceSopenharmony_ci
93d4afb5ceSopenharmony_cilws_unit_test_packet_disposition
94d4afb5ceSopenharmony_ciprocess_expect(abs_unit_test_priv_t *priv)
95d4afb5ceSopenharmony_ci{
96d4afb5ceSopenharmony_ci	assert(priv->disposition == LPE_CONTINUE);
97d4afb5ceSopenharmony_ci
98d4afb5ceSopenharmony_ci	while (priv->expect->flags & LWS_AUT_EXPECT_RX &&
99d4afb5ceSopenharmony_ci	       priv->disposition == LPE_CONTINUE) {
100d4afb5ceSopenharmony_ci		int f = priv->expect->flags & LWS_AUT_EXPECT_LOCAL_CLOSE, s;
101d4afb5ceSopenharmony_ci
102d4afb5ceSopenharmony_ci		if (priv->expect->pre)
103d4afb5ceSopenharmony_ci			priv->expect->pre(priv->abs);
104d4afb5ceSopenharmony_ci
105d4afb5ceSopenharmony_ci		lwsl_info("%s: rx()\n", __func__);
106d4afb5ceSopenharmony_ci		lwsl_hexdump_debug(priv->expect->buffer, priv->expect->len);
107d4afb5ceSopenharmony_ci		s = priv->abs->ap->rx(priv->abs->api, priv->expect->buffer,
108d4afb5ceSopenharmony_ci							priv->expect->len);
109d4afb5ceSopenharmony_ci
110d4afb5ceSopenharmony_ci		if (!!f != !!s) {
111d4afb5ceSopenharmony_ci			lwsl_notice("%s: expected rx return %d, got %d\n",
112d4afb5ceSopenharmony_ci					__func__, !!f, s);
113d4afb5ceSopenharmony_ci
114d4afb5ceSopenharmony_ci			return lws_unit_test_packet_dispose(priv, LPE_FAILED,
115d4afb5ceSopenharmony_ci						  "rx unexpected return");
116d4afb5ceSopenharmony_ci		}
117d4afb5ceSopenharmony_ci
118d4afb5ceSopenharmony_ci		if (priv->expect->flags & LWS_AUT_EXPECT_TEST_END) {
119d4afb5ceSopenharmony_ci			lws_unit_test_packet_dispose(priv, LPE_SUCCEEDED, NULL);
120d4afb5ceSopenharmony_ci			break;
121d4afb5ceSopenharmony_ci		}
122d4afb5ceSopenharmony_ci
123d4afb5ceSopenharmony_ci		priv->expect++;
124d4afb5ceSopenharmony_ci	}
125d4afb5ceSopenharmony_ci
126d4afb5ceSopenharmony_ci	return LPE_CONTINUE;
127d4afb5ceSopenharmony_ci}
128d4afb5ceSopenharmony_ci
129d4afb5ceSopenharmony_cistatic lws_seq_cb_return_t
130d4afb5ceSopenharmony_ciunit_test_sequencer_cb(struct lws_sequencer *seq, void *user, int event,
131d4afb5ceSopenharmony_ci		       void *data, void *aux)
132d4afb5ceSopenharmony_ci{
133d4afb5ceSopenharmony_ci	seq_priv_t *s = (seq_priv_t *)user;
134d4afb5ceSopenharmony_ci	abs_unit_test_priv_t *priv = (abs_unit_test_priv_t *)s->ai->ati;
135d4afb5ceSopenharmony_ci	time_t now;
136d4afb5ceSopenharmony_ci
137d4afb5ceSopenharmony_ci	switch ((int)event) {
138d4afb5ceSopenharmony_ci	case LWSSEQ_CREATED: /* our sequencer just got started */
139d4afb5ceSopenharmony_ci		lwsl_notice("%s: %s: created\n", __func__,
140d4afb5ceSopenharmony_ci			    lws_seq_name(seq));
141d4afb5ceSopenharmony_ci		if (s->ai->at->client_conn(s->ai)) {
142d4afb5ceSopenharmony_ci			lwsl_notice("%s: %s: abstract client conn failed\n",
143d4afb5ceSopenharmony_ci					__func__, lws_seq_name(seq));
144d4afb5ceSopenharmony_ci
145d4afb5ceSopenharmony_ci			return LWSSEQ_RET_DESTROY;
146d4afb5ceSopenharmony_ci		}
147d4afb5ceSopenharmony_ci		break;
148d4afb5ceSopenharmony_ci
149d4afb5ceSopenharmony_ci	case LWSSEQ_DESTROYED:
150d4afb5ceSopenharmony_ci		/*
151d4afb5ceSopenharmony_ci		 * This sequencer is about to be destroyed.  If we have any
152d4afb5ceSopenharmony_ci		 * other assets in play, detach them from us.
153d4afb5ceSopenharmony_ci		 */
154d4afb5ceSopenharmony_ci
155d4afb5ceSopenharmony_ci		if (priv->abs)
156d4afb5ceSopenharmony_ci			lws_abs_destroy_instance(&priv->abs);
157d4afb5ceSopenharmony_ci
158d4afb5ceSopenharmony_ci		break;
159d4afb5ceSopenharmony_ci
160d4afb5ceSopenharmony_ci	case LWSSEQ_HEARTBEAT:
161d4afb5ceSopenharmony_ci
162d4afb5ceSopenharmony_ci		/* synthesize a wsi-style timeout */
163d4afb5ceSopenharmony_ci
164d4afb5ceSopenharmony_ci		if (!priv->timeout)
165d4afb5ceSopenharmony_ci			goto ph;
166d4afb5ceSopenharmony_ci
167d4afb5ceSopenharmony_ci		time(&now);
168d4afb5ceSopenharmony_ci
169d4afb5ceSopenharmony_ci		if (now <= priv->timeout)
170d4afb5ceSopenharmony_ci			goto ph;
171d4afb5ceSopenharmony_ci
172d4afb5ceSopenharmony_ci		if (priv->expect->flags & LWS_AUT_EXPECT_SHOULD_TIMEOUT) {
173d4afb5ceSopenharmony_ci			lwsl_user("%s: test got expected timeout\n",
174d4afb5ceSopenharmony_ci				  __func__);
175d4afb5ceSopenharmony_ci			lws_unit_test_packet_dispose(priv,
176d4afb5ceSopenharmony_ci					LPE_FAILED_UNEXPECTED_TIMEOUT, NULL);
177d4afb5ceSopenharmony_ci
178d4afb5ceSopenharmony_ci			return LWSSEQ_RET_DESTROY;
179d4afb5ceSopenharmony_ci		}
180d4afb5ceSopenharmony_ci		lwsl_user("%s: seq timed out\n", __func__);
181d4afb5ceSopenharmony_ci
182d4afb5ceSopenharmony_ciph:
183d4afb5ceSopenharmony_ci		if (priv->abs->ap->heartbeat)
184d4afb5ceSopenharmony_ci			priv->abs->ap->heartbeat(priv->abs->api);
185d4afb5ceSopenharmony_ci		break;
186d4afb5ceSopenharmony_ci
187d4afb5ceSopenharmony_ci	case UTSEQ_MSG_DISPOSITION_KNOWN:
188d4afb5ceSopenharmony_ci
189d4afb5ceSopenharmony_ci		lwsl_info("%s: %s: DISPOSITION_KNOWN %s: %s\n", __func__,
190d4afb5ceSopenharmony_ci			  priv->abs->ap->name,
191d4afb5ceSopenharmony_ci			  priv->current_test->name,
192d4afb5ceSopenharmony_ci			  priv->disposition == LPE_SUCCEEDED ? "OK" : "FAIL");
193d4afb5ceSopenharmony_ci
194d4afb5ceSopenharmony_ci		/*
195d4afb5ceSopenharmony_ci		 * if the test has a callback, call it back to let it
196d4afb5ceSopenharmony_ci		 * know the result
197d4afb5ceSopenharmony_ci		 */
198d4afb5ceSopenharmony_ci		if (priv->result_cb)
199d4afb5ceSopenharmony_ci			priv->result_cb(priv->result_cb_arg, priv->disposition);
200d4afb5ceSopenharmony_ci
201d4afb5ceSopenharmony_ci		return LWSSEQ_RET_DESTROY;
202d4afb5ceSopenharmony_ci
203d4afb5ceSopenharmony_ci        case UTSEQ_MSG_CONNECTING:
204d4afb5ceSopenharmony_ci		lwsl_debug("UTSEQ_MSG_CONNECTING\n");
205d4afb5ceSopenharmony_ci
206d4afb5ceSopenharmony_ci		if (priv->abs->ap->accept)
207d4afb5ceSopenharmony_ci			priv->abs->ap->accept(priv->abs->api);
208d4afb5ceSopenharmony_ci
209d4afb5ceSopenharmony_ci		priv->established = 1;
210d4afb5ceSopenharmony_ci
211d4afb5ceSopenharmony_ci		/* fallthru */
212d4afb5ceSopenharmony_ci
213d4afb5ceSopenharmony_ci        case UTSEQ_MSG_POST_TX_KICK:
214d4afb5ceSopenharmony_ci        	if (priv->disposition)
215d4afb5ceSopenharmony_ci        		break;
216d4afb5ceSopenharmony_ci
217d4afb5ceSopenharmony_ci		if (process_expect(priv) != LPE_CONTINUE) {
218d4afb5ceSopenharmony_ci			lwsl_notice("%s: UTSEQ_MSG_POST_TX_KICK failed\n",
219d4afb5ceSopenharmony_ci				 __func__);
220d4afb5ceSopenharmony_ci			return LWSSEQ_RET_DESTROY;
221d4afb5ceSopenharmony_ci		}
222d4afb5ceSopenharmony_ci		break;
223d4afb5ceSopenharmony_ci
224d4afb5ceSopenharmony_ci	case UTSEQ_MSG_WRITEABLE:
225d4afb5ceSopenharmony_ci		/*
226d4afb5ceSopenharmony_ci		 * inform the protocol our transport is writeable now
227d4afb5ceSopenharmony_ci		 */
228d4afb5ceSopenharmony_ci		priv->abs->ap->writeable(priv->abs->api, 1024);
229d4afb5ceSopenharmony_ci		break;
230d4afb5ceSopenharmony_ci
231d4afb5ceSopenharmony_ci	case UTSEQ_MSG_CLOSING:
232d4afb5ceSopenharmony_ci
233d4afb5ceSopenharmony_ci		if (!(priv->expect->flags & LWS_AUT_EXPECT_LOCAL_CLOSE)) {
234d4afb5ceSopenharmony_ci			lwsl_user("%s: got unexpected close\n", __func__);
235d4afb5ceSopenharmony_ci
236d4afb5ceSopenharmony_ci			lws_unit_test_packet_dispose(priv,
237d4afb5ceSopenharmony_ci					LPE_FAILED_UNEXPECTED_CLOSE, NULL);
238d4afb5ceSopenharmony_ci			goto done;
239d4afb5ceSopenharmony_ci		}
240d4afb5ceSopenharmony_ci
241d4afb5ceSopenharmony_ci		/* tell the abstract protocol we are closing on them */
242d4afb5ceSopenharmony_ci
243d4afb5ceSopenharmony_ci		if (priv->abs && priv->abs->ap->closed)
244d4afb5ceSopenharmony_ci			priv->abs->ap->closed(priv->abs->api);
245d4afb5ceSopenharmony_ci
246d4afb5ceSopenharmony_ci		goto done;
247d4afb5ceSopenharmony_ci
248d4afb5ceSopenharmony_ci	case UTSEQ_MSG_TIMEOUT: /* current step timed out */
249d4afb5ceSopenharmony_ci
250d4afb5ceSopenharmony_ci		s->ai->at->close(s->ai->ati);
251d4afb5ceSopenharmony_ci
252d4afb5ceSopenharmony_ci		if (!(priv->expect->flags & LWS_AUT_EXPECT_SHOULD_TIMEOUT)) {
253d4afb5ceSopenharmony_ci			lwsl_user("%s: got unexpected timeout\n", __func__);
254d4afb5ceSopenharmony_ci
255d4afb5ceSopenharmony_ci			lws_unit_test_packet_dispose(priv,
256d4afb5ceSopenharmony_ci					LPE_FAILED_UNEXPECTED_TIMEOUT, NULL);
257d4afb5ceSopenharmony_ci			return LWSSEQ_RET_DESTROY;
258d4afb5ceSopenharmony_ci		}
259d4afb5ceSopenharmony_ci		goto done;
260d4afb5ceSopenharmony_ci
261d4afb5ceSopenharmony_cidone:
262d4afb5ceSopenharmony_ci		lws_seq_timeout_us(lws_seq_from_user(s),
263d4afb5ceSopenharmony_ci					 LWSSEQTO_NONE);
264d4afb5ceSopenharmony_ci		priv->expect++;
265d4afb5ceSopenharmony_ci		if (!priv->expect->buffer) {
266d4afb5ceSopenharmony_ci			/* the sequence has completed */
267d4afb5ceSopenharmony_ci			lwsl_user("%s: sequence completed OK\n", __func__);
268d4afb5ceSopenharmony_ci
269d4afb5ceSopenharmony_ci			return LWSSEQ_RET_DESTROY;
270d4afb5ceSopenharmony_ci		}
271d4afb5ceSopenharmony_ci		break;
272d4afb5ceSopenharmony_ci
273d4afb5ceSopenharmony_ci	default:
274d4afb5ceSopenharmony_ci		break;
275d4afb5ceSopenharmony_ci	}
276d4afb5ceSopenharmony_ci
277d4afb5ceSopenharmony_ci	return LWSSEQ_RET_CONTINUE;
278d4afb5ceSopenharmony_ci}
279d4afb5ceSopenharmony_ci
280d4afb5ceSopenharmony_cistatic int
281d4afb5ceSopenharmony_cilws_atcut_close(lws_abs_transport_inst_t *ati)
282d4afb5ceSopenharmony_ci{
283d4afb5ceSopenharmony_ci	abs_unit_test_priv_t *priv = (abs_unit_test_priv_t *)ati;
284d4afb5ceSopenharmony_ci
285d4afb5ceSopenharmony_ci	lwsl_notice("%s\n", __func__);
286d4afb5ceSopenharmony_ci
287d4afb5ceSopenharmony_ci	lws_seq_queue_event(priv->seq, UTSEQ_MSG_CLOSING, NULL, NULL);
288d4afb5ceSopenharmony_ci
289d4afb5ceSopenharmony_ci	return 0;
290d4afb5ceSopenharmony_ci}
291d4afb5ceSopenharmony_ci
292d4afb5ceSopenharmony_cistatic int
293d4afb5ceSopenharmony_cilws_atcut_tx(lws_abs_transport_inst_t *ati, uint8_t *buf, size_t len)
294d4afb5ceSopenharmony_ci{
295d4afb5ceSopenharmony_ci	abs_unit_test_priv_t *priv = (abs_unit_test_priv_t *)ati;
296d4afb5ceSopenharmony_ci
297d4afb5ceSopenharmony_ci	assert(priv->disposition == LPE_CONTINUE);
298d4afb5ceSopenharmony_ci
299d4afb5ceSopenharmony_ci	lwsl_info("%s: received tx\n", __func__);
300d4afb5ceSopenharmony_ci
301d4afb5ceSopenharmony_ci	if (priv->expect->pre)
302d4afb5ceSopenharmony_ci		priv->expect->pre(priv->abs);
303d4afb5ceSopenharmony_ci
304d4afb5ceSopenharmony_ci	if (!(priv->expect->flags & LWS_AUT_EXPECT_TX)) {
305d4afb5ceSopenharmony_ci		lwsl_notice("%s: unexpected tx\n", __func__);
306d4afb5ceSopenharmony_ci		lwsl_hexdump_notice(buf, len);
307d4afb5ceSopenharmony_ci		lws_unit_test_packet_dispose(priv, LPE_FAILED, "unexpected tx");
308d4afb5ceSopenharmony_ci
309d4afb5ceSopenharmony_ci		return 1;
310d4afb5ceSopenharmony_ci	}
311d4afb5ceSopenharmony_ci
312d4afb5ceSopenharmony_ci	if (len != priv->expect->len) {
313d4afb5ceSopenharmony_ci		lwsl_notice("%s: unexpected tx len %zu, expected %zu\n",
314d4afb5ceSopenharmony_ci				__func__, len, priv->expect->len);
315d4afb5ceSopenharmony_ci		lws_unit_test_packet_dispose(priv, LPE_FAILED,
316d4afb5ceSopenharmony_ci					     "tx len mismatch");
317d4afb5ceSopenharmony_ci
318d4afb5ceSopenharmony_ci		return 1;
319d4afb5ceSopenharmony_ci	}
320d4afb5ceSopenharmony_ci
321d4afb5ceSopenharmony_ci	if (memcmp(buf, priv->expect->buffer, len)) {
322d4afb5ceSopenharmony_ci		lwsl_notice("%s: tx mismatch (exp / actual)\n", __func__);
323d4afb5ceSopenharmony_ci		lwsl_hexdump_debug(priv->expect->buffer, len);
324d4afb5ceSopenharmony_ci		lwsl_hexdump_debug(buf, len);
325d4afb5ceSopenharmony_ci		lws_unit_test_packet_dispose(priv, LPE_FAILED,
326d4afb5ceSopenharmony_ci					     "tx data mismatch");
327d4afb5ceSopenharmony_ci
328d4afb5ceSopenharmony_ci		return 1;
329d4afb5ceSopenharmony_ci	}
330d4afb5ceSopenharmony_ci
331d4afb5ceSopenharmony_ci	if (priv->expect->flags & LWS_AUT_EXPECT_TEST_END) {
332d4afb5ceSopenharmony_ci		lws_unit_test_packet_dispose(priv, LPE_SUCCEEDED, NULL);
333d4afb5ceSopenharmony_ci
334d4afb5ceSopenharmony_ci		return 1;
335d4afb5ceSopenharmony_ci	}
336d4afb5ceSopenharmony_ci
337d4afb5ceSopenharmony_ci	priv->expect++;
338d4afb5ceSopenharmony_ci
339d4afb5ceSopenharmony_ci	lws_seq_queue_event(priv->seq, UTSEQ_MSG_POST_TX_KICK, NULL, NULL);
340d4afb5ceSopenharmony_ci
341d4afb5ceSopenharmony_ci	return 0;
342d4afb5ceSopenharmony_ci}
343d4afb5ceSopenharmony_ci
344d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CLIENT)
345d4afb5ceSopenharmony_cistatic int
346d4afb5ceSopenharmony_cilws_atcut_client_conn(const lws_abs_t *abs)
347d4afb5ceSopenharmony_ci{
348d4afb5ceSopenharmony_ci	abs_unit_test_priv_t *priv = (abs_unit_test_priv_t *)abs->ati;
349d4afb5ceSopenharmony_ci	const lws_token_map_t *tm;
350d4afb5ceSopenharmony_ci
351d4afb5ceSopenharmony_ci	if (priv->established) {
352d4afb5ceSopenharmony_ci		lwsl_err("%s: already established\n", __func__);
353d4afb5ceSopenharmony_ci		return 1;
354d4afb5ceSopenharmony_ci	}
355d4afb5ceSopenharmony_ci
356d4afb5ceSopenharmony_ci	/* set up the test start pieces... the array of test expects... */
357d4afb5ceSopenharmony_ci
358d4afb5ceSopenharmony_ci	tm = lws_abs_get_token(abs->at_tokens, LTMI_PEER_V_EXPECT_TEST);
359d4afb5ceSopenharmony_ci	if (!tm) {
360d4afb5ceSopenharmony_ci		lwsl_notice("%s: unit_test needs LTMI_PEER_V_EXPECT_TEST\n",
361d4afb5ceSopenharmony_ci			    __func__);
362d4afb5ceSopenharmony_ci
363d4afb5ceSopenharmony_ci		return 1;
364d4afb5ceSopenharmony_ci	}
365d4afb5ceSopenharmony_ci	priv->current_test = (lws_unit_test_t *)tm->u.value;
366d4afb5ceSopenharmony_ci
367d4afb5ceSopenharmony_ci	/* ... and the callback to deliver the result to */
368d4afb5ceSopenharmony_ci	tm = lws_abs_get_token(abs->at_tokens, LTMI_PEER_V_EXPECT_RESULT_CB);
369d4afb5ceSopenharmony_ci	if (tm)
370d4afb5ceSopenharmony_ci		priv->result_cb = (lws_unit_test_packet_test_cb)tm->u.value;
371d4afb5ceSopenharmony_ci	else
372d4afb5ceSopenharmony_ci		priv->result_cb = NULL;
373d4afb5ceSopenharmony_ci
374d4afb5ceSopenharmony_ci	/* ... and the arg to deliver it with */
375d4afb5ceSopenharmony_ci	tm = lws_abs_get_token(abs->at_tokens,
376d4afb5ceSopenharmony_ci			       LTMI_PEER_V_EXPECT_RESULT_CB_ARG);
377d4afb5ceSopenharmony_ci	if (tm)
378d4afb5ceSopenharmony_ci		priv->result_cb_arg = tm->u.value;
379d4afb5ceSopenharmony_ci
380d4afb5ceSopenharmony_ci	priv->expect = priv->current_test->expect_array;
381d4afb5ceSopenharmony_ci	priv->disposition = LPE_CONTINUE;
382d4afb5ceSopenharmony_ci	priv->note[0] = '\0';
383d4afb5ceSopenharmony_ci
384d4afb5ceSopenharmony_ci	lws_seq_timeout_us(priv->seq, priv->current_test->max_secs *
385d4afb5ceSopenharmony_ci					    LWS_US_PER_SEC);
386d4afb5ceSopenharmony_ci
387d4afb5ceSopenharmony_ci	lwsl_notice("%s: %s: test '%s': start\n", __func__, abs->ap->name,
388d4afb5ceSopenharmony_ci		    priv->current_test->name);
389d4afb5ceSopenharmony_ci
390d4afb5ceSopenharmony_ci	lws_seq_queue_event(priv->seq, UTSEQ_MSG_CONNECTING, NULL, NULL);
391d4afb5ceSopenharmony_ci
392d4afb5ceSopenharmony_ci	return 0;
393d4afb5ceSopenharmony_ci}
394d4afb5ceSopenharmony_ci#endif
395d4afb5ceSopenharmony_ci
396d4afb5ceSopenharmony_cistatic int
397d4afb5ceSopenharmony_cilws_atcut_ask_for_writeable(lws_abs_transport_inst_t *ati)
398d4afb5ceSopenharmony_ci{
399d4afb5ceSopenharmony_ci	abs_unit_test_priv_t *priv = (abs_unit_test_priv_t *)ati;
400d4afb5ceSopenharmony_ci
401d4afb5ceSopenharmony_ci	if (!priv->established)
402d4afb5ceSopenharmony_ci		return 1;
403d4afb5ceSopenharmony_ci
404d4afb5ceSopenharmony_ci	/*
405d4afb5ceSopenharmony_ci	 * Queue a writeable event... this won't be handled by teh sequencer
406d4afb5ceSopenharmony_ci	 * until we have returned to the event loop, just like a real
407d4afb5ceSopenharmony_ci	 * callback_on_writable()
408d4afb5ceSopenharmony_ci	 */
409d4afb5ceSopenharmony_ci	lws_seq_queue_event(priv->seq, UTSEQ_MSG_WRITEABLE, NULL, NULL);
410d4afb5ceSopenharmony_ci
411d4afb5ceSopenharmony_ci	return 0;
412d4afb5ceSopenharmony_ci}
413d4afb5ceSopenharmony_ci
414d4afb5ceSopenharmony_ci/*
415d4afb5ceSopenharmony_ci * An abstract protocol + transport has been instantiated
416d4afb5ceSopenharmony_ci */
417d4afb5ceSopenharmony_ci
418d4afb5ceSopenharmony_cistatic int
419d4afb5ceSopenharmony_cilws_atcut_create(lws_abs_t *ai)
420d4afb5ceSopenharmony_ci{
421d4afb5ceSopenharmony_ci	abs_unit_test_priv_t *priv;
422d4afb5ceSopenharmony_ci	struct lws_sequencer *seq;
423d4afb5ceSopenharmony_ci	lws_seq_info_t i;
424d4afb5ceSopenharmony_ci	seq_priv_t *s;
425d4afb5ceSopenharmony_ci
426d4afb5ceSopenharmony_ci	memset(&i, 0, sizeof(i));
427d4afb5ceSopenharmony_ci	i.context = ai->vh->context;
428d4afb5ceSopenharmony_ci	i.user_size = sizeof(*s);
429d4afb5ceSopenharmony_ci	i.puser = (void **)&s;
430d4afb5ceSopenharmony_ci	i.cb = unit_test_sequencer_cb;
431d4afb5ceSopenharmony_ci	i.name = "unit-test-seq";
432d4afb5ceSopenharmony_ci
433d4afb5ceSopenharmony_ci	/*
434d4afb5ceSopenharmony_ci	 * Create the sequencer for the steps in a single unit test
435d4afb5ceSopenharmony_ci	 */
436d4afb5ceSopenharmony_ci
437d4afb5ceSopenharmony_ci	seq = lws_seq_create(&i);
438d4afb5ceSopenharmony_ci	if (!seq) {
439d4afb5ceSopenharmony_ci		lwsl_err("%s: unable to create sequencer\n", __func__);
440d4afb5ceSopenharmony_ci
441d4afb5ceSopenharmony_ci		return 1;
442d4afb5ceSopenharmony_ci	}
443d4afb5ceSopenharmony_ci
444d4afb5ceSopenharmony_ci	priv = ai->ati;
445d4afb5ceSopenharmony_ci	memset(s, 0, sizeof(*s));
446d4afb5ceSopenharmony_ci	memset(priv, 0, sizeof(*priv));
447d4afb5ceSopenharmony_ci
448d4afb5ceSopenharmony_ci	/* the sequencer priv just points to the lws_abs_t */
449d4afb5ceSopenharmony_ci	s->ai = ai;
450d4afb5ceSopenharmony_ci	priv->abs = ai;
451d4afb5ceSopenharmony_ci	priv->seq = seq;
452d4afb5ceSopenharmony_ci
453d4afb5ceSopenharmony_ci	return 0;
454d4afb5ceSopenharmony_ci}
455d4afb5ceSopenharmony_ci
456d4afb5ceSopenharmony_cistatic void
457d4afb5ceSopenharmony_cilws_atcut_destroy(lws_abs_transport_inst_t **pati)
458d4afb5ceSopenharmony_ci{
459d4afb5ceSopenharmony_ci	/*
460d4afb5ceSopenharmony_ci	 * We don't free anything because the abstract layer combined our
461d4afb5ceSopenharmony_ci	 * allocation with that of the instance, and it will free the whole
462d4afb5ceSopenharmony_ci	 * thing after this.
463d4afb5ceSopenharmony_ci	 */
464d4afb5ceSopenharmony_ci	*pati = NULL;
465d4afb5ceSopenharmony_ci}
466d4afb5ceSopenharmony_ci
467d4afb5ceSopenharmony_cistatic int
468d4afb5ceSopenharmony_cilws_atcut_set_timeout(lws_abs_transport_inst_t *ati, int reason, int secs)
469d4afb5ceSopenharmony_ci{
470d4afb5ceSopenharmony_ci	abs_unit_test_priv_t *priv = (abs_unit_test_priv_t *)ati;
471d4afb5ceSopenharmony_ci	time_t now;
472d4afb5ceSopenharmony_ci
473d4afb5ceSopenharmony_ci	time(&now);
474d4afb5ceSopenharmony_ci
475d4afb5ceSopenharmony_ci	if (secs)
476d4afb5ceSopenharmony_ci		priv->timeout = now + secs;
477d4afb5ceSopenharmony_ci	else
478d4afb5ceSopenharmony_ci		priv->timeout = 0;
479d4afb5ceSopenharmony_ci
480d4afb5ceSopenharmony_ci	return 0;
481d4afb5ceSopenharmony_ci}
482d4afb5ceSopenharmony_ci
483d4afb5ceSopenharmony_cistatic int
484d4afb5ceSopenharmony_cilws_atcut_state(lws_abs_transport_inst_t *ati)
485d4afb5ceSopenharmony_ci{
486d4afb5ceSopenharmony_ci	abs_unit_test_priv_t *priv = (abs_unit_test_priv_t *)ati;
487d4afb5ceSopenharmony_ci
488d4afb5ceSopenharmony_ci	if (!priv || (!priv->established && !priv->connecting))
489d4afb5ceSopenharmony_ci		return 0;
490d4afb5ceSopenharmony_ci
491d4afb5ceSopenharmony_ci	return 1;
492d4afb5ceSopenharmony_ci}
493d4afb5ceSopenharmony_ci
494d4afb5ceSopenharmony_cistatic const char *dnames[] = {
495d4afb5ceSopenharmony_ci	"INCOMPLETE",
496d4afb5ceSopenharmony_ci	"PASS",
497d4afb5ceSopenharmony_ci	"FAIL",
498d4afb5ceSopenharmony_ci	"FAIL(TIMEOUT)",
499d4afb5ceSopenharmony_ci	"FAIL(UNEXPECTED PASS)",
500d4afb5ceSopenharmony_ci	"FAIL(UNEXPECTED CLOSE)",
501d4afb5ceSopenharmony_ci	"SKIPPED"
502d4afb5ceSopenharmony_ci	"?",
503d4afb5ceSopenharmony_ci	"?"
504d4afb5ceSopenharmony_ci};
505d4afb5ceSopenharmony_ci
506d4afb5ceSopenharmony_ci
507d4afb5ceSopenharmony_ciconst char *
508d4afb5ceSopenharmony_cilws_unit_test_result_name(int in)
509d4afb5ceSopenharmony_ci{
510d4afb5ceSopenharmony_ci	if (in < 0 || in > (int)LWS_ARRAY_SIZE(dnames))
511d4afb5ceSopenharmony_ci		return "unknown";
512d4afb5ceSopenharmony_ci
513d4afb5ceSopenharmony_ci	return dnames[in];
514d4afb5ceSopenharmony_ci}
515d4afb5ceSopenharmony_ci
516d4afb5ceSopenharmony_cistatic int
517d4afb5ceSopenharmony_cilws_atcut_compare(lws_abs_t *abs1, lws_abs_t *abs2)
518d4afb5ceSopenharmony_ci{
519d4afb5ceSopenharmony_ci	return 0;
520d4afb5ceSopenharmony_ci}
521d4afb5ceSopenharmony_ci
522d4afb5ceSopenharmony_ciconst lws_abs_transport_t lws_abs_transport_cli_unit_test = {
523d4afb5ceSopenharmony_ci	.name			= "unit_test",
524d4afb5ceSopenharmony_ci	.alloc			= sizeof(abs_unit_test_priv_t),
525d4afb5ceSopenharmony_ci
526d4afb5ceSopenharmony_ci	.create			= lws_atcut_create,
527d4afb5ceSopenharmony_ci	.destroy		= lws_atcut_destroy,
528d4afb5ceSopenharmony_ci	.compare		= lws_atcut_compare,
529d4afb5ceSopenharmony_ci
530d4afb5ceSopenharmony_ci	.tx			= lws_atcut_tx,
531d4afb5ceSopenharmony_ci#if !defined(LWS_WITH_CLIENT)
532d4afb5ceSopenharmony_ci	.client_conn		= NULL,
533d4afb5ceSopenharmony_ci#else
534d4afb5ceSopenharmony_ci	.client_conn		= lws_atcut_client_conn,
535d4afb5ceSopenharmony_ci#endif
536d4afb5ceSopenharmony_ci	.close			= lws_atcut_close,
537d4afb5ceSopenharmony_ci	.ask_for_writeable	= lws_atcut_ask_for_writeable,
538d4afb5ceSopenharmony_ci	.set_timeout		= lws_atcut_set_timeout,
539d4afb5ceSopenharmony_ci	.state			= lws_atcut_state,
540d4afb5ceSopenharmony_ci};
541