diff --git a/src/TinyMqtt.cpp b/src/TinyMqtt.cpp index ff816b2..a9be1f9 100644 --- a/src/TinyMqtt.cpp +++ b/src/TinyMqtt.cpp @@ -1,14 +1,6 @@ #include "TinyMqtt.h" #include -void outstring(const char* prefix, const char*p, uint16_t len) -{ - return; - Serial << prefix << "='"; - while(len--) Serial << (char)*p++; - Serial << '\'' << endl; -} - MqttBroker::MqttBroker(uint16_t port) { server = new TcpServer(port); @@ -447,11 +439,9 @@ if (mesg->type() != MqttMessage::Type::PingReq && mesg->type() != MqttMessage::T if (mqtt_flags & FlagWill) // Will topic { mesg->getString(payload, len); // Will Topic - outstring("WillTopic", payload, len); payload += len; mesg->getString(payload, len); // Will Message - outstring("WillMessage", payload, len); payload += len; } // FIXME forgetting credential is allowed (security hole) @@ -468,7 +458,9 @@ if (mesg->type() != MqttMessage::Type::PingReq && mesg->type() != MqttMessage::T payload += len; } - Serial << "Connected client:" << clientId.c_str() << ", keep alive=" << keep_alive << '.' << endl; + #ifdef TINY_MQTT_DEBUG + Serial << "Connected client:" << clientId.c_str() << ", keep alive=" << keep_alive << '.' << endl; + #endif bclose = false; mqtt_connected=true; { @@ -522,7 +514,6 @@ if (mesg->type() != MqttMessage::Type::PingReq && mesg->type() != MqttMessage::T { mesg->getString(payload, len); // Topic debug( " topic (" << std::string(payload, len) << ')'); - outstring(" un/subscribes", payload, len); // subscribe(Topic(payload, len)); Topic topic(payload, len); payload += len; @@ -602,10 +593,12 @@ if (mesg->type() != MqttMessage::Type::PingReq && mesg->type() != MqttMessage::T }; if (bclose) { - Serial << "*************** Error msg 0x" << _HEX(mesg->type()); - mesg->hexdump("-------ERROR ------"); - dump(); - Serial << endl; + #ifdef TINY_MQTT_DEBUG + Serial << "*************** Error msg 0x" << _HEX(mesg->type()); + mesg->hexdump("-------ERROR ------"); + dump(); + Serial << endl; + #endif close(); } else @@ -722,8 +715,10 @@ void MqttMessage::incoming(char in_byte) break; case Complete: default: - Serial << "Spurious " << _HEX(in_byte) << endl; - hexdump("spurious"); + #ifdef TINY_MQTT_DEBUG + Serial << "Spurious " << _HEX(in_byte) << endl; + hexdump("spurious"); + #endif reset(); break; } @@ -778,6 +773,8 @@ MqttError MqttMessage::sendTo(MqttClient* client) void MqttMessage::hexdump(const char* prefix) const { + (void)prefix; +#ifdef TINY_MQTT_DEBUG uint16_t addr=0; const int bytes_per_row = 8; const char* hex_to_str = " | "; @@ -813,4 +810,5 @@ void MqttMessage::hexdump(const char* prefix) const } Serial << endl; +#endif } diff --git a/src/TinyMqtt.h b/src/TinyMqtt.h index a8c7d3e..8a17500 100644 --- a/src/TinyMqtt.h +++ b/src/TinyMqtt.h @@ -29,7 +29,7 @@ // #define TINY_MQTT_DEBUG #ifdef TINY_MQTT_DEBUG - #define debug(what) { Serial << __LINE__ << ' ' << what << endl; delay(100); } + #define debug(what) { Serial << (int)__LINE__ << ' ' << what << endl; delay(100); } #else #define debug(what) {} #endif @@ -160,6 +160,8 @@ class MqttClient void connect(MqttBroker* parent); void connect(std::string broker, uint16_t port, uint16_t keep_alive = 10); + // TODO it seems that connected returns true in tcp mode even if + // no negociation occured (only if tcp link is established) bool connected() { return (parent!=nullptr and client==nullptr) or (client and client->connected()); } @@ -198,23 +200,27 @@ class MqttClient void dump(std::string indent="") { - uint32_t ms=millis(); - Serial << indent << "+-- " << '\'' << clientId.c_str() << "' " << (connected() ? " ON " : " OFF"); - Serial << ", alive=" << alive << '/' << ms << ", ka=" << keep_alive << ' '; - Serial << (client && client->connected() ? "" : "dis") << "connected"; - if (subscriptions.size()) - { - bool c = false; - Serial << " ["; - for(auto s: subscriptions) - { - if (c) Serial << ", "; - Serial << s.str().c_str(); - c=true; - } - Serial << ']'; - } - Serial << endl; + (void)indent; + #ifdef TINY_MQTT_DEBUG + uint32_t ms=millis(); + Serial << indent << "+-- " << '\'' << clientId.c_str() << "' " << (connected() ? " ON " : " OFF"); + Serial << ", alive=" << alive << '/' << ms << ", ka=" << keep_alive << ' '; + Serial << (client && client->connected() ? "" : "dis") << "connected"; + if (subscriptions.size()) + { + bool c = false; + Serial << " ["; + for(auto s: subscriptions) + (void)indent; + { + if (c) Serial << ", "; + Serial << s.str().c_str(); + c=true; + } + Serial << ']'; + } + Serial << endl; + #endif } static long counter; // Number of processed messages @@ -235,7 +241,7 @@ class MqttClient MqttError publishIfSubscribed(const Topic& topic, MqttMessage& msg); void clientAlive(uint32_t more_seconds); - void processMessage(const MqttMessage* message); + void processMessage(MqttMessage* message); bool mqtt_connected = false; char mqtt_flags; diff --git a/tests/local-tests/Makefile b/tests/local-tests/Makefile index 21bc2bf..4ffcbc9 100644 --- a/tests/local-tests/Makefile +++ b/tests/local-tests/Makefile @@ -1,6 +1,11 @@ # 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 := local-tests ARDUINO_LIBS := AUnit AceCommon AceTime TinyMqtt EspMock ESP8266WiFi ESPAsyncTCP ARDUINO_LIB_DIRS := ../../../EspMock/libraries diff --git a/tests/local-tests/local-tests.ino b/tests/local-tests/local-tests.ino index b77e143..f812905 100644 --- a/tests/local-tests/local-tests.ino +++ b/tests/local-tests/local-tests.ino @@ -68,8 +68,8 @@ test(local_publish_should_be_dispatched) publisher.publish("a/c"); assertEqual(published.size(), (size_t)1); // 1 client has received something - assertTrue(published[""]["a/b"] == 1); - assertTrue(published[""]["a/c"] == 2); + assertEqual(published[""]["a/b"], 1); + assertEqual(published[""]["a/c"], 2); } test(local_publish_should_be_dispatched_to_local_clients) @@ -91,10 +91,10 @@ test(local_publish_should_be_dispatched_to_local_clients) publisher.publish("a/c"); assertEqual(published.size(), (size_t)2); // 2 clients have received something - assertTrue(published["A"]["a/b"] == 1); - assertTrue(published["A"]["a/c"] == 1); - assertTrue(published["B"]["a/b"] == 1); - assertTrue(published["B"]["a/c"] == 0); + 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(local_unsubscribe) @@ -114,7 +114,7 @@ test(local_unsubscribe) publisher.publish("a/b"); publisher.publish("a/b"); - assertTrue(published[""]["a/b"] == 1); // Only one publish has been received + assertEqual(published[""]["a/b"], 1); // Only one publish has been received } test(local_nocallback_when_destroyed) diff --git a/tests/network-tests/network-tests.ino b/tests/network-tests/network-tests.ino index 7056f58..f953114 100644 --- a/tests/network-tests/network-tests.ino +++ b/tests/network-tests/network-tests.ino @@ -19,6 +19,18 @@ std::map> published; // map[client_id] => map char* lastPayload = nullptr; size_t lastLength; +void start_servers(int n, bool early_accept = true) +{ + ESP8266WiFiClass::resetInstances(); + ESP8266WiFiClass::earlyAccept = early_accept; + while(n) + { + ESP8266WiFiClass::selectInstance(n--); + WiFi.mode(WIFI_STA); + WiFi.begin("fake_ssid", "fake_pwd"); + } +} + void onPublish(const MqttClient* srce, const Topic& topic, const char* payload, size_t length) { if (srce) @@ -41,43 +53,90 @@ test(network_single_broker_begin) test(network_client_to_broker_connexion) { + start_servers(2, true); + assertEqual(WiFi.status(), WL_CONNECTED); MqttBroker broker(1883); broker.begin(); + IPAddress broker_ip = WiFi.localIP(); - Serial << "TODO IP = " << WiFi.localIP() << endl; - + ESP8266WiFiClass::selectInstance(2); MqttClient client; - client.connect(WiFi.localIP().toString().c_str(), 1883); + client.connect(broker_ip.toString().c_str(), 1883); broker.loop(); - assertEqual(broker.clientsCount(), (size_t)1); + assertTrue(broker.clientsCount() == 1); + assertTrue(client.connected()); } -/* -test(network_one_broker_one_client) +test(network_one_client_one_broker_publish_and_subscribe_through_network) { + start_servers(2, true); published.clear(); assertEqual(WiFi.status(), WL_CONNECTED); MqttBroker broker(1883); broker.begin(); + IPAddress ip_broker = WiFi.localIP(); - Serial << "TODO IP = " << WiFi.localIP() << endl; - + // We have a 2nd ESP in order to test through wifi (opposed to local) + ESP8266WiFiClass::selectInstance(2); MqttClient client; - client.connect(WiFi.localIP().toString().c_str(), 1883); + client.connect(ip_broker.toString().c_str(), 1883); + broker.loop(); + assertTrue(client.connected()); + client.setCallback(onPublish); client.subscribe("a/b"); client.publish("a/b", "ab"); - // client.loop(); + + for (int i =0; i<2; i++) + { + client.loop(); + broker.loop(); + } + + assertEqual(published.size(), (size_t)1); + assertEqual((int)lastLength, (int)2); // sizeof(ab) +} + +test(network_one_client_one_broker_hudge_publish_and_subscribe_through_network) +{ + start_servers(2, true); + published.clear(); + assertEqual(WiFi.status(), WL_CONNECTED); + + MqttBroker broker(1883); + broker.begin(); + IPAddress ip_broker = WiFi.localIP(); + + // We have a 2nd ESP in order to test through wifi (opposed to local) + ESP8266WiFiClass::selectInstance(2); + MqttClient client; + client.connect(ip_broker.toString().c_str(), 1883); + broker.loop(); + assertTrue(client.connected()); + + std::string sent; + + for(int i=0; i<200; i++) + sent += char('0'+i%10); + + client.setCallback(onPublish); + client.subscribe("a/b"); + client.publish("a/b", sent.c_str()); + + for (int i =0; i<2; i++) + { + client.loop(); + broker.loop(); + } assertEqual(published.size(), (size_t)1); + assertEqual((unsigned int)lastLength, (unsigned int)sent.size()); } -*/ -#if 0 test(network_client_should_unregister_when_destroyed) { assertEqual(broker.clientsCount(), (size_t)0); @@ -88,6 +147,11 @@ test(network_client_should_unregister_when_destroyed) assertEqual(broker.clientsCount(), (size_t)0); } +#if 0 + +// THESE TESTS ARE IN LOCAL MODE +// WE HAVE TO CONVERT THEM TO WIFI MODE (pass through virtual TCP link) + test(network_connect) { assertEqual(broker.clientsCount(), (size_t)0); @@ -219,12 +283,12 @@ test(network_hudge_payload) //---------------------------------------------------------------------------- // setup() and loop() void setup() { - delay(1000); + /* delay(1000); Serial.begin(115200); while(!Serial); Serial.println("=============[ FAKE NETWORK TinyMqtt TESTS ]========================"); - +*/ WiFi.mode(WIFI_STA); WiFi.begin("network", "password"); }