From b9575813911337f83adefb4ab46537c2a4a35660 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Fri, 24 Jan 2020 11:15:56 +0200 Subject: [PATCH] tests: net: websocket: Add TX unit tests for websocket API Add simple tests for testing sent and received websocket data. Signed-off-by: Jukka Rissanen --- subsys/net/lib/websocket/websocket.c | 18 ++++ tests/net/socket/websocket/src/main.c | 138 +++++++++++++++++++++++++- 2 files changed, 154 insertions(+), 2 deletions(-) diff --git a/subsys/net/lib/websocket/websocket.c b/subsys/net/lib/websocket/websocket.c index c6ebc86d894..fa3046be68e 100644 --- a/subsys/net/lib/websocket/websocket.c +++ b/subsys/net/lib/websocket/websocket.c @@ -48,6 +48,10 @@ static struct k_sem contexts_lock; extern const struct socket_op_vtable sock_fd_op_vtable; static const struct socket_op_vtable websocket_fd_op_vtable; +#if defined(CONFIG_NET_TEST) +int verify_sent_and_received_msg(struct msghdr *msg, bool split_msg); +#endif + static const char *opcode2str(enum websocket_opcode opcode) { switch (opcode) { @@ -465,8 +469,15 @@ static int websocket_prepare_and_send(struct websocket_context *ctx, LOG_HEXDUMP_DBG(payload, payload_len, "Payload"); } +#if defined(CONFIG_NET_TEST) + /* Simulate a case where the payload is split to two. The unit test + * does not set mask bit in this case. + */ + return verify_sent_and_received_msg(&msg, !(header[1] & BIT(7))); +#else return sendmsg(ctx->real_sock, &msg, timeout == K_NO_WAIT ? MSG_DONTWAIT : 0); +#endif /* CONFIG_NET_TEST */ } int websocket_send_msg(int ws_sock, const u8_t *payload, size_t payload_len, @@ -487,6 +498,12 @@ int websocket_send_msg(int ws_sock, const u8_t *payload, size_t payload_len, return -EINVAL; } +#if defined(CONFIG_NET_TEST) + /* Websocket unit test does not use socket layer but feeds + * the data directly here when testing this function. + */ + ctx = INT_TO_POINTER(ws_sock); +#else ctx = z_get_fd_obj(ws_sock, NULL, 0); if (ctx == NULL) { return -EBADF; @@ -495,6 +512,7 @@ int websocket_send_msg(int ws_sock, const u8_t *payload, size_t payload_len, if (!PART_OF_ARRAY(contexts, ctx)) { return -ENOENT; } +#endif /* CONFIG_NET_TEST */ NET_DBG("[%p] Len %zd %s/%d/%s", ctx, payload_len, opcode2str(opcode), mask, final ? "final" : "more"); diff --git a/tests/net/socket/websocket/src/main.c b/tests/net/socket/websocket/src/main.c index 9abc5b92c45..9cd78da3a1e 100644 --- a/tests/net/socket/websocket/src/main.c +++ b/tests/net/socket/websocket/src/main.c @@ -15,8 +15,33 @@ LOG_MODULE_REGISTER(net_test, CONFIG_NET_WEBSOCKET_LOG_LEVEL); #include "websocket_internal.h" +/* Generated by http://www.lipsum.com/ + * 2 paragraphs, 178 words, 1160 bytes of Lorem Ipsum + */ +static const char lorem_ipsum[] = + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. " + "Vestibulum ultricies sapien tellus, ac viverra dolor bibendum " + "lacinia. Vestibulum et nisl tristique tellus finibus gravida " + "vitae sit amet nunc. Suspendisse maximus justo mi, vitae porta " + "risus suscipit vitae. Curabitur ut fringilla velit. Donec ac nisi " + "in dui semper lobortis sed nec ante. Sed nec luctus dui. Sed ut " + "ante nisi. Mauris congue euismod felis, et maximus ex pellentesque " + "nec. Proin nibh nisl, semper at nunc in, mattis pharetra metus. Nam " + "turpis risus, pulvinar sit amet varius ac, pellentesque quis purus." + " " + "Nam consequat purus in lacinia fringilla. Morbi volutpat, tellus " + "nec tempus dapibus, ante sem aliquam dui, eu feugiat libero diam " + "at leo. Sed suscipit egestas orci in ultrices. Integer in elementum " + "ligula, vel sollicitudin velit. Nullam sit amet eleifend libero. " + "Proin sit amet consequat tellus, vel vulputate arcu. Curabitur quis " + "lobortis lacus. Sed faucibus vestibulum enim vel elementum. Vivamus " + "enim nunc, auctor in purus at, aliquet pulvinar eros. Cras dapibus " + "nec quam laoreet sagittis. Quisque dictum ante odio, at imperdiet " + "est convallis a. Morbi mattis ut orci vitae volutpat." + "\n"; + #define MAX_RECV_BUF_LEN 256 -static u8_t recv_buf[MAX_RECV_BUF_LEN]; +static u8_t recv_buf[MAX(sizeof(lorem_ipsum), MAX_RECV_BUF_LEN)]; /* We need to allocate bigger buffer for the websocket data we receive so that * the websocket header fits into it. @@ -25,6 +50,7 @@ static u8_t recv_buf[MAX_RECV_BUF_LEN]; static u8_t temp_recv_buf[MAX_RECV_BUF_LEN + EXTRA_BUF_SPACE]; static u8_t feed_buf[MAX_RECV_BUF_LEN + EXTRA_BUF_SPACE]; +static size_t test_msg_len; struct test_data { u8_t *input_buf; @@ -121,6 +147,8 @@ static void test_recv(int count) &ctx, &msg_type, &remaining, recv_buf + total_read, sizeof(recv_buf) - total_read); + zassert_true(ret <= (sizeof(recv_buf) - total_read), + "Invalid number of bytes read (%d)", ret); total_read += ret; zassert_equal(total_read, sizeof(frame1) - FRAME1_HDR_SIZE, "Invalid amount of data read (%d)", ret); @@ -241,6 +269,110 @@ static void test_recv_two_msg(void) test_recv_2(sizeof(frame1) + FRAME1_HDR_SIZE / 2); } +int verify_sent_and_received_msg(struct msghdr *msg, bool split_msg) +{ + static struct websocket_context ctx; + u32_t msg_type = -1; + u64_t remaining = -1; + size_t split_len = 0, total_read = 0; + int ret; + + memset(&ctx, 0, sizeof(ctx)); + + ctx.tmp_buf = temp_recv_buf; + ctx.tmp_buf_len = sizeof(temp_recv_buf); + + /* Read first the header */ + ret = test_recv_buf(msg->msg_iov[0].iov_base, + msg->msg_iov[0].iov_len, + &ctx, &msg_type, &remaining, + recv_buf, sizeof(recv_buf)); + zassert_equal(ret, -EAGAIN, "Msg header not found"); + + /* Then the first split if it is enabled */ + if (split_msg) { + split_len = msg->msg_iov[1].iov_len / 2; + + ret = test_recv_buf(msg->msg_iov[1].iov_base, + split_len, + &ctx, &msg_type, &remaining, + recv_buf, sizeof(recv_buf)); + zassert_true(ret > 0, "Cannot read data (%d)", ret); + + total_read = ret; + } + + /* Then the data */ + while (remaining > 0) { + ret = test_recv_buf((u8_t *)msg->msg_iov[1].iov_base + + total_read, + msg->msg_iov[1].iov_len - total_read, + &ctx, &msg_type, &remaining, + recv_buf, sizeof(recv_buf)); + zassert_true(ret > 0, "Cannot read data (%d)", ret); + + if (memcmp(recv_buf, lorem_ipsum + total_read, ret) != 0) { + LOG_HEXDUMP_ERR(lorem_ipsum + total_read, ret, + "Received message should be"); + LOG_HEXDUMP_ERR(recv_buf, ret, "but it was instead"); + zassert_true(false, "Invalid received message " + "after %d bytes", total_read); + } + + total_read += ret; + } + + zassert_equal(total_read, test_msg_len, + "Msg body not valid, received %d instead of %zd", + total_read, test_msg_len); + + NET_DBG("Received %zd header and %zd body", + msg->msg_iov[0].iov_len, total_read); + + return msg->msg_iov[0].iov_len + total_read; +} + +static void test_send_and_recv_lorem_ipsum(void) +{ + static struct websocket_context ctx; + int ret; + + memset(&ctx, 0, sizeof(ctx)); + + ctx.tmp_buf = temp_recv_buf; + ctx.tmp_buf_len = sizeof(temp_recv_buf); + + test_msg_len = sizeof(lorem_ipsum) - 1; + + ret = websocket_send_msg(POINTER_TO_INT(&ctx), + lorem_ipsum, test_msg_len, + WEBSOCKET_OPCODE_DATA_TEXT, true, true, + K_FOREVER); + zassert_equal(ret, test_msg_len, + "Should have sent %zd bytes but sent %d instead", + test_msg_len, ret); +} + +static void test_recv_two_large_split_msg(void) +{ + static struct websocket_context ctx; + int ret; + + memset(&ctx, 0, sizeof(ctx)); + + ctx.tmp_buf = temp_recv_buf; + ctx.tmp_buf_len = sizeof(temp_recv_buf); + + test_msg_len = sizeof(lorem_ipsum) - 1; + + ret = websocket_send_msg(POINTER_TO_INT(&ctx), lorem_ipsum, + test_msg_len, WEBSOCKET_OPCODE_DATA_TEXT, + false, true, K_FOREVER); + zassert_equal(ret, test_msg_len, + "1st should have sent %zd bytes but sent %d instead", + test_msg_len, ret); +} + void test_main(void) { k_thread_system_pool_assign(k_current_get()); @@ -256,7 +388,9 @@ void test_main(void) ztest_unit_test(test_recv_10_byte), ztest_unit_test(test_recv_12_byte), ztest_unit_test(test_recv_whole_msg), - ztest_unit_test(test_recv_two_msg) + ztest_unit_test(test_recv_two_msg), + ztest_unit_test(test_send_and_recv_lorem_ipsum), + ztest_unit_test(test_recv_two_large_split_msg) ); ztest_run_test_suite(websocket);