diff --git a/src/MqttStreaming.h b/src/MqttStreaming.h index 6066a7a..4918db4 100644 --- a/src/MqttStreaming.h +++ b/src/MqttStreaming.h @@ -38,6 +38,7 @@ 4. Simple _FMT mechanism ala printf, but without the typeunsafetyness and no internal buffers for replaceable stream printing */ +#pragma once #ifndef ARDUINO_STREAMING #define ARDUINO_STREAMING diff --git a/src/TinyMqtt.cpp b/src/TinyMqtt.cpp index 9bed544..ff816b2 100644 --- a/src/TinyMqtt.cpp +++ b/src/TinyMqtt.cpp @@ -84,7 +84,7 @@ void MqttClient::connect(MqttBroker* parentBroker) void MqttClient::connect(std::string broker, uint16_t port, uint16_t ka) { - debug("cnx: closing"); + debug("MqttClient::connect"); keep_alive = ka; close(); if (client) delete client; diff --git a/src/TinyMqtt.h b/src/TinyMqtt.h index ecea277..a8c7d3e 100644 --- a/src/TinyMqtt.h +++ b/src/TinyMqtt.h @@ -235,7 +235,7 @@ class MqttClient MqttError publishIfSubscribed(const Topic& topic, MqttMessage& msg); void clientAlive(uint32_t more_seconds); - void processMessage(MqttMessage* message); + void processMessage(const MqttMessage* message); bool mqtt_connected = false; char mqtt_flags; diff --git a/tests/local-tests/local-tests.ino b/tests/local-tests/local-tests.ino index b62a9a1..b77e143 100644 --- a/tests/local-tests/local-tests.ino +++ b/tests/local-tests/local-tests.ino @@ -143,7 +143,7 @@ void setup() { Serial.begin(115200); while(!Serial); - Serial.println("=============[ NO WIFI CONNECTION TinyMqtt TESTS ]========================"); + Serial.println("=============[ LOCAL TinyMqtt TESTS ]========================"); } void loop() { diff --git a/tests/network-tests/Makefile b/tests/network-tests/Makefile new file mode 100644 index 0000000..cedb61a --- /dev/null +++ b/tests/network-tests/Makefile @@ -0,0 +1,13 @@ +# See https://github.com/bxparks/EpoxyDuino for documentation about this +# Makefile to compile and run Arduino programs natively on Linux or MacOS. + +EXTRA_CXXFLAGS=-g3 -O0 + +# Remove flto flag from EpoxyDuino (too many ) +CXXFLAGS = -Wextra -Wall -std=gnu++11 -fno-exceptions -fno-threadsafe-statics + +APP_NAME := network-tests +ARDUINO_LIBS := AUnit AceCommon AceTime TinyMqtt EspMock ESP8266WiFi ESPAsyncTCP +ARDUINO_LIB_DIRS := ../../../EspMock/libraries +EPOXY_CORE := EPOXY_CORE_ESP8266 +include ../../../EpoxyDuino/EpoxyDuino.mk diff --git a/tests/network-tests/network-tests.ino b/tests/network-tests/network-tests.ino new file mode 100644 index 0000000..7056f58 --- /dev/null +++ b/tests/network-tests/network-tests.ino @@ -0,0 +1,236 @@ +#include +#include +#include +#include + +/** + * TinyMqtt network unit tests. + * + * No wifi connection unit tests. + * Checks with a local broker. Clients must connect to the local broker + **/ + +using namespace std; + +MqttBroker broker(1883); + +std::map> published; // map[client_id] => map[topic] = count + +char* lastPayload = nullptr; +size_t lastLength; + +void onPublish(const MqttClient* srce, const Topic& topic, const char* payload, size_t length) +{ + if (srce) + published[srce->id()][topic]++; + + if (lastPayload) free(lastPayload); + lastPayload = strdup(payload); + lastLength = length; +} + +test(network_single_broker_begin) +{ + assertEqual(WiFi.status(), WL_CONNECTED); + + MqttBroker broker(1883); + broker.begin(); + + // TODO Nothing is tested here ! +} + +test(network_client_to_broker_connexion) +{ + assertEqual(WiFi.status(), WL_CONNECTED); + + MqttBroker broker(1883); + broker.begin(); + + Serial << "TODO IP = " << WiFi.localIP() << endl; + + MqttClient client; + client.connect(WiFi.localIP().toString().c_str(), 1883); + broker.loop(); + + assertEqual(broker.clientsCount(), (size_t)1); +} + +/* +test(network_one_broker_one_client) +{ + published.clear(); + assertEqual(WiFi.status(), WL_CONNECTED); + + MqttBroker broker(1883); + broker.begin(); + + Serial << "TODO IP = " << WiFi.localIP() << endl; + + MqttClient client; + client.connect(WiFi.localIP().toString().c_str(), 1883); + client.setCallback(onPublish); + client.subscribe("a/b"); + client.publish("a/b", "ab"); + // client.loop(); + + assertEqual(published.size(), (size_t)1); +} +*/ + +#if 0 +test(network_client_should_unregister_when_destroyed) +{ + assertEqual(broker.clientsCount(), (size_t)0); + { + MqttClient client(&broker); + assertEqual(broker.clientsCount(), (size_t)1); + } + assertEqual(broker.clientsCount(), (size_t)0); +} + +test(network_connect) +{ + assertEqual(broker.clientsCount(), (size_t)0); + + MqttClient client(&broker); + assertTrue(client.connected()); + assertEqual(broker.clientsCount(), (size_t)1); +} + +test(network_publish_should_be_dispatched) +{ + published.clear(); + assertEqual(broker.clientsCount(), (size_t)0); + + MqttClient subscriber(&broker); + subscriber.subscribe("a/b"); + subscriber.subscribe("a/c"); + subscriber.setCallback(onPublish); + + MqttClient publisher(&broker); + publisher.publish("a/b"); + publisher.publish("a/c"); + publisher.publish("a/c"); + + assertEqual(published.size(), (size_t)1); // 1 client has received something + assertEqual(published[""]["a/b"], 1); + assertEqual(published[""]["a/c"], 2); +} + +test(network_publish_should_be_dispatched_to_clients) +{ + published.clear(); + assertEqual(broker.clientsCount(), (size_t)0); + + MqttClient subscriber_a(&broker, "A"); + subscriber_a.setCallback(onPublish); + subscriber_a.subscribe("a/b"); + subscriber_a.subscribe("a/c"); + + MqttClient subscriber_b(&broker, "B"); + subscriber_b.setCallback(onPublish); + subscriber_b.subscribe("a/b"); + + MqttClient publisher(&broker); + publisher.publish("a/b"); // A and B should receive this + publisher.publish("a/c"); // A should receive this + + assertEqual(published.size(), (size_t)2); // 2 clients have received something + assertEqual(published["A"]["a/b"], 1); + assertEqual(published["A"]["a/c"], 1); + assertEqual(published["B"]["a/b"], 1); + assertEqual(published["B"]["a/c"], 0); +} + +test(network_unsubscribe) +{ + published.clear(); + assertEqual(broker.clientsCount(), (size_t)0); + + MqttClient subscriber(&broker); + subscriber.setCallback(onPublish); + subscriber.subscribe("a/b"); + + MqttClient publisher(&broker); + publisher.publish("a/b"); // This publish is received + + subscriber.unsubscribe("a/b"); + + publisher.publish("a/b"); // Those one, no (unsubscribed) + publisher.publish("a/b"); + + assertEqual(published[""]["a/b"], 1); // Only one publish has been received +} + +test(network_nocallback_when_destroyed) +{ + published.clear(); + assertEqual(broker.clientsCount(), (size_t)0); + + MqttClient publisher(&broker); + + { + MqttClient subscriber(&broker); + subscriber.setCallback(onPublish); + subscriber.subscribe("a/b"); + publisher.publish("a/b"); + } + + publisher.publish("a/b"); + + assertEqual(published.size(), (size_t)1); // Only one publish has been received +} + +test(network_small_payload) +{ + published.clear(); + + const char* payload="abcd"; + + MqttClient subscriber(&broker); + subscriber.setCallback(onPublish); + subscriber.subscribe("a/b"); + + MqttClient publisher(&broker); + publisher.publish("a/b", payload, strlen(payload)); // This publish is received + + // coming from MqttClient::publish(...) + assertEqual(payload, lastPayload); + assertEqual(lastLength, (size_t)4); +} + +test(network_hudge_payload) +{ + const char* payload="This payload is hudge, just because its length exceeds 127. Thus when encoding length, we have to encode it on two bytes at min. This should not prevent the message from being encoded and decoded successfully !"; + + MqttClient subscriber(&broker); + subscriber.setCallback(onPublish); + subscriber.subscribe("a/b"); + + MqttClient publisher(&broker); + publisher.publish("a/b", payload); // This publish is received + + // onPublish should have filled lastPayload and lastLength + assertEqual(payload, lastPayload); + assertEqual(lastLength, strlen(payload)); +} +#endif + +//---------------------------------------------------------------------------- +// setup() and loop() +void setup() { + delay(1000); + Serial.begin(115200); + while(!Serial); + + Serial.println("=============[ FAKE NETWORK TinyMqtt TESTS ]========================"); + + WiFi.mode(WIFI_STA); + WiFi.begin("network", "password"); +} + +void loop() { + aunit::TestRunner::run(); + + if (Serial.available()) ESP.reset(); +}