mqtt tests: adding weekend test for mqtt library to exercise publishing/receiving different data and references esp-mqtt commits to pass these tests

testing conditions:
transports (tcp, ssl, ws..)
qos (0, 1, 2)
short repeated messages (packed packets)
oversized messages (fragmented packets)
publish from a different thread

Closes https://github.com/espressif/esp-idf/issues/2870 by means of including commit 815623dfe5 from esp-mqtt
Closes https://github.com/espressif/esp-idf/issues/2975 by means of including commit 752953dc3b from esp-mqtt
Closes https://github.com/espressif/esp-idf/issues/2850 by means of including commits df455d2a5f 17fd713bce from esp-mqtt
This commit is contained in:
David Cermak
2019-01-31 17:09:34 +01:00
committed by Rocha Euripedes
parent 79e16da5c4
commit 202acd4d6d
13 changed files with 665 additions and 0 deletions

View File

@@ -0,0 +1,9 @@
# The following four lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(mqtt_publish)
target_add_binary_data(mqtt_publish.elf "main/iot_eclipse_org.pem" TEXT)

View File

@@ -0,0 +1,7 @@
#
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
# project subdirectory.
#
PROJECT_NAME := mqtt_publish
include $(IDF_PATH)/make/project.mk

View File

@@ -0,0 +1,91 @@
# ESP-MQTT advanced published test
(See the README.md file in the upper level 'examples' directory for more information about examples.)
Main purpose of this example is to test the MQTT library to correctly publish and receive messages (of different size and sequences) over different transports.
It is possible to run this example manually without any test to exercise how the MQTT library deals with
- reception of fragmented messages
- runtime updates of URI
## How to use example
This example waits for user input to provide these parameters:
- transport: string parameter, one of: tcp, ssl, ws, wss
- pattern: sample string to be transmitted as message
- pattern repeats: number of repeats of pattern in one MQTT message
- repeated: number of repeats ESP32 publishes the message, also ESP32 expects to receive the same message the same number of repeats
- qos: number specifying qos, one of: 0, 1, 2
### Hardware Required
This example can be executed on any ESP32 board, the only required interface is WiFi and connection to internet.
### Configure the project
```
make menuconfig
```
* Set serial port under Serial Flasher Options.
* Set ssid and password for the board to connect to AP.
* Set brokers for all 4 transports (TCP, SSL, WS, WSS), also set certificate if needed
* Set topics for publishing from and to ESP32
### Build and Flash
Build the project and flash it to the board, then run monitor tool to view serial output:
```
make -j4 flash monitor
```
(To exit the serial monitor, type ``Ctrl-]``.)
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
## Example Output
```
I (4730) event: sta ip: 192.168.0.125, mask: 255.255.255.0, gw: 192.168.0.2
I (4730) PUBLISH_TEST: [APP] Free memory: 236728 bytes
I (4730) system_api: Base MAC address is not set, read default base MAC address from BLK0 of EFUSE
D (4740) MQTT_CLIENT: MQTT client_id=ESP32_09885C
I (31360) PUBLISH_TEST: PATTERN:1234 REPEATED:10 PUBLISHED:10
```
- User enters "tcp 1234 10 10 1"
```
EXPECTED STRING 1234123412341234123412341234123412341234, SIZE:40
W (31360) MQTT_CLIENT: Client asked to stop, but was not started
I (31360) PUBLISH_TEST: [TCP transport] Startup..
D (31370) MQTT_CLIENT: Core selection disabled
I (31370) PUBLISH_TEST: Note free memory: 224652 bytes
I (31370) PUBLISH_TEST: Other event id:7
D (31390) MQTT_CLIENT: Transport connected to mqtt://192.168.0.163:1883
I (31400) MQTT_CLIENT: Sending MQTT CONNECT message, type: 1, id: 0000
D (31410) MQTT_CLIENT: Connected
I (31410) PUBLISH_TEST: MQTT_EVENT_CONNECTED
D (31410) MQTT_CLIENT: mqtt_enqueue id: 31184, type=8 successful
D (31410) OUTBOX: ENQUEUE msgid=31184, msg_type=8, len=20, size=20
D (31420) MQTT_CLIENT: Sent subscribe topic=/xxx.topic123, id: 31184, type=8 successful
I (31430) PUBLISH_TEST: sent subscribe successful, msg_id=31184
D (31440) MQTT_CLIENT: mqtt_enqueue id: 16584, type=3 successful
D (31440) OUTBOX: ENQUEUE msgid=16584, msg_type=3, len=59, size=79
I (31450) PUBLISH_TEST: [16584] Publishing...
D (31450) MQTT_CLIENT: msg_type=9, msg_id=31184
D (31460) MQTT_CLIENT: pending_id=16584, pending_msg_count = 2
D (31460) OUTBOX: DELETED msgid=31184, msg_type=8, remain size=59
D (31470) MQTT_CLIENT: Subscribe successful
I (31470) PUBLISH_TEST: MQTT_EVENT_SUBSCRIBED, msg_id=31184
D (31480) MQTT_CLIENT: msg_type=4, msg_id=16584
D (31480) MQTT_CLIENT: pending_id=16584, pending_msg_count = 1
D (31490) OUTBOX: DELETED msgid=16584, msg_type=3, remain size=0
D (31500) MQTT_CLIENT: received MQTT_MSG_TYPE_PUBACK, finish QoS1 publish
I (31500) PUBLISH_TEST: MQTT_EVENT_PUBLISHED, msg_id=16584
D (31510) MQTT_CLIENT: mqtt_enqueue id: 44615, type=3 successful
D (31520) OUTBOX: ENQUEUE msgid=44615, msg_type=3, len=59, size=59
I (31530) PUBLISH_TEST: [44615] Publishing...
...
```

View File

@@ -0,0 +1,4 @@
set(COMPONENT_SRCS "publish_test.c")
set(COMPONENT_ADD_INCLUDEDIRS ".")
register_component()

View File

@@ -0,0 +1,62 @@
menu "Example Configuration"
config WIFI_SSID
string "WiFi SSID"
default "myssid"
help
SSID (network name) for the example to connect to.
config WIFI_PASSWORD
string "WiFi Password"
default "mypassword"
help
WiFi password (WPA or WPA2) for the example to use.
config BROKER_SSL_URI
string "Broker SSL URL"
default "mqtts://iot.eclipse.org:8883"
help
URL of an mqtt broker for ssl transport
config BROKER_TCP_URI
string "Broker TCP URL"
default "mqtt://iot.eclipse.org:1883"
help
URL of an mqtt broker for tcp transport
config BROKER_WS_URI
string "Broker WS URL"
default "ws://iot.eclipse.org:80/ws"
help
URL of an mqtt broker for ws transport
config BROKER_WSS_URI
string "Broker WSS URL"
default "wss://iot.eclipse.org:443/ws"
help
URL of an mqtt broker for wss transport
config PUBLISH_TOPIC
string "publish topic"
default "/topic/publish/esp2py"
help
topic to which esp32 client publishes
config SUBSCIBE_TOPIC
string "subscribe topic"
default "/topic/subscribe/py2esp"
help
topic to which esp32 client subsribes (and expects data)
config BROKER_CERTIFICATE_OVERRIDE
string "Broker certificate override"
default ""
help
Please leave empty if broker certificate included from a textfile; otherwise fill in a base64 part of PEM
format certificate
config BROKER_CERTIFICATE_OVERRIDDEN
bool
default y if BROKER_CERTIFICATE_OVERRIDE != ""
endmenu

View File

@@ -0,0 +1 @@
COMPONENT_EMBED_TXTFILES := iot_eclipse_org.pem

View File

@@ -0,0 +1,27 @@
-----BEGIN CERTIFICATE-----
MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/
MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow
SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT
GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC
AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF
q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8
SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0
Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA
a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj
/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T
AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG
CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv
bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k
c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw
VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC
ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz
MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu
Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF
AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo
uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/
wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu
X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG
PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6
KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==
-----END CERTIFICATE-----

View File

@@ -0,0 +1,258 @@
/* MQTT publish test
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include "esp_wifi.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "esp_event_loop.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "freertos/queue.h"
#include "freertos/event_groups.h"
#include "lwip/sockets.h"
#include "lwip/dns.h"
#include "lwip/netdb.h"
#include "esp_log.h"
#include "mqtt_client.h"
static const char *TAG = "PUBLISH_TEST";
static EventGroupHandle_t wifi_event_group;
static EventGroupHandle_t mqtt_event_group;
const static int CONNECTED_BIT = BIT0;
static esp_mqtt_client_handle_t mqtt_client = NULL;
static char *expected_data = NULL;
static char *actual_data = NULL;
static size_t expected_size = 0;
static size_t expected_published = 0;
static size_t actual_published = 0;
static int qos_test = 0;
static esp_err_t wifi_event_handler(void *ctx, system_event_t *event)
{
switch (event->event_id) {
case SYSTEM_EVENT_STA_START:
esp_wifi_connect();
break;
case SYSTEM_EVENT_STA_GOT_IP:
xEventGroupSetBits(wifi_event_group, CONNECTED_BIT);
break;
case SYSTEM_EVENT_STA_DISCONNECTED:
esp_wifi_connect();
xEventGroupClearBits(wifi_event_group, CONNECTED_BIT);
break;
default:
break;
}
return ESP_OK;
}
static void wifi_init(void)
{
tcpip_adapter_init();
wifi_event_group = xEventGroupCreate();
ESP_ERROR_CHECK(esp_event_loop_init(wifi_event_handler, NULL));
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM));
wifi_config_t wifi_config = {
.sta = {
.ssid = CONFIG_WIFI_SSID,
.password = CONFIG_WIFI_PASSWORD,
},
};
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));
ESP_LOGI(TAG, "start the WIFI SSID:[%s]", CONFIG_WIFI_SSID);
ESP_ERROR_CHECK(esp_wifi_start());
ESP_LOGI(TAG, "Waiting for wifi");
xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT, false, true, portMAX_DELAY);
}
#if CONFIG_BROKER_CERTIFICATE_OVERRIDDEN == 1
static const uint8_t iot_eclipse_org_pem_start[] = "-----BEGIN CERTIFICATE-----\n" CONFIG_BROKER_CERTIFICATE_OVERRIDE "\n-----END CERTIFICATE-----";
#else
extern const uint8_t iot_eclipse_org_pem_start[] asm("_binary_iot_eclipse_org_pem_start");
#endif
extern const uint8_t iot_eclipse_org_pem_end[] asm("_binary_iot_eclipse_org_pem_end");
static esp_err_t mqtt_event_handler(esp_mqtt_event_handle_t event)
{
esp_mqtt_client_handle_t client = event->client;
static int msg_id = 0;
static int actual_len = 0;
// your_context_t *context = event->context;
switch (event->event_id) {
case MQTT_EVENT_CONNECTED:
ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
xEventGroupSetBits(mqtt_event_group, CONNECTED_BIT);
msg_id = esp_mqtt_client_subscribe(client, CONFIG_SUBSCIBE_TOPIC, qos_test);
ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
break;
case MQTT_EVENT_DISCONNECTED:
ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");
break;
case MQTT_EVENT_SUBSCRIBED:
ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id);
break;
case MQTT_EVENT_UNSUBSCRIBED:
ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);
break;
case MQTT_EVENT_PUBLISHED:
ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);
break;
case MQTT_EVENT_DATA:
ESP_LOGI(TAG, "MQTT_EVENT_DATA");
printf("TOPIC=%.*s\r\n", event->topic_len, event->topic);
printf("DATA=%.*s\r\n", event->data_len, event->data);
printf("ID=%d, total_len=%d, data_len=%d, current_data_offset=%d\n", event->msg_id, event->total_data_len, event->data_len, event->current_data_offset);
if (event->topic) {
actual_len = event->data_len;
msg_id = event->msg_id;
} else {
actual_len += event->data_len;
// check consisency with msg_id across multiple data events for single msg
if (msg_id != event->msg_id) {
ESP_LOGI(TAG, "Wrong msg_id in chunked message %d != %d", msg_id, event->msg_id);
abort();
}
}
memcpy(actual_data + event->current_data_offset, event->data, event->data_len);
if (actual_len == event->total_data_len) {
if (0 == memcmp(actual_data, expected_data, expected_size)) {
printf("OK!");
memset(actual_data, 0, expected_size);
actual_published ++;
if (actual_published == expected_published) {
printf("Correct pattern received exactly x times\n");
ESP_LOGI(TAG, "Test finished correctly!");
}
} else {
printf("FAILED!");
abort();
}
}
break;
case MQTT_EVENT_ERROR:
ESP_LOGI(TAG, "MQTT_EVENT_ERROR");
break;
default:
ESP_LOGI(TAG, "Other event id:%d", event->event_id);
break;
}
return ESP_OK;
}
static void mqtt_app_start(void)
{
mqtt_event_group = xEventGroupCreate();
const esp_mqtt_client_config_t mqtt_cfg = {
.event_handle = mqtt_event_handler,
.cert_pem = (const char *)iot_eclipse_org_pem_start,
};
ESP_LOGI(TAG, "[APP] Free memory: %d bytes", esp_get_free_heap_size());
mqtt_client = esp_mqtt_client_init(&mqtt_cfg);
}
static void get_string(char *line, size_t size)
{
int count = 0;
while (count < size) {
int c = fgetc(stdin);
if (c == '\n') {
line[count] = '\0';
break;
} else if (c > 0 && c < 127) {
line[count] = c;
++count;
}
vTaskDelay(10 / portTICK_PERIOD_MS);
}
}
void app_main()
{
char line[256];
char pattern[32];
char transport[32];
int repeat = 0;
ESP_LOGI(TAG, "[APP] Free memory: %d bytes", esp_get_free_heap_size());
ESP_LOGI(TAG, "[APP] IDF version: %s", esp_get_idf_version());
esp_log_level_set("*", ESP_LOG_INFO);
esp_log_level_set("MQTT_CLIENT", ESP_LOG_VERBOSE);
esp_log_level_set("TRANSPORT_TCP", ESP_LOG_VERBOSE);
esp_log_level_set("TRANSPORT_SSL", ESP_LOG_VERBOSE);
esp_log_level_set("TRANSPORT", ESP_LOG_VERBOSE);
esp_log_level_set("OUTBOX", ESP_LOG_VERBOSE);
nvs_flash_init();
wifi_init();
mqtt_app_start();
while (1) {
get_string(line, sizeof(line));
sscanf(line, "%s %s %d %d %d", transport, pattern, &repeat, &expected_published, &qos_test);
ESP_LOGI(TAG, "PATTERN:%s REPEATED:%d PUBLISHED:%d\n", pattern, repeat, expected_published);
int pattern_size = strlen(pattern);
free(expected_data);
free(actual_data);
actual_published = 0;
expected_size = pattern_size * repeat;
expected_data = malloc(expected_size);
actual_data = malloc(expected_size);
for (int i = 0; i < repeat; i++) {
memcpy(expected_data + i * pattern_size, pattern, pattern_size);
}
printf("EXPECTED STRING %.*s, SIZE:%d\n", expected_size, expected_data, expected_size);
esp_mqtt_client_stop(mqtt_client);
if (0 == strcmp(transport, "tcp")) {
ESP_LOGI(TAG, "[TCP transport] Startup..");
esp_mqtt_client_set_uri(mqtt_client, CONFIG_BROKER_TCP_URI);
} else if (0 == strcmp(transport, "ssl")) {
ESP_LOGI(TAG, "[SSL transport] Startup..");
esp_mqtt_client_set_uri(mqtt_client, CONFIG_BROKER_SSL_URI);
} else if (0 == strcmp(transport, "ws")) {
ESP_LOGI(TAG, "[WS transport] Startup..");
esp_mqtt_client_set_uri(mqtt_client, CONFIG_BROKER_WS_URI);
} else if (0 == strcmp(transport, "wss")) {
ESP_LOGI(TAG, "[WSS transport] Startup..");
esp_mqtt_client_set_uri(mqtt_client, CONFIG_BROKER_WSS_URI);
} else {
ESP_LOGE(TAG, "Unexpected transport");
abort();
}
xEventGroupClearBits(mqtt_event_group, CONNECTED_BIT);
esp_mqtt_client_start(mqtt_client);
ESP_LOGI(TAG, "Note free memory: %d bytes", esp_get_free_heap_size());
xEventGroupWaitBits(mqtt_event_group, CONNECTED_BIT, false, true, portMAX_DELAY);
for (int i = 0; i < expected_published; i++) {
int msg_id = esp_mqtt_client_publish(mqtt_client, CONFIG_PUBLISH_TOPIC, expected_data, expected_size, qos_test, 0);
ESP_LOGI(TAG, "[%d] Publishing...", msg_id);
}
}
}

View File

@@ -0,0 +1,5 @@
CONFIG_BROKER_SSL_URI="mqtts://${EXAMPLE_MQTT_BROKER_SSL}"
CONFIG_BROKER_TCP_URI="mqtt://${EXAMPLE_MQTT_BROKER_TCP}"
CONFIG_BROKER_WS_URI="ws://${EXAMPLE_MQTT_BROKER_WS}/ws"
CONFIG_BROKER_WSS_URI="wss://${EXAMPLE_MQTT_BROKER_WSS}/ws"
CONFIG_BROKER_CERTIFICATE_OVERRIDE="${EXAMPLE_MQTT_BROKER_CERTIFICATE}"