unit-test.c 12 KB

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