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 * A helper for running multiple unit tests against abstract protocols. 25d4afb5ceSopenharmony_ci * 26d4afb5ceSopenharmony_ci * An lws_seq_t is used to base its actions in the event loop and manage 27d4afb5ceSopenharmony_ci * the sequencing of multiple tests. A new abstract connection is instantiated 28d4afb5ceSopenharmony_ci * for each test using te 29d4afb5ceSopenharmony_ci */ 30d4afb5ceSopenharmony_ci 31d4afb5ceSopenharmony_ci#include <private-lib-core.h> 32d4afb5ceSopenharmony_ci 33d4afb5ceSopenharmony_cistruct lws_seq_test_sequencer { 34d4afb5ceSopenharmony_ci lws_abs_t original_abs; 35d4afb5ceSopenharmony_ci 36d4afb5ceSopenharmony_ci lws_test_sequencer_args_t args; 37d4afb5ceSopenharmony_ci 38d4afb5ceSopenharmony_ci struct lws_context *context; 39d4afb5ceSopenharmony_ci struct lws_vhost *vhost; 40d4afb5ceSopenharmony_ci struct lws_sequencer *unit_test_seq; 41d4afb5ceSopenharmony_ci 42d4afb5ceSopenharmony_ci /* holds the per-test token for the unit-test transport to consume */ 43d4afb5ceSopenharmony_ci lws_token_map_t uttt[4]; 44d4afb5ceSopenharmony_ci 45d4afb5ceSopenharmony_ci lws_abs_t *instance; 46d4afb5ceSopenharmony_ci 47d4afb5ceSopenharmony_ci int state; 48d4afb5ceSopenharmony_ci}; 49d4afb5ceSopenharmony_ci 50d4afb5ceSopenharmony_ci/* sequencer messages specific to this sequencer */ 51d4afb5ceSopenharmony_ci 52d4afb5ceSopenharmony_cienum { 53d4afb5ceSopenharmony_ci SEQ_MSG_PASS = LWSSEQ_USER_BASE, 54d4afb5ceSopenharmony_ci SEQ_MSG_FAIL, 55d4afb5ceSopenharmony_ci SEQ_MSG_FAIL_TIMEOUT, 56d4afb5ceSopenharmony_ci}; 57d4afb5ceSopenharmony_ci 58d4afb5ceSopenharmony_ci/* 59d4afb5ceSopenharmony_ci * We get called back when the unit test transport has decided if the test 60d4afb5ceSopenharmony_ci * passed or failed. We get the priv, and report to the sequencer message queue 61d4afb5ceSopenharmony_ci * what the result was. 62d4afb5ceSopenharmony_ci */ 63d4afb5ceSopenharmony_ci 64d4afb5ceSopenharmony_cistatic int 65d4afb5ceSopenharmony_ciunit_test_result_cb(const void *cb_user, int disposition) 66d4afb5ceSopenharmony_ci{ 67d4afb5ceSopenharmony_ci const struct lws_seq_test_sequencer *s = 68d4afb5ceSopenharmony_ci (const struct lws_seq_test_sequencer *)cb_user; 69d4afb5ceSopenharmony_ci int r; 70d4afb5ceSopenharmony_ci 71d4afb5ceSopenharmony_ci lwsl_debug("%s: disp %d\n", __func__, disposition); 72d4afb5ceSopenharmony_ci 73d4afb5ceSopenharmony_ci switch (disposition) { 74d4afb5ceSopenharmony_ci case LPE_FAILED_UNEXPECTED_PASS: 75d4afb5ceSopenharmony_ci case LPE_FAILED_UNEXPECTED_CLOSE: 76d4afb5ceSopenharmony_ci case LPE_FAILED: 77d4afb5ceSopenharmony_ci r = SEQ_MSG_FAIL; 78d4afb5ceSopenharmony_ci break; 79d4afb5ceSopenharmony_ci 80d4afb5ceSopenharmony_ci case LPE_FAILED_UNEXPECTED_TIMEOUT: 81d4afb5ceSopenharmony_ci r = SEQ_MSG_FAIL_TIMEOUT; 82d4afb5ceSopenharmony_ci break; 83d4afb5ceSopenharmony_ci 84d4afb5ceSopenharmony_ci case LPE_SUCCEEDED: 85d4afb5ceSopenharmony_ci r = SEQ_MSG_PASS; 86d4afb5ceSopenharmony_ci break; 87d4afb5ceSopenharmony_ci 88d4afb5ceSopenharmony_ci default: 89d4afb5ceSopenharmony_ci assert(0); 90d4afb5ceSopenharmony_ci return -1; 91d4afb5ceSopenharmony_ci } 92d4afb5ceSopenharmony_ci 93d4afb5ceSopenharmony_ci lws_seq_queue_event(s->unit_test_seq, r, NULL, NULL); 94d4afb5ceSopenharmony_ci 95d4afb5ceSopenharmony_ci ((struct lws_seq_test_sequencer *)s)->instance = NULL; 96d4afb5ceSopenharmony_ci 97d4afb5ceSopenharmony_ci return 0; 98d4afb5ceSopenharmony_ci} 99d4afb5ceSopenharmony_ci 100d4afb5ceSopenharmony_ci/* 101d4afb5ceSopenharmony_ci * We receive the unit test result callback's messages via the message queue. 102d4afb5ceSopenharmony_ci * 103d4afb5ceSopenharmony_ci * We log the results and always move on to the next test until there are no 104d4afb5ceSopenharmony_ci * more tests. 105d4afb5ceSopenharmony_ci */ 106d4afb5ceSopenharmony_ci 107d4afb5ceSopenharmony_cistatic lws_seq_cb_return_t 108d4afb5ceSopenharmony_citest_sequencer_cb(struct lws_sequencer *seq, void *user, int event, void *data, 109d4afb5ceSopenharmony_ci void *aux) 110d4afb5ceSopenharmony_ci{ 111d4afb5ceSopenharmony_ci struct lws_seq_test_sequencer *s = 112d4afb5ceSopenharmony_ci (struct lws_seq_test_sequencer *)user; 113d4afb5ceSopenharmony_ci lws_unit_test_packet_t *exp = (lws_unit_test_packet_t *) 114d4afb5ceSopenharmony_ci s->args.tests[s->state].expect_array; 115d4afb5ceSopenharmony_ci lws_abs_t test_abs; 116d4afb5ceSopenharmony_ci 117d4afb5ceSopenharmony_ci switch ((int)event) { 118d4afb5ceSopenharmony_ci case LWSSEQ_CREATED: /* our sequencer just got started */ 119d4afb5ceSopenharmony_ci lwsl_notice("%s: %s: created\n", __func__, 120d4afb5ceSopenharmony_ci lws_seq_name(seq)); 121d4afb5ceSopenharmony_ci s->state = 0; /* first thing we'll do is the first url */ 122d4afb5ceSopenharmony_ci goto step; 123d4afb5ceSopenharmony_ci 124d4afb5ceSopenharmony_ci case LWSSEQ_DESTROYED: 125d4afb5ceSopenharmony_ci /* 126d4afb5ceSopenharmony_ci * We are going down... if we have a child unit test sequencer 127d4afb5ceSopenharmony_ci * still around inform and destroy it 128d4afb5ceSopenharmony_ci */ 129d4afb5ceSopenharmony_ci if (s->instance) { 130d4afb5ceSopenharmony_ci s->instance->at->close(s->instance); 131d4afb5ceSopenharmony_ci s->instance = NULL; 132d4afb5ceSopenharmony_ci } 133d4afb5ceSopenharmony_ci break; 134d4afb5ceSopenharmony_ci 135d4afb5ceSopenharmony_ci case SEQ_MSG_FAIL_TIMEOUT: /* current step timed out */ 136d4afb5ceSopenharmony_ci if (exp->flags & LWS_AUT_EXPECT_SHOULD_TIMEOUT) { 137d4afb5ceSopenharmony_ci lwsl_user("%s: test %d got expected timeout\n", 138d4afb5ceSopenharmony_ci __func__, s->state); 139d4afb5ceSopenharmony_ci 140d4afb5ceSopenharmony_ci goto pass; 141d4afb5ceSopenharmony_ci } 142d4afb5ceSopenharmony_ci lwsl_user("%s: seq timed out at step %d\n", __func__, s->state); 143d4afb5ceSopenharmony_ci 144d4afb5ceSopenharmony_ci s->args.results[s->state] = LPE_FAILED_UNEXPECTED_TIMEOUT; 145d4afb5ceSopenharmony_ci goto done; /* always move on to the next test */ 146d4afb5ceSopenharmony_ci 147d4afb5ceSopenharmony_ci case SEQ_MSG_FAIL: 148d4afb5ceSopenharmony_ci if (exp->flags & LWS_AUT_EXPECT_SHOULD_FAIL) { 149d4afb5ceSopenharmony_ci /* 150d4afb5ceSopenharmony_ci * in this case, we expected to fail like this, it's OK 151d4afb5ceSopenharmony_ci */ 152d4afb5ceSopenharmony_ci lwsl_user("%s: test %d failed as expected\n", 153d4afb5ceSopenharmony_ci __func__, s->state); 154d4afb5ceSopenharmony_ci 155d4afb5ceSopenharmony_ci goto pass; /* always move on to the next test */ 156d4afb5ceSopenharmony_ci } 157d4afb5ceSopenharmony_ci 158d4afb5ceSopenharmony_ci lwsl_user("%s: seq failed at step %d\n", __func__, s->state); 159d4afb5ceSopenharmony_ci 160d4afb5ceSopenharmony_ci s->args.results[s->state] = LPE_FAILED; 161d4afb5ceSopenharmony_ci goto done; /* always move on to the next test */ 162d4afb5ceSopenharmony_ci 163d4afb5ceSopenharmony_ci case SEQ_MSG_PASS: 164d4afb5ceSopenharmony_ci if (exp->flags & (LWS_AUT_EXPECT_SHOULD_FAIL | 165d4afb5ceSopenharmony_ci LWS_AUT_EXPECT_SHOULD_TIMEOUT)) { 166d4afb5ceSopenharmony_ci /* 167d4afb5ceSopenharmony_ci * In these specific cases, done would be a failure, 168d4afb5ceSopenharmony_ci * we expected to timeout or fail 169d4afb5ceSopenharmony_ci */ 170d4afb5ceSopenharmony_ci lwsl_user("%s: seq failed at step %d\n", __func__, 171d4afb5ceSopenharmony_ci s->state); 172d4afb5ceSopenharmony_ci 173d4afb5ceSopenharmony_ci s->args.results[s->state] = LPE_FAILED_UNEXPECTED_PASS; 174d4afb5ceSopenharmony_ci 175d4afb5ceSopenharmony_ci goto done; /* always move on to the next test */ 176d4afb5ceSopenharmony_ci } 177d4afb5ceSopenharmony_ci lwsl_info("%s: seq done test %d\n", __func__, s->state); 178d4afb5ceSopenharmony_cipass: 179d4afb5ceSopenharmony_ci (*s->args.count_passes)++; 180d4afb5ceSopenharmony_ci s->args.results[s->state] = LPE_SUCCEEDED; 181d4afb5ceSopenharmony_ci 182d4afb5ceSopenharmony_cidone: 183d4afb5ceSopenharmony_ci lws_seq_timeout_us(lws_seq_from_user(s), LWSSEQTO_NONE); 184d4afb5ceSopenharmony_ci s->state++; 185d4afb5ceSopenharmony_cistep: 186d4afb5ceSopenharmony_ci if (!s->args.tests[s->state].name) { 187d4afb5ceSopenharmony_ci /* the sequence has completed */ 188d4afb5ceSopenharmony_ci lwsl_user("%s: sequence completed OK\n", __func__); 189d4afb5ceSopenharmony_ci 190d4afb5ceSopenharmony_ci if (s->args.cb) 191d4afb5ceSopenharmony_ci s->args.cb(s->args.cb_user); 192d4afb5ceSopenharmony_ci 193d4afb5ceSopenharmony_ci return LWSSEQ_RET_DESTROY; 194d4afb5ceSopenharmony_ci } 195d4afb5ceSopenharmony_ci lwsl_info("%s: starting test %d\n", __func__, s->state); 196d4afb5ceSopenharmony_ci 197d4afb5ceSopenharmony_ci if (s->state >= s->args.results_max) { 198d4afb5ceSopenharmony_ci lwsl_err("%s: results array is too small\n", __func__); 199d4afb5ceSopenharmony_ci 200d4afb5ceSopenharmony_ci return LWSSEQ_RET_DESTROY; 201d4afb5ceSopenharmony_ci } 202d4afb5ceSopenharmony_ci test_abs = s->original_abs; 203d4afb5ceSopenharmony_ci s->uttt[0].name_index = LTMI_PEER_V_EXPECT_TEST; 204d4afb5ceSopenharmony_ci s->uttt[0].u.value = (void *)&s->args.tests[s->state]; 205d4afb5ceSopenharmony_ci s->uttt[1].name_index = LTMI_PEER_V_EXPECT_RESULT_CB; 206d4afb5ceSopenharmony_ci s->uttt[1].u.value = (void *)unit_test_result_cb; 207d4afb5ceSopenharmony_ci s->uttt[2].name_index = LTMI_PEER_V_EXPECT_RESULT_CB_ARG; 208d4afb5ceSopenharmony_ci s->uttt[2].u.value = (void *)s; 209d4afb5ceSopenharmony_ci /* give the unit test transport the test tokens */ 210d4afb5ceSopenharmony_ci test_abs.at_tokens = s->uttt; 211d4afb5ceSopenharmony_ci 212d4afb5ceSopenharmony_ci s->instance = lws_abs_bind_and_create_instance(&test_abs); 213d4afb5ceSopenharmony_ci if (!s->instance) { 214d4afb5ceSopenharmony_ci lwsl_notice("%s: failed to create step %d unit test\n", 215d4afb5ceSopenharmony_ci __func__, s->state); 216d4afb5ceSopenharmony_ci 217d4afb5ceSopenharmony_ci return LWSSEQ_RET_DESTROY; 218d4afb5ceSopenharmony_ci } 219d4afb5ceSopenharmony_ci (*s->args.count_tests)++; 220d4afb5ceSopenharmony_ci break; 221d4afb5ceSopenharmony_ci 222d4afb5ceSopenharmony_ci default: 223d4afb5ceSopenharmony_ci break; 224d4afb5ceSopenharmony_ci } 225d4afb5ceSopenharmony_ci 226d4afb5ceSopenharmony_ci return LWSSEQ_RET_CONTINUE; 227d4afb5ceSopenharmony_ci} 228d4afb5ceSopenharmony_ci 229d4afb5ceSopenharmony_ci 230d4afb5ceSopenharmony_ci/* 231d4afb5ceSopenharmony_ci * Creates an lws_sequencer to manage the test sequence 232d4afb5ceSopenharmony_ci */ 233d4afb5ceSopenharmony_ci 234d4afb5ceSopenharmony_ciint 235d4afb5ceSopenharmony_cilws_abs_unit_test_sequencer(const lws_test_sequencer_args_t *args) 236d4afb5ceSopenharmony_ci{ 237d4afb5ceSopenharmony_ci struct lws_seq_test_sequencer *s; 238d4afb5ceSopenharmony_ci struct lws_sequencer *seq; 239d4afb5ceSopenharmony_ci lws_seq_info_t i; 240d4afb5ceSopenharmony_ci 241d4afb5ceSopenharmony_ci memset(&i, 0, sizeof(i)); 242d4afb5ceSopenharmony_ci i.context = args->abs->vh->context; 243d4afb5ceSopenharmony_ci i.user_size = sizeof(struct lws_seq_test_sequencer); 244d4afb5ceSopenharmony_ci i.puser = (void **)&s; 245d4afb5ceSopenharmony_ci i.cb = test_sequencer_cb; 246d4afb5ceSopenharmony_ci i.name = "test-seq"; 247d4afb5ceSopenharmony_ci 248d4afb5ceSopenharmony_ci /* 249d4afb5ceSopenharmony_ci * Create a sequencer in the event loop to manage the tests 250d4afb5ceSopenharmony_ci */ 251d4afb5ceSopenharmony_ci 252d4afb5ceSopenharmony_ci seq = lws_seq_create(&i); 253d4afb5ceSopenharmony_ci if (!seq) { 254d4afb5ceSopenharmony_ci lwsl_err("%s: unable to create sequencer\n", __func__); 255d4afb5ceSopenharmony_ci return 1; 256d4afb5ceSopenharmony_ci } 257d4afb5ceSopenharmony_ci 258d4afb5ceSopenharmony_ci /* 259d4afb5ceSopenharmony_ci * Take a copy of the original lws_abs_t we were passed so we can use 260d4afb5ceSopenharmony_ci * it as the basis of the lws_abs_t we create the individual tests with 261d4afb5ceSopenharmony_ci */ 262d4afb5ceSopenharmony_ci s->original_abs = *args->abs; 263d4afb5ceSopenharmony_ci 264d4afb5ceSopenharmony_ci s->args = *args; 265d4afb5ceSopenharmony_ci 266d4afb5ceSopenharmony_ci s->context = args->abs->vh->context; 267d4afb5ceSopenharmony_ci s->vhost = args->abs->vh; 268d4afb5ceSopenharmony_ci s->unit_test_seq = seq; 269d4afb5ceSopenharmony_ci 270d4afb5ceSopenharmony_ci *s->args.count_tests = 0; 271d4afb5ceSopenharmony_ci *s->args.count_passes = 0; 272d4afb5ceSopenharmony_ci 273d4afb5ceSopenharmony_ci return 0; 274d4afb5ceSopenharmony_ci} 275