From 1166cf62aa1812463640996dde2fc47fe33a4138 Mon Sep 17 00:00:00 2001
From: David Bourgeois <david.bourgeois@cyanview.com>
Date: Thu, 6 Feb 2020 17:54:58 +0100
Subject: [PATCH] Add 3 tests of incoming publish

---
 test/unit/mqtt/test_mqtt.c | 245 +++++++++++++++++++++++++++++++++++++
 1 file changed, 245 insertions(+)

diff --git a/test/unit/mqtt/test_mqtt.c b/test/unit/mqtt/test_mqtt.c
index 7cff13ea..d4965d16 100644
--- a/test/unit/mqtt/test_mqtt.c
+++ b/test/unit/mqtt/test_mqtt.c
@@ -4,10 +4,19 @@
 #include "lwip/apps/mqtt.h"
 #include "lwip/apps/mqtt_priv.h"
 #include "lwip/netif.h"
+#include <string.h>
+
+static int debug = 1;
 
 const ip_addr_t test_mqtt_local_ip = IPADDR4_INIT_BYTES(192, 168, 1, 1);
 const ip_addr_t test_mqtt_remote_ip = IPADDR4_INIT_BYTES(192, 168, 1, 2);
 const ip_addr_t test_mqtt_netmask = IPADDR4_INIT_BYTES(255, 255, 255, 0);
+unsigned int tot_incoming_len;
+
+#define TEST_TOPIC "topic"
+#define TEST_MESSAGE "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
+static char test_topic[] = TEST_TOPIC;
+static char test_message[] = TEST_MESSAGE;
 
 static err_t test_mqtt_netif_output(struct netif *netif, struct pbuf *p,
        const ip4_addr_t *ipaddr)
@@ -63,11 +72,40 @@ mqtt_teardown(void)
 
 static void test_mqtt_connection_cb(mqtt_client_t *client, void *arg, mqtt_connection_status_t status)
 {
+  if (debug)
+    printf("  < Connect callback\n");
   LWIP_UNUSED_ARG(client);
   LWIP_UNUSED_ARG(arg);
   LWIP_UNUSED_ARG(status);
 }
 
+static void test_mqtt_sub_cb(void *arg, err_t err)
+{
+  if (debug)
+    printf("  < Subscribe callback\n");
+  LWIP_UNUSED_ARG(arg);
+  fail_unless(err == ERR_OK);
+}
+
+static void test_1_mqtt_incoming_publish_cb(void *arg, const char *topic, u32_t tot_data_len)
+{
+  LWIP_UNUSED_ARG(arg);
+  if (debug)
+    printf("    < Topic: \"%s\" (message len: %d)\n", topic, tot_data_len);
+  tot_incoming_len = tot_data_len;
+  fail_unless(strncmp(test_topic, topic, sizeof(test_topic)) == 0);
+}
+
+static void test_1_mqtt_incoming_data_cb(void *arg, const u8_t *data, u16_t len, u8_t flags)
+{
+  LWIP_UNUSED_ARG(arg);
+  LWIP_UNUSED_ARG(flags);
+  tot_incoming_len -= len;
+  if (debug)
+    printf("    < Data: \"%.*s\" (len: %d, rem: %d)\n", len, data, len, tot_incoming_len);
+  fail_unless(strncmp(test_message, (const char *)data, sizeof(test_message)) == 0);
+}
+
 START_TEST(basic_connect)
 {
   mqtt_client_t* client;
@@ -106,10 +144,217 @@ START_TEST(basic_connect)
 }
 END_TEST
 
+START_TEST(basic_sub_pub)
+{
+  mqtt_client_t* client;
+  struct netif netif;
+  err_t err;
+  struct mqtt_connect_client_info_t client_info = {
+    "dumm",
+    NULL, NULL,
+    10,
+    NULL, NULL, 0, 0
+  };
+  struct pbuf *p;
+  unsigned char rxbuf[] = {0x20, 0x02, 0x00, 0x00};
+  u8_t rx_sub[] = {0x90, 0x03, 0x00, 0x01, 0x00};
+  u8_t rx_data[] = {
+    0x31, 0x45, 0x00, 0x05, /* HEADER */
+    0x74, 0x6f, 0x70, 0x69, 0x63, /* TEST_TOPIC */
+    0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c,
+    0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+    0x79, 0x7a, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a,
+    0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56,
+    0x57, 0x58, 0x59, 0x5a, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+    0x38, 0x39,
+  };
+
+  LWIP_UNUSED_ARG(_i);
+
+  test_mqtt_init_netif(&netif, &test_mqtt_local_ip, &test_mqtt_netmask);
+
+  client = mqtt_client_new();
+  fail_unless(client != NULL);
+  err = mqtt_client_connect(client, &test_mqtt_remote_ip, 1234, test_mqtt_connection_cb, NULL, &client_info);
+  fail_unless(err == ERR_OK);
+
+  client->conn->connected(client->conn->callback_arg, client->conn, ERR_OK);
+  p = pbuf_alloc(PBUF_RAW, sizeof(rxbuf), PBUF_REF);
+  fail_unless(p != NULL);
+  p->payload = rxbuf;
+  /* since we hack the rx path, we have to hack the rx window, too: */
+  client->conn->rcv_wnd -= p->tot_len;
+  if (client->conn->recv(client->conn->callback_arg, client->conn, p, ERR_OK) != ERR_OK) {
+    pbuf_free(p);
+  }
+
+  /* Test Subscribe */
+  if (debug)
+    printf("> Basic subscribe\n");
+  mqtt_subscribe(client, test_topic, 1, test_mqtt_sub_cb, NULL);
+  p = pbuf_alloc(PBUF_RAW, sizeof(rx_sub), PBUF_REF);
+  fail_unless(p != NULL);
+  p->payload = rx_sub;
+  /* since we hack the rx path, we have to hack the rx window, too: */
+  client->conn->rcv_wnd -= p->tot_len;
+  if (client->conn->recv(client->conn->callback_arg, client->conn, p, ERR_OK) != ERR_OK) {
+    pbuf_free(p);
+  }
+
+  if (debug)
+    printf("  < Receive publish\n");
+  /* Test incoming publish */
+  mqtt_set_inpub_callback(client, test_1_mqtt_incoming_publish_cb, test_1_mqtt_incoming_data_cb, NULL);
+  p = pbuf_alloc(PBUF_RAW, sizeof(rx_data), PBUF_REF);
+  fail_unless(p != NULL);
+  p->payload = rx_data;
+  /* since we hack the rx path, we have to hack the rx window, too: */
+  client->conn->rcv_wnd -= p->tot_len;
+  if (client->conn->recv(client->conn->callback_arg, client->conn, p, ERR_OK) != ERR_OK) {
+    pbuf_free(p);
+  }
+
+  mqtt_disconnect(client);
+  /* fixme: mqtt_client_fre() is missing... */
+  mem_free(client);
+}
+END_TEST
+
+START_TEST(segmented_sub_pub)
+{
+  mqtt_client_t* client;
+  struct netif netif;
+  err_t err;
+  struct mqtt_connect_client_info_t client_info = {
+    "dumm",
+    NULL, NULL,
+    10,
+    NULL, NULL, 0, 0
+  };
+  struct pbuf *p;
+  unsigned char rxbuf[] = {0x20, 0x02, 0x00, 0x00};
+  u8_t rx_sub[] = {0x90, 0x03, 0x00, 0x01, 0x00};
+
+  /*
+   * RX data split over 2 TCP segments in the topic part of MQTT
+   */
+  u8_t rx_data_1[] = {
+    0x31, 0x45, 0x00, 0x05,
+    0x74, 0x6f, 0x70
+  };
+  u8_t rx_data_2[] = {
+    0x69, 0x63, 0x61, 0x62,
+    0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
+    0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a,
+    0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c,
+    0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+    0x59, 0x5a, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+  };
+
+  /*
+   * RX data split over 2 TCP segments in the message part of MQTT
+   */
+  u8_t rx_data_3[] = {
+    0x31, 0x45, 0x00, 0x05,
+    0x74, 0x6f, 0x70,
+    0x69, 0x63, 0x61, 0x62,
+  };
+
+  u8_t rx_data_4[] = {
+    0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
+    0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a,
+    0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c,
+    0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+    0x59, 0x5a, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+  };
+
+
+  LWIP_UNUSED_ARG(_i);
+
+  test_mqtt_init_netif(&netif, &test_mqtt_local_ip, &test_mqtt_netmask);
+
+  client = mqtt_client_new();
+  fail_unless(client != NULL);
+  err = mqtt_client_connect(client, &test_mqtt_remote_ip, 1234, test_mqtt_connection_cb, NULL, &client_info);
+  fail_unless(err == ERR_OK);
+
+  client->conn->connected(client->conn->callback_arg, client->conn, ERR_OK);
+  p = pbuf_alloc(PBUF_RAW, sizeof(rxbuf), PBUF_REF);
+  fail_unless(p != NULL);
+  p->payload = rxbuf;
+  /* since we hack the rx path, we have to hack the rx window, too: */
+  client->conn->rcv_wnd -= p->tot_len;
+  if (client->conn->recv(client->conn->callback_arg, client->conn, p, ERR_OK) != ERR_OK) {
+    pbuf_free(p);
+  }
+
+  /* Subscribe */
+  p = pbuf_alloc(PBUF_RAW, sizeof(rx_sub), PBUF_REF);
+  fail_unless(p != NULL);
+  p->payload = rx_sub;
+  /* since we hack the rx path, we have to hack the rx window, too: */
+  client->conn->rcv_wnd -= p->tot_len;
+  if (client->conn->recv(client->conn->callback_arg, client->conn, p, ERR_OK) != ERR_OK) {
+    pbuf_free(p);
+  }
+
+  /* Callback for incoming publish */
+  mqtt_set_inpub_callback(client, test_1_mqtt_incoming_publish_cb, test_1_mqtt_incoming_data_cb, NULL);
+
+  /* Segmented message */
+  if (debug)
+    printf("> Receive segmented topic\n");
+  p = pbuf_alloc(PBUF_RAW, sizeof(rx_data_1), PBUF_REF);
+  fail_unless(p != NULL);
+  p->payload = rx_data_1;
+  /* since we hack the rx path, we have to hack the rx window, too: */
+  client->conn->rcv_wnd -= p->tot_len;
+  if (client->conn->recv(client->conn->callback_arg, client->conn, p, ERR_OK) != ERR_OK) {
+    pbuf_free(p);
+  }
+
+  p = pbuf_alloc(PBUF_RAW, sizeof(rx_data_2), PBUF_REF);
+  fail_unless(p != NULL);
+  p->payload = rx_data_2;
+  /* since we hack the rx path, we have to hack the rx window, too: */
+  client->conn->rcv_wnd -= p->tot_len;
+  if (client->conn->recv(client->conn->callback_arg, client->conn, p, ERR_OK) != ERR_OK) {
+    pbuf_free(p);
+  }
+
+  /* Segmented message */
+  if (debug)
+    printf("> Receive segmented message\n");
+  p = pbuf_alloc(PBUF_RAW, sizeof(rx_data_3), PBUF_REF);
+  fail_unless(p != NULL);
+  p->payload = rx_data_3;
+  /* since we hack the rx path, we have to hack the rx window, too: */
+  client->conn->rcv_wnd -= p->tot_len;
+  if (client->conn->recv(client->conn->callback_arg, client->conn, p, ERR_OK) != ERR_OK) {
+    pbuf_free(p);
+  }
+
+  p = pbuf_alloc(PBUF_RAW, sizeof(rx_data_4), PBUF_REF);
+  fail_unless(p != NULL);
+  p->payload = rx_data_4;
+  /* since we hack the rx path, we have to hack the rx window, too: */
+  client->conn->rcv_wnd -= p->tot_len;
+  if (client->conn->recv(client->conn->callback_arg, client->conn, p, ERR_OK) != ERR_OK) {
+    pbuf_free(p);
+  }
+
+  mqtt_disconnect(client);
+  /* fixme: mqtt_client_fre() is missing... */
+  mem_free(client);
+}
+END_TEST
+
 Suite* mqtt_suite(void)
 {
   testfunc tests[] = {
     TESTFUNC(basic_connect),
+    TESTFUNC(basic_sub_pub),
+    TESTFUNC(segmented_sub_pub),
   };
   return create_suite("MQTT", tests, sizeof(tests)/sizeof(testfunc), mqtt_setup, mqtt_teardown);
 }
-- 
2.25.0

