Compare commits
81 Commits
Author | SHA1 | Date | |
---|---|---|---|
26ce89fa47 | |||
a29d0c3d72 | |||
fa3c4362ea | |||
b381728998 | |||
2bcd9b074a | |||
2ed03ad522 | |||
2d053d2df0 | |||
ee30733e24 | |||
4daba0ae5c | |||
af860133e8 | |||
a0f09681f5 | |||
05a601cc55 | |||
3637cbec69 | |||
b1bdbb7aaf | |||
539838822c | |||
b5f90b679b | |||
4ecd32ec08 | |||
7517de7974 | |||
8154cbc09c | |||
0e8e3123cf | |||
9eff4b3308 | |||
a1cfd5af56 | |||
0e2d6c322b | |||
b2f3a6d2ec | |||
0c2d12d8b0 | |||
c87c9a47b3 | |||
3b3a8da8d2 | |||
9e1a6e6479 | |||
54be6e87db | |||
f029640ee6 | |||
bb101c58e8 | |||
8795fdf0f5 | |||
8498284792 | |||
49f307506b | |||
dddfffbe0c | |||
bef5814858 | |||
f46d0011ee | |||
10925659ef | |||
4c8ce14dad | |||
df4122466c | |||
d724864095 | |||
33170273a9 | |||
35ead348e3 | |||
341661671b | |||
4739ca0802 | |||
36bb1ffa6a | |||
83b69a766e | |||
baeb59e263 | |||
67eba6dad4 | |||
98a9c296f6 | |||
68400b7b6c | |||
21b75a2c4a | |||
830f34c7d0 | |||
0bb4efcea5 | |||
31521085ea | |||
8a1d7fb620 | |||
803f54b0bd | |||
6f97ea04f2 | |||
6bb06187b7 | |||
efebd2e5e4 | |||
5cdadf43da | |||
2f97e4a558 | |||
15a0e41c81 | |||
aa9afc7b44 | |||
461cbdb6e8 | |||
47a37a4663 | |||
efcf6dbf1e | |||
d5c13d578e | |||
b6f2cb29bc | |||
c1d327cac6 | |||
5ace47bc93 | |||
da87f50b98 | |||
8c56c2f9fc | |||
ce6b128efb | |||
2b582f6899 | |||
545d0045f9 | |||
fc02df2f6f | |||
a181852893 | |||
c51f6c1673 | |||
0d11ce4a7e | |||
1c54371b1c |
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
tests/bin
|
7
.travis.yml
Normal file
7
.travis.yml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
sudo: false
|
||||||
|
language: cpp
|
||||||
|
compiler:
|
||||||
|
- g++
|
||||||
|
script: cd tests && make && make test
|
||||||
|
os:
|
||||||
|
- linux
|
@ -1,3 +1,26 @@
|
|||||||
|
2.7
|
||||||
|
* Fix remaining-length handling to prevent buffer overrun
|
||||||
|
* Add large-payload API - beginPublish/write/publish/endPublish
|
||||||
|
* Add yield call to improve reliability on ESP
|
||||||
|
* Add Clean Session flag to connect options
|
||||||
|
* Add ESP32 support for functional callback signature
|
||||||
|
* Various other fixes
|
||||||
|
|
||||||
|
2.4
|
||||||
|
* Add MQTT_SOCKET_TIMEOUT to prevent it blocking indefinitely
|
||||||
|
whilst waiting for inbound data
|
||||||
|
* Fixed return code when publishing >256 bytes
|
||||||
|
|
||||||
|
2.3
|
||||||
|
* Add publish(topic,payload,retained) function
|
||||||
|
|
||||||
|
2.2
|
||||||
|
* Change code layout to match Arduino Library reqs
|
||||||
|
|
||||||
|
2.1
|
||||||
|
* Add MAX_TRANSFER_SIZE def to chunk messages if needed
|
||||||
|
* Reject topic/payloads that exceed MQTT_MAX_PACKET_SIZE
|
||||||
|
|
||||||
2.0
|
2.0
|
||||||
* Add (and default to) MQTT 3.1.1 support
|
* Add (and default to) MQTT 3.1.1 support
|
||||||
* Fix PROGMEM handling for Intel Galileo/ESP8266
|
* Fix PROGMEM handling for Intel Galileo/ESP8266
|
@ -8,7 +8,7 @@ a server that supports MQTT.
|
|||||||
The library comes with a number of example sketches. See File > Examples > PubSubClient
|
The library comes with a number of example sketches. See File > Examples > PubSubClient
|
||||||
within the Arduino application.
|
within the Arduino application.
|
||||||
|
|
||||||
Full API documentation is available here: http://knolleary.github.io/pubsubclient/
|
Full API documentation is available here: https://pubsubclient.knolleary.net
|
||||||
|
|
||||||
## Limitations
|
## Limitations
|
||||||
|
|
||||||
@ -31,10 +31,13 @@ boards and shields, including:
|
|||||||
- Arduino Ethernet Shield
|
- Arduino Ethernet Shield
|
||||||
- Arduino YUN – use the included `YunClient` in place of `EthernetClient`, and
|
- Arduino YUN – use the included `YunClient` in place of `EthernetClient`, and
|
||||||
be sure to do a `Bridge.begin()` first
|
be sure to do a `Bridge.begin()` first
|
||||||
- Arduino WiFi Shield
|
- Arduino WiFi Shield - if you want to send packets > 90 bytes with this shield,
|
||||||
- Sparkfun WiFly Shield – when used with [this library](https://github.com/dpslwk/WiFly)
|
enable the `MQTT_MAX_TRANSFER_SIZE` define in `PubSubClient.h`.
|
||||||
|
- Sparkfun WiFly Shield – [library](https://github.com/dpslwk/WiFly)
|
||||||
|
- TI CC3000 WiFi - [library](https://github.com/sparkfun/SFE_CC3000_Library)
|
||||||
- Intel Galileo/Edison
|
- Intel Galileo/Edison
|
||||||
- ESP8266
|
- ESP8266
|
||||||
|
- ESP32
|
||||||
|
|
||||||
The library cannot currently be used with hardware based on the ENC28J60 chip –
|
The library cannot currently be used with hardware based on the ENC28J60 chip –
|
||||||
such as the Nanode or the Nuelectronics Ethernet Shield. For those, there is an
|
such as the Nanode or the Nuelectronics Ethernet Shield. For those, there is an
|
||||||
|
132
examples/mqtt_esp8266/mqtt_esp8266.ino
Normal file
132
examples/mqtt_esp8266/mqtt_esp8266.ino
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
/*
|
||||||
|
Basic ESP8266 MQTT example
|
||||||
|
|
||||||
|
This sketch demonstrates the capabilities of the pubsub library in combination
|
||||||
|
with the ESP8266 board/library.
|
||||||
|
|
||||||
|
It connects to an MQTT server then:
|
||||||
|
- publishes "hello world" to the topic "outTopic" every two seconds
|
||||||
|
- subscribes to the topic "inTopic", printing out any messages
|
||||||
|
it receives. NB - it assumes the received payloads are strings not binary
|
||||||
|
- If the first character of the topic "inTopic" is an 1, switch ON the ESP Led,
|
||||||
|
else switch it off
|
||||||
|
|
||||||
|
It will reconnect to the server if the connection is lost using a blocking
|
||||||
|
reconnect function. See the 'mqtt_reconnect_nonblocking' example for how to
|
||||||
|
achieve the same result without blocking the main loop.
|
||||||
|
|
||||||
|
To install the ESP8266 board, (using Arduino 1.6.4+):
|
||||||
|
- Add the following 3rd party board manager under "File -> Preferences -> Additional Boards Manager URLs":
|
||||||
|
http://arduino.esp8266.com/stable/package_esp8266com_index.json
|
||||||
|
- Open the "Tools -> Board -> Board Manager" and click install for the ESP8266"
|
||||||
|
- Select your ESP8266 in "Tools -> Board"
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <ESP8266WiFi.h>
|
||||||
|
#include <PubSubClient.h>
|
||||||
|
|
||||||
|
// Update these with values suitable for your network.
|
||||||
|
|
||||||
|
const char* ssid = "........";
|
||||||
|
const char* password = "........";
|
||||||
|
const char* mqtt_server = "broker.mqtt-dashboard.com";
|
||||||
|
|
||||||
|
WiFiClient espClient;
|
||||||
|
PubSubClient client(espClient);
|
||||||
|
long lastMsg = 0;
|
||||||
|
char msg[50];
|
||||||
|
int value = 0;
|
||||||
|
|
||||||
|
void setup_wifi() {
|
||||||
|
|
||||||
|
delay(10);
|
||||||
|
// We start by connecting to a WiFi network
|
||||||
|
Serial.println();
|
||||||
|
Serial.print("Connecting to ");
|
||||||
|
Serial.println(ssid);
|
||||||
|
|
||||||
|
WiFi.begin(ssid, password);
|
||||||
|
|
||||||
|
while (WiFi.status() != WL_CONNECTED) {
|
||||||
|
delay(500);
|
||||||
|
Serial.print(".");
|
||||||
|
}
|
||||||
|
|
||||||
|
randomSeed(micros());
|
||||||
|
|
||||||
|
Serial.println("");
|
||||||
|
Serial.println("WiFi connected");
|
||||||
|
Serial.println("IP address: ");
|
||||||
|
Serial.println(WiFi.localIP());
|
||||||
|
}
|
||||||
|
|
||||||
|
void callback(char* topic, byte* payload, unsigned int length) {
|
||||||
|
Serial.print("Message arrived [");
|
||||||
|
Serial.print(topic);
|
||||||
|
Serial.print("] ");
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
|
Serial.print((char)payload[i]);
|
||||||
|
}
|
||||||
|
Serial.println();
|
||||||
|
|
||||||
|
// Switch on the LED if an 1 was received as first character
|
||||||
|
if ((char)payload[0] == '1') {
|
||||||
|
digitalWrite(BUILTIN_LED, LOW); // Turn the LED on (Note that LOW is the voltage level
|
||||||
|
// but actually the LED is on; this is because
|
||||||
|
// it is active low on the ESP-01)
|
||||||
|
} else {
|
||||||
|
digitalWrite(BUILTIN_LED, HIGH); // Turn the LED off by making the voltage HIGH
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void reconnect() {
|
||||||
|
// Loop until we're reconnected
|
||||||
|
while (!client.connected()) {
|
||||||
|
Serial.print("Attempting MQTT connection...");
|
||||||
|
// Create a random client ID
|
||||||
|
String clientId = "ESP8266Client-";
|
||||||
|
clientId += String(random(0xffff), HEX);
|
||||||
|
// Attempt to connect
|
||||||
|
if (client.connect(clientId.c_str())) {
|
||||||
|
Serial.println("connected");
|
||||||
|
// Once connected, publish an announcement...
|
||||||
|
client.publish("outTopic", "hello world");
|
||||||
|
// ... and resubscribe
|
||||||
|
client.subscribe("inTopic");
|
||||||
|
} else {
|
||||||
|
Serial.print("failed, rc=");
|
||||||
|
Serial.print(client.state());
|
||||||
|
Serial.println(" try again in 5 seconds");
|
||||||
|
// Wait 5 seconds before retrying
|
||||||
|
delay(5000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
pinMode(BUILTIN_LED, OUTPUT); // Initialize the BUILTIN_LED pin as an output
|
||||||
|
Serial.begin(115200);
|
||||||
|
setup_wifi();
|
||||||
|
client.setServer(mqtt_server, 1883);
|
||||||
|
client.setCallback(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
|
||||||
|
if (!client.connected()) {
|
||||||
|
reconnect();
|
||||||
|
}
|
||||||
|
client.loop();
|
||||||
|
|
||||||
|
long now = millis();
|
||||||
|
if (now - lastMsg > 2000) {
|
||||||
|
lastMsg = now;
|
||||||
|
++value;
|
||||||
|
snprintf (msg, 50, "hello world #%ld", value);
|
||||||
|
Serial.print("Publish message: ");
|
||||||
|
Serial.println(msg);
|
||||||
|
client.publish("outTopic", msg);
|
||||||
|
}
|
||||||
|
}
|
179
examples/mqtt_large_message/mqtt_large_message.ino
Normal file
179
examples/mqtt_large_message/mqtt_large_message.ino
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
/*
|
||||||
|
Long message ESP8266 MQTT example
|
||||||
|
|
||||||
|
This sketch demonstrates sending arbitrarily large messages in combination
|
||||||
|
with the ESP8266 board/library.
|
||||||
|
|
||||||
|
It connects to an MQTT server then:
|
||||||
|
- publishes "hello world" to the topic "outTopic"
|
||||||
|
- subscribes to the topic "greenBottles/#", printing out any messages
|
||||||
|
it receives. NB - it assumes the received payloads are strings not binary
|
||||||
|
- If the sub-topic is a number, it publishes a "greenBottles/lyrics" message
|
||||||
|
with a payload consisting of the lyrics to "10 green bottles", replacing
|
||||||
|
10 with the number given in the sub-topic.
|
||||||
|
|
||||||
|
It will reconnect to the server if the connection is lost using a blocking
|
||||||
|
reconnect function. See the 'mqtt_reconnect_nonblocking' example for how to
|
||||||
|
achieve the same result without blocking the main loop.
|
||||||
|
|
||||||
|
To install the ESP8266 board, (using Arduino 1.6.4+):
|
||||||
|
- Add the following 3rd party board manager under "File -> Preferences -> Additional Boards Manager URLs":
|
||||||
|
http://arduino.esp8266.com/stable/package_esp8266com_index.json
|
||||||
|
- Open the "Tools -> Board -> Board Manager" and click install for the ESP8266"
|
||||||
|
- Select your ESP8266 in "Tools -> Board"
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <ESP8266WiFi.h>
|
||||||
|
#include <PubSubClient.h>
|
||||||
|
|
||||||
|
// Update these with values suitable for your network.
|
||||||
|
|
||||||
|
const char* ssid = "........";
|
||||||
|
const char* password = "........";
|
||||||
|
const char* mqtt_server = "broker.mqtt-dashboard.com";
|
||||||
|
|
||||||
|
WiFiClient espClient;
|
||||||
|
PubSubClient client(espClient);
|
||||||
|
long lastMsg = 0;
|
||||||
|
char msg[50];
|
||||||
|
int value = 0;
|
||||||
|
|
||||||
|
void setup_wifi() {
|
||||||
|
|
||||||
|
delay(10);
|
||||||
|
// We start by connecting to a WiFi network
|
||||||
|
Serial.println();
|
||||||
|
Serial.print("Connecting to ");
|
||||||
|
Serial.println(ssid);
|
||||||
|
|
||||||
|
WiFi.begin(ssid, password);
|
||||||
|
|
||||||
|
while (WiFi.status() != WL_CONNECTED) {
|
||||||
|
delay(500);
|
||||||
|
Serial.print(".");
|
||||||
|
}
|
||||||
|
|
||||||
|
randomSeed(micros());
|
||||||
|
|
||||||
|
Serial.println("");
|
||||||
|
Serial.println("WiFi connected");
|
||||||
|
Serial.println("IP address: ");
|
||||||
|
Serial.println(WiFi.localIP());
|
||||||
|
}
|
||||||
|
|
||||||
|
void callback(char* topic, byte* payload, unsigned int length) {
|
||||||
|
Serial.print("Message arrived [");
|
||||||
|
Serial.print(topic);
|
||||||
|
Serial.print("] ");
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
|
Serial.print((char)payload[i]);
|
||||||
|
}
|
||||||
|
Serial.println();
|
||||||
|
|
||||||
|
// Find out how many bottles we should generate lyrics for
|
||||||
|
String topicStr(topic);
|
||||||
|
int bottleCount = 0; // assume no bottles unless we correctly parse a value from the topic
|
||||||
|
if (topicStr.indexOf('/') >= 0) {
|
||||||
|
// The topic includes a '/', we'll try to read the number of bottles from just after that
|
||||||
|
topicStr.remove(0, topicStr.indexOf('/')+1);
|
||||||
|
// Now see if there's a number of bottles after the '/'
|
||||||
|
bottleCount = topicStr.toInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bottleCount > 0) {
|
||||||
|
// Work out how big our resulting message will be
|
||||||
|
int msgLen = 0;
|
||||||
|
for (int i = bottleCount; i > 0; i--) {
|
||||||
|
String numBottles(i);
|
||||||
|
msgLen += 2*numBottles.length();
|
||||||
|
if (i == 1) {
|
||||||
|
msgLen += 2*String(" green bottle, standing on the wall\n").length();
|
||||||
|
} else {
|
||||||
|
msgLen += 2*String(" green bottles, standing on the wall\n").length();
|
||||||
|
}
|
||||||
|
msgLen += String("And if one green bottle should accidentally fall\nThere'll be ").length();
|
||||||
|
switch (i) {
|
||||||
|
case 1:
|
||||||
|
msgLen += String("no green bottles, standing on the wall\n\n").length();
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
msgLen += String("1 green bottle, standing on the wall\n\n").length();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
numBottles = i-1;
|
||||||
|
msgLen += numBottles.length();
|
||||||
|
msgLen += String(" green bottles, standing on the wall\n\n").length();
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now we can start to publish the message
|
||||||
|
client.beginPublish("greenBottles/lyrics", msgLen, false);
|
||||||
|
for (int i = bottleCount; i > 0; i--) {
|
||||||
|
for (int j = 0; j < 2; j++) {
|
||||||
|
client.print(i);
|
||||||
|
if (i == 1) {
|
||||||
|
client.print(" green bottle, standing on the wall\n");
|
||||||
|
} else {
|
||||||
|
client.print(" green bottles, standing on the wall\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
client.print("And if one green bottle should accidentally fall\nThere'll be ");
|
||||||
|
switch (i) {
|
||||||
|
case 1:
|
||||||
|
client.print("no green bottles, standing on the wall\n\n");
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
client.print("1 green bottle, standing on the wall\n\n");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
client.print(i-1);
|
||||||
|
client.print(" green bottles, standing on the wall\n\n");
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// Now we're done!
|
||||||
|
client.endPublish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void reconnect() {
|
||||||
|
// Loop until we're reconnected
|
||||||
|
while (!client.connected()) {
|
||||||
|
Serial.print("Attempting MQTT connection...");
|
||||||
|
// Create a random client ID
|
||||||
|
String clientId = "ESP8266Client-";
|
||||||
|
clientId += String(random(0xffff), HEX);
|
||||||
|
// Attempt to connect
|
||||||
|
if (client.connect(clientId.c_str())) {
|
||||||
|
Serial.println("connected");
|
||||||
|
// Once connected, publish an announcement...
|
||||||
|
client.publish("outTopic", "hello world");
|
||||||
|
// ... and resubscribe
|
||||||
|
client.subscribe("greenBottles/#");
|
||||||
|
} else {
|
||||||
|
Serial.print("failed, rc=");
|
||||||
|
Serial.print(client.state());
|
||||||
|
Serial.println(" try again in 5 seconds");
|
||||||
|
// Wait 5 seconds before retrying
|
||||||
|
delay(5000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
pinMode(BUILTIN_LED, OUTPUT); // Initialize the BUILTIN_LED pin as an output
|
||||||
|
Serial.begin(115200);
|
||||||
|
setup_wifi();
|
||||||
|
client.setServer(mqtt_server, 1883);
|
||||||
|
client.setCallback(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
|
||||||
|
if (!client.connected()) {
|
||||||
|
reconnect();
|
||||||
|
}
|
||||||
|
client.loop();
|
||||||
|
}
|
@ -16,6 +16,9 @@ connect KEYWORD2
|
|||||||
disconnect KEYWORD2
|
disconnect KEYWORD2
|
||||||
publish KEYWORD2
|
publish KEYWORD2
|
||||||
publish_P KEYWORD2
|
publish_P KEYWORD2
|
||||||
|
beginPublish KEYWORD2
|
||||||
|
endPublish KEYWORD2
|
||||||
|
write KEYWORD2
|
||||||
subscribe KEYWORD2
|
subscribe KEYWORD2
|
||||||
unsubscribe KEYWORD2
|
unsubscribe KEYWORD2
|
||||||
loop KEYWORD2
|
loop KEYWORD2
|
17
library.json
Normal file
17
library.json
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"name": "PubSubClient",
|
||||||
|
"keywords": "ethernet, mqtt, m2m, iot",
|
||||||
|
"description": "A client library for MQTT messaging. MQTT is a lightweight messaging protocol ideal for small devices. This library allows you to send and receive MQTT messages. It supports the latest MQTT 3.1.1 protocol and can be configured to use the older MQTT 3.1 if needed. It supports all Arduino Ethernet Client compatible hardware, including the Intel Galileo/Edison, ESP8266 and TI CC3000.",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/knolleary/pubsubclient.git"
|
||||||
|
},
|
||||||
|
"version": "2.7",
|
||||||
|
"exclude": "tests",
|
||||||
|
"examples": "examples/*/*.ino",
|
||||||
|
"frameworks": "arduino",
|
||||||
|
"platforms": [
|
||||||
|
"atmelavr",
|
||||||
|
"espressif"
|
||||||
|
]
|
||||||
|
}
|
@ -1,9 +1,9 @@
|
|||||||
name=PubSubClient
|
name=PubSubClient
|
||||||
version=2.0
|
version=2.7
|
||||||
author=Nick O'Leary <nick.oleary@gmail.com>
|
author=Nick O'Leary <nick.oleary@gmail.com>
|
||||||
maintainer=Nick O'Leary <nick.oleary@gmail.com>
|
maintainer=Nick O'Leary <nick.oleary@gmail.com>
|
||||||
sentence=A client library for MQTT messaging.
|
sentence=A client library for MQTT messaging.
|
||||||
paragraph=MQTT is a lightweight messaging protocol ideal for small devices. This library allows you to send and receive MQTT messages from a remote server. It supports the latest MQTT 3.1.1 protocol and can be configured to use the older MQTT 3.1 if needed. It supports all Arduino Ethernet Client compatible hardware, including the Intel Galileo/Edison and ESP8266.
|
paragraph=MQTT is a lightweight messaging protocol ideal for small devices. This library allows you to send and receive MQTT messages. It supports the latest MQTT 3.1.1 protocol and can be configured to use the older MQTT 3.1 if needed. It supports all Arduino Ethernet Client compatible hardware, including the Intel Galileo/Edison, ESP8266 and TI CC3000.
|
||||||
category=Communication
|
category=Communication
|
||||||
url=http://knolleary.github.io/pubsubclient/
|
url=http://pubsubclient.knolleary.net
|
||||||
architectures=*
|
architectures=*
|
@ -102,18 +102,22 @@ PubSubClient::PubSubClient(const char* domain, uint16_t port, MQTT_CALLBACK_SIGN
|
|||||||
}
|
}
|
||||||
|
|
||||||
boolean PubSubClient::connect(const char *id) {
|
boolean PubSubClient::connect(const char *id) {
|
||||||
return connect(id,NULL,NULL,0,0,0,0);
|
return connect(id,NULL,NULL,0,0,0,0,1);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean PubSubClient::connect(const char *id, const char *user, const char *pass) {
|
boolean PubSubClient::connect(const char *id, const char *user, const char *pass) {
|
||||||
return connect(id,user,pass,0,0,0,0);
|
return connect(id,user,pass,0,0,0,0,1);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean PubSubClient::connect(const char *id, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage) {
|
boolean PubSubClient::connect(const char *id, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage) {
|
||||||
return connect(id,NULL,NULL,willTopic,willQos,willRetain,willMessage);
|
return connect(id,NULL,NULL,willTopic,willQos,willRetain,willMessage,1);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean PubSubClient::connect(const char *id, const char *user, const char *pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage) {
|
boolean PubSubClient::connect(const char *id, const char *user, const char *pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage) {
|
||||||
|
return connect(id,user,pass,willTopic,willQos,willRetain,willMessage,1);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean PubSubClient::connect(const char *id, const char *user, const char *pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage, boolean cleanSession) {
|
||||||
if (!connected()) {
|
if (!connected()) {
|
||||||
int result = 0;
|
int result = 0;
|
||||||
|
|
||||||
@ -122,10 +126,10 @@ boolean PubSubClient::connect(const char *id, const char *user, const char *pass
|
|||||||
} else {
|
} else {
|
||||||
result = _client->connect(this->ip, this->port);
|
result = _client->connect(this->ip, this->port);
|
||||||
}
|
}
|
||||||
if (result) {
|
if (result == 1) {
|
||||||
nextMsgId = 1;
|
nextMsgId = 1;
|
||||||
// Leave room in the buffer for header and variable length field
|
// Leave room in the buffer for header and variable length field
|
||||||
uint16_t length = 5;
|
uint16_t length = MQTT_MAX_HEADER_SIZE;
|
||||||
unsigned int j;
|
unsigned int j;
|
||||||
|
|
||||||
#if MQTT_VERSION == MQTT_VERSION_3_1
|
#if MQTT_VERSION == MQTT_VERSION_3_1
|
||||||
@ -141,9 +145,12 @@ boolean PubSubClient::connect(const char *id, const char *user, const char *pass
|
|||||||
|
|
||||||
uint8_t v;
|
uint8_t v;
|
||||||
if (willTopic) {
|
if (willTopic) {
|
||||||
v = 0x06|(willQos<<3)|(willRetain<<5);
|
v = 0x04|(willQos<<3)|(willRetain<<5);
|
||||||
} else {
|
} else {
|
||||||
v = 0x02;
|
v = 0x00;
|
||||||
|
}
|
||||||
|
if (cleanSession) {
|
||||||
|
v = v|0x02;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(user != NULL) {
|
if(user != NULL) {
|
||||||
@ -158,26 +165,32 @@ boolean PubSubClient::connect(const char *id, const char *user, const char *pass
|
|||||||
|
|
||||||
buffer[length++] = ((MQTT_KEEPALIVE) >> 8);
|
buffer[length++] = ((MQTT_KEEPALIVE) >> 8);
|
||||||
buffer[length++] = ((MQTT_KEEPALIVE) & 0xFF);
|
buffer[length++] = ((MQTT_KEEPALIVE) & 0xFF);
|
||||||
|
|
||||||
|
CHECK_STRING_LENGTH(length,id)
|
||||||
length = writeString(id,buffer,length);
|
length = writeString(id,buffer,length);
|
||||||
if (willTopic) {
|
if (willTopic) {
|
||||||
|
CHECK_STRING_LENGTH(length,willTopic)
|
||||||
length = writeString(willTopic,buffer,length);
|
length = writeString(willTopic,buffer,length);
|
||||||
|
CHECK_STRING_LENGTH(length,willMessage)
|
||||||
length = writeString(willMessage,buffer,length);
|
length = writeString(willMessage,buffer,length);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(user != NULL) {
|
if(user != NULL) {
|
||||||
|
CHECK_STRING_LENGTH(length,user)
|
||||||
length = writeString(user,buffer,length);
|
length = writeString(user,buffer,length);
|
||||||
if(pass != NULL) {
|
if(pass != NULL) {
|
||||||
|
CHECK_STRING_LENGTH(length,pass)
|
||||||
length = writeString(pass,buffer,length);
|
length = writeString(pass,buffer,length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
write(MQTTCONNECT,buffer,length-5);
|
write(MQTTCONNECT,buffer,length-MQTT_MAX_HEADER_SIZE);
|
||||||
|
|
||||||
lastInActivity = lastOutActivity = millis();
|
lastInActivity = lastOutActivity = millis();
|
||||||
|
|
||||||
while (!_client->available()) {
|
while (!_client->available()) {
|
||||||
unsigned long t = millis();
|
unsigned long t = millis();
|
||||||
if (t-lastInActivity > MQTT_KEEPALIVE*1000UL) {
|
if (t-lastInActivity >= ((int32_t) MQTT_SOCKET_TIMEOUT*1000UL)) {
|
||||||
_state = MQTT_CONNECTION_TIMEOUT;
|
_state = MQTT_CONNECTION_TIMEOUT;
|
||||||
_client->stop();
|
_client->stop();
|
||||||
return false;
|
return false;
|
||||||
@ -202,16 +215,37 @@ boolean PubSubClient::connect(const char *id, const char *user, const char *pass
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t PubSubClient::readByte() {
|
// reads a byte into result
|
||||||
while(!_client->available()) {}
|
boolean PubSubClient::readByte(uint8_t * result) {
|
||||||
return _client->read();
|
uint32_t previousMillis = millis();
|
||||||
|
while(!_client->available()) {
|
||||||
|
yield();
|
||||||
|
uint32_t currentMillis = millis();
|
||||||
|
if(currentMillis - previousMillis >= ((int32_t) MQTT_SOCKET_TIMEOUT * 1000)){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*result = _client->read();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// reads a byte into result[*index] and increments index
|
||||||
|
boolean PubSubClient::readByte(uint8_t * result, uint16_t * index){
|
||||||
|
uint16_t current_index = *index;
|
||||||
|
uint8_t * write_address = &(result[current_index]);
|
||||||
|
if(readByte(write_address)){
|
||||||
|
*index = current_index + 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t PubSubClient::readPacket(uint8_t* lengthLength) {
|
uint16_t PubSubClient::readPacket(uint8_t* lengthLength) {
|
||||||
uint16_t len = 0;
|
uint16_t len = 0;
|
||||||
buffer[len++] = readByte();
|
if(!readByte(buffer, &len)) return 0;
|
||||||
bool isPublish = (buffer[0]&0xF0) == MQTTPUBLISH;
|
bool isPublish = (buffer[0]&0xF0) == MQTTPUBLISH;
|
||||||
uint32_t multiplier = 1;
|
uint32_t multiplier = 1;
|
||||||
uint16_t length = 0;
|
uint16_t length = 0;
|
||||||
@ -220,7 +254,13 @@ uint16_t PubSubClient::readPacket(uint8_t* lengthLength) {
|
|||||||
uint8_t start = 0;
|
uint8_t start = 0;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
digit = readByte();
|
if (len == 5) {
|
||||||
|
// Invalid remaining length encoding - kill the connection
|
||||||
|
_state = MQTT_DISCONNECTED;
|
||||||
|
_client->stop();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if(!readByte(&digit)) return 0;
|
||||||
buffer[len++] = digit;
|
buffer[len++] = digit;
|
||||||
length += (digit & 127) * multiplier;
|
length += (digit & 127) * multiplier;
|
||||||
multiplier *= 128;
|
multiplier *= 128;
|
||||||
@ -229,8 +269,8 @@ uint16_t PubSubClient::readPacket(uint8_t* lengthLength) {
|
|||||||
|
|
||||||
if (isPublish) {
|
if (isPublish) {
|
||||||
// Read in topic length to calculate bytes to skip over for Stream writing
|
// Read in topic length to calculate bytes to skip over for Stream writing
|
||||||
buffer[len++] = readByte();
|
if(!readByte(buffer, &len)) return 0;
|
||||||
buffer[len++] = readByte();
|
if(!readByte(buffer, &len)) return 0;
|
||||||
skip = (buffer[*lengthLength+1]<<8)+buffer[*lengthLength+2];
|
skip = (buffer[*lengthLength+1]<<8)+buffer[*lengthLength+2];
|
||||||
start = 2;
|
start = 2;
|
||||||
if (buffer[0]&MQTTQOS1) {
|
if (buffer[0]&MQTTQOS1) {
|
||||||
@ -240,7 +280,7 @@ uint16_t PubSubClient::readPacket(uint8_t* lengthLength) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (uint16_t i = start;i<length;i++) {
|
for (uint16_t i = start;i<length;i++) {
|
||||||
digit = readByte();
|
if(!readByte(&digit)) return 0;
|
||||||
if (this->stream) {
|
if (this->stream) {
|
||||||
if (isPublish && len-*lengthLength-2>skip) {
|
if (isPublish && len-*lengthLength-2>skip) {
|
||||||
this->stream->write(digit);
|
this->stream->write(digit);
|
||||||
@ -286,12 +326,10 @@ boolean PubSubClient::loop() {
|
|||||||
uint8_t type = buffer[0]&0xF0;
|
uint8_t type = buffer[0]&0xF0;
|
||||||
if (type == MQTTPUBLISH) {
|
if (type == MQTTPUBLISH) {
|
||||||
if (callback) {
|
if (callback) {
|
||||||
uint16_t tl = (buffer[llen+1]<<8)+buffer[llen+2];
|
uint16_t tl = (buffer[llen+1]<<8)+buffer[llen+2]; /* topic length in bytes */
|
||||||
char topic[tl+1];
|
memmove(buffer+llen+2,buffer+llen+3,tl); /* move topic inside buffer 1 byte to front */
|
||||||
for (uint16_t i=0;i<tl;i++) {
|
buffer[llen+2+tl] = 0; /* end the topic as a 'C' string with \x00 */
|
||||||
topic[i] = buffer[llen+3+i];
|
char *topic = (char*) buffer+llen+2;
|
||||||
}
|
|
||||||
topic[tl] = 0;
|
|
||||||
// msgId only present for QOS>0
|
// msgId only present for QOS>0
|
||||||
if ((buffer[0]&0x06) == MQTTQOS1) {
|
if ((buffer[0]&0x06) == MQTTQOS1) {
|
||||||
msgId = (buffer[llen+3+tl]<<8)+buffer[llen+3+tl+1];
|
msgId = (buffer[llen+3+tl]<<8)+buffer[llen+3+tl+1];
|
||||||
@ -317,6 +355,9 @@ boolean PubSubClient::loop() {
|
|||||||
} else if (type == MQTTPINGRESP) {
|
} else if (type == MQTTPINGRESP) {
|
||||||
pingOutstanding = false;
|
pingOutstanding = false;
|
||||||
}
|
}
|
||||||
|
} else if (!connected()) {
|
||||||
|
// readPacket has closed the connection
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -328,14 +369,22 @@ boolean PubSubClient::publish(const char* topic, const char* payload) {
|
|||||||
return publish(topic,(const uint8_t*)payload,strlen(payload),false);
|
return publish(topic,(const uint8_t*)payload,strlen(payload),false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean PubSubClient::publish(const char* topic, const char* payload, boolean retained) {
|
||||||
|
return publish(topic,(const uint8_t*)payload,strlen(payload),retained);
|
||||||
|
}
|
||||||
|
|
||||||
boolean PubSubClient::publish(const char* topic, const uint8_t* payload, unsigned int plength) {
|
boolean PubSubClient::publish(const char* topic, const uint8_t* payload, unsigned int plength) {
|
||||||
return publish(topic, payload, plength, false);
|
return publish(topic, payload, plength, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean PubSubClient::publish(const char* topic, const uint8_t* payload, unsigned int plength, boolean retained) {
|
boolean PubSubClient::publish(const char* topic, const uint8_t* payload, unsigned int plength, boolean retained) {
|
||||||
if (connected()) {
|
if (connected()) {
|
||||||
|
if (MQTT_MAX_PACKET_SIZE < MQTT_MAX_HEADER_SIZE + 2+strlen(topic) + plength) {
|
||||||
|
// Too long
|
||||||
|
return false;
|
||||||
|
}
|
||||||
// Leave room in the buffer for header and variable length field
|
// Leave room in the buffer for header and variable length field
|
||||||
uint16_t length = 5;
|
uint16_t length = MQTT_MAX_HEADER_SIZE;
|
||||||
length = writeString(topic,buffer,length);
|
length = writeString(topic,buffer,length);
|
||||||
uint16_t i;
|
uint16_t i;
|
||||||
for (i=0;i<plength;i++) {
|
for (i=0;i<plength;i++) {
|
||||||
@ -345,11 +394,15 @@ boolean PubSubClient::publish(const char* topic, const uint8_t* payload, unsigne
|
|||||||
if (retained) {
|
if (retained) {
|
||||||
header |= 1;
|
header |= 1;
|
||||||
}
|
}
|
||||||
return write(header,buffer,length-5);
|
return write(header,buffer,length-MQTT_MAX_HEADER_SIZE);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean PubSubClient::publish_P(const char* topic, const char* payload, boolean retained) {
|
||||||
|
return publish_P(topic, (const uint8_t*)payload, strlen(payload), retained);
|
||||||
|
}
|
||||||
|
|
||||||
boolean PubSubClient::publish_P(const char* topic, const uint8_t* payload, unsigned int plength, boolean retained) {
|
boolean PubSubClient::publish_P(const char* topic, const uint8_t* payload, unsigned int plength, boolean retained) {
|
||||||
uint8_t llen = 0;
|
uint8_t llen = 0;
|
||||||
uint8_t digit;
|
uint8_t digit;
|
||||||
@ -395,12 +448,43 @@ boolean PubSubClient::publish_P(const char* topic, const uint8_t* payload, unsig
|
|||||||
return rc == tlen + 4 + plength;
|
return rc == tlen + 4 + plength;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean PubSubClient::write(uint8_t header, uint8_t* buf, uint16_t length) {
|
boolean PubSubClient::beginPublish(const char* topic, unsigned int plength, boolean retained) {
|
||||||
|
if (connected()) {
|
||||||
|
// Send the header and variable length field
|
||||||
|
uint16_t length = MQTT_MAX_HEADER_SIZE;
|
||||||
|
length = writeString(topic,buffer,length);
|
||||||
|
uint16_t i;
|
||||||
|
uint8_t header = MQTTPUBLISH;
|
||||||
|
if (retained) {
|
||||||
|
header |= 1;
|
||||||
|
}
|
||||||
|
size_t hlen = buildHeader(header, buffer, plength+length-MQTT_MAX_HEADER_SIZE);
|
||||||
|
uint16_t rc = _client->write(buffer+(MQTT_MAX_HEADER_SIZE-hlen),length-(MQTT_MAX_HEADER_SIZE-hlen));
|
||||||
|
lastOutActivity = millis();
|
||||||
|
return (rc == (length-(MQTT_MAX_HEADER_SIZE-hlen)));
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PubSubClient::endPublish() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t PubSubClient::write(uint8_t data) {
|
||||||
|
lastOutActivity = millis();
|
||||||
|
return _client->write(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t PubSubClient::write(const uint8_t *buffer, size_t size) {
|
||||||
|
lastOutActivity = millis();
|
||||||
|
return _client->write(buffer,size);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t PubSubClient::buildHeader(uint8_t header, uint8_t* buf, uint16_t length) {
|
||||||
uint8_t lenBuf[4];
|
uint8_t lenBuf[4];
|
||||||
uint8_t llen = 0;
|
uint8_t llen = 0;
|
||||||
uint8_t digit;
|
uint8_t digit;
|
||||||
uint8_t pos = 0;
|
uint8_t pos = 0;
|
||||||
uint8_t rc;
|
|
||||||
uint16_t len = length;
|
uint16_t len = length;
|
||||||
do {
|
do {
|
||||||
digit = len % 128;
|
digit = len % 128;
|
||||||
@ -414,12 +498,33 @@ boolean PubSubClient::write(uint8_t header, uint8_t* buf, uint16_t length) {
|
|||||||
|
|
||||||
buf[4-llen] = header;
|
buf[4-llen] = header;
|
||||||
for (int i=0;i<llen;i++) {
|
for (int i=0;i<llen;i++) {
|
||||||
buf[5-llen+i] = lenBuf[i];
|
buf[MQTT_MAX_HEADER_SIZE-llen+i] = lenBuf[i];
|
||||||
}
|
}
|
||||||
rc = _client->write(buf+(4-llen),length+1+llen);
|
return llen+1; // Full header size is variable length bit plus the 1-byte fixed header
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean PubSubClient::write(uint8_t header, uint8_t* buf, uint16_t length) {
|
||||||
|
uint16_t rc;
|
||||||
|
uint8_t hlen = buildHeader(header, buf, length);
|
||||||
|
|
||||||
|
#ifdef MQTT_MAX_TRANSFER_SIZE
|
||||||
|
uint8_t* writeBuf = buf+(MQTT_MAX_HEADER_SIZE-hlen);
|
||||||
|
uint16_t bytesRemaining = length+hlen; //Match the length type
|
||||||
|
uint8_t bytesToWrite;
|
||||||
|
boolean result = true;
|
||||||
|
while((bytesRemaining > 0) && result) {
|
||||||
|
bytesToWrite = (bytesRemaining > MQTT_MAX_TRANSFER_SIZE)?MQTT_MAX_TRANSFER_SIZE:bytesRemaining;
|
||||||
|
rc = _client->write(writeBuf,bytesToWrite);
|
||||||
|
result = (rc == bytesToWrite);
|
||||||
|
bytesRemaining -= rc;
|
||||||
|
writeBuf += rc;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
#else
|
||||||
|
rc = _client->write(buf+(MQTT_MAX_HEADER_SIZE-hlen),length+hlen);
|
||||||
lastOutActivity = millis();
|
lastOutActivity = millis();
|
||||||
return (rc == 1+llen+length);
|
return (rc == hlen+length);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean PubSubClient::subscribe(const char* topic) {
|
boolean PubSubClient::subscribe(const char* topic) {
|
||||||
@ -427,12 +532,16 @@ boolean PubSubClient::subscribe(const char* topic) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
boolean PubSubClient::subscribe(const char* topic, uint8_t qos) {
|
boolean PubSubClient::subscribe(const char* topic, uint8_t qos) {
|
||||||
if (qos < 0 || qos > 1)
|
if (qos > 1) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
if (MQTT_MAX_PACKET_SIZE < 9 + strlen(topic)) {
|
||||||
|
// Too long
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (connected()) {
|
if (connected()) {
|
||||||
// Leave room in the buffer for header and variable length field
|
// Leave room in the buffer for header and variable length field
|
||||||
uint16_t length = 5;
|
uint16_t length = MQTT_MAX_HEADER_SIZE;
|
||||||
nextMsgId++;
|
nextMsgId++;
|
||||||
if (nextMsgId == 0) {
|
if (nextMsgId == 0) {
|
||||||
nextMsgId = 1;
|
nextMsgId = 1;
|
||||||
@ -441,14 +550,18 @@ boolean PubSubClient::subscribe(const char* topic, uint8_t qos) {
|
|||||||
buffer[length++] = (nextMsgId & 0xFF);
|
buffer[length++] = (nextMsgId & 0xFF);
|
||||||
length = writeString((char*)topic, buffer,length);
|
length = writeString((char*)topic, buffer,length);
|
||||||
buffer[length++] = qos;
|
buffer[length++] = qos;
|
||||||
return write(MQTTSUBSCRIBE|MQTTQOS1,buffer,length-5);
|
return write(MQTTSUBSCRIBE|MQTTQOS1,buffer,length-MQTT_MAX_HEADER_SIZE);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean PubSubClient::unsubscribe(const char* topic) {
|
boolean PubSubClient::unsubscribe(const char* topic) {
|
||||||
|
if (MQTT_MAX_PACKET_SIZE < 9 + strlen(topic)) {
|
||||||
|
// Too long
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (connected()) {
|
if (connected()) {
|
||||||
uint16_t length = 5;
|
uint16_t length = MQTT_MAX_HEADER_SIZE;
|
||||||
nextMsgId++;
|
nextMsgId++;
|
||||||
if (nextMsgId == 0) {
|
if (nextMsgId == 0) {
|
||||||
nextMsgId = 1;
|
nextMsgId = 1;
|
||||||
@ -456,7 +569,7 @@ boolean PubSubClient::unsubscribe(const char* topic) {
|
|||||||
buffer[length++] = (nextMsgId >> 8);
|
buffer[length++] = (nextMsgId >> 8);
|
||||||
buffer[length++] = (nextMsgId & 0xFF);
|
buffer[length++] = (nextMsgId & 0xFF);
|
||||||
length = writeString(topic, buffer,length);
|
length = writeString(topic, buffer,length);
|
||||||
return write(MQTTUNSUBSCRIBE|MQTTQOS1,buffer,length-5);
|
return write(MQTTUNSUBSCRIBE|MQTTQOS1,buffer,length-MQTT_MAX_HEADER_SIZE);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -466,6 +579,7 @@ void PubSubClient::disconnect() {
|
|||||||
buffer[1] = 0;
|
buffer[1] = 0;
|
||||||
_client->write(buffer,2);
|
_client->write(buffer,2);
|
||||||
_state = MQTT_DISCONNECTED;
|
_state = MQTT_DISCONNECTED;
|
||||||
|
_client->flush();
|
||||||
_client->stop();
|
_client->stop();
|
||||||
lastInActivity = lastOutActivity = millis();
|
lastInActivity = lastOutActivity = millis();
|
||||||
}
|
}
|
||||||
@ -493,8 +607,9 @@ boolean PubSubClient::connected() {
|
|||||||
if (!rc) {
|
if (!rc) {
|
||||||
if (this->_state == MQTT_CONNECTED) {
|
if (this->_state == MQTT_CONNECTED) {
|
||||||
this->_state = MQTT_CONNECTION_LOST;
|
this->_state = MQTT_CONNECTION_LOST;
|
||||||
|
_client->flush();
|
||||||
|
_client->stop();
|
||||||
}
|
}
|
||||||
_client->stop();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
@ -518,7 +633,7 @@ PubSubClient& PubSubClient::setServer(const char * domain, uint16_t port) {
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
PubSubClient& PubSubClient::setCallback(void(*callback)(char*,uint8_t*,unsigned int)){
|
PubSubClient& PubSubClient::setCallback(MQTT_CALLBACK_SIGNATURE) {
|
||||||
this->callback = callback;
|
this->callback = callback;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
@ -17,14 +17,29 @@
|
|||||||
|
|
||||||
// MQTT_VERSION : Pick the version
|
// MQTT_VERSION : Pick the version
|
||||||
//#define MQTT_VERSION MQTT_VERSION_3_1
|
//#define MQTT_VERSION MQTT_VERSION_3_1
|
||||||
|
#ifndef MQTT_VERSION
|
||||||
#define MQTT_VERSION MQTT_VERSION_3_1_1
|
#define MQTT_VERSION MQTT_VERSION_3_1_1
|
||||||
|
#endif
|
||||||
|
|
||||||
// MQTT_MAX_PACKET_SIZE : Maximum packet size
|
// MQTT_MAX_PACKET_SIZE : Maximum packet size
|
||||||
|
#ifndef MQTT_MAX_PACKET_SIZE
|
||||||
#define MQTT_MAX_PACKET_SIZE 128
|
#define MQTT_MAX_PACKET_SIZE 128
|
||||||
|
#endif
|
||||||
|
|
||||||
// MQTT_KEEPALIVE : keepAlive interval in Seconds
|
// MQTT_KEEPALIVE : keepAlive interval in Seconds
|
||||||
|
#ifndef MQTT_KEEPALIVE
|
||||||
#define MQTT_KEEPALIVE 15
|
#define MQTT_KEEPALIVE 15
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// MQTT_SOCKET_TIMEOUT: socket timeout interval in Seconds
|
||||||
|
#ifndef MQTT_SOCKET_TIMEOUT
|
||||||
|
#define MQTT_SOCKET_TIMEOUT 15
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// MQTT_MAX_TRANSFER_SIZE : limit how much data is passed to the network client
|
||||||
|
// in each write call. Needed for the Arduino Wifi Shield. Leave undefined to
|
||||||
|
// pass the entire MQTT packet in each write call.
|
||||||
|
//#define MQTT_MAX_TRANSFER_SIZE 80
|
||||||
|
|
||||||
// Possible values for client.state()
|
// Possible values for client.state()
|
||||||
#define MQTT_CONNECTION_TIMEOUT -4
|
#define MQTT_CONNECTION_TIMEOUT -4
|
||||||
@ -58,9 +73,19 @@
|
|||||||
#define MQTTQOS1 (1 << 1)
|
#define MQTTQOS1 (1 << 1)
|
||||||
#define MQTTQOS2 (2 << 1)
|
#define MQTTQOS2 (2 << 1)
|
||||||
|
|
||||||
#define MQTT_CALLBACK_SIGNATURE void (*callback)(char*,uint8_t*,unsigned int)
|
// Maximum size of fixed header and variable length size header
|
||||||
|
#define MQTT_MAX_HEADER_SIZE 5
|
||||||
|
|
||||||
class PubSubClient {
|
#if defined(ESP8266) || defined(ESP32)
|
||||||
|
#include <functional>
|
||||||
|
#define MQTT_CALLBACK_SIGNATURE std::function<void(char*, uint8_t*, unsigned int)> callback
|
||||||
|
#else
|
||||||
|
#define MQTT_CALLBACK_SIGNATURE void (*callback)(char*, uint8_t*, unsigned int)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define CHECK_STRING_LENGTH(l,s) if (l+2+strlen(s) > MQTT_MAX_PACKET_SIZE) {_client->stop();return false;}
|
||||||
|
|
||||||
|
class PubSubClient : public Print {
|
||||||
private:
|
private:
|
||||||
Client* _client;
|
Client* _client;
|
||||||
uint8_t buffer[MQTT_MAX_PACKET_SIZE];
|
uint8_t buffer[MQTT_MAX_PACKET_SIZE];
|
||||||
@ -70,9 +95,15 @@ private:
|
|||||||
bool pingOutstanding;
|
bool pingOutstanding;
|
||||||
MQTT_CALLBACK_SIGNATURE;
|
MQTT_CALLBACK_SIGNATURE;
|
||||||
uint16_t readPacket(uint8_t*);
|
uint16_t readPacket(uint8_t*);
|
||||||
uint8_t readByte();
|
boolean readByte(uint8_t * result);
|
||||||
|
boolean readByte(uint8_t * result, uint16_t * index);
|
||||||
boolean write(uint8_t header, uint8_t* buf, uint16_t length);
|
boolean write(uint8_t header, uint8_t* buf, uint16_t length);
|
||||||
uint16_t writeString(const char* string, uint8_t* buf, uint16_t pos);
|
uint16_t writeString(const char* string, uint8_t* buf, uint16_t pos);
|
||||||
|
// Build up the header ready to send
|
||||||
|
// Returns the size of the header
|
||||||
|
// Note: the header is built at the end of the first MQTT_MAX_HEADER_SIZE bytes, so will start
|
||||||
|
// (MQTT_MAX_HEADER_SIZE - <returned size>) bytes into the buffer
|
||||||
|
size_t buildHeader(uint8_t header, uint8_t* buf, uint16_t length);
|
||||||
IPAddress ip;
|
IPAddress ip;
|
||||||
const char* domain;
|
const char* domain;
|
||||||
uint16_t port;
|
uint16_t port;
|
||||||
@ -105,11 +136,31 @@ public:
|
|||||||
boolean connect(const char* id, const char* user, const char* pass);
|
boolean connect(const char* id, const char* user, const char* pass);
|
||||||
boolean connect(const char* id, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage);
|
boolean connect(const char* id, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage);
|
||||||
boolean connect(const char* id, const char* user, const char* pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage);
|
boolean connect(const char* id, const char* user, const char* pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage);
|
||||||
|
boolean connect(const char* id, const char* user, const char* pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage, boolean cleanSession);
|
||||||
void disconnect();
|
void disconnect();
|
||||||
boolean publish(const char* topic, const char* payload);
|
boolean publish(const char* topic, const char* payload);
|
||||||
|
boolean publish(const char* topic, const char* payload, boolean retained);
|
||||||
boolean publish(const char* topic, const uint8_t * payload, unsigned int plength);
|
boolean publish(const char* topic, const uint8_t * payload, unsigned int plength);
|
||||||
boolean publish(const char* topic, const uint8_t * payload, unsigned int plength, boolean retained);
|
boolean publish(const char* topic, const uint8_t * payload, unsigned int plength, boolean retained);
|
||||||
|
boolean publish_P(const char* topic, const char* payload, boolean retained);
|
||||||
boolean publish_P(const char* topic, const uint8_t * payload, unsigned int plength, boolean retained);
|
boolean publish_P(const char* topic, const uint8_t * payload, unsigned int plength, boolean retained);
|
||||||
|
// Start to publish a message.
|
||||||
|
// This API:
|
||||||
|
// beginPublish(...)
|
||||||
|
// one or more calls to write(...)
|
||||||
|
// endPublish()
|
||||||
|
// Allows for arbitrarily large payloads to be sent without them having to be copied into
|
||||||
|
// a new buffer and held in memory at one time
|
||||||
|
// Returns 1 if the message was started successfully, 0 if there was an error
|
||||||
|
boolean beginPublish(const char* topic, unsigned int plength, boolean retained);
|
||||||
|
// Finish off this publish message (started with beginPublish)
|
||||||
|
// Returns 1 if the packet was sent successfully, 0 if there was an error
|
||||||
|
int endPublish();
|
||||||
|
// Write a single byte of payload (only to be used with beginPublish/endPublish)
|
||||||
|
virtual size_t write(uint8_t);
|
||||||
|
// Write size bytes from buffer into the payload (only to be used with beginPublish/endPublish)
|
||||||
|
// Returns the number of bytes written
|
||||||
|
virtual size_t write(const uint8_t *buffer, size_t size);
|
||||||
boolean subscribe(const char* topic);
|
boolean subscribe(const char* topic);
|
||||||
boolean subscribe(const char* topic, uint8_t qos);
|
boolean subscribe(const char* topic, uint8_t qos);
|
||||||
boolean unsubscribe(const char* topic);
|
boolean unsubscribe(const char* topic);
|
@ -4,15 +4,22 @@ TEST_SRC=$(wildcard ${SRC_PATH}/*_spec.cpp)
|
|||||||
TEST_BIN= $(TEST_SRC:${SRC_PATH}/%.cpp=${OUT_PATH}/%)
|
TEST_BIN= $(TEST_SRC:${SRC_PATH}/%.cpp=${OUT_PATH}/%)
|
||||||
VPATH=${SRC_PATH}
|
VPATH=${SRC_PATH}
|
||||||
SHIM_FILES=${SRC_PATH}/lib/*.cpp
|
SHIM_FILES=${SRC_PATH}/lib/*.cpp
|
||||||
PSC_FILE=../PubSubClient/PubSubClient.cpp
|
PSC_FILE=../src/PubSubClient.cpp
|
||||||
CC=g++
|
CC=g++
|
||||||
CFLAGS=-I${SRC_PATH}/lib -I../PubSubClient
|
CFLAGS=-I${SRC_PATH}/lib -I../src
|
||||||
|
|
||||||
all: $(TEST_BIN)
|
all: $(TEST_BIN)
|
||||||
|
|
||||||
${OUT_PATH}/%: ${SRC_PATH}/%.cpp ${PSC_FILE} ${SHIM_FILES}
|
${OUT_PATH}/%: ${SRC_PATH}/%.cpp ${PSC_FILE} ${SHIM_FILES}
|
||||||
mkdir -p ${OUT_PATH}
|
mkdir -p ${OUT_PATH}
|
||||||
${CC} ${CFLAGS} $^ -o $@
|
${CC} ${CFLAGS} $^ -o $@
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
@rm -rf ${OUT_PATH}
|
@rm -rf ${OUT_PATH}
|
||||||
|
|
||||||
|
test:
|
||||||
|
@bin/connect_spec
|
||||||
|
@bin/publish_spec
|
||||||
|
@bin/receive_spec
|
||||||
|
@bin/subscribe_spec
|
||||||
|
@bin/keepalive_spec
|
||||||
|
@ -19,6 +19,8 @@ int test_connect_fails_no_network() {
|
|||||||
PubSubClient client(server, 1883, callback, shimClient);
|
PubSubClient client(server, 1883, callback, shimClient);
|
||||||
int rc = client.connect((char*)"client_test1");
|
int rc = client.connect((char*)"client_test1");
|
||||||
IS_FALSE(rc);
|
IS_FALSE(rc);
|
||||||
|
int state = client.state();
|
||||||
|
IS_TRUE(state == MQTT_CONNECT_FAILED);
|
||||||
END_IT
|
END_IT
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,44 +31,52 @@ int test_connect_fails_on_no_response() {
|
|||||||
PubSubClient client(server, 1883, callback, shimClient);
|
PubSubClient client(server, 1883, callback, shimClient);
|
||||||
int rc = client.connect((char*)"client_test1");
|
int rc = client.connect((char*)"client_test1");
|
||||||
IS_FALSE(rc);
|
IS_FALSE(rc);
|
||||||
|
int state = client.state();
|
||||||
|
IS_TRUE(state == MQTT_CONNECTION_TIMEOUT);
|
||||||
END_IT
|
END_IT
|
||||||
}
|
}
|
||||||
|
|
||||||
int test_connect_properly_formatted() {
|
int test_connect_properly_formatted() {
|
||||||
IT("sends a properly formatted connect packet and succeeds");
|
IT("sends a properly formatted connect packet and succeeds");
|
||||||
ShimClient shimClient;
|
ShimClient shimClient;
|
||||||
|
|
||||||
shimClient.setAllowConnect(true);
|
shimClient.setAllowConnect(true);
|
||||||
byte expectServer[] = { 172, 16, 0, 2 };
|
byte expectServer[] = { 172, 16, 0, 2 };
|
||||||
shimClient.expectConnect(expectServer,1883);
|
shimClient.expectConnect(expectServer,1883);
|
||||||
byte connect[] = {0x10,0x1a,0x0,0x6,0x4d,0x51,0x49,0x73,0x64,0x70,0x3,0x2,0x0,0xf,0x0,0xc,0x63,0x6c,0x69,0x65,0x6e,0x74,0x5f,0x74,0x65,0x73,0x74,0x31};
|
byte connect[] = {0x10,0x18,0x0,0x4,0x4d,0x51,0x54,0x54,0x4,0x2,0x0,0xf,0x0,0xc,0x63,0x6c,0x69,0x65,0x6e,0x74,0x5f,0x74,0x65,0x73,0x74,0x31};
|
||||||
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
|
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
|
||||||
|
|
||||||
shimClient.expect(connect,28);
|
shimClient.expect(connect,26);
|
||||||
shimClient.respond(connack,4);
|
shimClient.respond(connack,4);
|
||||||
|
|
||||||
PubSubClient client(server, 1883, callback, shimClient);
|
PubSubClient client(server, 1883, callback, shimClient);
|
||||||
|
int state = client.state();
|
||||||
|
IS_TRUE(state == MQTT_DISCONNECTED);
|
||||||
|
|
||||||
int rc = client.connect((char*)"client_test1");
|
int rc = client.connect((char*)"client_test1");
|
||||||
IS_TRUE(rc);
|
IS_TRUE(rc);
|
||||||
IS_FALSE(shimClient.error());
|
IS_FALSE(shimClient.error());
|
||||||
|
|
||||||
|
state = client.state();
|
||||||
|
IS_TRUE(state == MQTT_CONNECTED);
|
||||||
|
|
||||||
END_IT
|
END_IT
|
||||||
}
|
}
|
||||||
|
|
||||||
int test_connect_properly_formatted_hostname() {
|
int test_connect_properly_formatted_hostname() {
|
||||||
IT("accepts a hostname");
|
IT("accepts a hostname");
|
||||||
ShimClient shimClient;
|
ShimClient shimClient;
|
||||||
|
|
||||||
shimClient.setAllowConnect(true);
|
shimClient.setAllowConnect(true);
|
||||||
shimClient.expectConnect((char* const)"localhost",1883);
|
shimClient.expectConnect((char* const)"localhost",1883);
|
||||||
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
|
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
|
||||||
shimClient.respond(connack,4);
|
shimClient.respond(connack,4);
|
||||||
|
|
||||||
PubSubClient client((char* const)"localhost", 1883, callback, shimClient);
|
PubSubClient client((char* const)"localhost", 1883, callback, shimClient);
|
||||||
int rc = client.connect((char*)"client_test1");
|
int rc = client.connect((char*)"client_test1");
|
||||||
IS_TRUE(rc);
|
IS_TRUE(rc);
|
||||||
IS_FALSE(shimClient.error());
|
IS_FALSE(shimClient.error());
|
||||||
|
|
||||||
END_IT
|
END_IT
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,10 +87,41 @@ int test_connect_fails_on_bad_rc() {
|
|||||||
shimClient.setAllowConnect(true);
|
shimClient.setAllowConnect(true);
|
||||||
byte connack[] = { 0x20, 0x02, 0x00, 0x01 };
|
byte connack[] = { 0x20, 0x02, 0x00, 0x01 };
|
||||||
shimClient.respond(connack,4);
|
shimClient.respond(connack,4);
|
||||||
|
|
||||||
PubSubClient client(server, 1883, callback, shimClient);
|
PubSubClient client(server, 1883, callback, shimClient);
|
||||||
int rc = client.connect((char*)"client_test1");
|
int rc = client.connect((char*)"client_test1");
|
||||||
IS_FALSE(rc);
|
IS_FALSE(rc);
|
||||||
|
|
||||||
|
int state = client.state();
|
||||||
|
IS_TRUE(state == 0x01);
|
||||||
|
|
||||||
|
END_IT
|
||||||
|
}
|
||||||
|
|
||||||
|
int test_connect_non_clean_session() {
|
||||||
|
IT("sends a properly formatted non-clean session connect packet and succeeds");
|
||||||
|
ShimClient shimClient;
|
||||||
|
|
||||||
|
shimClient.setAllowConnect(true);
|
||||||
|
byte expectServer[] = { 172, 16, 0, 2 };
|
||||||
|
shimClient.expectConnect(expectServer,1883);
|
||||||
|
byte connect[] = {0x10,0x18,0x0,0x4,0x4d,0x51,0x54,0x54,0x4,0x0,0x0,0xf,0x0,0xc,0x63,0x6c,0x69,0x65,0x6e,0x74,0x5f,0x74,0x65,0x73,0x74,0x31};
|
||||||
|
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
|
||||||
|
|
||||||
|
shimClient.expect(connect,26);
|
||||||
|
shimClient.respond(connack,4);
|
||||||
|
|
||||||
|
PubSubClient client(server, 1883, callback, shimClient);
|
||||||
|
int state = client.state();
|
||||||
|
IS_TRUE(state == MQTT_DISCONNECTED);
|
||||||
|
|
||||||
|
int rc = client.connect((char*)"client_test1",0,0,0,0,0,0,0);
|
||||||
|
IS_TRUE(rc);
|
||||||
|
IS_FALSE(shimClient.error());
|
||||||
|
|
||||||
|
state = client.state();
|
||||||
|
IS_TRUE(state == MQTT_CONNECTED);
|
||||||
|
|
||||||
END_IT
|
END_IT
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,12 +129,12 @@ int test_connect_accepts_username_password() {
|
|||||||
IT("accepts a username and password");
|
IT("accepts a username and password");
|
||||||
ShimClient shimClient;
|
ShimClient shimClient;
|
||||||
shimClient.setAllowConnect(true);
|
shimClient.setAllowConnect(true);
|
||||||
|
|
||||||
byte connect[] = { 0x10,0x26,0x0,0x6,0x4d,0x51,0x49,0x73,0x64,0x70,0x3,0xc2,0x0,0xf,0x0,0xc,0x63,0x6c,0x69,0x65,0x6e,0x74,0x5f,0x74,0x65,0x73,0x74,0x31,0x0,0x4,0x75,0x73,0x65,0x72,0x0,0x4,0x70,0x61,0x73,0x73};
|
byte connect[] = { 0x10,0x24,0x0,0x4,0x4d,0x51,0x54,0x54,0x4,0xc2,0x0,0xf,0x0,0xc,0x63,0x6c,0x69,0x65,0x6e,0x74,0x5f,0x74,0x65,0x73,0x74,0x31,0x0,0x4,0x75,0x73,0x65,0x72,0x0,0x4,0x70,0x61,0x73,0x73};
|
||||||
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
|
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
|
||||||
shimClient.expect(connect,0x28);
|
shimClient.expect(connect,0x26);
|
||||||
shimClient.respond(connack,4);
|
shimClient.respond(connack,4);
|
||||||
|
|
||||||
PubSubClient client(server, 1883, callback, shimClient);
|
PubSubClient client(server, 1883, callback, shimClient);
|
||||||
int rc = client.connect((char*)"client_test1",(char*)"user",(char*)"pass");
|
int rc = client.connect((char*)"client_test1",(char*)"user",(char*)"pass");
|
||||||
IS_TRUE(rc);
|
IS_TRUE(rc);
|
||||||
@ -106,14 +147,31 @@ int test_connect_accepts_username_no_password() {
|
|||||||
IT("accepts a username but no password");
|
IT("accepts a username but no password");
|
||||||
ShimClient shimClient;
|
ShimClient shimClient;
|
||||||
shimClient.setAllowConnect(true);
|
shimClient.setAllowConnect(true);
|
||||||
|
|
||||||
byte connect[] = { 0x10,0x20,0x0,0x6,0x4d,0x51,0x49,0x73,0x64,0x70,0x3,0x82,0x0,0xf,0x0,0xc,0x63,0x6c,0x69,0x65,0x6e,0x74,0x5f,0x74,0x65,0x73,0x74,0x31,0x0,0x4,0x75,0x73,0x65,0x72};
|
byte connect[] = { 0x10,0x1e,0x0,0x4,0x4d,0x51,0x54,0x54,0x4,0x82,0x0,0xf,0x0,0xc,0x63,0x6c,0x69,0x65,0x6e,0x74,0x5f,0x74,0x65,0x73,0x74,0x31,0x0,0x4,0x75,0x73,0x65,0x72};
|
||||||
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
|
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
|
||||||
shimClient.expect(connect,0x22);
|
shimClient.expect(connect,0x20);
|
||||||
shimClient.respond(connack,4);
|
shimClient.respond(connack,4);
|
||||||
|
|
||||||
PubSubClient client(server, 1883, callback, shimClient);
|
PubSubClient client(server, 1883, callback, shimClient);
|
||||||
int rc = client.connect((char*)"client_test1",(char*)"user",'\0');
|
int rc = client.connect((char*)"client_test1",(char*)"user",0);
|
||||||
|
IS_TRUE(rc);
|
||||||
|
IS_FALSE(shimClient.error());
|
||||||
|
|
||||||
|
END_IT
|
||||||
|
}
|
||||||
|
int test_connect_accepts_username_blank_password() {
|
||||||
|
IT("accepts a username and blank password");
|
||||||
|
ShimClient shimClient;
|
||||||
|
shimClient.setAllowConnect(true);
|
||||||
|
|
||||||
|
byte connect[] = { 0x10,0x20,0x0,0x4,0x4d,0x51,0x54,0x54,0x4,0xc2,0x0,0xf,0x0,0xc,0x63,0x6c,0x69,0x65,0x6e,0x74,0x5f,0x74,0x65,0x73,0x74,0x31,0x0,0x4,0x75,0x73,0x65,0x72,0x0,0x0};
|
||||||
|
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
|
||||||
|
shimClient.expect(connect,0x26);
|
||||||
|
shimClient.respond(connack,4);
|
||||||
|
|
||||||
|
PubSubClient client(server, 1883, callback, shimClient);
|
||||||
|
int rc = client.connect((char*)"client_test1",(char*)"user",(char*)"pass");
|
||||||
IS_TRUE(rc);
|
IS_TRUE(rc);
|
||||||
IS_FALSE(shimClient.error());
|
IS_FALSE(shimClient.error());
|
||||||
|
|
||||||
@ -124,14 +182,14 @@ int test_connect_ignores_password_no_username() {
|
|||||||
IT("ignores a password but no username");
|
IT("ignores a password but no username");
|
||||||
ShimClient shimClient;
|
ShimClient shimClient;
|
||||||
shimClient.setAllowConnect(true);
|
shimClient.setAllowConnect(true);
|
||||||
|
|
||||||
byte connect[] = {0x10,0x1a,0x0,0x6,0x4d,0x51,0x49,0x73,0x64,0x70,0x3,0x2,0x0,0xf,0x0,0xc,0x63,0x6c,0x69,0x65,0x6e,0x74,0x5f,0x74,0x65,0x73,0x74,0x31};
|
byte connect[] = {0x10,0x18,0x0,0x4,0x4d,0x51,0x54,0x54,0x4,0x2,0x0,0xf,0x0,0xc,0x63,0x6c,0x69,0x65,0x6e,0x74,0x5f,0x74,0x65,0x73,0x74,0x31};
|
||||||
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
|
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
|
||||||
shimClient.expect(connect,28);
|
shimClient.expect(connect,26);
|
||||||
shimClient.respond(connack,4);
|
shimClient.respond(connack,4);
|
||||||
|
|
||||||
PubSubClient client(server, 1883, callback, shimClient);
|
PubSubClient client(server, 1883, callback, shimClient);
|
||||||
int rc = client.connect((char*)"client_test1",'\0',(char*)"pass");
|
int rc = client.connect((char*)"client_test1",0,(char*)"pass");
|
||||||
IS_TRUE(rc);
|
IS_TRUE(rc);
|
||||||
IS_FALSE(shimClient.error());
|
IS_FALSE(shimClient.error());
|
||||||
|
|
||||||
@ -142,12 +200,12 @@ int test_connect_with_will() {
|
|||||||
IT("accepts a will");
|
IT("accepts a will");
|
||||||
ShimClient shimClient;
|
ShimClient shimClient;
|
||||||
shimClient.setAllowConnect(true);
|
shimClient.setAllowConnect(true);
|
||||||
|
|
||||||
byte connect[] = {0x10,0x32,0x0,0x6,0x4d,0x51,0x49,0x73,0x64,0x70,0x3,0xe,0x0,0xf,0x0,0xc,0x63,0x6c,0x69,0x65,0x6e,0x74,0x5f,0x74,0x65,0x73,0x74,0x31,0x0,0x9,0x77,0x69,0x6c,0x6c,0x54,0x6f,0x70,0x69,0x63,0x0,0xb,0x77,0x69,0x6c,0x6c,0x4d,0x65,0x73,0x73,0x61,0x67,0x65};
|
byte connect[] = {0x10,0x30,0x0,0x4,0x4d,0x51,0x54,0x54,0x4,0xe,0x0,0xf,0x0,0xc,0x63,0x6c,0x69,0x65,0x6e,0x74,0x5f,0x74,0x65,0x73,0x74,0x31,0x0,0x9,0x77,0x69,0x6c,0x6c,0x54,0x6f,0x70,0x69,0x63,0x0,0xb,0x77,0x69,0x6c,0x6c,0x4d,0x65,0x73,0x73,0x61,0x67,0x65};
|
||||||
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
|
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
|
||||||
shimClient.expect(connect,0x34);
|
shimClient.expect(connect,0x32);
|
||||||
shimClient.respond(connack,4);
|
shimClient.respond(connack,4);
|
||||||
|
|
||||||
PubSubClient client(server, 1883, callback, shimClient);
|
PubSubClient client(server, 1883, callback, shimClient);
|
||||||
int rc = client.connect((char*)"client_test1",(char*)"willTopic",1,0,(char*)"willMessage");
|
int rc = client.connect((char*)"client_test1",(char*)"willTopic",1,0,(char*)"willMessage");
|
||||||
IS_TRUE(rc);
|
IS_TRUE(rc);
|
||||||
@ -160,12 +218,12 @@ int test_connect_with_will_username_password() {
|
|||||||
IT("accepts a will, username and password");
|
IT("accepts a will, username and password");
|
||||||
ShimClient shimClient;
|
ShimClient shimClient;
|
||||||
shimClient.setAllowConnect(true);
|
shimClient.setAllowConnect(true);
|
||||||
|
|
||||||
byte connect[] = {0x10,0x42,0x0,0x6,0x4d,0x51,0x49,0x73,0x64,0x70,0x3,0xce,0x0,0xf,0x0,0xc,0x63,0x6c,0x69,0x65,0x6e,0x74,0x5f,0x74,0x65,0x73,0x74,0x31,0x0,0x9,0x77,0x69,0x6c,0x6c,0x54,0x6f,0x70,0x69,0x63,0x0,0xb,0x77,0x69,0x6c,0x6c,0x4d,0x65,0x73,0x73,0x61,0x67,0x65,0x0,0x4,0x75,0x73,0x65,0x72,0x0,0x8,0x70,0x61,0x73,0x73,0x77,0x6f,0x72,0x64};
|
byte connect[] = {0x10,0x40,0x0,0x4,0x4d,0x51,0x54,0x54,0x4,0xce,0x0,0xf,0x0,0xc,0x63,0x6c,0x69,0x65,0x6e,0x74,0x5f,0x74,0x65,0x73,0x74,0x31,0x0,0x9,0x77,0x69,0x6c,0x6c,0x54,0x6f,0x70,0x69,0x63,0x0,0xb,0x77,0x69,0x6c,0x6c,0x4d,0x65,0x73,0x73,0x61,0x67,0x65,0x0,0x4,0x75,0x73,0x65,0x72,0x0,0x8,0x70,0x61,0x73,0x73,0x77,0x6f,0x72,0x64};
|
||||||
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
|
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
|
||||||
shimClient.expect(connect,0x44);
|
shimClient.expect(connect,0x42);
|
||||||
shimClient.respond(connack,4);
|
shimClient.respond(connack,4);
|
||||||
|
|
||||||
PubSubClient client(server, 1883, callback, shimClient);
|
PubSubClient client(server, 1883, callback, shimClient);
|
||||||
int rc = client.connect((char*)"client_test1",(char*)"user",(char*)"password",(char*)"willTopic",1,0,(char*)"willMessage");
|
int rc = client.connect((char*)"client_test1",(char*)"user",(char*)"password",(char*)"willTopic",1,0,(char*)"willMessage");
|
||||||
IS_TRUE(rc);
|
IS_TRUE(rc);
|
||||||
@ -177,52 +235,68 @@ int test_connect_with_will_username_password() {
|
|||||||
int test_connect_disconnect_connect() {
|
int test_connect_disconnect_connect() {
|
||||||
IT("connects, disconnects and connects again");
|
IT("connects, disconnects and connects again");
|
||||||
ShimClient shimClient;
|
ShimClient shimClient;
|
||||||
|
|
||||||
shimClient.setAllowConnect(true);
|
shimClient.setAllowConnect(true);
|
||||||
byte expectServer[] = { 172, 16, 0, 2 };
|
byte expectServer[] = { 172, 16, 0, 2 };
|
||||||
shimClient.expectConnect(expectServer,1883);
|
shimClient.expectConnect(expectServer,1883);
|
||||||
byte connect[] = {0x10,0x1a,0x0,0x6,0x4d,0x51,0x49,0x73,0x64,0x70,0x3,0x2,0x0,0xf,0x0,0xc,0x63,0x6c,0x69,0x65,0x6e,0x74,0x5f,0x74,0x65,0x73,0x74,0x31};
|
byte connect[] = {0x10,0x18,0x0,0x4,0x4d,0x51,0x54,0x54,0x4,0x2,0x0,0xf,0x0,0xc,0x63,0x6c,0x69,0x65,0x6e,0x74,0x5f,0x74,0x65,0x73,0x74,0x31};
|
||||||
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
|
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
|
||||||
|
|
||||||
shimClient.expect(connect,28);
|
shimClient.expect(connect,26);
|
||||||
shimClient.respond(connack,4);
|
shimClient.respond(connack,4);
|
||||||
|
|
||||||
PubSubClient client(server, 1883, callback, shimClient);
|
PubSubClient client(server, 1883, callback, shimClient);
|
||||||
|
|
||||||
|
int state = client.state();
|
||||||
|
IS_TRUE(state == MQTT_DISCONNECTED);
|
||||||
|
|
||||||
int rc = client.connect((char*)"client_test1");
|
int rc = client.connect((char*)"client_test1");
|
||||||
IS_TRUE(rc);
|
IS_TRUE(rc);
|
||||||
IS_FALSE(shimClient.error());
|
IS_FALSE(shimClient.error());
|
||||||
|
|
||||||
|
state = client.state();
|
||||||
|
IS_TRUE(state == MQTT_CONNECTED);
|
||||||
|
|
||||||
byte disconnect[] = {0xE0,0x00};
|
byte disconnect[] = {0xE0,0x00};
|
||||||
shimClient.expect(disconnect,2);
|
shimClient.expect(disconnect,2);
|
||||||
|
|
||||||
client.disconnect();
|
client.disconnect();
|
||||||
|
|
||||||
IS_FALSE(client.connected());
|
IS_FALSE(client.connected());
|
||||||
IS_FALSE(shimClient.connected());
|
IS_FALSE(shimClient.connected());
|
||||||
IS_FALSE(shimClient.error());
|
IS_FALSE(shimClient.error());
|
||||||
|
|
||||||
|
state = client.state();
|
||||||
|
IS_TRUE(state == MQTT_DISCONNECTED);
|
||||||
|
|
||||||
shimClient.expect(connect,28);
|
shimClient.expect(connect,28);
|
||||||
shimClient.respond(connack,4);
|
shimClient.respond(connack,4);
|
||||||
rc = client.connect((char*)"client_test1");
|
rc = client.connect((char*)"client_test1");
|
||||||
IS_TRUE(rc);
|
IS_TRUE(rc);
|
||||||
IS_FALSE(shimClient.error());
|
IS_FALSE(shimClient.error());
|
||||||
|
state = client.state();
|
||||||
|
IS_TRUE(state == MQTT_CONNECTED);
|
||||||
|
|
||||||
END_IT
|
END_IT
|
||||||
}
|
}
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
|
SUITE("Connect");
|
||||||
|
|
||||||
test_connect_fails_no_network();
|
test_connect_fails_no_network();
|
||||||
test_connect_fails_on_no_response();
|
test_connect_fails_on_no_response();
|
||||||
|
|
||||||
test_connect_properly_formatted();
|
test_connect_properly_formatted();
|
||||||
|
test_connect_non_clean_session();
|
||||||
|
test_connect_accepts_username_password();
|
||||||
test_connect_fails_on_bad_rc();
|
test_connect_fails_on_bad_rc();
|
||||||
test_connect_properly_formatted_hostname();
|
test_connect_properly_formatted_hostname();
|
||||||
test_connect_accepts_username_password();
|
|
||||||
test_connect_accepts_username_no_password();
|
test_connect_accepts_username_no_password();
|
||||||
test_connect_ignores_password_no_username();
|
test_connect_ignores_password_no_username();
|
||||||
test_connect_with_will();
|
test_connect_with_will();
|
||||||
test_connect_with_will_username_password();
|
test_connect_with_will_username_password();
|
||||||
test_connect_disconnect_connect();
|
test_connect_disconnect_connect();
|
||||||
|
|
||||||
FINISH
|
FINISH
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
#include "Buffer.h"
|
#include "Buffer.h"
|
||||||
#include "BDDTest.h"
|
#include "BDDTest.h"
|
||||||
#include "trace.h"
|
#include "trace.h"
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
byte server[] = { 172, 16, 0, 2 };
|
byte server[] = { 172, 16, 0, 2 };
|
||||||
|
|
||||||
@ -13,49 +13,53 @@ void callback(char* topic, byte* payload, unsigned int length) {
|
|||||||
|
|
||||||
|
|
||||||
int test_keepalive_pings_idle() {
|
int test_keepalive_pings_idle() {
|
||||||
IT("keeps an idle connection alive");
|
IT("keeps an idle connection alive (takes 1 minute)");
|
||||||
|
|
||||||
ShimClient shimClient;
|
ShimClient shimClient;
|
||||||
shimClient.setAllowConnect(true);
|
shimClient.setAllowConnect(true);
|
||||||
|
|
||||||
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
|
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
|
||||||
shimClient.respond(connack,4);
|
shimClient.respond(connack,4);
|
||||||
|
|
||||||
PubSubClient client(server, 1883, callback, shimClient);
|
PubSubClient client(server, 1883, callback, shimClient);
|
||||||
int rc = client.connect((char*)"client_test1");
|
int rc = client.connect((char*)"client_test1");
|
||||||
IS_TRUE(rc);
|
IS_TRUE(rc);
|
||||||
|
|
||||||
byte pingreq[] = { 0xC0,0x0 };
|
byte pingreq[] = { 0xC0,0x0 };
|
||||||
shimClient.expect(pingreq,2);
|
shimClient.expect(pingreq,2);
|
||||||
byte pingresp[] = { 0xD0,0x0 };
|
byte pingresp[] = { 0xD0,0x0 };
|
||||||
shimClient.respond(pingresp,2);
|
shimClient.respond(pingresp,2);
|
||||||
|
|
||||||
for (int i = 0; i < 50; i++) {
|
for (int i = 0; i < 50; i++) {
|
||||||
sleep(1);
|
sleep(1);
|
||||||
|
if ( i == 15 || i == 31 || i == 47) {
|
||||||
|
shimClient.expect(pingreq,2);
|
||||||
|
shimClient.respond(pingresp,2);
|
||||||
|
}
|
||||||
rc = client.loop();
|
rc = client.loop();
|
||||||
IS_TRUE(rc);
|
IS_TRUE(rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
IS_FALSE(shimClient.error());
|
IS_FALSE(shimClient.error());
|
||||||
|
|
||||||
END_IT
|
END_IT
|
||||||
}
|
}
|
||||||
|
|
||||||
int test_keepalive_pings_with_outbound_qos0() {
|
int test_keepalive_pings_with_outbound_qos0() {
|
||||||
IT("keeps a connection alive that only sends qos0");
|
IT("keeps a connection alive that only sends qos0 (takes 1 minute)");
|
||||||
|
|
||||||
ShimClient shimClient;
|
ShimClient shimClient;
|
||||||
shimClient.setAllowConnect(true);
|
shimClient.setAllowConnect(true);
|
||||||
|
|
||||||
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
|
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
|
||||||
shimClient.respond(connack,4);
|
shimClient.respond(connack,4);
|
||||||
|
|
||||||
PubSubClient client(server, 1883, callback, shimClient);
|
PubSubClient client(server, 1883, callback, shimClient);
|
||||||
int rc = client.connect((char*)"client_test1");
|
int rc = client.connect((char*)"client_test1");
|
||||||
IS_TRUE(rc);
|
IS_TRUE(rc);
|
||||||
|
|
||||||
byte publish[] = {0x30,0xe,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64};
|
byte publish[] = {0x30,0xe,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64};
|
||||||
|
|
||||||
for (int i = 0; i < 50; i++) {
|
for (int i = 0; i < 50; i++) {
|
||||||
TRACE(i<<":");
|
TRACE(i<<":");
|
||||||
shimClient.expect(publish,16);
|
shimClient.expect(publish,16);
|
||||||
@ -73,25 +77,25 @@ int test_keepalive_pings_with_outbound_qos0() {
|
|||||||
IS_TRUE(rc);
|
IS_TRUE(rc);
|
||||||
IS_FALSE(shimClient.error());
|
IS_FALSE(shimClient.error());
|
||||||
}
|
}
|
||||||
|
|
||||||
END_IT
|
END_IT
|
||||||
}
|
}
|
||||||
|
|
||||||
int test_keepalive_pings_with_inbound_qos0() {
|
int test_keepalive_pings_with_inbound_qos0() {
|
||||||
IT("keeps a connection alive that only receives qos0");
|
IT("keeps a connection alive that only receives qos0 (takes 1 minute)");
|
||||||
|
|
||||||
ShimClient shimClient;
|
ShimClient shimClient;
|
||||||
shimClient.setAllowConnect(true);
|
shimClient.setAllowConnect(true);
|
||||||
|
|
||||||
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
|
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
|
||||||
shimClient.respond(connack,4);
|
shimClient.respond(connack,4);
|
||||||
|
|
||||||
PubSubClient client(server, 1883, callback, shimClient);
|
PubSubClient client(server, 1883, callback, shimClient);
|
||||||
int rc = client.connect((char*)"client_test1");
|
int rc = client.connect((char*)"client_test1");
|
||||||
IS_TRUE(rc);
|
IS_TRUE(rc);
|
||||||
|
|
||||||
byte publish[] = {0x30,0xe,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64};
|
byte publish[] = {0x30,0xe,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64};
|
||||||
|
|
||||||
for (int i = 0; i < 50; i++) {
|
for (int i = 0; i < 50; i++) {
|
||||||
TRACE(i<<":");
|
TRACE(i<<":");
|
||||||
sleep(1);
|
sleep(1);
|
||||||
@ -106,23 +110,23 @@ int test_keepalive_pings_with_inbound_qos0() {
|
|||||||
IS_TRUE(rc);
|
IS_TRUE(rc);
|
||||||
IS_FALSE(shimClient.error());
|
IS_FALSE(shimClient.error());
|
||||||
}
|
}
|
||||||
|
|
||||||
END_IT
|
END_IT
|
||||||
}
|
}
|
||||||
|
|
||||||
int test_keepalive_no_pings_inbound_qos1() {
|
int test_keepalive_no_pings_inbound_qos1() {
|
||||||
IT("does not send pings for connections with inbound qos1");
|
IT("does not send pings for connections with inbound qos1 (takes 1 minute)");
|
||||||
|
|
||||||
ShimClient shimClient;
|
ShimClient shimClient;
|
||||||
shimClient.setAllowConnect(true);
|
shimClient.setAllowConnect(true);
|
||||||
|
|
||||||
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
|
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
|
||||||
shimClient.respond(connack,4);
|
shimClient.respond(connack,4);
|
||||||
|
|
||||||
PubSubClient client(server, 1883, callback, shimClient);
|
PubSubClient client(server, 1883, callback, shimClient);
|
||||||
int rc = client.connect((char*)"client_test1");
|
int rc = client.connect((char*)"client_test1");
|
||||||
IS_TRUE(rc);
|
IS_TRUE(rc);
|
||||||
|
|
||||||
byte publish[] = {0x32,0x10,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x12,0x34,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64};
|
byte publish[] = {0x32,0x10,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x12,0x34,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64};
|
||||||
byte puback[] = {0x40,0x2,0x12,0x34};
|
byte puback[] = {0x40,0x2,0x12,0x34};
|
||||||
|
|
||||||
@ -139,27 +143,30 @@ int test_keepalive_no_pings_inbound_qos1() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int test_keepalive_disconnects_hung() {
|
int test_keepalive_disconnects_hung() {
|
||||||
IT("disconnects a hung connection");
|
IT("disconnects a hung connection (takes 30 seconds)");
|
||||||
|
|
||||||
ShimClient shimClient;
|
ShimClient shimClient;
|
||||||
shimClient.setAllowConnect(true);
|
shimClient.setAllowConnect(true);
|
||||||
|
|
||||||
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
|
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
|
||||||
shimClient.respond(connack,4);
|
shimClient.respond(connack,4);
|
||||||
|
|
||||||
PubSubClient client(server, 1883, callback, shimClient);
|
PubSubClient client(server, 1883, callback, shimClient);
|
||||||
int rc = client.connect((char*)"client_test1");
|
int rc = client.connect((char*)"client_test1");
|
||||||
IS_TRUE(rc);
|
IS_TRUE(rc);
|
||||||
|
|
||||||
byte pingreq[] = { 0xC0,0x0 };
|
byte pingreq[] = { 0xC0,0x0 };
|
||||||
shimClient.expect(pingreq,2);
|
shimClient.expect(pingreq,2);
|
||||||
|
|
||||||
for (int i = 0; i < 32; i++) {
|
for (int i = 0; i < 32; i++) {
|
||||||
sleep(1);
|
sleep(1);
|
||||||
rc = client.loop();
|
rc = client.loop();
|
||||||
}
|
}
|
||||||
IS_FALSE(rc);
|
IS_FALSE(rc);
|
||||||
|
|
||||||
|
int state = client.state();
|
||||||
|
IS_TRUE(state == MQTT_CONNECTION_TIMEOUT);
|
||||||
|
|
||||||
IS_FALSE(shimClient.error());
|
IS_FALSE(shimClient.error());
|
||||||
|
|
||||||
END_IT
|
END_IT
|
||||||
@ -167,11 +174,12 @@ int test_keepalive_disconnects_hung() {
|
|||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
|
SUITE("Keep-alive");
|
||||||
test_keepalive_pings_idle();
|
test_keepalive_pings_idle();
|
||||||
test_keepalive_pings_with_outbound_qos0();
|
test_keepalive_pings_with_outbound_qos0();
|
||||||
test_keepalive_pings_with_inbound_qos0();
|
test_keepalive_pings_with_inbound_qos0();
|
||||||
test_keepalive_no_pings_inbound_qos1();
|
test_keepalive_no_pings_inbound_qos1();
|
||||||
test_keepalive_disconnects_hung();
|
test_keepalive_disconnects_hung();
|
||||||
|
|
||||||
FINISH
|
FINISH
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
#include "Print.h"
|
||||||
|
|
||||||
|
|
||||||
extern "C"{
|
extern "C"{
|
||||||
@ -20,4 +21,6 @@ extern "C"{
|
|||||||
#define PROGMEM
|
#define PROGMEM
|
||||||
#define pgm_read_byte_near(x) *(x)
|
#define pgm_read_byte_near(x) *(x)
|
||||||
|
|
||||||
|
#define yield(x) {}
|
||||||
|
|
||||||
#endif // Arduino_h
|
#endif // Arduino_h
|
||||||
|
@ -9,25 +9,29 @@ int testCount = 0;
|
|||||||
int testPasses = 0;
|
int testPasses = 0;
|
||||||
const char* testDescription;
|
const char* testDescription;
|
||||||
|
|
||||||
std::list<std::string> failureList;
|
std::list<std::string> failureList;
|
||||||
|
|
||||||
|
void bddtest_suite(const char* name) {
|
||||||
|
LOG(name << "\n");
|
||||||
|
}
|
||||||
|
|
||||||
int bddtest_test(const char* file, int line, const char* assertion, int result) {
|
int bddtest_test(const char* file, int line, const char* assertion, int result) {
|
||||||
if (!result) {
|
if (!result) {
|
||||||
LOG("F");
|
LOG("✗\n");
|
||||||
std::ostringstream os;
|
std::ostringstream os;
|
||||||
os << " ! "<<testDescription<<"\n " <<file << ":" <<line<<" : "<<assertion<<" ["<<result<<"]";
|
os << " ! "<<testDescription<<"\n " <<file << ":" <<line<<" : "<<assertion<<" ["<<result<<"]";
|
||||||
failureList.push_back(os.str());
|
failureList.push_back(os.str());
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void bddtest_start(const char* description) {
|
void bddtest_start(const char* description) {
|
||||||
TRACE(" - "<<description << "\n");
|
LOG(" - "<<description<<" ");
|
||||||
testDescription = description;
|
testDescription = description;
|
||||||
testCount ++;
|
testCount ++;
|
||||||
}
|
}
|
||||||
void bddtest_end() {
|
void bddtest_end() {
|
||||||
LOG(".");
|
LOG("✓\n");
|
||||||
testPasses ++;
|
testPasses ++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,8 +39,10 @@ int bddtest_summary() {
|
|||||||
for (std::list<std::string>::iterator it = failureList.begin(); it != failureList.end(); it++) {
|
for (std::list<std::string>::iterator it = failureList.begin(); it != failureList.end(); it++) {
|
||||||
LOG("\n");
|
LOG("\n");
|
||||||
LOG(*it);
|
LOG(*it);
|
||||||
|
LOG("\n");
|
||||||
}
|
}
|
||||||
LOG("\n" << std::dec << testPasses << "/" << testCount << " tests passed\n");
|
|
||||||
|
LOG(std::dec << testPasses << "/" << testCount << " tests passed\n\n");
|
||||||
if (testPasses == testCount) {
|
if (testPasses == testCount) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
#ifndef bddtest_h
|
#ifndef bddtest_h
|
||||||
#define bddtest_h
|
#define bddtest_h
|
||||||
|
|
||||||
|
void bddtest_suite(const char* name);
|
||||||
int bddtest_test(const char*, int, const char*, int);
|
int bddtest_test(const char*, int, const char*, int);
|
||||||
void bddtest_start(const char*);
|
void bddtest_start(const char*);
|
||||||
void bddtest_end();
|
void bddtest_end();
|
||||||
int bddtest_summary();
|
int bddtest_summary();
|
||||||
|
|
||||||
|
#define SUITE(x) { bddtest_suite(x); }
|
||||||
#define TEST(x) { if (!bddtest_test(__FILE__, __LINE__, #x, (x))) return false; }
|
#define TEST(x) { if (!bddtest_test(__FILE__, __LINE__, #x, (x))) return false; }
|
||||||
|
|
||||||
#define IT(x) { bddtest_start(x); }
|
#define IT(x) { bddtest_start(x); }
|
||||||
|
@ -2,9 +2,13 @@
|
|||||||
#include "Arduino.h"
|
#include "Arduino.h"
|
||||||
|
|
||||||
Buffer::Buffer() {
|
Buffer::Buffer() {
|
||||||
|
this->pos = 0;
|
||||||
|
this->length = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Buffer::Buffer(uint8_t* buf, size_t size) {
|
Buffer::Buffer(uint8_t* buf, size_t size) {
|
||||||
|
this->pos = 0;
|
||||||
|
this->length = 0;
|
||||||
this->add(buf,size);
|
this->add(buf,size);
|
||||||
}
|
}
|
||||||
bool Buffer::available() {
|
bool Buffer::available() {
|
||||||
|
44
tests/src/lib/IPAddress.cpp
Normal file
44
tests/src/lib/IPAddress.cpp
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <IPAddress.h>
|
||||||
|
|
||||||
|
IPAddress::IPAddress()
|
||||||
|
{
|
||||||
|
memset(_address, 0, sizeof(_address));
|
||||||
|
}
|
||||||
|
|
||||||
|
IPAddress::IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet)
|
||||||
|
{
|
||||||
|
_address[0] = first_octet;
|
||||||
|
_address[1] = second_octet;
|
||||||
|
_address[2] = third_octet;
|
||||||
|
_address[3] = fourth_octet;
|
||||||
|
}
|
||||||
|
|
||||||
|
IPAddress::IPAddress(uint32_t address)
|
||||||
|
{
|
||||||
|
memcpy(_address, &address, sizeof(_address));
|
||||||
|
}
|
||||||
|
|
||||||
|
IPAddress::IPAddress(const uint8_t *address)
|
||||||
|
{
|
||||||
|
memcpy(_address, address, sizeof(_address));
|
||||||
|
}
|
||||||
|
|
||||||
|
IPAddress& IPAddress::operator=(const uint8_t *address)
|
||||||
|
{
|
||||||
|
memcpy(_address, address, sizeof(_address));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
IPAddress& IPAddress::operator=(uint32_t address)
|
||||||
|
{
|
||||||
|
memcpy(_address, (const uint8_t *)&address, sizeof(_address));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IPAddress::operator==(const uint8_t* addr)
|
||||||
|
{
|
||||||
|
return memcmp(addr, _address, sizeof(_address)) == 0;
|
||||||
|
}
|
||||||
|
|
@ -1,11 +1,72 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* MIT License:
|
||||||
|
* Copyright (c) 2011 Adrian McEwen
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* adrianm@mcqn.com 1/1/2011
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef IPAddress_h
|
#ifndef IPAddress_h
|
||||||
#define IPAddress_h
|
#define IPAddress_h
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
|
|
||||||
#define IPAddress uint8_t*
|
// A class to make it easier to handle and pass around IP addresses
|
||||||
|
|
||||||
}
|
class IPAddress {
|
||||||
|
private:
|
||||||
|
uint8_t _address[4]; // IPv4 address
|
||||||
|
// Access the raw byte array containing the address. Because this returns a pointer
|
||||||
|
// to the internal structure rather than a copy of the address this function should only
|
||||||
|
// be used when you know that the usage of the returned uint8_t* will be transient and not
|
||||||
|
// stored.
|
||||||
|
uint8_t* raw_address() { return _address; };
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Constructors
|
||||||
|
IPAddress();
|
||||||
|
IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet);
|
||||||
|
IPAddress(uint32_t address);
|
||||||
|
IPAddress(const uint8_t *address);
|
||||||
|
|
||||||
|
// Overloaded cast operator to allow IPAddress objects to be used where a pointer
|
||||||
|
// to a four-byte uint8_t array is expected
|
||||||
|
operator uint32_t() { return *((uint32_t*)_address); };
|
||||||
|
bool operator==(const IPAddress& addr) { return (*((uint32_t*)_address)) == (*((uint32_t*)addr._address)); };
|
||||||
|
bool operator==(const uint8_t* addr);
|
||||||
|
|
||||||
|
// Overloaded index operator to allow getting and setting individual octets of the address
|
||||||
|
uint8_t operator[](int index) const { return _address[index]; };
|
||||||
|
uint8_t& operator[](int index) { return _address[index]; };
|
||||||
|
|
||||||
|
// Overloaded copy operators to allow initialisation of IPAddress objects from other types
|
||||||
|
IPAddress& operator=(const uint8_t *address);
|
||||||
|
IPAddress& operator=(uint32_t address);
|
||||||
|
|
||||||
|
|
||||||
|
friend class EthernetClass;
|
||||||
|
friend class UDP;
|
||||||
|
friend class Client;
|
||||||
|
friend class Server;
|
||||||
|
friend class DhcpClass;
|
||||||
|
friend class DNSClient;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
28
tests/src/lib/Print.h
Normal file
28
tests/src/lib/Print.h
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
Print.h - Base class that provides print() and println()
|
||||||
|
Copyright (c) 2008 David A. Mellis. All right reserved.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef Print_h
|
||||||
|
#define Print_h
|
||||||
|
|
||||||
|
class Print {
|
||||||
|
public:
|
||||||
|
virtual size_t write(uint8_t) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -26,10 +26,10 @@ int ShimClient::connect(IPAddress ip, uint16_t port) {
|
|||||||
this->_connected = true;
|
this->_connected = true;
|
||||||
}
|
}
|
||||||
if (this->_expectedPort !=0) {
|
if (this->_expectedPort !=0) {
|
||||||
if (memcmp(ip,this->_expectedIP,4) != 0) {
|
// if (memcmp(ip,this->_expectedIP,4) != 0) {
|
||||||
TRACE( "ip mismatch\n");
|
// TRACE( "ip mismatch\n");
|
||||||
this->_error = true;
|
// this->_error = true;
|
||||||
}
|
// }
|
||||||
if (port != this->_expectedPort) {
|
if (port != this->_expectedPort) {
|
||||||
TRACE( "port mismatch\n");
|
TRACE( "port mismatch\n");
|
||||||
this->_error = true;
|
this->_error = true;
|
||||||
@ -80,7 +80,7 @@ size_t ShimClient::write(const uint8_t *buf, size_t size) {
|
|||||||
TRACE(":");
|
TRACE(":");
|
||||||
}
|
}
|
||||||
TRACE(std::hex << (unsigned int)(buf[i]));
|
TRACE(std::hex << (unsigned int)(buf[i]));
|
||||||
|
|
||||||
if (!this->expectAnything) {
|
if (!this->expectAnything) {
|
||||||
if (this->expectBuffer->available()) {
|
if (this->expectBuffer->available()) {
|
||||||
uint8_t expected = this->expectBuffer->next();
|
uint8_t expected = this->expectBuffer->next();
|
||||||
@ -100,7 +100,7 @@ int ShimClient::available() {
|
|||||||
return this->responseBuffer->available();
|
return this->responseBuffer->available();
|
||||||
}
|
}
|
||||||
int ShimClient::read() { return this->responseBuffer->next(); }
|
int ShimClient::read() { return this->responseBuffer->next(); }
|
||||||
int ShimClient::read(uint8_t *buf, size_t size) {
|
int ShimClient::read(uint8_t *buf, size_t size) {
|
||||||
uint16_t i = 0;
|
uint16_t i = 0;
|
||||||
for (;i<size;i++) {
|
for (;i<size;i++) {
|
||||||
buf[i] = this->read();
|
buf[i] = this->read();
|
||||||
@ -151,4 +151,3 @@ void ShimClient::expectConnect(const char *host, uint16_t port) {
|
|||||||
this->_expectedHost = host;
|
this->_expectedHost = host;
|
||||||
this->_expectedPort = port;
|
this->_expectedPort = port;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,20 +15,20 @@ int test_publish() {
|
|||||||
IT("publishes a null-terminated string");
|
IT("publishes a null-terminated string");
|
||||||
ShimClient shimClient;
|
ShimClient shimClient;
|
||||||
shimClient.setAllowConnect(true);
|
shimClient.setAllowConnect(true);
|
||||||
|
|
||||||
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
|
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
|
||||||
shimClient.respond(connack,4);
|
shimClient.respond(connack,4);
|
||||||
|
|
||||||
PubSubClient client(server, 1883, callback, shimClient);
|
PubSubClient client(server, 1883, callback, shimClient);
|
||||||
int rc = client.connect((char*)"client_test1");
|
int rc = client.connect((char*)"client_test1");
|
||||||
IS_TRUE(rc);
|
IS_TRUE(rc);
|
||||||
|
|
||||||
byte publish[] = {0x30,0xe,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64};
|
byte publish[] = {0x30,0xe,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64};
|
||||||
shimClient.expect(publish,16);
|
shimClient.expect(publish,16);
|
||||||
|
|
||||||
rc = client.publish((char*)"topic",(char*)"payload");
|
rc = client.publish((char*)"topic",(char*)"payload");
|
||||||
IS_TRUE(rc);
|
IS_TRUE(rc);
|
||||||
|
|
||||||
IS_FALSE(shimClient.error());
|
IS_FALSE(shimClient.error());
|
||||||
|
|
||||||
END_IT
|
END_IT
|
||||||
@ -39,23 +39,23 @@ int test_publish_bytes() {
|
|||||||
IT("publishes a byte array");
|
IT("publishes a byte array");
|
||||||
ShimClient shimClient;
|
ShimClient shimClient;
|
||||||
shimClient.setAllowConnect(true);
|
shimClient.setAllowConnect(true);
|
||||||
|
|
||||||
byte payload[] = { 0x01,0x02,0x03,0x0,0x05 };
|
byte payload[] = { 0x01,0x02,0x03,0x0,0x05 };
|
||||||
int length = 5;
|
int length = 5;
|
||||||
|
|
||||||
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
|
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
|
||||||
shimClient.respond(connack,4);
|
shimClient.respond(connack,4);
|
||||||
|
|
||||||
PubSubClient client(server, 1883, callback, shimClient);
|
PubSubClient client(server, 1883, callback, shimClient);
|
||||||
int rc = client.connect((char*)"client_test1");
|
int rc = client.connect((char*)"client_test1");
|
||||||
IS_TRUE(rc);
|
IS_TRUE(rc);
|
||||||
|
|
||||||
byte publish[] = {0x30,0xc,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x1,0x2,0x3,0x0,0x5};
|
byte publish[] = {0x30,0xc,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x1,0x2,0x3,0x0,0x5};
|
||||||
shimClient.expect(publish,14);
|
shimClient.expect(publish,14);
|
||||||
|
|
||||||
rc = client.publish((char*)"topic",payload,length);
|
rc = client.publish((char*)"topic",payload,length);
|
||||||
IS_TRUE(rc);
|
IS_TRUE(rc);
|
||||||
|
|
||||||
IS_FALSE(shimClient.error());
|
IS_FALSE(shimClient.error());
|
||||||
|
|
||||||
END_IT
|
END_IT
|
||||||
@ -63,26 +63,49 @@ int test_publish_bytes() {
|
|||||||
|
|
||||||
|
|
||||||
int test_publish_retained() {
|
int test_publish_retained() {
|
||||||
IT("publishes retained");
|
IT("publishes retained - 1");
|
||||||
ShimClient shimClient;
|
ShimClient shimClient;
|
||||||
shimClient.setAllowConnect(true);
|
shimClient.setAllowConnect(true);
|
||||||
|
|
||||||
byte payload[] = { 0x01,0x02,0x03,0x0,0x05 };
|
byte payload[] = { 0x01,0x02,0x03,0x0,0x05 };
|
||||||
int length = 5;
|
int length = 5;
|
||||||
|
|
||||||
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
|
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
|
||||||
shimClient.respond(connack,4);
|
shimClient.respond(connack,4);
|
||||||
|
|
||||||
PubSubClient client(server, 1883, callback, shimClient);
|
PubSubClient client(server, 1883, callback, shimClient);
|
||||||
int rc = client.connect((char*)"client_test1");
|
int rc = client.connect((char*)"client_test1");
|
||||||
IS_TRUE(rc);
|
IS_TRUE(rc);
|
||||||
|
|
||||||
byte publish[] = {0x31,0xc,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x1,0x2,0x3,0x0,0x5};
|
byte publish[] = {0x31,0xc,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x1,0x2,0x3,0x0,0x5};
|
||||||
shimClient.expect(publish,14);
|
shimClient.expect(publish,14);
|
||||||
|
|
||||||
rc = client.publish((char*)"topic",payload,length,true);
|
rc = client.publish((char*)"topic",payload,length,true);
|
||||||
IS_TRUE(rc);
|
IS_TRUE(rc);
|
||||||
|
|
||||||
|
IS_FALSE(shimClient.error());
|
||||||
|
|
||||||
|
END_IT
|
||||||
|
}
|
||||||
|
|
||||||
|
int test_publish_retained_2() {
|
||||||
|
IT("publishes retained - 2");
|
||||||
|
ShimClient shimClient;
|
||||||
|
shimClient.setAllowConnect(true);
|
||||||
|
|
||||||
|
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
|
||||||
|
shimClient.respond(connack,4);
|
||||||
|
|
||||||
|
PubSubClient client(server, 1883, callback, shimClient);
|
||||||
|
int rc = client.connect((char*)"client_test1");
|
||||||
|
IS_TRUE(rc);
|
||||||
|
|
||||||
|
byte publish[] = {0x31,0xc,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,'A','B','C','D','E'};
|
||||||
|
shimClient.expect(publish,14);
|
||||||
|
|
||||||
|
rc = client.publish((char*)"topic",(char*)"ABCDE",true);
|
||||||
|
IS_TRUE(rc);
|
||||||
|
|
||||||
IS_FALSE(shimClient.error());
|
IS_FALSE(shimClient.error());
|
||||||
|
|
||||||
END_IT
|
END_IT
|
||||||
@ -91,52 +114,77 @@ int test_publish_retained() {
|
|||||||
int test_publish_not_connected() {
|
int test_publish_not_connected() {
|
||||||
IT("publish fails when not connected");
|
IT("publish fails when not connected");
|
||||||
ShimClient shimClient;
|
ShimClient shimClient;
|
||||||
|
|
||||||
PubSubClient client(server, 1883, callback, shimClient);
|
PubSubClient client(server, 1883, callback, shimClient);
|
||||||
|
|
||||||
int rc = client.publish((char*)"topic",(char*)"payload");
|
int rc = client.publish((char*)"topic",(char*)"payload");
|
||||||
IS_FALSE(rc);
|
IS_FALSE(rc);
|
||||||
|
|
||||||
IS_FALSE(shimClient.error());
|
IS_FALSE(shimClient.error());
|
||||||
|
|
||||||
END_IT
|
END_IT
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int test_publish_too_long() {
|
||||||
|
IT("publish fails when topic/payload are too long");
|
||||||
|
ShimClient shimClient;
|
||||||
|
shimClient.setAllowConnect(true);
|
||||||
|
|
||||||
|
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
|
||||||
|
shimClient.respond(connack,4);
|
||||||
|
|
||||||
|
PubSubClient client(server, 1883, callback, shimClient);
|
||||||
|
int rc = client.connect((char*)"client_test1");
|
||||||
|
IS_TRUE(rc);
|
||||||
|
|
||||||
|
// 0 1 2 3 4 5 6 7 8 9 0 1 2
|
||||||
|
rc = client.publish((char*)"topic",(char*)"123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890");
|
||||||
|
IS_FALSE(rc);
|
||||||
|
|
||||||
|
IS_FALSE(shimClient.error());
|
||||||
|
|
||||||
|
END_IT
|
||||||
|
}
|
||||||
|
|
||||||
int test_publish_P() {
|
int test_publish_P() {
|
||||||
IT("publishes using PROGMEM");
|
IT("publishes using PROGMEM");
|
||||||
ShimClient shimClient;
|
ShimClient shimClient;
|
||||||
shimClient.setAllowConnect(true);
|
shimClient.setAllowConnect(true);
|
||||||
|
|
||||||
byte payload[] = { 0x01,0x02,0x03,0x0,0x05 };
|
byte payload[] = { 0x01,0x02,0x03,0x0,0x05 };
|
||||||
int length = 5;
|
int length = 5;
|
||||||
|
|
||||||
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
|
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
|
||||||
shimClient.respond(connack,4);
|
shimClient.respond(connack,4);
|
||||||
|
|
||||||
PubSubClient client(server, 1883, callback, shimClient);
|
PubSubClient client(server, 1883, callback, shimClient);
|
||||||
int rc = client.connect((char*)"client_test1");
|
int rc = client.connect((char*)"client_test1");
|
||||||
IS_TRUE(rc);
|
IS_TRUE(rc);
|
||||||
|
|
||||||
byte publish[] = {0x31,0xc,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x1,0x2,0x3,0x0,0x5};
|
byte publish[] = {0x31,0xc,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x1,0x2,0x3,0x0,0x5};
|
||||||
shimClient.expect(publish,14);
|
shimClient.expect(publish,14);
|
||||||
|
|
||||||
rc = client.publish_P((char*)"topic",payload,length,true);
|
rc = client.publish_P((char*)"topic",payload,length,true);
|
||||||
IS_TRUE(rc);
|
IS_TRUE(rc);
|
||||||
|
|
||||||
IS_FALSE(shimClient.error());
|
IS_FALSE(shimClient.error());
|
||||||
|
|
||||||
END_IT
|
END_IT
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
|
SUITE("Publish");
|
||||||
test_publish();
|
test_publish();
|
||||||
test_publish_bytes();
|
test_publish_bytes();
|
||||||
test_publish_retained();
|
test_publish_retained();
|
||||||
|
test_publish_retained_2();
|
||||||
test_publish_not_connected();
|
test_publish_not_connected();
|
||||||
|
test_publish_too_long();
|
||||||
test_publish_P();
|
test_publish_P();
|
||||||
|
|
||||||
FINISH
|
FINISH
|
||||||
}
|
}
|
||||||
|
@ -29,29 +29,29 @@ void callback(char* topic, byte* payload, unsigned int length) {
|
|||||||
int test_receive_callback() {
|
int test_receive_callback() {
|
||||||
IT("receives a callback message");
|
IT("receives a callback message");
|
||||||
reset_callback();
|
reset_callback();
|
||||||
|
|
||||||
ShimClient shimClient;
|
ShimClient shimClient;
|
||||||
shimClient.setAllowConnect(true);
|
shimClient.setAllowConnect(true);
|
||||||
|
|
||||||
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
|
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
|
||||||
shimClient.respond(connack,4);
|
shimClient.respond(connack,4);
|
||||||
|
|
||||||
PubSubClient client(server, 1883, callback, shimClient);
|
PubSubClient client(server, 1883, callback, shimClient);
|
||||||
int rc = client.connect((char*)"client_test1");
|
int rc = client.connect((char*)"client_test1");
|
||||||
IS_TRUE(rc);
|
IS_TRUE(rc);
|
||||||
|
|
||||||
byte publish[] = {0x30,0xe,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64};
|
byte publish[] = {0x30,0xe,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64};
|
||||||
shimClient.respond(publish,16);
|
shimClient.respond(publish,16);
|
||||||
|
|
||||||
rc = client.loop();
|
rc = client.loop();
|
||||||
|
|
||||||
IS_TRUE(rc);
|
IS_TRUE(rc);
|
||||||
|
|
||||||
IS_TRUE(callback_called);
|
IS_TRUE(callback_called);
|
||||||
IS_TRUE(strcmp(lastTopic,"topic")==0);
|
IS_TRUE(strcmp(lastTopic,"topic")==0);
|
||||||
IS_TRUE(memcmp(lastPayload,"payload",7)==0);
|
IS_TRUE(memcmp(lastPayload,"payload",7)==0);
|
||||||
IS_TRUE(lastLength == 7);
|
IS_TRUE(lastLength == 7);
|
||||||
|
|
||||||
IS_FALSE(shimClient.error());
|
IS_FALSE(shimClient.error());
|
||||||
|
|
||||||
END_IT
|
END_IT
|
||||||
@ -60,31 +60,31 @@ int test_receive_callback() {
|
|||||||
int test_receive_stream() {
|
int test_receive_stream() {
|
||||||
IT("receives a streamed callback message");
|
IT("receives a streamed callback message");
|
||||||
reset_callback();
|
reset_callback();
|
||||||
|
|
||||||
Stream stream;
|
Stream stream;
|
||||||
stream.expect((uint8_t*)"payload",7);
|
stream.expect((uint8_t*)"payload",7);
|
||||||
|
|
||||||
ShimClient shimClient;
|
ShimClient shimClient;
|
||||||
shimClient.setAllowConnect(true);
|
shimClient.setAllowConnect(true);
|
||||||
|
|
||||||
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
|
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
|
||||||
shimClient.respond(connack,4);
|
shimClient.respond(connack,4);
|
||||||
|
|
||||||
PubSubClient client(server, 1883, callback, shimClient, stream);
|
PubSubClient client(server, 1883, callback, shimClient, stream);
|
||||||
int rc = client.connect((char*)"client_test1");
|
int rc = client.connect((char*)"client_test1");
|
||||||
IS_TRUE(rc);
|
IS_TRUE(rc);
|
||||||
|
|
||||||
byte publish[] = {0x30,0xe,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64};
|
byte publish[] = {0x30,0xe,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64};
|
||||||
shimClient.respond(publish,16);
|
shimClient.respond(publish,16);
|
||||||
|
|
||||||
rc = client.loop();
|
rc = client.loop();
|
||||||
|
|
||||||
IS_TRUE(rc);
|
IS_TRUE(rc);
|
||||||
|
|
||||||
IS_TRUE(callback_called);
|
IS_TRUE(callback_called);
|
||||||
IS_TRUE(strcmp(lastTopic,"topic")==0);
|
IS_TRUE(strcmp(lastTopic,"topic")==0);
|
||||||
IS_TRUE(lastLength == 7);
|
IS_TRUE(lastLength == 7);
|
||||||
|
|
||||||
IS_FALSE(stream.error());
|
IS_FALSE(stream.error());
|
||||||
IS_FALSE(shimClient.error());
|
IS_FALSE(shimClient.error());
|
||||||
|
|
||||||
@ -94,34 +94,34 @@ int test_receive_stream() {
|
|||||||
int test_receive_max_sized_message() {
|
int test_receive_max_sized_message() {
|
||||||
IT("receives an max-sized message");
|
IT("receives an max-sized message");
|
||||||
reset_callback();
|
reset_callback();
|
||||||
|
|
||||||
ShimClient shimClient;
|
ShimClient shimClient;
|
||||||
shimClient.setAllowConnect(true);
|
shimClient.setAllowConnect(true);
|
||||||
|
|
||||||
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
|
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
|
||||||
shimClient.respond(connack,4);
|
shimClient.respond(connack,4);
|
||||||
|
|
||||||
PubSubClient client(server, 1883, callback, shimClient);
|
PubSubClient client(server, 1883, callback, shimClient);
|
||||||
int rc = client.connect((char*)"client_test1");
|
int rc = client.connect((char*)"client_test1");
|
||||||
IS_TRUE(rc);
|
IS_TRUE(rc);
|
||||||
|
|
||||||
byte length = MQTT_MAX_PACKET_SIZE;
|
int length = MQTT_MAX_PACKET_SIZE;
|
||||||
byte publish[] = {0x30,length-2,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64};
|
byte publish[] = {0x30,length-2,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64};
|
||||||
byte bigPublish[length];
|
byte bigPublish[length];
|
||||||
memset(bigPublish,'A',length);
|
memset(bigPublish,'A',length);
|
||||||
bigPublish[length] = 'B';
|
bigPublish[length] = 'B';
|
||||||
memcpy(bigPublish,publish,16);
|
memcpy(bigPublish,publish,16);
|
||||||
shimClient.respond(bigPublish,length);
|
shimClient.respond(bigPublish,length);
|
||||||
|
|
||||||
rc = client.loop();
|
rc = client.loop();
|
||||||
|
|
||||||
IS_TRUE(rc);
|
IS_TRUE(rc);
|
||||||
|
|
||||||
IS_TRUE(callback_called);
|
IS_TRUE(callback_called);
|
||||||
IS_TRUE(strcmp(lastTopic,"topic")==0);
|
IS_TRUE(strcmp(lastTopic,"topic")==0);
|
||||||
IS_TRUE(lastLength == length-9);
|
IS_TRUE(lastLength == length-9);
|
||||||
IS_TRUE(memcmp(lastPayload,bigPublish+9,lastLength)==0);
|
IS_TRUE(memcmp(lastPayload,bigPublish+9,lastLength)==0);
|
||||||
|
|
||||||
IS_FALSE(shimClient.error());
|
IS_FALSE(shimClient.error());
|
||||||
|
|
||||||
END_IT
|
END_IT
|
||||||
@ -130,71 +130,100 @@ int test_receive_max_sized_message() {
|
|||||||
int test_receive_oversized_message() {
|
int test_receive_oversized_message() {
|
||||||
IT("drops an oversized message");
|
IT("drops an oversized message");
|
||||||
reset_callback();
|
reset_callback();
|
||||||
|
|
||||||
ShimClient shimClient;
|
ShimClient shimClient;
|
||||||
shimClient.setAllowConnect(true);
|
shimClient.setAllowConnect(true);
|
||||||
|
|
||||||
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
|
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
|
||||||
shimClient.respond(connack,4);
|
shimClient.respond(connack,4);
|
||||||
|
|
||||||
PubSubClient client(server, 1883, callback, shimClient);
|
PubSubClient client(server, 1883, callback, shimClient);
|
||||||
int rc = client.connect((char*)"client_test1");
|
int rc = client.connect((char*)"client_test1");
|
||||||
IS_TRUE(rc);
|
IS_TRUE(rc);
|
||||||
|
|
||||||
byte length = MQTT_MAX_PACKET_SIZE+1;
|
int length = MQTT_MAX_PACKET_SIZE+1;
|
||||||
byte publish[] = {0x30,length-2,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64};
|
byte publish[] = {0x30,length-2,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64};
|
||||||
byte bigPublish[length];
|
byte bigPublish[length];
|
||||||
memset(bigPublish,'A',length);
|
memset(bigPublish,'A',length);
|
||||||
bigPublish[length] = 'B';
|
bigPublish[length] = 'B';
|
||||||
memcpy(bigPublish,publish,16);
|
memcpy(bigPublish,publish,16);
|
||||||
shimClient.respond(bigPublish,length);
|
shimClient.respond(bigPublish,length);
|
||||||
|
|
||||||
rc = client.loop();
|
rc = client.loop();
|
||||||
|
|
||||||
IS_TRUE(rc);
|
IS_TRUE(rc);
|
||||||
|
|
||||||
IS_FALSE(callback_called);
|
IS_FALSE(callback_called);
|
||||||
|
|
||||||
IS_FALSE(shimClient.error());
|
IS_FALSE(shimClient.error());
|
||||||
|
|
||||||
END_IT
|
END_IT
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int test_drop_invalid_remaining_length_message() {
|
||||||
|
IT("drops invalid remaining length message");
|
||||||
|
reset_callback();
|
||||||
|
|
||||||
|
ShimClient shimClient;
|
||||||
|
shimClient.setAllowConnect(true);
|
||||||
|
|
||||||
|
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
|
||||||
|
shimClient.respond(connack,4);
|
||||||
|
|
||||||
|
PubSubClient client(server, 1883, callback, shimClient);
|
||||||
|
int rc = client.connect((char*)"client_test1");
|
||||||
|
IS_TRUE(rc);
|
||||||
|
|
||||||
|
byte publish[] = {0x30,0x92,0x92,0x92,0x92,0x01,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64};
|
||||||
|
shimClient.respond(publish,20);
|
||||||
|
|
||||||
|
rc = client.loop();
|
||||||
|
|
||||||
|
IS_FALSE(rc);
|
||||||
|
|
||||||
|
IS_FALSE(callback_called);
|
||||||
|
|
||||||
|
IS_FALSE(shimClient.error());
|
||||||
|
|
||||||
|
END_IT
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int test_receive_oversized_stream_message() {
|
int test_receive_oversized_stream_message() {
|
||||||
IT("drops an oversized message");
|
IT("drops an oversized message");
|
||||||
reset_callback();
|
reset_callback();
|
||||||
|
|
||||||
Stream stream;
|
Stream stream;
|
||||||
|
|
||||||
ShimClient shimClient;
|
ShimClient shimClient;
|
||||||
shimClient.setAllowConnect(true);
|
shimClient.setAllowConnect(true);
|
||||||
|
|
||||||
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
|
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
|
||||||
shimClient.respond(connack,4);
|
shimClient.respond(connack,4);
|
||||||
|
|
||||||
PubSubClient client(server, 1883, callback, shimClient, stream);
|
PubSubClient client(server, 1883, callback, shimClient, stream);
|
||||||
int rc = client.connect((char*)"client_test1");
|
int rc = client.connect((char*)"client_test1");
|
||||||
IS_TRUE(rc);
|
IS_TRUE(rc);
|
||||||
|
|
||||||
byte length = MQTT_MAX_PACKET_SIZE+1;
|
int length = MQTT_MAX_PACKET_SIZE+1;
|
||||||
byte publish[] = {0x30,length-2,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64};
|
byte publish[] = {0x30,length-2,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64};
|
||||||
|
|
||||||
byte bigPublish[length];
|
byte bigPublish[length];
|
||||||
memset(bigPublish,'A',length);
|
memset(bigPublish,'A',length);
|
||||||
bigPublish[length] = 'B';
|
bigPublish[length] = 'B';
|
||||||
memcpy(bigPublish,publish,16);
|
memcpy(bigPublish,publish,16);
|
||||||
|
|
||||||
shimClient.respond(bigPublish,length);
|
shimClient.respond(bigPublish,length);
|
||||||
stream.expect(bigPublish+9,length-9);
|
stream.expect(bigPublish+9,length-9);
|
||||||
|
|
||||||
rc = client.loop();
|
rc = client.loop();
|
||||||
|
|
||||||
IS_TRUE(rc);
|
IS_TRUE(rc);
|
||||||
|
|
||||||
IS_TRUE(callback_called);
|
IS_TRUE(callback_called);
|
||||||
IS_TRUE(strcmp(lastTopic,"topic")==0);
|
IS_TRUE(strcmp(lastTopic,"topic")==0);
|
||||||
IS_TRUE(lastLength == length-9);
|
IS_TRUE(lastLength == length-9);
|
||||||
|
|
||||||
IS_FALSE(stream.error());
|
IS_FALSE(stream.error());
|
||||||
IS_FALSE(shimClient.error());
|
IS_FALSE(shimClient.error());
|
||||||
|
|
||||||
@ -204,32 +233,32 @@ int test_receive_oversized_stream_message() {
|
|||||||
int test_receive_qos1() {
|
int test_receive_qos1() {
|
||||||
IT("receives a qos1 message");
|
IT("receives a qos1 message");
|
||||||
reset_callback();
|
reset_callback();
|
||||||
|
|
||||||
ShimClient shimClient;
|
ShimClient shimClient;
|
||||||
shimClient.setAllowConnect(true);
|
shimClient.setAllowConnect(true);
|
||||||
|
|
||||||
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
|
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
|
||||||
shimClient.respond(connack,4);
|
shimClient.respond(connack,4);
|
||||||
|
|
||||||
PubSubClient client(server, 1883, callback, shimClient);
|
PubSubClient client(server, 1883, callback, shimClient);
|
||||||
int rc = client.connect((char*)"client_test1");
|
int rc = client.connect((char*)"client_test1");
|
||||||
IS_TRUE(rc);
|
IS_TRUE(rc);
|
||||||
|
|
||||||
byte publish[] = {0x32,0x10,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x12,0x34,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64};
|
byte publish[] = {0x32,0x10,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x12,0x34,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64};
|
||||||
shimClient.respond(publish,18);
|
shimClient.respond(publish,18);
|
||||||
|
|
||||||
byte puback[] = {0x40,0x2,0x12,0x34};
|
byte puback[] = {0x40,0x2,0x12,0x34};
|
||||||
shimClient.expect(puback,4);
|
shimClient.expect(puback,4);
|
||||||
|
|
||||||
rc = client.loop();
|
rc = client.loop();
|
||||||
|
|
||||||
IS_TRUE(rc);
|
IS_TRUE(rc);
|
||||||
|
|
||||||
IS_TRUE(callback_called);
|
IS_TRUE(callback_called);
|
||||||
IS_TRUE(strcmp(lastTopic,"topic")==0);
|
IS_TRUE(strcmp(lastTopic,"topic")==0);
|
||||||
IS_TRUE(memcmp(lastPayload,"payload",7)==0);
|
IS_TRUE(memcmp(lastPayload,"payload",7)==0);
|
||||||
IS_TRUE(lastLength == 7);
|
IS_TRUE(lastLength == 7);
|
||||||
|
|
||||||
IS_FALSE(shimClient.error());
|
IS_FALSE(shimClient.error());
|
||||||
|
|
||||||
END_IT
|
END_IT
|
||||||
@ -237,12 +266,14 @@ int test_receive_qos1() {
|
|||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
|
SUITE("Receive");
|
||||||
test_receive_callback();
|
test_receive_callback();
|
||||||
test_receive_stream();
|
test_receive_stream();
|
||||||
test_receive_max_sized_message();
|
test_receive_max_sized_message();
|
||||||
|
test_drop_invalid_remaining_length_message();
|
||||||
test_receive_oversized_message();
|
test_receive_oversized_message();
|
||||||
test_receive_oversized_stream_message();
|
test_receive_oversized_stream_message();
|
||||||
test_receive_qos1();
|
test_receive_qos1();
|
||||||
|
|
||||||
FINISH
|
FINISH
|
||||||
}
|
}
|
||||||
|
@ -11,8 +11,6 @@ void callback(char* topic, byte* payload, unsigned int length) {
|
|||||||
// handle message arrived
|
// handle message arrived
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int test_subscribe_no_qos() {
|
int test_subscribe_no_qos() {
|
||||||
IT("subscribe without qos defaults to 0");
|
IT("subscribe without qos defaults to 0");
|
||||||
ShimClient shimClient;
|
ShimClient shimClient;
|
||||||
@ -20,7 +18,7 @@ int test_subscribe_no_qos() {
|
|||||||
|
|
||||||
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
|
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
|
||||||
shimClient.respond(connack,4);
|
shimClient.respond(connack,4);
|
||||||
|
|
||||||
PubSubClient client(server, 1883, callback, shimClient);
|
PubSubClient client(server, 1883, callback, shimClient);
|
||||||
int rc = client.connect((char*)"client_test1");
|
int rc = client.connect((char*)"client_test1");
|
||||||
IS_TRUE(rc);
|
IS_TRUE(rc);
|
||||||
@ -29,10 +27,10 @@ int test_subscribe_no_qos() {
|
|||||||
shimClient.expect(subscribe,12);
|
shimClient.expect(subscribe,12);
|
||||||
byte suback[] = { 0x90,0x3,0x0,0x2,0x0 };
|
byte suback[] = { 0x90,0x3,0x0,0x2,0x0 };
|
||||||
shimClient.respond(suback,5);
|
shimClient.respond(suback,5);
|
||||||
|
|
||||||
rc = client.subscribe((char*)"topic");
|
rc = client.subscribe((char*)"topic");
|
||||||
IS_TRUE(rc);
|
IS_TRUE(rc);
|
||||||
|
|
||||||
IS_FALSE(shimClient.error());
|
IS_FALSE(shimClient.error());
|
||||||
|
|
||||||
END_IT
|
END_IT
|
||||||
@ -45,7 +43,7 @@ int test_subscribe_qos_1() {
|
|||||||
|
|
||||||
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
|
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
|
||||||
shimClient.respond(connack,4);
|
shimClient.respond(connack,4);
|
||||||
|
|
||||||
PubSubClient client(server, 1883, callback, shimClient);
|
PubSubClient client(server, 1883, callback, shimClient);
|
||||||
int rc = client.connect((char*)"client_test1");
|
int rc = client.connect((char*)"client_test1");
|
||||||
IS_TRUE(rc);
|
IS_TRUE(rc);
|
||||||
@ -54,10 +52,10 @@ int test_subscribe_qos_1() {
|
|||||||
shimClient.expect(subscribe,12);
|
shimClient.expect(subscribe,12);
|
||||||
byte suback[] = { 0x90,0x3,0x0,0x2,0x1 };
|
byte suback[] = { 0x90,0x3,0x0,0x2,0x1 };
|
||||||
shimClient.respond(suback,5);
|
shimClient.respond(suback,5);
|
||||||
|
|
||||||
rc = client.subscribe((char*)"topic",1);
|
rc = client.subscribe((char*)"topic",1);
|
||||||
IS_TRUE(rc);
|
IS_TRUE(rc);
|
||||||
|
|
||||||
IS_FALSE(shimClient.error());
|
IS_FALSE(shimClient.error());
|
||||||
|
|
||||||
END_IT
|
END_IT
|
||||||
@ -66,39 +64,66 @@ int test_subscribe_qos_1() {
|
|||||||
int test_subscribe_not_connected() {
|
int test_subscribe_not_connected() {
|
||||||
IT("subscribe fails when not connected");
|
IT("subscribe fails when not connected");
|
||||||
ShimClient shimClient;
|
ShimClient shimClient;
|
||||||
|
|
||||||
PubSubClient client(server, 1883, callback, shimClient);
|
PubSubClient client(server, 1883, callback, shimClient);
|
||||||
|
|
||||||
int rc = client.subscribe((char*)"topic");
|
int rc = client.subscribe((char*)"topic");
|
||||||
IS_FALSE(rc);
|
IS_FALSE(rc);
|
||||||
|
|
||||||
IS_FALSE(shimClient.error());
|
IS_FALSE(shimClient.error());
|
||||||
|
|
||||||
END_IT
|
END_IT
|
||||||
}
|
}
|
||||||
|
|
||||||
int test_subscribe_invalid_qos() {
|
int test_subscribe_invalid_qos() {
|
||||||
IT("subscribe fails when not connected");
|
IT("subscribe fails with invalid qos values");
|
||||||
ShimClient shimClient;
|
ShimClient shimClient;
|
||||||
shimClient.setAllowConnect(true);
|
shimClient.setAllowConnect(true);
|
||||||
|
|
||||||
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
|
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
|
||||||
shimClient.respond(connack,4);
|
shimClient.respond(connack,4);
|
||||||
|
|
||||||
PubSubClient client(server, 1883, callback, shimClient);
|
PubSubClient client(server, 1883, callback, shimClient);
|
||||||
int rc = client.connect((char*)"client_test1");
|
int rc = client.connect((char*)"client_test1");
|
||||||
IS_TRUE(rc);
|
IS_TRUE(rc);
|
||||||
|
|
||||||
rc = client.subscribe((char*)"topic",2);
|
rc = client.subscribe((char*)"topic",2);
|
||||||
IS_FALSE(rc);
|
IS_FALSE(rc);
|
||||||
rc = client.subscribe((char*)"topic",254);
|
rc = client.subscribe((char*)"topic",254);
|
||||||
IS_FALSE(rc);
|
IS_FALSE(rc);
|
||||||
|
|
||||||
IS_FALSE(shimClient.error());
|
IS_FALSE(shimClient.error());
|
||||||
|
|
||||||
END_IT
|
END_IT
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int test_subscribe_too_long() {
|
||||||
|
IT("subscribe fails with too long topic");
|
||||||
|
ShimClient shimClient;
|
||||||
|
shimClient.setAllowConnect(true);
|
||||||
|
|
||||||
|
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
|
||||||
|
shimClient.respond(connack,4);
|
||||||
|
|
||||||
|
PubSubClient client(server, 1883, callback, shimClient);
|
||||||
|
int rc = client.connect((char*)"client_test1");
|
||||||
|
IS_TRUE(rc);
|
||||||
|
|
||||||
|
// max length should be allowed
|
||||||
|
// 0 1 2 3 4 5 6 7 8 9 0 1 2
|
||||||
|
rc = client.subscribe((char*)"12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789");
|
||||||
|
IS_TRUE(rc);
|
||||||
|
|
||||||
|
// 0 1 2 3 4 5 6 7 8 9 0 1 2
|
||||||
|
rc = client.subscribe((char*)"123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890");
|
||||||
|
IS_FALSE(rc);
|
||||||
|
|
||||||
|
IS_FALSE(shimClient.error());
|
||||||
|
|
||||||
|
END_IT
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int test_unsubscribe() {
|
int test_unsubscribe() {
|
||||||
IT("unsubscribes");
|
IT("unsubscribes");
|
||||||
ShimClient shimClient;
|
ShimClient shimClient;
|
||||||
@ -106,7 +131,7 @@ int test_unsubscribe() {
|
|||||||
|
|
||||||
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
|
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
|
||||||
shimClient.respond(connack,4);
|
shimClient.respond(connack,4);
|
||||||
|
|
||||||
PubSubClient client(server, 1883, callback, shimClient);
|
PubSubClient client(server, 1883, callback, shimClient);
|
||||||
int rc = client.connect((char*)"client_test1");
|
int rc = client.connect((char*)"client_test1");
|
||||||
IS_TRUE(rc);
|
IS_TRUE(rc);
|
||||||
@ -115,10 +140,10 @@ int test_unsubscribe() {
|
|||||||
shimClient.expect(unsubscribe,12);
|
shimClient.expect(unsubscribe,12);
|
||||||
byte unsuback[] = { 0xB0,0x2,0x0,0x2 };
|
byte unsuback[] = { 0xB0,0x2,0x0,0x2 };
|
||||||
shimClient.respond(unsuback,4);
|
shimClient.respond(unsuback,4);
|
||||||
|
|
||||||
rc = client.unsubscribe((char*)"topic");
|
rc = client.unsubscribe((char*)"topic");
|
||||||
IS_TRUE(rc);
|
IS_TRUE(rc);
|
||||||
|
|
||||||
IS_FALSE(shimClient.error());
|
IS_FALSE(shimClient.error());
|
||||||
|
|
||||||
END_IT
|
END_IT
|
||||||
@ -127,12 +152,12 @@ int test_unsubscribe() {
|
|||||||
int test_unsubscribe_not_connected() {
|
int test_unsubscribe_not_connected() {
|
||||||
IT("unsubscribe fails when not connected");
|
IT("unsubscribe fails when not connected");
|
||||||
ShimClient shimClient;
|
ShimClient shimClient;
|
||||||
|
|
||||||
PubSubClient client(server, 1883, callback, shimClient);
|
PubSubClient client(server, 1883, callback, shimClient);
|
||||||
|
|
||||||
int rc = client.unsubscribe((char*)"topic");
|
int rc = client.unsubscribe((char*)"topic");
|
||||||
IS_FALSE(rc);
|
IS_FALSE(rc);
|
||||||
|
|
||||||
IS_FALSE(shimClient.error());
|
IS_FALSE(shimClient.error());
|
||||||
|
|
||||||
END_IT
|
END_IT
|
||||||
@ -140,10 +165,12 @@ int test_unsubscribe_not_connected() {
|
|||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
|
SUITE("Subscribe");
|
||||||
test_subscribe_no_qos();
|
test_subscribe_no_qos();
|
||||||
test_subscribe_qos_1();
|
test_subscribe_qos_1();
|
||||||
test_subscribe_not_connected();
|
test_subscribe_not_connected();
|
||||||
test_subscribe_invalid_qos();
|
test_subscribe_invalid_qos();
|
||||||
|
test_subscribe_too_long();
|
||||||
test_unsubscribe();
|
test_unsubscribe();
|
||||||
test_unsubscribe_not_connected();
|
test_unsubscribe_not_connected();
|
||||||
FINISH
|
FINISH
|
||||||
|
@ -1,43 +1,39 @@
|
|||||||
import unittest
|
import unittest
|
||||||
import settings
|
import settings
|
||||||
|
|
||||||
import time
|
import time
|
||||||
import mosquitto
|
import mosquitto
|
||||||
|
|
||||||
import serial
|
|
||||||
|
|
||||||
def on_message(mosq, obj, msg):
|
def on_message(mosq, obj, msg):
|
||||||
obj.message_queue.append(msg)
|
obj.message_queue.append(msg)
|
||||||
|
|
||||||
|
|
||||||
class mqtt_basic(unittest.TestCase):
|
class mqtt_basic(unittest.TestCase):
|
||||||
|
|
||||||
message_queue = []
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def setUpClass(self):
|
|
||||||
self.client = mosquitto.Mosquitto("pubsubclient_ut", clean_session=True,obj=self)
|
|
||||||
self.client.connect(settings.server_ip)
|
|
||||||
self.client.on_message = on_message
|
|
||||||
self.client.subscribe("outTopic",0)
|
|
||||||
|
|
||||||
@classmethod
|
message_queue = []
|
||||||
def tearDownClass(self):
|
|
||||||
self.client.disconnect()
|
|
||||||
|
|
||||||
def test_one(self):
|
|
||||||
i=30
|
|
||||||
while len(self.message_queue) == 0 and i > 0:
|
|
||||||
self.client.loop()
|
|
||||||
time.sleep(0.5)
|
|
||||||
i -= 1
|
|
||||||
self.assertTrue(i>0, "message receive timed-out")
|
|
||||||
self.assertEqual(len(self.message_queue), 1, "unexpected number of messages received")
|
|
||||||
msg = self.message_queue[0]
|
|
||||||
self.assertEqual(msg.mid,0,"message id not 0")
|
|
||||||
self.assertEqual(msg.topic,"outTopic","message topic incorrect")
|
|
||||||
self.assertEqual(msg.payload,"hello world")
|
|
||||||
self.assertEqual(msg.qos,0,"message qos not 0")
|
|
||||||
self.assertEqual(msg.retain,False,"message retain flag incorrect")
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(self):
|
||||||
|
self.client = mosquitto.Mosquitto("pubsubclient_ut", clean_session=True, obj=self)
|
||||||
|
self.client.connect(settings.server_ip)
|
||||||
|
self.client.on_message = on_message
|
||||||
|
self.client.subscribe("outTopic", 0)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def tearDownClass(self):
|
||||||
|
self.client.disconnect()
|
||||||
|
|
||||||
|
def test_one(self):
|
||||||
|
i = 30
|
||||||
|
while len(self.message_queue) == 0 and i > 0:
|
||||||
|
self.client.loop()
|
||||||
|
time.sleep(0.5)
|
||||||
|
i -= 1
|
||||||
|
self.assertTrue(i > 0, "message receive timed-out")
|
||||||
|
self.assertEqual(len(self.message_queue), 1, "unexpected number of messages received")
|
||||||
|
msg = self.message_queue[0]
|
||||||
|
self.assertEqual(msg.mid, 0, "message id not 0")
|
||||||
|
self.assertEqual(msg.topic, "outTopic", "message topic incorrect")
|
||||||
|
self.assertEqual(msg.payload, "hello world")
|
||||||
|
self.assertEqual(msg.qos, 0, "message qos not 0")
|
||||||
|
self.assertEqual(msg.retain, False, "message retain flag incorrect")
|
||||||
|
@ -1,64 +1,59 @@
|
|||||||
import unittest
|
import unittest
|
||||||
import settings
|
import settings
|
||||||
|
|
||||||
import time
|
import time
|
||||||
import mosquitto
|
import mosquitto
|
||||||
|
|
||||||
import serial
|
|
||||||
|
|
||||||
def on_message(mosq, obj, msg):
|
def on_message(mosq, obj, msg):
|
||||||
obj.message_queue.append(msg)
|
obj.message_queue.append(msg)
|
||||||
|
|
||||||
|
|
||||||
class mqtt_publish_in_callback(unittest.TestCase):
|
class mqtt_publish_in_callback(unittest.TestCase):
|
||||||
|
|
||||||
message_queue = []
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def setUpClass(self):
|
|
||||||
self.client = mosquitto.Mosquitto("pubsubclient_ut", clean_session=True,obj=self)
|
|
||||||
self.client.connect(settings.server_ip)
|
|
||||||
self.client.on_message = on_message
|
|
||||||
self.client.subscribe("outTopic",0)
|
|
||||||
|
|
||||||
@classmethod
|
message_queue = []
|
||||||
def tearDownClass(self):
|
|
||||||
self.client.disconnect()
|
|
||||||
|
|
||||||
def test_connect(self):
|
|
||||||
i=30
|
|
||||||
while len(self.message_queue) == 0 and i > 0:
|
|
||||||
self.client.loop()
|
|
||||||
time.sleep(0.5)
|
|
||||||
i -= 1
|
|
||||||
self.assertTrue(i>0, "message receive timed-out")
|
|
||||||
self.assertEqual(len(self.message_queue), 1, "unexpected number of messages received")
|
|
||||||
msg = self.message_queue.pop(0)
|
|
||||||
self.assertEqual(msg.mid,0,"message id not 0")
|
|
||||||
self.assertEqual(msg.topic,"outTopic","message topic incorrect")
|
|
||||||
self.assertEqual(msg.payload,"hello world")
|
|
||||||
self.assertEqual(msg.qos,0,"message qos not 0")
|
|
||||||
self.assertEqual(msg.retain,False,"message retain flag incorrect")
|
|
||||||
|
|
||||||
|
|
||||||
def test_publish(self):
|
@classmethod
|
||||||
self.assertEqual(len(self.message_queue), 0, "message queue not empty")
|
def setUpClass(self):
|
||||||
payload = "abcdefghij"
|
self.client = mosquitto.Mosquitto("pubsubclient_ut", clean_session=True, obj=self)
|
||||||
self.client.publish("inTopic",payload)
|
self.client.connect(settings.server_ip)
|
||||||
|
self.client.on_message = on_message
|
||||||
i=30
|
self.client.subscribe("outTopic", 0)
|
||||||
while len(self.message_queue) == 0 and i > 0:
|
|
||||||
self.client.loop()
|
|
||||||
time.sleep(0.5)
|
|
||||||
i -= 1
|
|
||||||
|
|
||||||
self.assertTrue(i>0, "message receive timed-out")
|
@classmethod
|
||||||
self.assertEqual(len(self.message_queue), 1, "unexpected number of messages received")
|
def tearDownClass(self):
|
||||||
msg = self.message_queue.pop(0)
|
self.client.disconnect()
|
||||||
self.assertEqual(msg.mid,0,"message id not 0")
|
|
||||||
self.assertEqual(msg.topic,"outTopic","message topic incorrect")
|
|
||||||
self.assertEqual(msg.payload,payload)
|
|
||||||
self.assertEqual(msg.qos,0,"message qos not 0")
|
|
||||||
self.assertEqual(msg.retain,False,"message retain flag incorrect")
|
|
||||||
|
|
||||||
|
|
||||||
|
def test_connect(self):
|
||||||
|
i = 30
|
||||||
|
while len(self.message_queue) == 0 and i > 0:
|
||||||
|
self.client.loop()
|
||||||
|
time.sleep(0.5)
|
||||||
|
i -= 1
|
||||||
|
self.assertTrue(i > 0, "message receive timed-out")
|
||||||
|
self.assertEqual(len(self.message_queue), 1, "unexpected number of messages received")
|
||||||
|
msg = self.message_queue.pop(0)
|
||||||
|
self.assertEqual(msg.mid, 0, "message id not 0")
|
||||||
|
self.assertEqual(msg.topic, "outTopic", "message topic incorrect")
|
||||||
|
self.assertEqual(msg.payload, "hello world")
|
||||||
|
self.assertEqual(msg.qos, 0, "message qos not 0")
|
||||||
|
self.assertEqual(msg.retain, False, "message retain flag incorrect")
|
||||||
|
|
||||||
|
def test_publish(self):
|
||||||
|
self.assertEqual(len(self.message_queue), 0, "message queue not empty")
|
||||||
|
payload = "abcdefghij"
|
||||||
|
self.client.publish("inTopic", payload)
|
||||||
|
|
||||||
|
i = 30
|
||||||
|
while len(self.message_queue) == 0 and i > 0:
|
||||||
|
self.client.loop()
|
||||||
|
time.sleep(0.5)
|
||||||
|
i -= 1
|
||||||
|
|
||||||
|
self.assertTrue(i > 0, "message receive timed-out")
|
||||||
|
self.assertEqual(len(self.message_queue), 1, "unexpected number of messages received")
|
||||||
|
msg = self.message_queue.pop(0)
|
||||||
|
self.assertEqual(msg.mid, 0, "message id not 0")
|
||||||
|
self.assertEqual(msg.topic, "outTopic", "message topic incorrect")
|
||||||
|
self.assertEqual(msg.payload, payload)
|
||||||
|
self.assertEqual(msg.qos, 0, "message qos not 0")
|
||||||
|
self.assertEqual(msg.retain, False, "message retain flag incorrect")
|
||||||
|
@ -10,170 +10,172 @@ import re
|
|||||||
|
|
||||||
from testcases import settings
|
from testcases import settings
|
||||||
|
|
||||||
|
|
||||||
class Workspace(object):
|
class Workspace(object):
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
self.root_dir = os.getcwd()
|
|
||||||
self.build_dir = os.path.join(self.root_dir,"tmpbin");
|
|
||||||
self.log_dir = os.path.join(self.root_dir,"logs");
|
|
||||||
self.tests_dir = os.path.join(self.root_dir,"testcases");
|
|
||||||
self.examples_dir = os.path.join(self.root_dir,"../PubSubClient/examples")
|
|
||||||
self.examples = []
|
|
||||||
self.tests = []
|
|
||||||
if not os.path.isdir("../PubSubClient"):
|
|
||||||
raise Exception("Cannot find PubSubClient library")
|
|
||||||
try:
|
|
||||||
import ino
|
|
||||||
except:
|
|
||||||
raise Exception("ino tool not installed")
|
|
||||||
|
|
||||||
def init(self):
|
def __init__(self):
|
||||||
if os.path.isdir(self.build_dir):
|
self.root_dir = os.getcwd()
|
||||||
shutil.rmtree(self.build_dir)
|
self.build_dir = os.path.join(self.root_dir, "tmpbin")
|
||||||
os.mkdir(self.build_dir)
|
self.log_dir = os.path.join(self.root_dir, "logs")
|
||||||
if os.path.isdir(self.log_dir):
|
self.tests_dir = os.path.join(self.root_dir, "testcases")
|
||||||
shutil.rmtree(self.log_dir)
|
self.examples_dir = os.path.join(self.root_dir, "../PubSubClient/examples")
|
||||||
os.mkdir(self.log_dir)
|
self.examples = []
|
||||||
|
self.tests = []
|
||||||
os.chdir(self.build_dir)
|
if not os.path.isdir("../PubSubClient"):
|
||||||
call(["ino","init"])
|
raise Exception("Cannot find PubSubClient library")
|
||||||
|
try:
|
||||||
shutil.copytree("../../PubSubClient","lib/PubSubClient")
|
return __import__('ino')
|
||||||
|
except ImportError:
|
||||||
filenames = []
|
raise Exception("ino tool not installed")
|
||||||
for root, dirs, files in os.walk(self.examples_dir):
|
|
||||||
filenames += [os.path.join(root,f) for f in files if f.endswith(".ino")]
|
def init(self):
|
||||||
filenames.sort()
|
if os.path.isdir(self.build_dir):
|
||||||
for e in filenames:
|
shutil.rmtree(self.build_dir)
|
||||||
self.examples.append(Sketch(self,e))
|
os.mkdir(self.build_dir)
|
||||||
|
if os.path.isdir(self.log_dir):
|
||||||
filenames = []
|
shutil.rmtree(self.log_dir)
|
||||||
for root, dirs, files in os.walk(self.tests_dir):
|
os.mkdir(self.log_dir)
|
||||||
filenames += [os.path.join(root,f) for f in files if f.endswith(".ino")]
|
|
||||||
filenames.sort()
|
os.chdir(self.build_dir)
|
||||||
for e in filenames:
|
call(["ino", "init"])
|
||||||
self.tests.append(Sketch(self,e))
|
|
||||||
|
shutil.copytree("../../PubSubClient", "lib/PubSubClient")
|
||||||
def clean(self):
|
|
||||||
shutil.rmtree(self.build_dir)
|
filenames = []
|
||||||
|
for root, dirs, files in os.walk(self.examples_dir):
|
||||||
|
filenames += [os.path.join(root, f) for f in files if f.endswith(".ino")]
|
||||||
|
filenames.sort()
|
||||||
|
for e in filenames:
|
||||||
|
self.examples.append(Sketch(self, e))
|
||||||
|
|
||||||
|
filenames = []
|
||||||
|
for root, dirs, files in os.walk(self.tests_dir):
|
||||||
|
filenames += [os.path.join(root, f) for f in files if f.endswith(".ino")]
|
||||||
|
filenames.sort()
|
||||||
|
for e in filenames:
|
||||||
|
self.tests.append(Sketch(self, e))
|
||||||
|
|
||||||
|
def clean(self):
|
||||||
|
shutil.rmtree(self.build_dir)
|
||||||
|
|
||||||
|
|
||||||
class Sketch(object):
|
class Sketch(object):
|
||||||
def __init__(self,wksp,fn):
|
def __init__(self, wksp, fn):
|
||||||
self.w = wksp
|
self.w = wksp
|
||||||
self.filename = fn
|
self.filename = fn
|
||||||
self.basename = os.path.basename(self.filename)
|
self.basename = os.path.basename(self.filename)
|
||||||
self.build_log = os.path.join(self.w.log_dir,"%s.log"%(os.path.basename(self.filename),))
|
self.build_log = os.path.join(self.w.log_dir, "%s.log" % (os.path.basename(self.filename),))
|
||||||
self.build_err_log = os.path.join(self.w.log_dir,"%s.err.log"%(os.path.basename(self.filename),))
|
self.build_err_log = os.path.join(self.w.log_dir, "%s.err.log" % (os.path.basename(self.filename),))
|
||||||
self.build_upload_log = os.path.join(self.w.log_dir,"%s.upload.log"%(os.path.basename(self.filename),))
|
self.build_upload_log = os.path.join(self.w.log_dir, "%s.upload.log" % (os.path.basename(self.filename),))
|
||||||
|
|
||||||
def build(self):
|
def build(self):
|
||||||
sys.stdout.write(" Build: ")
|
sys.stdout.write(" Build: ")
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
|
|
||||||
# Copy sketch over, replacing IP addresses as necessary
|
|
||||||
fin = open(self.filename,"r")
|
|
||||||
lines = fin.readlines()
|
|
||||||
fin.close()
|
|
||||||
fout = open(os.path.join(self.w.build_dir,"src","sketch.ino"),"w")
|
|
||||||
for l in lines:
|
|
||||||
if re.match(r"^byte server\[\] = {",l):
|
|
||||||
fout.write("byte server[] = { %s };\n"%(settings.server_ip.replace(".",", "),))
|
|
||||||
elif re.match(r"^byte ip\[\] = {",l):
|
|
||||||
fout.write("byte ip[] = { %s };\n"%(settings.arduino_ip.replace(".",", "),))
|
|
||||||
else:
|
|
||||||
fout.write(l)
|
|
||||||
fout.flush()
|
|
||||||
fout.close()
|
|
||||||
|
|
||||||
# Run build
|
|
||||||
fout = open(self.build_log, "w")
|
|
||||||
ferr = open(self.build_err_log, "w")
|
|
||||||
rc = call(["ino","build"],stdout=fout,stderr=ferr)
|
|
||||||
fout.close()
|
|
||||||
ferr.close()
|
|
||||||
if rc == 0:
|
|
||||||
sys.stdout.write("pass")
|
|
||||||
sys.stdout.write("\n")
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
sys.stdout.write("fail")
|
|
||||||
sys.stdout.write("\n")
|
|
||||||
with open(self.build_err_log) as f:
|
|
||||||
for line in f:
|
|
||||||
print " ",line,
|
|
||||||
return False
|
|
||||||
|
|
||||||
def upload(self):
|
|
||||||
sys.stdout.write(" Upload: ")
|
|
||||||
sys.stdout.flush()
|
|
||||||
fout = open(self.build_upload_log, "w")
|
|
||||||
rc = call(["ino","upload"],stdout=fout,stderr=fout)
|
|
||||||
fout.close()
|
|
||||||
if rc == 0:
|
|
||||||
sys.stdout.write("pass")
|
|
||||||
sys.stdout.write("\n")
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
sys.stdout.write("fail")
|
|
||||||
sys.stdout.write("\n")
|
|
||||||
with open(self.build_upload_log) as f:
|
|
||||||
for line in f:
|
|
||||||
print " ",line,
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
# Copy sketch over, replacing IP addresses as necessary
|
||||||
|
fin = open(self.filename, "r")
|
||||||
|
lines = fin.readlines()
|
||||||
|
fin.close()
|
||||||
|
fout = open(os.path.join(self.w.build_dir, "src", "sketch.ino"), "w")
|
||||||
|
for l in lines:
|
||||||
|
if re.match(r"^byte server\[\] = {", l):
|
||||||
|
fout.write("byte server[] = { %s };\n" % (settings.server_ip.replace(".", ", "),))
|
||||||
|
elif re.match(r"^byte ip\[\] = {", l):
|
||||||
|
fout.write("byte ip[] = { %s };\n" % (settings.arduino_ip.replace(".", ", "),))
|
||||||
|
else:
|
||||||
|
fout.write(l)
|
||||||
|
fout.flush()
|
||||||
|
fout.close()
|
||||||
|
|
||||||
|
# Run build
|
||||||
|
fout = open(self.build_log, "w")
|
||||||
|
ferr = open(self.build_err_log, "w")
|
||||||
|
rc = call(["ino", "build"], stdout=fout, stderr=ferr)
|
||||||
|
fout.close()
|
||||||
|
ferr.close()
|
||||||
|
if rc == 0:
|
||||||
|
sys.stdout.write("pass")
|
||||||
|
sys.stdout.write("\n")
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
sys.stdout.write("fail")
|
||||||
|
sys.stdout.write("\n")
|
||||||
|
with open(self.build_err_log) as f:
|
||||||
|
for line in f:
|
||||||
|
print(" " + line)
|
||||||
|
return False
|
||||||
|
|
||||||
|
def upload(self):
|
||||||
|
sys.stdout.write(" Upload: ")
|
||||||
|
sys.stdout.flush()
|
||||||
|
fout = open(self.build_upload_log, "w")
|
||||||
|
rc = call(["ino", "upload"], stdout=fout, stderr=fout)
|
||||||
|
fout.close()
|
||||||
|
if rc == 0:
|
||||||
|
sys.stdout.write("pass")
|
||||||
|
sys.stdout.write("\n")
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
sys.stdout.write("fail")
|
||||||
|
sys.stdout.write("\n")
|
||||||
|
with open(self.build_upload_log) as f:
|
||||||
|
for line in f:
|
||||||
|
print(" " + line)
|
||||||
|
return False
|
||||||
|
|
||||||
|
def test(self):
|
||||||
|
# import the matching test case, if it exists
|
||||||
|
try:
|
||||||
|
basename = os.path.basename(self.filename)[:-4]
|
||||||
|
i = importlib.import_module("testcases." + basename)
|
||||||
|
except:
|
||||||
|
sys.stdout.write(" Test: no tests found")
|
||||||
|
sys.stdout.write("\n")
|
||||||
|
return
|
||||||
|
c = getattr(i, basename)
|
||||||
|
|
||||||
|
testmethods = [m for m in dir(c) if m.startswith("test_")]
|
||||||
|
testmethods.sort()
|
||||||
|
tests = []
|
||||||
|
for m in testmethods:
|
||||||
|
tests.append(c(m))
|
||||||
|
|
||||||
|
result = unittest.TestResult()
|
||||||
|
c.setUpClass()
|
||||||
|
if self.upload():
|
||||||
|
sys.stdout.write(" Test: ")
|
||||||
|
sys.stdout.flush()
|
||||||
|
for t in tests:
|
||||||
|
t.run(result)
|
||||||
|
print(str(result.testsRun - len(result.failures) - len(result.errors)) + "/" + str(result.testsRun))
|
||||||
|
if not result.wasSuccessful():
|
||||||
|
if len(result.failures) > 0:
|
||||||
|
for f in result.failures:
|
||||||
|
print("-- " + str(f[0]))
|
||||||
|
print(f[1])
|
||||||
|
if len(result.errors) > 0:
|
||||||
|
print(" Errors:")
|
||||||
|
for f in result.errors:
|
||||||
|
print("-- " + str(f[0]))
|
||||||
|
print(f[1])
|
||||||
|
c.tearDownClass()
|
||||||
|
|
||||||
def test(self):
|
|
||||||
# import the matching test case, if it exists
|
|
||||||
try:
|
|
||||||
basename = os.path.basename(self.filename)[:-4]
|
|
||||||
i = importlib.import_module("testcases."+basename)
|
|
||||||
except:
|
|
||||||
sys.stdout.write(" Test: no tests found")
|
|
||||||
sys.stdout.write("\n")
|
|
||||||
return
|
|
||||||
c = getattr(i,basename)
|
|
||||||
|
|
||||||
testmethods = [m for m in dir(c) if m.startswith("test_")]
|
|
||||||
testmethods.sort()
|
|
||||||
tests = []
|
|
||||||
for m in testmethods:
|
|
||||||
tests.append(c(m))
|
|
||||||
|
|
||||||
result = unittest.TestResult()
|
|
||||||
c.setUpClass()
|
|
||||||
if self.upload():
|
|
||||||
sys.stdout.write(" Test: ")
|
|
||||||
sys.stdout.flush()
|
|
||||||
for t in tests:
|
|
||||||
t.run(result)
|
|
||||||
print "%d/%d"%(result.testsRun-len(result.failures)-len(result.errors),result.testsRun)
|
|
||||||
if not result.wasSuccessful():
|
|
||||||
if len(result.failures) > 0:
|
|
||||||
for f in result.failures:
|
|
||||||
print "-- %s"%(str(f[0]),)
|
|
||||||
print f[1]
|
|
||||||
if len(result.errors) > 0:
|
|
||||||
print " Errors:"
|
|
||||||
for f in result.errors:
|
|
||||||
print "-- %s"%(str(f[0]),)
|
|
||||||
print f[1]
|
|
||||||
c.tearDownClass()
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
run_tests = True
|
run_tests = True
|
||||||
|
|
||||||
w = Workspace()
|
w = Workspace()
|
||||||
w.init()
|
w.init()
|
||||||
|
|
||||||
for e in w.examples:
|
for e in w.examples:
|
||||||
print "--------------------------------------"
|
print("--------------------------------------")
|
||||||
print "[%s]"%(e.basename,)
|
print("[" + e.basename + "]")
|
||||||
if e.build() and run_tests:
|
if e.build() and run_tests:
|
||||||
e.test()
|
e.test()
|
||||||
for e in w.tests:
|
for e in w.tests:
|
||||||
print "--------------------------------------"
|
print("--------------------------------------")
|
||||||
print "[%s]"%(e.basename,)
|
print("[" + e.basename + "]")
|
||||||
if e.build() and run_tests:
|
if e.build() and run_tests:
|
||||||
e.test()
|
e.test()
|
||||||
|
|
||||||
w.clean()
|
w.clean()
|
||||||
|
Reference in New Issue
Block a user