/* * Copyright (c) 2022 René Beckmann * * SPDX-License-Identifier: Apache-2.0 */ #include #include /* for ARRAY_SIZE */ #include #include #include #include LOG_MODULE_REGISTER(test); static const struct mqtt_sn_data client_id = MQTT_SN_DATA_STRING_LITERAL("zephyr"); static uint8_t tx[255]; static uint8_t rx[255]; static struct msg_send_data { int called; size_t msg_sz; int ret; struct mqtt_sn_client *client; } msg_send_data; static int msg_send(struct mqtt_sn_client *client, void *buf, size_t sz) { msg_send_data.called++; msg_send_data.msg_sz = sz; msg_send_data.client = client; return msg_send_data.ret; } static void assert_msg_send(int called, size_t msg_sz) { zassert_equal(msg_send_data.called, called, "msg_send called %d times instead of %d", msg_send_data.called, called); zassert_equal(msg_send_data.msg_sz, msg_sz, "msg_sz is %zu instead of %zu", msg_send_data.msg_sz, msg_sz); memset(&msg_send_data, 0, sizeof(msg_send_data)); } static struct { struct mqtt_sn_evt last_evt; int called; } evt_cb_data; static void evt_cb(struct mqtt_sn_client *client, const struct mqtt_sn_evt *evt) { memcpy(&evt_cb_data.last_evt, evt, sizeof(*evt)); evt_cb_data.called++; } static bool tp_initialized; static struct mqtt_sn_transport transport; static int tp_init(struct mqtt_sn_transport *tp) { tp_initialized = true; return 0; } static struct { void *data; ssize_t sz; } recv_data; static ssize_t tp_recv(struct mqtt_sn_client *client, void *buffer, size_t length) { if (recv_data.data && recv_data.sz > 0 && length >= recv_data.sz) { memcpy(buffer, recv_data.data, recv_data.sz); } return recv_data.sz; } int tp_poll(struct mqtt_sn_client *client) { return recv_data.sz; } static ZTEST_BMEM struct mqtt_sn_client mqtt_clients[3]; static ZTEST_BMEM struct mqtt_sn_client *mqtt_client; static void setup(void *f) { ARG_UNUSED(f); static ZTEST_BMEM size_t i; mqtt_client = &mqtt_clients[i++]; transport = (struct mqtt_sn_transport){ .init = tp_init, .msg_send = msg_send, .recv = tp_recv, .poll = tp_poll}; tp_initialized = false; memset(&evt_cb_data, 0, sizeof(evt_cb_data)); memset(&msg_send_data, 0, sizeof(msg_send_data)); memset(&recv_data, 0, sizeof(recv_data)); } static int input(struct mqtt_sn_client *client, void *buf, size_t sz) { recv_data.data = buf; recv_data.sz = sz; return mqtt_sn_input(client); } static void mqtt_sn_connect_no_will(struct mqtt_sn_client *client) { /* connack with return code accepted */ static uint8_t connack[] = {3, 0x05, 0x00}; int err; err = mqtt_sn_client_init(client, &client_id, &transport, evt_cb, tx, sizeof(tx), rx, sizeof(rx)); zassert_equal(err, 0, "unexpected error %d"); zassert_true(tp_initialized, "Transport not initialized"); err = mqtt_sn_connect(client, false, false); zassert_equal(err, 0, "unexpected error %d"); assert_msg_send(1, 12); zassert_equal(client->state, 0, "Wrong state"); zassert_equal(evt_cb_data.called, 0, "Unexpected event"); err = input(client, connack, sizeof(connack)); zassert_equal(err, 0, "unexpected error %d"); zassert_equal(client->state, 1, "Wrong state"); zassert_equal(evt_cb_data.called, 1, "NO event"); zassert_equal(evt_cb_data.last_evt.type, MQTT_SN_EVT_CONNECTED, "Wrong event"); k_sleep(K_MSEC(10)); } static ZTEST(mqtt_sn_client, test_mqtt_sn_connect_no_will) { mqtt_sn_connect_no_will(mqtt_client); } static ZTEST(mqtt_sn_client, test_mqtt_sn_connect_will) { static uint8_t willtopicreq[] = {2, 0x06}; static uint8_t willmsgreq[] = {2, 0x08}; static uint8_t connack[] = {3, 0x05, 0x00}; int err; err = mqtt_sn_client_init(mqtt_client, &client_id, &transport, evt_cb, tx, sizeof(tx), rx, sizeof(rx)); zassert_equal(err, 0, "unexpected error %d"); mqtt_client->will_topic = MQTT_SN_DATA_STRING_LITERAL("topic"); mqtt_client->will_msg = MQTT_SN_DATA_STRING_LITERAL("msg"); err = mqtt_sn_connect(mqtt_client, true, false); zassert_equal(err, 0, "unexpected error %d"); assert_msg_send(1, 12); zassert_equal(mqtt_client->state, 0, "Wrong state"); err = input(mqtt_client, willtopicreq, sizeof(willtopicreq)); zassert_equal(err, 0, "unexpected error %d"); zassert_equal(mqtt_client->state, 0, "Wrong state"); assert_msg_send(1, 8); err = input(mqtt_client, willmsgreq, sizeof(willmsgreq)); zassert_equal(err, 0, "unexpected error %d"); zassert_equal(mqtt_client->state, 0, "Wrong state"); zassert_equal(evt_cb_data.called, 0, "Unexpected event"); assert_msg_send(1, 5); err = input(mqtt_client, connack, sizeof(connack)); zassert_equal(err, 0, "unexpected error %d"); zassert_equal(mqtt_client->state, 1, "Wrong state"); zassert_equal(evt_cb_data.called, 1, "NO event"); zassert_equal(evt_cb_data.last_evt.type, MQTT_SN_EVT_CONNECTED, "Wrong event"); k_sleep(K_MSEC(10)); } static ZTEST(mqtt_sn_client, test_mqtt_sn_publish_qos0) { struct mqtt_sn_data data = MQTT_SN_DATA_STRING_LITERAL("Hello, World!"); struct mqtt_sn_data topic = MQTT_SN_DATA_STRING_LITERAL("zephyr"); /* registration ack with topic ID 0x1A1B, msg ID 0x0001, return code accepted */ uint8_t regack[] = {7, 0x0B, 0x1A, 0x1B, 0x00, 0x01, 0}; int err; mqtt_sn_connect_no_will(mqtt_client); err = mqtt_sn_publish(mqtt_client, MQTT_SN_QOS_0, &topic, false, &data); zassert_equal(err, 0, "Unexpected error %d", err); assert_msg_send(0, 0); k_sleep(K_MSEC(10)); /* Expect a REGISTER to be sent */ assert_msg_send(1, 12); err = input(mqtt_client, regack, sizeof(regack)); zassert_equal(err, 0, "unexpected error %d"); assert_msg_send(0, 0); k_sleep(K_MSEC(10)); assert_msg_send(1, 20); zassert_true(sys_slist_is_empty(&mqtt_client->publish), "Publish not empty"); zassert_false(sys_slist_is_empty(&mqtt_client->topic), "Topic empty"); } ZTEST_SUITE(mqtt_sn_client, NULL, NULL, setup, NULL, NULL);