net: mqtt-sn: Update MQTT-SN Unit Tests

Fixes: #78010
This commit adds tests for the "Gateway Advertisement and Discovery"
process. This includes tests for handling SEARCHGW, GWINFO, and ADVERTISE
as well as manually adding a Gateway for use. Gateway pruning when
missing ADVERTISE messages is also tested.

Signed-off-by: Kenneth Witham <kennywitham4@gmail.com>
This commit is contained in:
Kenneth Witham 2024-10-28 08:10:25 -07:00 committed by Anas Nashif
commit cc33fd685f
2 changed files with 252 additions and 32 deletions

View file

@ -18,3 +18,8 @@ CONFIG_ZTEST_STACK_SIZE=8192
CONFIG_STACK_USAGE=y
CONFIG_STACK_SENTINEL=y
CONFIG_DEBUG=y
# Reduce MQTT_SN delay times for testing
CONFIG_MQTT_SN_LIB_T_SEARCHGW=0
CONFIG_MQTT_SN_LIB_T_GWINFO=0
CONFIG_MQTT_SN_LIB_N_ADV=1

View file

@ -15,6 +15,9 @@
LOG_MODULE_REGISTER(test);
static const struct mqtt_sn_data client_id = MQTT_SN_DATA_STRING_LITERAL("zephyr");
static const struct mqtt_sn_data client2_id = MQTT_SN_DATA_STRING_LITERAL("zephyr2");
static const uint8_t gw_id = 12;
static const struct mqtt_sn_data gw_addr = MQTT_SN_DATA_STRING_LITERAL("gw1");
static uint8_t tx[255];
static uint8_t rx[255];
@ -23,24 +26,45 @@ static struct msg_send_data {
int called;
size_t msg_sz;
int ret;
const void *dest_addr;
size_t addrlen;
struct mqtt_sn_client *client;
} msg_send_data;
static int msg_send(struct mqtt_sn_client *client, void *buf, size_t sz)
struct k_sem mqtt_sn_tx_sem;
struct k_sem mqtt_sn_rx_sem;
struct k_sem mqtt_sn_cb_sem;
int mqtt_sn_data_cmp(struct mqtt_sn_data data1, struct mqtt_sn_data data2)
{
return data1.size == data2.size && strncmp(data1.data, data2.data, data1.size);
}
static int msg_sendto(struct mqtt_sn_client *client, void *buf, size_t sz, const void *dest_addr,
size_t addrlen)
{
msg_send_data.called++;
msg_send_data.msg_sz = sz;
msg_send_data.client = client;
msg_send_data.dest_addr = dest_addr;
msg_send_data.addrlen = addrlen;
k_sem_give(&mqtt_sn_tx_sem);
return msg_send_data.ret;
}
static void assert_msg_send(int called, size_t msg_sz)
static void assert_msg_send(int called, size_t msg_sz, const struct mqtt_sn_data *dest_addr)
{
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);
if (dest_addr != NULL) {
zassert_equal(mqtt_sn_data_cmp(*dest_addr,
*((struct mqtt_sn_data *)msg_send_data.dest_addr)),
0, "Addresses incorrect");
}
memset(&msg_send_data, 0, sizeof(msg_send_data));
}
@ -54,6 +78,8 @@ 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++;
k_sem_give(&mqtt_sn_cb_sem);
}
static bool tp_initialized;
@ -68,23 +94,30 @@ static int tp_init(struct mqtt_sn_transport *tp)
static struct {
void *data;
ssize_t sz;
} recv_data;
const void *src_addr;
size_t addrlen;
} recvfrom_data;
static ssize_t tp_recv(struct mqtt_sn_client *client, void *buffer, size_t length)
static ssize_t tp_recvfrom(struct mqtt_sn_client *client, void *buffer, size_t length,
void *src_addr, size_t *addrlen)
{
if (recv_data.data && recv_data.sz > 0 && length >= recv_data.sz) {
memcpy(buffer, recv_data.data, recv_data.sz);
if (recvfrom_data.data && recvfrom_data.sz > 0 && length >= recvfrom_data.sz) {
memcpy(buffer, recvfrom_data.data, recvfrom_data.sz);
memcpy(src_addr, recvfrom_data.src_addr, recvfrom_data.addrlen);
*addrlen = recvfrom_data.addrlen;
k_sem_give(&mqtt_sn_rx_sem);
}
return recv_data.sz;
return recvfrom_data.sz;
}
int tp_poll(struct mqtt_sn_client *client)
{
return recv_data.sz;
return recvfrom_data.sz;
}
static ZTEST_BMEM struct mqtt_sn_client mqtt_clients[3];
static ZTEST_BMEM struct mqtt_sn_client mqtt_clients[8];
static ZTEST_BMEM struct mqtt_sn_client *mqtt_client;
static void setup(void *f)
@ -95,18 +128,24 @@ static void setup(void *f)
mqtt_client = &mqtt_clients[i++];
transport = (struct mqtt_sn_transport){
.init = tp_init, .msg_send = msg_send, .recv = tp_recv, .poll = tp_poll};
.init = tp_init, .sendto = msg_sendto, .recvfrom = tp_recvfrom, .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));
memset(&recvfrom_data, 0, sizeof(recvfrom_data));
k_sem_init(&mqtt_sn_tx_sem, 0, 1);
k_sem_init(&mqtt_sn_rx_sem, 0, 1);
k_sem_init(&mqtt_sn_cb_sem, 0, 1);
}
static int input(struct mqtt_sn_client *client, void *buf, size_t sz)
static int input(struct mqtt_sn_client *client, void *buf, size_t sz,
const struct mqtt_sn_data *src_addr)
{
recv_data.data = buf;
recv_data.sz = sz;
recvfrom_data.data = buf;
recvfrom_data.sz = sz;
recvfrom_data.src_addr = src_addr->data;
recvfrom_data.addrlen = src_addr->size;
return mqtt_sn_input(client);
}
@ -122,24 +161,187 @@ static void mqtt_sn_connect_no_will(struct mqtt_sn_client *client)
zassert_equal(err, 0, "unexpected error %d");
zassert_true(tp_initialized, "Transport not initialized");
err = mqtt_sn_add_gw(client, gw_id, gw_addr);
zassert_equal(err, 0, "unexpected error %d");
zassert_equal(evt_cb_data.called, 0, "Unexpected event");
zassert_false(sys_slist_is_empty(&client->gateway), "GW not saved.");
err = mqtt_sn_connect(client, false, false);
zassert_equal(err, 0, "unexpected error %d");
assert_msg_send(1, 12);
assert_msg_send(1, 12, &gw_addr);
zassert_equal(client->state, 0, "Wrong state");
zassert_equal(evt_cb_data.called, 0, "Unexpected event");
err = input(client, connack, sizeof(connack));
err = input(client, connack, sizeof(connack), &gw_addr);
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_handle_advertise)
{
static uint8_t advertise[] = {5, 0x00, 0x0c, 0, 1};
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");
err = input(mqtt_client, advertise, sizeof(advertise), &gw_addr);
zassert_equal(err, 0, "unexpected error %d");
zassert_false(sys_slist_is_empty(&mqtt_client->gateway), "GW not saved.");
zassert_equal(evt_cb_data.called, 1, "NO event");
zassert_equal(evt_cb_data.last_evt.type, MQTT_SN_EVT_ADVERTISE, "Wrong event");
err = input(mqtt_client, advertise, sizeof(advertise), &gw_addr);
zassert_equal(err, 0, "unexpected error %d");
zassert_false(sys_slist_is_empty(&mqtt_client->gateway), "GW not saved.");
zassert_equal(sys_slist_len(&mqtt_client->gateway), 1, "Too many Gateways stored.");
zassert_equal(evt_cb_data.called, 2, "Unexpected event");
zassert_equal(evt_cb_data.last_evt.type, MQTT_SN_EVT_ADVERTISE, "Wrong event");
err = mqtt_sn_connect(mqtt_client, false, false);
zassert_equal(err, 0, "unexpected error %d");
assert_msg_send(1, 12, &gw_addr);
zassert_equal(mqtt_client->state, 0, "Wrong state");
zassert_equal(evt_cb_data.called, 2, "Unexpected event");
err = input(mqtt_client, connack, sizeof(connack), &gw_addr);
zassert_equal(err, 0, "unexpected error %d");
zassert_equal(mqtt_client->state, 1, "Wrong state");
zassert_equal(evt_cb_data.called, 3, "NO event");
zassert_equal(evt_cb_data.last_evt.type, MQTT_SN_EVT_CONNECTED, "Wrong event");
err = k_sem_take(&mqtt_sn_cb_sem, K_NO_WAIT);
err = k_sem_take(&mqtt_sn_cb_sem, K_SECONDS(10));
zassert_equal(err, 0, "Timed out waiting for callback.");
zassert_true(sys_slist_is_empty(&mqtt_client->gateway), "GW not cleared on timeout");
zassert_equal(evt_cb_data.called, 4, "NO event");
zassert_equal(evt_cb_data.last_evt.type, MQTT_SN_EVT_DISCONNECTED, "Wrong event");
zassert_equal(mqtt_client->state, 0, "Wrong state");
mqtt_sn_client_deinit(mqtt_client);
}
static ZTEST(mqtt_sn_client, test_mqtt_sn_add_gw)
{
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");
err = mqtt_sn_add_gw(mqtt_client, gw_id, gw_addr);
zassert_equal(err, 0, "unexpected error %d");
zassert_false(sys_slist_is_empty(&mqtt_client->gateway), "GW not saved.");
zassert_equal(evt_cb_data.called, 0, "Unexpected event");
mqtt_sn_client_deinit(mqtt_client);
}
/* Test send SEARCHGW and GW response */
static ZTEST(mqtt_sn_client, test_mqtt_sn_search_gw)
{
int err;
static uint8_t gwinfo[3];
gwinfo[0] = 3;
gwinfo[1] = 0x02;
gwinfo[2] = gw_id;
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");
err = k_sem_take(&mqtt_sn_tx_sem, K_NO_WAIT);
err = mqtt_sn_search(mqtt_client, 1);
zassert_equal(err, 0, "unexpected error %d");
err = k_sem_take(&mqtt_sn_tx_sem, K_SECONDS(10));
zassert_equal(err, 0, "Timed out waiting for callback.");
assert_msg_send(1, 3, NULL);
zassert_equal(mqtt_client->state, 0, "Wrong state");
zassert_equal(evt_cb_data.called, 0, "Unexpected event");
err = input(mqtt_client, gwinfo, sizeof(gwinfo), &gw_addr);
zassert_equal(err, 0, "unexpected error %d");
zassert_false(sys_slist_is_empty(&mqtt_client->gateway), "GW not saved.");
zassert_equal(evt_cb_data.last_evt.type, MQTT_SN_EVT_GWINFO, "Wrong event");
mqtt_sn_client_deinit(mqtt_client);
}
/* Test send SEARCHGW and peer response */
static ZTEST(mqtt_sn_client, test_mqtt_sn_search_peer)
{
int err;
static uint8_t gwinfo[3 + 3];
gwinfo[0] = 3 + gw_addr.size;
gwinfo[1] = 0x02;
gwinfo[2] = gw_id;
memcpy(&gwinfo[3], gw_addr.data, 3);
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");
err = k_sem_take(&mqtt_sn_tx_sem, K_NO_WAIT);
err = mqtt_sn_search(mqtt_client, 1);
zassert_equal(err, 0, "unexpected error %d");
err = k_sem_take(&mqtt_sn_tx_sem, K_SECONDS(10));
zassert_equal(err, 0, "Timed out waiting for callback.");
assert_msg_send(1, 3, NULL);
zassert_equal(mqtt_client->state, 0, "Wrong state");
zassert_equal(evt_cb_data.called, 0, "Unexpected event");
err = input(mqtt_client, gwinfo, sizeof(gwinfo), &gw_addr);
zassert_equal(err, 0, "unexpected error %d");
zassert_false(sys_slist_is_empty(&mqtt_client->gateway), "GW not saved.");
zassert_equal(evt_cb_data.called, 1, "NO event");
zassert_equal(evt_cb_data.last_evt.type, MQTT_SN_EVT_GWINFO, "Wrong event");
mqtt_sn_client_deinit(mqtt_client);
}
static ZTEST(mqtt_sn_client, test_mqtt_sn_respond_searchgw)
{
int err;
static uint8_t searchgw[] = {3, 0x01, 1};
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");
err = mqtt_sn_add_gw(mqtt_client, gw_id, gw_addr);
zassert_equal(err, 0, "unexpected error %d");
zassert_false(sys_slist_is_empty(&mqtt_client->gateway), "GW not saved.");
zassert_equal(evt_cb_data.called, 0, "Unexpected event");
err = k_sem_take(&mqtt_sn_tx_sem, K_NO_WAIT);
err = input(mqtt_client, searchgw, sizeof(searchgw), &client2_id);
zassert_equal(err, 0, "unexpected error %d");
err = k_sem_take(&mqtt_sn_tx_sem, K_SECONDS(10));
zassert_equal(err, 0, "Timed out waiting for callback.");
zassert_equal(evt_cb_data.called, 1, "NO event");
zassert_equal(evt_cb_data.last_evt.type, MQTT_SN_EVT_SEARCHGW, "Wrong event");
assert_msg_send(1, 3 + gw_addr.size, NULL);
mqtt_sn_client_deinit(mqtt_client);
}
static ZTEST(mqtt_sn_client, test_mqtt_sn_connect_no_will)
{
mqtt_sn_connect_no_will(mqtt_client);
mqtt_sn_client_deinit(mqtt_client);
}
static ZTEST(mqtt_sn_client, test_mqtt_sn_connect_will)
@ -154,31 +356,37 @@ static ZTEST(mqtt_sn_client, test_mqtt_sn_connect_will)
sizeof(rx));
zassert_equal(err, 0, "unexpected error %d");
err = mqtt_sn_add_gw(mqtt_client, gw_id, gw_addr);
zassert_equal(err, 0, "unexpected error %d");
zassert_false(sys_slist_is_empty(&mqtt_client->gateway), "GW not saved.");
zassert_equal(evt_cb_data.called, 0, "Unexpected event");
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);
assert_msg_send(1, 12, &gw_addr);
zassert_equal(mqtt_client->state, 0, "Wrong state");
err = input(mqtt_client, willtopicreq, sizeof(willtopicreq));
err = input(mqtt_client, willtopicreq, sizeof(willtopicreq), &gw_addr);
zassert_equal(err, 0, "unexpected error %d");
zassert_equal(mqtt_client->state, 0, "Wrong state");
assert_msg_send(1, 8);
assert_msg_send(1, 8, &gw_addr);
err = input(mqtt_client, willmsgreq, sizeof(willmsgreq));
err = input(mqtt_client, willmsgreq, sizeof(willmsgreq), &gw_addr);
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);
assert_msg_send(1, 5, &gw_addr);
err = input(mqtt_client, connack, sizeof(connack));
err = input(mqtt_client, connack, sizeof(connack), &gw_addr);
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));
mqtt_sn_client_deinit(mqtt_client);
}
static ZTEST(mqtt_sn_client, test_mqtt_sn_publish_qos0)
@ -190,21 +398,28 @@ static ZTEST(mqtt_sn_client, test_mqtt_sn_publish_qos0)
int err;
mqtt_sn_connect_no_will(mqtt_client);
err = k_sem_take(&mqtt_sn_tx_sem, K_NO_WAIT);
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));
assert_msg_send(0, 0, NULL);
/* Expect a REGISTER to be sent */
assert_msg_send(1, 12);
err = input(mqtt_client, regack, sizeof(regack));
err = k_sem_take(&mqtt_sn_tx_sem, K_SECONDS(10));
zassert_equal(err, 0, "Timed out waiting for callback.");
assert_msg_send(1, 12, &gw_addr);
err = input(mqtt_client, regack, sizeof(regack), &gw_addr);
zassert_equal(err, 0, "unexpected error %d");
assert_msg_send(0, 0);
k_sleep(K_MSEC(10));
assert_msg_send(1, 20);
err = k_sem_take(&mqtt_sn_tx_sem, K_NO_WAIT);
assert_msg_send(0, 0, NULL);
err = k_sem_take(&mqtt_sn_tx_sem, K_SECONDS(10));
zassert_equal(err, 0, "Timed out waiting for callback.");
assert_msg_send(1, 20, &gw_addr);
zassert_true(sys_slist_is_empty(&mqtt_client->publish), "Publish not empty");
zassert_false(sys_slist_is_empty(&mqtt_client->topic), "Topic empty");
mqtt_sn_client_deinit(mqtt_client);
}
ZTEST_SUITE(mqtt_sn_client, NULL, NULL, setup, NULL, NULL);