tests: net: Add mqtt testcases
Add two testcases for mqtt_publisher and mqtt_subscriber. The combination of the two, covering most of the MQTT APIs. Change-Id: Ib663ee1f550362ca493501046ddf8508a25ac956 Signed-off-by: Wu Jiequan <jiequanx.wu@intel.com>
This commit is contained in:
parent
3f8f1ed3b0
commit
0e3d582623
18 changed files with 1367 additions and 0 deletions
8
tests/net/mqtt_publisher/Makefile
Normal file
8
tests/net/mqtt_publisher/Makefile
Normal file
|
@ -0,0 +1,8 @@
|
|||
BOARD ?= qemu_x86
|
||||
CONF_FILE ?= prj_$(BOARD).conf
|
||||
|
||||
include $(ZEPHYR_BASE)/Makefile.test
|
||||
|
||||
ifeq ($(BOARD), qemu_x86)
|
||||
include $(ZEPHYR_BASE)/samples/net/common/Makefile.ipstack
|
||||
endif
|
52
tests/net/mqtt_publisher/prj_arduino_101.conf
Normal file
52
tests/net/mqtt_publisher/prj_arduino_101.conf
Normal file
|
@ -0,0 +1,52 @@
|
|||
CONFIG_NETWORKING=y
|
||||
CONFIG_NET_TCP=y
|
||||
CONFIG_RANDOM_GENERATOR=y
|
||||
CONFIG_NET_ARP=y
|
||||
CONFIG_NET_L2_ETHERNET=y
|
||||
CONFIG_NET_LOG=y
|
||||
CONFIG_INIT_STACKS=y
|
||||
|
||||
CONFIG_NET_NBUF_RX_COUNT=16
|
||||
CONFIG_NET_NBUF_TX_COUNT=16
|
||||
CONFIG_NET_NBUF_RX_DATA_COUNT=16
|
||||
CONFIG_NET_NBUF_TX_DATA_COUNT=16
|
||||
|
||||
CONFIG_NET_IPV6_RA_RDNSS=y
|
||||
CONFIG_NET_IFACE_UNICAST_IPV4_ADDR_COUNT=3
|
||||
|
||||
CONFIG_PRINTK=y
|
||||
#CONFIG_NET_DEBUG_NET_BUF=y
|
||||
|
||||
CONFIG_NET_IPV4=y
|
||||
# Enable IPv6 support
|
||||
CONFIG_NET_IPV6=n
|
||||
|
||||
# Enable the MQTT Lib
|
||||
CONFIG_MQTT_LIB=y
|
||||
|
||||
CONFIG_NET_APP_SETTINGS=y
|
||||
CONFIG_NET_APP_MY_IPV6_ADDR="2001:db8::1"
|
||||
CONFIG_NET_APP_PEER_IPV6_ADDR="2001:db8::2"
|
||||
|
||||
CONFIG_NET_APP_MY_IPV4_ADDR="192.168.1.101"
|
||||
CONFIG_NET_APP_PEER_IPV4_ADDR="192.168.1.10"
|
||||
|
||||
CONFIG_MAIN_STACK_SIZE=2048
|
||||
|
||||
# For IPv6
|
||||
CONFIG_NET_NBUF_DATA_SIZE=256
|
||||
|
||||
CONFIG_TEST_RANDOM_GENERATOR=y
|
||||
|
||||
# ENC28J60 Ethernet Device
|
||||
CONFIG_ETH_ENC28J60=y
|
||||
CONFIG_ETH_ENC28J60_0=y
|
||||
CONFIG_ETH_ENC28J60_0_SPI_PORT_NAME="SPI_1"
|
||||
CONFIG_ETH_ENC28J60_0_MAC3=0x2D
|
||||
CONFIG_ETH_ENC28J60_0_MAC4=0x30
|
||||
CONFIG_ETH_ENC28J60_0_MAC5=0x36
|
||||
|
||||
# Arduino 101
|
||||
CONFIG_SPI=y
|
||||
|
||||
CONFIG_ZTEST=y
|
39
tests/net/mqtt_publisher/prj_frdm_k64f.conf
Normal file
39
tests/net/mqtt_publisher/prj_frdm_k64f.conf
Normal file
|
@ -0,0 +1,39 @@
|
|||
CONFIG_NETWORKING=y
|
||||
CONFIG_NET_TCP=y
|
||||
CONFIG_RANDOM_GENERATOR=y
|
||||
CONFIG_NET_ARP=y
|
||||
CONFIG_NET_L2_ETHERNET=y
|
||||
CONFIG_NET_LOG=y
|
||||
CONFIG_INIT_STACKS=y
|
||||
|
||||
CONFIG_NET_NBUF_RX_COUNT=16
|
||||
CONFIG_NET_NBUF_TX_COUNT=16
|
||||
CONFIG_NET_NBUF_RX_DATA_COUNT=16
|
||||
CONFIG_NET_NBUF_TX_DATA_COUNT=16
|
||||
|
||||
CONFIG_NET_IPV6_RA_RDNSS=y
|
||||
CONFIG_NET_IFACE_UNICAST_IPV4_ADDR_COUNT=3
|
||||
|
||||
CONFIG_PRINTK=y
|
||||
#CONFIG_NET_DEBUG_NET_BUF=y
|
||||
|
||||
CONFIG_NET_IPV4=y
|
||||
# Enable IPv6 support
|
||||
CONFIG_NET_IPV6=n
|
||||
|
||||
# Enable the MQTT Lib
|
||||
CONFIG_MQTT_LIB=y
|
||||
|
||||
CONFIG_NET_APP_SETTINGS=y
|
||||
CONFIG_NET_APP_MY_IPV6_ADDR="2001:db8::1"
|
||||
CONFIG_NET_APP_PEER_IPV6_ADDR="2001:db8::2"
|
||||
|
||||
CONFIG_NET_APP_MY_IPV4_ADDR="192.168.1.101"
|
||||
CONFIG_NET_APP_PEER_IPV4_ADDR="192.168.1.10"
|
||||
|
||||
CONFIG_MAIN_STACK_SIZE=2048
|
||||
|
||||
# For IPv6
|
||||
CONFIG_NET_NBUF_DATA_SIZE=256
|
||||
|
||||
CONFIG_ZTEST=y
|
40
tests/net/mqtt_publisher/prj_qemu_x86.conf
Normal file
40
tests/net/mqtt_publisher/prj_qemu_x86.conf
Normal file
|
@ -0,0 +1,40 @@
|
|||
CONFIG_NETWORKING=y
|
||||
CONFIG_NET_TCP=y
|
||||
CONFIG_RANDOM_GENERATOR=y
|
||||
CONFIG_TEST_RANDOM_GENERATOR=y
|
||||
CONFIG_NET_LOG=y
|
||||
CONFIG_NET_SLIP_TAP=y
|
||||
CONFIG_INIT_STACKS=y
|
||||
|
||||
CONFIG_NET_NBUF_RX_COUNT=16
|
||||
CONFIG_NET_NBUF_TX_COUNT=16
|
||||
CONFIG_NET_NBUF_RX_DATA_COUNT=16
|
||||
CONFIG_NET_NBUF_TX_DATA_COUNT=16
|
||||
|
||||
CONFIG_NET_IPV6_RA_RDNSS=y
|
||||
CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=3
|
||||
CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=2
|
||||
|
||||
CONFIG_STDOUT_CONSOLE=y
|
||||
|
||||
# Enable IPv6 support
|
||||
CONFIG_NET_IPV6=n
|
||||
# Enable IPv4 support
|
||||
CONFIG_NET_IPV4=y
|
||||
|
||||
# Enable the MQTT Lib
|
||||
CONFIG_MQTT_LIB=y
|
||||
|
||||
CONFIG_NET_APP_SETTINGS=y
|
||||
CONFIG_NET_APP_MY_IPV6_ADDR="2001:db8::1"
|
||||
CONFIG_NET_APP_PEER_IPV6_ADDR="2001:db8::2"
|
||||
|
||||
CONFIG_NET_APP_MY_IPV4_ADDR="192.0.2.1"
|
||||
CONFIG_NET_APP_PEER_IPV4_ADDR="192.0.2.2"
|
||||
|
||||
CONFIG_MAIN_STACK_SIZE=2048
|
||||
|
||||
# For IPv6
|
||||
CONFIG_NET_NBUF_DATA_SIZE=256
|
||||
|
||||
CONFIG_ZTEST=y
|
3
tests/net/mqtt_publisher/src/Makefile
Normal file
3
tests/net/mqtt_publisher/src/Makefile
Normal file
|
@ -0,0 +1,3 @@
|
|||
include $(ZEPHYR_BASE)/tests/Makefile.test
|
||||
|
||||
obj-y += main.o test_mqtt_publish.o
|
42
tests/net/mqtt_publisher/src/config.h
Normal file
42
tests/net/mqtt_publisher/src/config.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (c) 2017 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef __CONFIG_H__
|
||||
#define __CONFIG_H__
|
||||
|
||||
#ifdef CONFIG_NET_APP_SETTINGS
|
||||
#ifdef CONFIG_NET_IPV6
|
||||
#define ZEPHYR_ADDR CONFIG_NET_APP_MY_IPV6_ADDR
|
||||
#define SERVER_ADDR CONFIG_NET_APP_PEER_IPV6_ADDR
|
||||
#else
|
||||
#define ZEPHYR_ADDR CONFIG_NET_APP_MY_IPV4_ADDR
|
||||
#define SERVER_ADDR CONFIG_NET_APP_PEER_IPV4_ADDR
|
||||
#endif
|
||||
#else
|
||||
#ifdef CONFIG_NET_IPV6
|
||||
#define ZEPHYR_ADDR "2001:db8::1"
|
||||
#define SERVER_ADDR "2001:db8::2"
|
||||
#else
|
||||
#define ZEPHYR_ADDR "192.168.1.101"
|
||||
#define SERVER_ADDR "192.168.1.10"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define SERVER_PORT 1883
|
||||
|
||||
#define APP_SLEEP_MSECS 500
|
||||
#define APP_TX_RX_TIMEOUT 300
|
||||
|
||||
#define APP_CONNECT_TRIES 10
|
||||
|
||||
#define APP_MAX_ITERATIONS 100
|
||||
|
||||
#define MQTT_CLIENTID "zephyr_publisher"
|
||||
|
||||
/* Set the following to 1 to enable the Bluemix topic format */
|
||||
#define APP_BLUEMIX_TOPIC 0
|
||||
|
||||
#endif
|
24
tests/net/mqtt_publisher/src/main.c
Normal file
24
tests/net/mqtt_publisher/src/main.c
Normal file
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright (c) 2017 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <ztest.h>
|
||||
|
||||
extern void test_mqtt_init(void);
|
||||
extern void test_mqtt_connect(void);
|
||||
extern void test_mqtt_pingreq(void);
|
||||
extern void test_mqtt_publish(void);
|
||||
extern void test_mqtt_disconnect(void);
|
||||
|
||||
void test_main(void)
|
||||
{
|
||||
ztest_test_suite(mqtt_test,
|
||||
ztest_unit_test(test_mqtt_init),
|
||||
ztest_unit_test(test_mqtt_connect),
|
||||
ztest_unit_test(test_mqtt_pingreq),
|
||||
ztest_unit_test(test_mqtt_publish),
|
||||
ztest_unit_test(test_mqtt_disconnect));
|
||||
ztest_run_test_suite(mqtt_test);
|
||||
}
|
448
tests/net/mqtt_publisher/src/test_mqtt_publish.c
Normal file
448
tests/net/mqtt_publisher/src/test_mqtt_publish.c
Normal file
|
@ -0,0 +1,448 @@
|
|||
/*
|
||||
* Copyright (c) 2017 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <net/mqtt.h>
|
||||
#include <ztest.h>
|
||||
|
||||
#include <net/net_context.h>
|
||||
#include <net/nbuf.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
/* Container for some structures used by the MQTT publisher app. */
|
||||
struct mqtt_client_ctx {
|
||||
/**
|
||||
* The connect message structure is only used during the connect
|
||||
* stage. Developers must set some msg properties before calling the
|
||||
* mqtt_tx_connect routine. See below.
|
||||
*/
|
||||
struct mqtt_connect_msg connect_msg;
|
||||
/**
|
||||
* This is the message that will be received by the server
|
||||
* (MQTT broker).
|
||||
*/
|
||||
struct mqtt_publish_msg pub_msg;
|
||||
|
||||
/**
|
||||
* This is the MQTT application context variable.
|
||||
*/
|
||||
struct mqtt_ctx mqtt_ctx;
|
||||
|
||||
/**
|
||||
* This variable will be passed to the connect callback, declared inside
|
||||
* the mqtt context struct. If not used, it could be set to NULL.
|
||||
*/
|
||||
void *connect_data;
|
||||
|
||||
/**
|
||||
* This variable will be passed to the disconnect callback, declared
|
||||
* inside the mqtt context struct. If not used, it could be set to NULL.
|
||||
*/
|
||||
void *disconnect_data;
|
||||
|
||||
/**
|
||||
* This variable will be passed to the publish_tx callback, declared
|
||||
* inside the mqtt context struct. If not used, it could be set to NULL.
|
||||
*/
|
||||
void *publish_data;
|
||||
};
|
||||
|
||||
/* This is mqtt payload message. */
|
||||
char payload[] = "DOORS:OPEN_QoSx";
|
||||
|
||||
/* This is the network context structure. */
|
||||
static struct net_context *net_ctx;
|
||||
|
||||
/* The mqtt client struct */
|
||||
static struct mqtt_client_ctx client_ctx;
|
||||
|
||||
/* This routine sets some basic properties for the network context variable */
|
||||
static int network_setup(struct net_context **net_ctx, const char *local_addr,
|
||||
const char *server_addr, uint16_t server_port);
|
||||
|
||||
/* The signature of this routine must match the connect callback declared at
|
||||
* the mqtt.h header.
|
||||
*/
|
||||
static void connect_cb(struct mqtt_ctx *mqtt_ctx)
|
||||
{
|
||||
struct mqtt_client_ctx *client_ctx;
|
||||
|
||||
client_ctx = CONTAINER_OF(mqtt_ctx, struct mqtt_client_ctx, mqtt_ctx);
|
||||
|
||||
TC_PRINT("[%s:%d]", __func__, __LINE__);
|
||||
|
||||
if (client_ctx->connect_data) {
|
||||
TC_PRINT(" user_data: %s",
|
||||
(const char *)client_ctx->connect_data);
|
||||
}
|
||||
|
||||
TC_PRINT("\n");
|
||||
}
|
||||
|
||||
/* The signature of this routine must match the disconnect callback declared at
|
||||
* the mqtt.h header.
|
||||
*/
|
||||
static void disconnect_cb(struct mqtt_ctx *mqtt_ctx)
|
||||
{
|
||||
struct mqtt_client_ctx *client_ctx;
|
||||
|
||||
client_ctx = CONTAINER_OF(mqtt_ctx, struct mqtt_client_ctx, mqtt_ctx);
|
||||
|
||||
TC_PRINT("[%s:%d]", __func__, __LINE__);
|
||||
|
||||
if (client_ctx->disconnect_data) {
|
||||
TC_PRINT(" user_data: %s",
|
||||
(const char *)client_ctx->disconnect_data);
|
||||
}
|
||||
|
||||
TC_PRINT("\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* The signature of this routine must match the publish_tx callback declared at
|
||||
* the mqtt.h header.
|
||||
*
|
||||
* NOTE: we have two callbacks for MQTT Publish related stuff:
|
||||
* - publish_tx, for publishers
|
||||
* - publish_rx, for subscribers
|
||||
*
|
||||
* Applications must keep a "message database" with pkt_id's. So far, this is
|
||||
* not implemented here. For example, if we receive a PUBREC message with an
|
||||
* unknown pkt_id, this routine must return an error, for example -EINVAL or
|
||||
* any negative value.
|
||||
*/
|
||||
static int publish_cb(struct mqtt_ctx *mqtt_ctx, uint16_t pkt_id,
|
||||
enum mqtt_packet type)
|
||||
{
|
||||
struct mqtt_client_ctx *client_ctx;
|
||||
const char *str;
|
||||
int rc = 0;
|
||||
|
||||
client_ctx = CONTAINER_OF(mqtt_ctx, struct mqtt_client_ctx, mqtt_ctx);
|
||||
|
||||
switch (type) {
|
||||
case MQTT_PUBACK:
|
||||
str = "MQTT_PUBACK";
|
||||
break;
|
||||
case MQTT_PUBCOMP:
|
||||
str = "MQTT_PUBCOMP";
|
||||
break;
|
||||
case MQTT_PUBREC:
|
||||
str = "MQTT_PUBREC";
|
||||
break;
|
||||
default:
|
||||
rc = -EINVAL;
|
||||
str = "Invalid MQTT packet";
|
||||
}
|
||||
|
||||
TC_PRINT("[%s:%d] <%s> packet id: %u", __func__, __LINE__, str, pkt_id);
|
||||
|
||||
if (client_ctx->publish_data) {
|
||||
TC_PRINT(", user_data: %s",
|
||||
(const char *)client_ctx->publish_data);
|
||||
}
|
||||
|
||||
TC_PRINT("\n");
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* The signature of this routine must match the malformed callback declared at
|
||||
* the mqtt.h header.
|
||||
*/
|
||||
static void malformed_cb(struct mqtt_ctx *mqtt_ctx, uint16_t pkt_type)
|
||||
{
|
||||
TC_PRINT("[%s:%d] pkt_type: %u\n", __func__, __LINE__, pkt_type);
|
||||
}
|
||||
|
||||
static char *get_mqtt_payload(enum mqtt_qos qos)
|
||||
{
|
||||
payload[strlen(payload) - 1] = '0' + qos;
|
||||
|
||||
return payload;
|
||||
}
|
||||
|
||||
static char *get_mqtt_topic(void)
|
||||
{
|
||||
return "sensors";
|
||||
}
|
||||
|
||||
static void prepare_mqtt_publish_msg(struct mqtt_publish_msg *pub_msg,
|
||||
enum mqtt_qos qos)
|
||||
{
|
||||
/* MQTT message payload may be anything, we we use C strings */
|
||||
pub_msg->msg = (uint8_t *)get_mqtt_payload(qos);
|
||||
/* Payload's length */
|
||||
pub_msg->msg_len = (uint16_t)strlen((char *)client_ctx.pub_msg.msg);
|
||||
/* MQTT Quality of Service */
|
||||
pub_msg->qos = qos;
|
||||
/* Message's topic */
|
||||
pub_msg->topic = get_mqtt_topic();
|
||||
pub_msg->topic_len = strlen(client_ctx.pub_msg.topic);
|
||||
/* Packet Identifier, always use different values */
|
||||
pub_msg->pkt_id = sys_rand32_get();
|
||||
}
|
||||
|
||||
#define RC_STR(rc) ((rc) == 0 ? "OK" : "ERROR")
|
||||
|
||||
#define PRINT_RESULT(func, rc) \
|
||||
TC_PRINT("[%s:%d] %s: %d <%s>\n", __func__, __LINE__, \
|
||||
(func), rc, RC_STR(rc))
|
||||
|
||||
/* In this routine we block until the connected variable is 1 */
|
||||
static int try_to_connect(struct mqtt_client_ctx *client_ctx)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (i++ < APP_CONNECT_TRIES && !client_ctx->mqtt_ctx.connected) {
|
||||
int rc;
|
||||
|
||||
rc = mqtt_tx_connect(&client_ctx->mqtt_ctx,
|
||||
&client_ctx->connect_msg);
|
||||
k_sleep(APP_SLEEP_MSECS);
|
||||
if (rc != 0) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (client_ctx->mqtt_ctx.connected) {
|
||||
return TC_PASS;
|
||||
}
|
||||
|
||||
return TC_FAIL;
|
||||
}
|
||||
|
||||
static int init_network(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* The net_ctx variable must be ready BEFORE passing it to the MQTT API.
|
||||
*/
|
||||
rc = network_setup(&net_ctx, ZEPHYR_ADDR, SERVER_ADDR, SERVER_PORT);
|
||||
if (rc != 0) {
|
||||
goto exit_app;
|
||||
}
|
||||
|
||||
/* Set everything to 0 and later just assign the required fields. */
|
||||
memset(&client_ctx, 0x00, sizeof(client_ctx));
|
||||
|
||||
/* The network context is the only field that must be set BEFORE
|
||||
* calling the mqtt_init routine.
|
||||
*/
|
||||
client_ctx.mqtt_ctx.net_ctx = net_ctx;
|
||||
|
||||
/* connect, disconnect and malformed may be set to NULL */
|
||||
client_ctx.mqtt_ctx.connect = connect_cb;
|
||||
|
||||
client_ctx.mqtt_ctx.disconnect = disconnect_cb;
|
||||
client_ctx.mqtt_ctx.malformed = malformed_cb;
|
||||
|
||||
client_ctx.mqtt_ctx.net_timeout = APP_TX_RX_TIMEOUT;
|
||||
|
||||
/* Publisher apps TX the MQTT PUBLISH msg */
|
||||
client_ctx.mqtt_ctx.publish_tx = publish_cb;
|
||||
|
||||
rc = mqtt_init(&client_ctx.mqtt_ctx, MQTT_APP_PUBLISHER);
|
||||
if (rc != 0) {
|
||||
goto exit_app;
|
||||
}
|
||||
|
||||
/* The connect message will be sent to the MQTT server (broker).
|
||||
* If clean_session here is 0, the mqtt_ctx clean_session variable
|
||||
* will be set to 0 also. Please don't do that, set always to 1.
|
||||
* Clean session = 0 is not yet supported.
|
||||
*/
|
||||
client_ctx.connect_msg.client_id = MQTT_CLIENTID;
|
||||
client_ctx.connect_msg.client_id_len = strlen(MQTT_CLIENTID);
|
||||
client_ctx.connect_msg.clean_session = 1;
|
||||
|
||||
client_ctx.connect_data = "CONNECTED";
|
||||
client_ctx.disconnect_data = "DISCONNECTED";
|
||||
client_ctx.publish_data = "PUBLISH";
|
||||
|
||||
return TC_PASS;
|
||||
|
||||
exit_app:
|
||||
net_context_put(net_ctx);
|
||||
|
||||
return TC_FAIL;
|
||||
}
|
||||
|
||||
static int test_connect(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = try_to_connect(&client_ctx);
|
||||
if (rc != 0) {
|
||||
return TC_FAIL;
|
||||
}
|
||||
|
||||
return TC_PASS;
|
||||
|
||||
}
|
||||
|
||||
static int test_pingreq(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = mqtt_tx_pingreq(&client_ctx.mqtt_ctx);
|
||||
k_sleep(APP_SLEEP_MSECS);
|
||||
if (rc != 0) {
|
||||
return TC_FAIL;
|
||||
}
|
||||
|
||||
return TC_PASS;
|
||||
}
|
||||
|
||||
static int test_publish(enum mqtt_qos qos)
|
||||
{
|
||||
int rc;
|
||||
|
||||
prepare_mqtt_publish_msg(&client_ctx.pub_msg, qos);
|
||||
rc = mqtt_tx_publish(&client_ctx.mqtt_ctx, &client_ctx.pub_msg);
|
||||
k_sleep(APP_SLEEP_MSECS);
|
||||
if (rc != 0) {
|
||||
return TC_FAIL;
|
||||
}
|
||||
|
||||
return TC_PASS;
|
||||
}
|
||||
|
||||
static int test_disconnect(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = mqtt_tx_disconnect(&client_ctx.mqtt_ctx);
|
||||
if (rc != 0) {
|
||||
return TC_FAIL;
|
||||
}
|
||||
|
||||
return TC_PASS;
|
||||
}
|
||||
|
||||
static int set_addr(struct sockaddr *sock_addr, const char *addr, uint16_t port)
|
||||
{
|
||||
void *ptr;
|
||||
int rc;
|
||||
|
||||
#ifdef CONFIG_NET_IPV6
|
||||
net_sin6(sock_addr)->sin6_port = htons(port);
|
||||
sock_addr->family = AF_INET6;
|
||||
ptr = &(net_sin6(sock_addr)->sin6_addr);
|
||||
rc = net_addr_pton(AF_INET6, addr, ptr);
|
||||
#else
|
||||
net_sin(sock_addr)->sin_port = htons(port);
|
||||
sock_addr->family = AF_INET;
|
||||
ptr = &(net_sin(sock_addr)->sin_addr);
|
||||
rc = net_addr_pton(AF_INET, addr, ptr);
|
||||
#endif
|
||||
|
||||
if (rc) {
|
||||
TC_PRINT("Invalid IP address: %s\n", addr);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int network_setup(struct net_context **net_ctx, const char *local_addr,
|
||||
const char *server_addr, uint16_t server_port)
|
||||
{
|
||||
#ifdef CONFIG_NET_IPV6
|
||||
socklen_t addr_len = sizeof(struct sockaddr_in6);
|
||||
sa_family_t family = AF_INET6;
|
||||
|
||||
#else
|
||||
socklen_t addr_len = sizeof(struct sockaddr_in);
|
||||
sa_family_t family = AF_INET;
|
||||
#endif
|
||||
struct sockaddr server_sock, local_sock;
|
||||
void *p;
|
||||
int rc;
|
||||
|
||||
rc = set_addr(&local_sock, local_addr, 0);
|
||||
if (rc) {
|
||||
TC_PRINT("set_addr (local) error\n");
|
||||
return TC_FAIL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NET_IPV6
|
||||
p = net_if_ipv6_addr_add(net_if_get_default(),
|
||||
&net_sin6(&local_sock)->sin6_addr,
|
||||
NET_ADDR_MANUAL, 0);
|
||||
#else
|
||||
p = net_if_ipv4_addr_add(net_if_get_default(),
|
||||
&net_sin(&local_sock)->sin_addr,
|
||||
NET_ADDR_MANUAL, 0);
|
||||
#endif
|
||||
|
||||
if (!p) {
|
||||
return TC_FAIL;
|
||||
}
|
||||
|
||||
rc = net_context_get(family, SOCK_STREAM, IPPROTO_TCP, net_ctx);
|
||||
if (rc) {
|
||||
TC_PRINT("net_context_get error\n");
|
||||
return TC_FAIL;
|
||||
}
|
||||
|
||||
rc = net_context_bind(*net_ctx, &local_sock, addr_len);
|
||||
if (rc) {
|
||||
TC_PRINT("net_context_bind error\n");
|
||||
goto lb_exit;
|
||||
}
|
||||
|
||||
rc = set_addr(&server_sock, server_addr, server_port);
|
||||
if (rc) {
|
||||
TC_PRINT("set_addr (server) error\n");
|
||||
goto lb_exit;
|
||||
}
|
||||
|
||||
rc = net_context_connect(*net_ctx, &server_sock, addr_len, NULL,
|
||||
APP_SLEEP_MSECS, NULL);
|
||||
if (rc) {
|
||||
TC_PRINT("net_context_connect error\n"
|
||||
"Is the server (broker) up and running?\n");
|
||||
goto lb_exit;
|
||||
}
|
||||
|
||||
return TC_PASS;
|
||||
|
||||
lb_exit:
|
||||
net_context_put(*net_ctx);
|
||||
|
||||
return TC_FAIL;
|
||||
}
|
||||
|
||||
void test_mqtt_init(void)
|
||||
{
|
||||
assert_true(init_network() == TC_PASS, NULL);
|
||||
}
|
||||
|
||||
void test_mqtt_connect(void)
|
||||
{
|
||||
assert_true(test_connect() == TC_PASS, NULL);
|
||||
}
|
||||
|
||||
void test_mqtt_pingreq(void)
|
||||
{
|
||||
assert_true(test_pingreq() == TC_PASS, NULL);
|
||||
}
|
||||
|
||||
void test_mqtt_publish(void)
|
||||
{
|
||||
assert_true(test_publish(MQTT_QoS0) == TC_PASS, NULL);
|
||||
assert_true(test_publish(MQTT_QoS1) == TC_PASS, NULL);
|
||||
assert_true(test_publish(MQTT_QoS2) == TC_PASS, NULL);
|
||||
}
|
||||
|
||||
void test_mqtt_disconnect(void)
|
||||
{
|
||||
assert_true(test_disconnect() == TC_PASS, NULL);
|
||||
}
|
4
tests/net/mqtt_publisher/testcase.ini
Normal file
4
tests/net/mqtt_publisher/testcase.ini
Normal file
|
@ -0,0 +1,4 @@
|
|||
[test]
|
||||
tags = net mqtt
|
||||
build_only = true
|
||||
platform_whitelist = frdm_k64f qemu_x86
|
14
tests/net/mqtt_subscriber/Makefile
Normal file
14
tests/net/mqtt_subscriber/Makefile
Normal file
|
@ -0,0 +1,14 @@
|
|||
#
|
||||
# Copyright (c) 2017 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
BOARD ?= qemu_x86
|
||||
CONF_FILE ?= prj_$(BOARD).conf
|
||||
|
||||
include $(ZEPHYR_BASE)/Makefile.test
|
||||
|
||||
ifeq ($(BOARD), qemu_x86)
|
||||
include $(ZEPHYR_BASE)/samples/net/common/Makefile.ipstack
|
||||
endif
|
52
tests/net/mqtt_subscriber/prj_arduino_101.conf
Normal file
52
tests/net/mqtt_subscriber/prj_arduino_101.conf
Normal file
|
@ -0,0 +1,52 @@
|
|||
CONFIG_NETWORKING=y
|
||||
CONFIG_NET_TCP=y
|
||||
CONFIG_RANDOM_GENERATOR=y
|
||||
CONFIG_NET_ARP=y
|
||||
CONFIG_NET_L2_ETHERNET=y
|
||||
CONFIG_NET_LOG=y
|
||||
CONFIG_INIT_STACKS=y
|
||||
|
||||
CONFIG_NET_NBUF_RX_COUNT=16
|
||||
CONFIG_NET_NBUF_TX_COUNT=16
|
||||
CONFIG_NET_NBUF_RX_DATA_COUNT=16
|
||||
CONFIG_NET_NBUF_TX_DATA_COUNT=16
|
||||
|
||||
CONFIG_NET_IPV6_RA_RDNSS=y
|
||||
CONFIG_NET_IFACE_UNICAST_IPV4_ADDR_COUNT=3
|
||||
|
||||
CONFIG_PRINTK=y
|
||||
#CONFIG_NET_DEBUG_NET_BUF=y
|
||||
|
||||
CONFIG_NET_IPV4=y
|
||||
# Enable IPv6 support
|
||||
CONFIG_NET_IPV6=n
|
||||
|
||||
# Enable the MQTT Lib
|
||||
CONFIG_MQTT_LIB=y
|
||||
|
||||
CONFIG_NET_APP_SETTINGS=y
|
||||
CONFIG_NET_APP_MY_IPV6_ADDR="2001:db8::1"
|
||||
CONFIG_NET_APP_PEER_IPV6_ADDR="2001:db8::2"
|
||||
|
||||
CONFIG_NET_APP_MY_IPV4_ADDR="192.168.1.101"
|
||||
CONFIG_NET_APP_PEER_IPV4_ADDR="192.168.1.10"
|
||||
|
||||
CONFIG_MAIN_STACK_SIZE=2048
|
||||
|
||||
# For IPv6
|
||||
CONFIG_NET_NBUF_DATA_SIZE=256
|
||||
|
||||
CONFIG_TEST_RANDOM_GENERATOR=y
|
||||
|
||||
# ENC28J60 Ethernet Device
|
||||
CONFIG_ETH_ENC28J60=y
|
||||
CONFIG_ETH_ENC28J60_0=y
|
||||
CONFIG_ETH_ENC28J60_0_SPI_PORT_NAME="SPI_1"
|
||||
CONFIG_ETH_ENC28J60_0_MAC3=0x2D
|
||||
CONFIG_ETH_ENC28J60_0_MAC4=0x30
|
||||
CONFIG_ETH_ENC28J60_0_MAC5=0x36
|
||||
|
||||
# Arduino 101
|
||||
CONFIG_SPI=y
|
||||
|
||||
CONFIG_ZTEST=y
|
39
tests/net/mqtt_subscriber/prj_frdm_k64f.conf
Normal file
39
tests/net/mqtt_subscriber/prj_frdm_k64f.conf
Normal file
|
@ -0,0 +1,39 @@
|
|||
CONFIG_NETWORKING=y
|
||||
CONFIG_NET_TCP=y
|
||||
CONFIG_RANDOM_GENERATOR=y
|
||||
CONFIG_NET_ARP=y
|
||||
CONFIG_NET_L2_ETHERNET=y
|
||||
CONFIG_NET_LOG=y
|
||||
CONFIG_INIT_STACKS=y
|
||||
|
||||
CONFIG_NET_NBUF_RX_COUNT=16
|
||||
CONFIG_NET_NBUF_TX_COUNT=16
|
||||
CONFIG_NET_NBUF_RX_DATA_COUNT=16
|
||||
CONFIG_NET_NBUF_TX_DATA_COUNT=16
|
||||
|
||||
CONFIG_NET_IPV6_RA_RDNSS=y
|
||||
CONFIG_NET_IFACE_UNICAST_IPV4_ADDR_COUNT=3
|
||||
|
||||
CONFIG_PRINTK=y
|
||||
#CONFIG_NET_DEBUG_NET_BUF=y
|
||||
|
||||
CONFIG_NET_IPV4=y
|
||||
# Enable IPv6 support
|
||||
CONFIG_NET_IPV6=n
|
||||
|
||||
# Enable the MQTT Lib
|
||||
CONFIG_MQTT_LIB=y
|
||||
|
||||
CONFIG_NET_APP_SETTINGS=y
|
||||
CONFIG_NET_APP_MY_IPV6_ADDR="2001:db8::1"
|
||||
CONFIG_NET_APP_PEER_IPV6_ADDR="2001:db8::2"
|
||||
|
||||
CONFIG_NET_APP_MY_IPV4_ADDR="192.168.1.101"
|
||||
CONFIG_NET_APP_PEER_IPV4_ADDR="192.168.1.10"
|
||||
|
||||
CONFIG_MAIN_STACK_SIZE=2048
|
||||
|
||||
# For IPv6
|
||||
CONFIG_NET_NBUF_DATA_SIZE=256
|
||||
|
||||
CONFIG_ZTEST=y
|
40
tests/net/mqtt_subscriber/prj_qemu_x86.conf
Normal file
40
tests/net/mqtt_subscriber/prj_qemu_x86.conf
Normal file
|
@ -0,0 +1,40 @@
|
|||
CONFIG_NETWORKING=y
|
||||
CONFIG_NET_TCP=y
|
||||
CONFIG_RANDOM_GENERATOR=y
|
||||
CONFIG_TEST_RANDOM_GENERATOR=y
|
||||
CONFIG_NET_LOG=y
|
||||
CONFIG_NET_SLIP_TAP=y
|
||||
CONFIG_INIT_STACKS=y
|
||||
|
||||
CONFIG_NET_NBUF_RX_COUNT=16
|
||||
CONFIG_NET_NBUF_TX_COUNT=16
|
||||
CONFIG_NET_NBUF_RX_DATA_COUNT=16
|
||||
CONFIG_NET_NBUF_TX_DATA_COUNT=16
|
||||
|
||||
CONFIG_NET_IPV6_RA_RDNSS=y
|
||||
CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=3
|
||||
CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=2
|
||||
|
||||
CONFIG_STDOUT_CONSOLE=y
|
||||
|
||||
# Enable IPv6 support
|
||||
CONFIG_NET_IPV6=n
|
||||
# Enable IPv4 support
|
||||
CONFIG_NET_IPV4=y
|
||||
|
||||
# Enable the MQTT Lib
|
||||
CONFIG_MQTT_LIB=y
|
||||
|
||||
CONFIG_NET_APP_SETTINGS=y
|
||||
CONFIG_NET_APP_MY_IPV6_ADDR="2001:db8::1"
|
||||
CONFIG_NET_APP_PEER_IPV6_ADDR="2001:db8::2"
|
||||
|
||||
CONFIG_NET_APP_MY_IPV4_ADDR="192.0.2.1"
|
||||
CONFIG_NET_APP_PEER_IPV4_ADDR="192.0.2.2"
|
||||
|
||||
CONFIG_MAIN_STACK_SIZE=2048
|
||||
|
||||
# For IPv6
|
||||
CONFIG_NET_NBUF_DATA_SIZE=256
|
||||
|
||||
CONFIG_ZTEST=y
|
9
tests/net/mqtt_subscriber/src/Makefile
Normal file
9
tests/net/mqtt_subscriber/src/Makefile
Normal file
|
@ -0,0 +1,9 @@
|
|||
#
|
||||
# Copyright (c) 2017 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
#
|
||||
include $(ZEPHYR_BASE)/tests/Makefile.test
|
||||
obj-y += main.o test_mqtt_subscribe.o
|
||||
|
42
tests/net/mqtt_subscriber/src/config.h
Normal file
42
tests/net/mqtt_subscriber/src/config.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (c) 2017 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef __CONFIG_H__
|
||||
#define __CONFIG_H__
|
||||
|
||||
#ifdef CONFIG_NET_APP_SETTINGS
|
||||
#ifdef CONFIG_NET_IPV6
|
||||
#define ZEPHYR_ADDR CONFIG_NET_APP_MY_IPV6_ADDR
|
||||
#define SERVER_ADDR CONFIG_NET_APP_PEER_IPV6_ADDR
|
||||
#else
|
||||
#define ZEPHYR_ADDR CONFIG_NET_APP_MY_IPV4_ADDR
|
||||
#define SERVER_ADDR CONFIG_NET_APP_PEER_IPV4_ADDR
|
||||
#endif
|
||||
#else
|
||||
#ifdef CONFIG_NET_IPV6
|
||||
#define ZEPHYR_ADDR "2001:db8::1"
|
||||
#define SERVER_ADDR "2001:db8::2"
|
||||
#else
|
||||
#define ZEPHYR_ADDR "192.168.1.101"
|
||||
#define SERVER_ADDR "192.168.1.10"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define SERVER_PORT 1883
|
||||
|
||||
#define APP_SLEEP_MSECS 500
|
||||
#define APP_TX_RX_TIMEOUT 300
|
||||
|
||||
#define APP_CONNECT_TRIES 10
|
||||
|
||||
#define APP_MAX_ITERATIONS 100
|
||||
|
||||
#define MQTT_CLIENTID "zephyr_publisher"
|
||||
|
||||
/* Set the following to 1 to enable the Bluemix topic format */
|
||||
#define APP_BLUEMIX_TOPIC 0
|
||||
|
||||
#endif
|
24
tests/net/mqtt_subscriber/src/main.c
Normal file
24
tests/net/mqtt_subscriber/src/main.c
Normal file
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright (c) 2017 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <ztest.h>
|
||||
|
||||
extern void test_mqtt_init(void);
|
||||
extern void test_mqtt_connect(void);
|
||||
extern void test_mqtt_subscribe(void);
|
||||
extern void test_mqtt_unsubscribe(void);
|
||||
extern void test_mqtt_disconnect(void);
|
||||
|
||||
void test_main(void)
|
||||
{
|
||||
ztest_test_suite(mqtt_test,
|
||||
ztest_unit_test(test_mqtt_init),
|
||||
ztest_unit_test(test_mqtt_connect),
|
||||
ztest_unit_test(test_mqtt_subscribe),
|
||||
ztest_unit_test(test_mqtt_unsubscribe),
|
||||
ztest_unit_test(test_mqtt_disconnect));
|
||||
ztest_run_test_suite(mqtt_test);
|
||||
}
|
483
tests/net/mqtt_subscriber/src/test_mqtt_subscribe.c
Normal file
483
tests/net/mqtt_subscriber/src/test_mqtt_subscribe.c
Normal file
|
@ -0,0 +1,483 @@
|
|||
/*
|
||||
* Copyright (c) 2017 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <ztest.h>
|
||||
#include <net/mqtt.h>
|
||||
|
||||
#include <net/net_context.h>
|
||||
#include <net/nbuf.h>
|
||||
|
||||
#include <misc/printk.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
/* Container for some structures used by the MQTT subscriber app. */
|
||||
struct mqtt_client_ctx {
|
||||
/**
|
||||
* The connect message structure is only used during the connect
|
||||
* stage. Developers must set some msg properties before calling the
|
||||
* mqtt_tx_connect routine. See below.
|
||||
*/
|
||||
struct mqtt_connect_msg connect_msg;
|
||||
/**
|
||||
* This is the message that will be received by the server
|
||||
* (MQTT broker).
|
||||
*/
|
||||
struct mqtt_publish_msg pub_msg;
|
||||
|
||||
/**
|
||||
* This is the MQTT application context variable.
|
||||
*/
|
||||
struct mqtt_ctx mqtt_ctx;
|
||||
|
||||
/**
|
||||
* This variable will be passed to the connect callback, declared inside
|
||||
* the mqtt context struct. If not used, it could be set to NULL.
|
||||
*/
|
||||
void *connect_data;
|
||||
|
||||
/**
|
||||
* This variable will be passed to the disconnect callback, declared
|
||||
* inside the mqtt context struct. If not used, it could be set to NULL.
|
||||
*/
|
||||
void *disconnect_data;
|
||||
|
||||
/**
|
||||
* This variable will be passed to the subscribe_tx callback, declared
|
||||
* inside the mqtt context struct. If not used, it could be set to NULL.
|
||||
*/
|
||||
void *subscribe_data;
|
||||
|
||||
/**
|
||||
* This variable will be passed to the unsubscribe_tx callback, declared
|
||||
* inside the mqtt context struct. If not used, it could be set to NULL.
|
||||
*/
|
||||
void *unsubscribe_data;
|
||||
};
|
||||
|
||||
/* This is the network context structure. */
|
||||
static struct net_context *net_ctx;
|
||||
|
||||
/* The mqtt client struct */
|
||||
static struct mqtt_client_ctx client_ctx;
|
||||
|
||||
/* This routine sets some basic properties for the network context variable */
|
||||
static int network_setup(struct net_context **net_ctx, const char *local_addr,
|
||||
const char *server_addr, uint16_t server_port);
|
||||
|
||||
/* The signature of this routine must match the connect callback declared at
|
||||
* the mqtt.h header.
|
||||
*/
|
||||
static void connect_cb(struct mqtt_ctx *mqtt_ctx)
|
||||
{
|
||||
struct mqtt_client_ctx *client_ctx;
|
||||
|
||||
client_ctx = CONTAINER_OF(mqtt_ctx, struct mqtt_client_ctx, mqtt_ctx);
|
||||
|
||||
printk("[%s:%d]", __func__, __LINE__);
|
||||
|
||||
if (client_ctx->connect_data) {
|
||||
printk(" user_data: %s",
|
||||
(const char *)client_ctx->connect_data);
|
||||
}
|
||||
|
||||
printk("\n");
|
||||
}
|
||||
|
||||
/* The signature of this routine must match the disconnect callback declared at
|
||||
* the mqtt.h header.
|
||||
*/
|
||||
static void disconnect_cb(struct mqtt_ctx *mqtt_ctx)
|
||||
{
|
||||
struct mqtt_client_ctx *client_ctx;
|
||||
|
||||
client_ctx = CONTAINER_OF(mqtt_ctx, struct mqtt_client_ctx, mqtt_ctx);
|
||||
|
||||
printk("[%s:%d]", __func__, __LINE__);
|
||||
|
||||
if (client_ctx->disconnect_data) {
|
||||
printk(" user_data: %s",
|
||||
(const char *)client_ctx->disconnect_data);
|
||||
}
|
||||
|
||||
printk("\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* The signature of this routine must match the publish_rx callback declared at
|
||||
* the mqtt.h header.
|
||||
*
|
||||
* NOTE: we have two callbacks for MQTT Publish related stuff:
|
||||
* - publish_tx, for publishers
|
||||
* - publish_rx, for subscribers
|
||||
*
|
||||
* Applications must keep a "message database" with pkt_id's. So far, this is
|
||||
* not implemented here. For example, if we receive a PUBREC message with an
|
||||
* unknown pkt_id, this routine must return an error, for example -EINVAL or
|
||||
* any negative value.
|
||||
*/
|
||||
static int publish_rx_cb(struct mqtt_ctx *mqtt_ctx, struct mqtt_publish_msg
|
||||
*msg, uint16_t pkt_id, enum mqtt_packet type)
|
||||
{
|
||||
struct mqtt_client_ctx *client_ctx;
|
||||
const char *str;
|
||||
int rc = 0;
|
||||
|
||||
client_ctx = CONTAINER_OF(mqtt_ctx, struct mqtt_client_ctx, mqtt_ctx);
|
||||
|
||||
switch (type) {
|
||||
case MQTT_PUBLISH:
|
||||
str = "MQTT_PUBLISH";
|
||||
printk("[%s:%d] <%s> msg: %s", __func__, __LINE__,
|
||||
str, msg->msg);
|
||||
break;
|
||||
case MQTT_PUBREL:
|
||||
str = "MQTT_PUBREL";
|
||||
printk("[%s:%d] <%s> packet id: %u", __func__, __LINE__,
|
||||
str, pkt_id);
|
||||
return 0;
|
||||
default:
|
||||
rc = -EINVAL;
|
||||
str = "Invalid MQTT packet";
|
||||
}
|
||||
|
||||
if (client_ctx->subscribe_data) {
|
||||
printk(", user_data: %s",
|
||||
(const char *)client_ctx->subscribe_data);
|
||||
}
|
||||
|
||||
printk("\n");
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* The signature of this routine must match the subscribe callback declared at
|
||||
* the mqtt.h header.
|
||||
*/
|
||||
static int subscriber_cb(struct mqtt_ctx *mqtt_ctx, uint16_t pkt_id,
|
||||
uint8_t items, enum mqtt_qos qos[])
|
||||
{
|
||||
struct mqtt_client_ctx *client_ctx;
|
||||
|
||||
client_ctx = CONTAINER_OF(mqtt_ctx, struct mqtt_client_ctx, mqtt_ctx);
|
||||
|
||||
printk("[%s:%d] items: %d packet id: %u", __func__, __LINE__,
|
||||
items, pkt_id);
|
||||
|
||||
if (client_ctx->subscribe_data) {
|
||||
printk(" user_data: %s",
|
||||
(const char *)client_ctx->subscribe_data);
|
||||
}
|
||||
|
||||
printk("\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* The signature of this routine must match the unsubscribe callback declared at
|
||||
* the mqtt.h header.
|
||||
*/
|
||||
static int unsubscribe_cb(struct mqtt_ctx *mqtt_ctx, uint16_t pkt_id)
|
||||
{
|
||||
struct mqtt_client_ctx *client_ctx;
|
||||
|
||||
client_ctx = CONTAINER_OF(mqtt_ctx, struct mqtt_client_ctx, mqtt_ctx);
|
||||
|
||||
printk("[%s:%d] packet id: %u", __func__, __LINE__, pkt_id);
|
||||
|
||||
if (client_ctx->unsubscribe_data) {
|
||||
printk(" user_data: %s",
|
||||
(const char *)client_ctx->unsubscribe_data);
|
||||
}
|
||||
|
||||
printk("\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* The signature of this routine must match the malformed callback declared at
|
||||
* the mqtt.h header.
|
||||
*/
|
||||
static void malformed_cb(struct mqtt_ctx *mqtt_ctx, uint16_t pkt_type)
|
||||
{
|
||||
printk("[%s:%d] pkt_type: %u\n", __func__, __LINE__, pkt_type);
|
||||
}
|
||||
|
||||
static char *get_mqtt_topic(void)
|
||||
{
|
||||
return "sensors";
|
||||
}
|
||||
|
||||
#define RC_STR(rc) ((rc) == 0 ? "OK" : "ERROR")
|
||||
|
||||
#define PRINT_RESULT(func, rc) \
|
||||
printk("[%s:%d] %s: %d <%s>\n", __func__, __LINE__, \
|
||||
(func), rc, RC_STR(rc))
|
||||
|
||||
/* In this routine we block until the connected variable is 1 */
|
||||
static int try_to_connect(struct mqtt_client_ctx *client_ctx)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (i++ < APP_CONNECT_TRIES && !client_ctx->mqtt_ctx.connected) {
|
||||
int rc;
|
||||
|
||||
rc = mqtt_tx_connect(&client_ctx->mqtt_ctx,
|
||||
&client_ctx->connect_msg);
|
||||
k_sleep(APP_SLEEP_MSECS);
|
||||
if (rc != 0) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (client_ctx->mqtt_ctx.connected) {
|
||||
return TC_PASS;
|
||||
}
|
||||
|
||||
return TC_FAIL;
|
||||
}
|
||||
|
||||
static int init_network(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* The net_ctx variable must be ready BEFORE passing it to the MQTT API.
|
||||
*/
|
||||
rc = network_setup(&net_ctx, ZEPHYR_ADDR, SERVER_ADDR, SERVER_PORT);
|
||||
if (rc != 0) {
|
||||
goto exit_app;
|
||||
}
|
||||
|
||||
/* Set everything to 0 and later just assign the required fields. */
|
||||
memset(&client_ctx, 0x00, sizeof(client_ctx));
|
||||
|
||||
/* The network context is the only field that must be set BEFORE
|
||||
* calling the mqtt_init routine.
|
||||
*/
|
||||
client_ctx.mqtt_ctx.net_ctx = net_ctx;
|
||||
|
||||
/* connect, disconnect and malformed may be set to NULL */
|
||||
client_ctx.mqtt_ctx.connect = connect_cb;
|
||||
|
||||
client_ctx.mqtt_ctx.disconnect = disconnect_cb;
|
||||
|
||||
client_ctx.mqtt_ctx.malformed = malformed_cb;
|
||||
|
||||
client_ctx.mqtt_ctx.subscribe = subscriber_cb;
|
||||
|
||||
client_ctx.mqtt_ctx.unsubscribe = unsubscribe_cb;
|
||||
|
||||
client_ctx.mqtt_ctx.net_timeout = APP_TX_RX_TIMEOUT;
|
||||
|
||||
/* Publisher apps TX the MQTT PUBLISH msg */
|
||||
client_ctx.mqtt_ctx.publish_rx = publish_rx_cb;
|
||||
|
||||
rc = mqtt_init(&client_ctx.mqtt_ctx, MQTT_APP_SUBSCRIBER);
|
||||
if (rc != 0) {
|
||||
goto exit_app;
|
||||
}
|
||||
|
||||
/* The connect message will be sent to the MQTT server (broker).
|
||||
* If clean_session here is 0, the mqtt_ctx clean_session variable
|
||||
* will be set to 0 also. Please don't do that, set always to 1.
|
||||
* Clean session = 0 is not yet supported.
|
||||
*/
|
||||
client_ctx.connect_msg.client_id = MQTT_CLIENTID;
|
||||
client_ctx.connect_msg.client_id_len = strlen(MQTT_CLIENTID);
|
||||
client_ctx.connect_msg.clean_session = 1;
|
||||
|
||||
client_ctx.connect_data = "CONNECTED";
|
||||
client_ctx.disconnect_data = "DISCONNECTED";
|
||||
client_ctx.subscribe_data = "SUBSCRIBE";
|
||||
client_ctx.unsubscribe_data = "UNSUBSCRIBE";
|
||||
|
||||
return TC_PASS;
|
||||
|
||||
exit_app:
|
||||
net_context_put(net_ctx);
|
||||
|
||||
return TC_FAIL;
|
||||
}
|
||||
|
||||
static int test_connect(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = try_to_connect(&client_ctx);
|
||||
if (rc != 0) {
|
||||
return TC_FAIL;
|
||||
}
|
||||
|
||||
return TC_PASS;
|
||||
}
|
||||
|
||||
static int test_subscribe(void)
|
||||
{
|
||||
int rc;
|
||||
const char *topic_sub = get_mqtt_topic();
|
||||
uint16_t pkt_id_sub = sys_rand32_get();
|
||||
static enum mqtt_qos mqtt_qos_sub[1];
|
||||
|
||||
rc = mqtt_tx_subscribe(&client_ctx.mqtt_ctx, pkt_id_sub, 1,
|
||||
&topic_sub, mqtt_qos_sub);
|
||||
k_sleep(APP_SLEEP_MSECS);
|
||||
if (rc != 0) {
|
||||
return TC_FAIL;
|
||||
}
|
||||
|
||||
return TC_PASS;
|
||||
}
|
||||
|
||||
static int test_unsubscribe(void)
|
||||
{
|
||||
int rc;
|
||||
const char *topic_sub = get_mqtt_topic();
|
||||
uint16_t pkt_id_unsub = sys_rand32_get();
|
||||
|
||||
rc = mqtt_tx_unsubscribe(&client_ctx.mqtt_ctx, pkt_id_unsub,
|
||||
1, &topic_sub);
|
||||
k_sleep(APP_SLEEP_MSECS);
|
||||
if (rc != 0) {
|
||||
return TC_FAIL;
|
||||
}
|
||||
|
||||
return TC_PASS;
|
||||
}
|
||||
|
||||
static int test_disconnect(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = mqtt_tx_disconnect(&client_ctx.mqtt_ctx);
|
||||
if (rc != 0) {
|
||||
return TC_FAIL;
|
||||
}
|
||||
|
||||
return TC_PASS;
|
||||
}
|
||||
|
||||
static int set_addr(struct sockaddr *sock_addr, const char *addr, uint16_t port)
|
||||
{
|
||||
void *ptr;
|
||||
int rc;
|
||||
|
||||
#ifdef CONFIG_NET_IPV6
|
||||
net_sin6(sock_addr)->sin6_port = htons(port);
|
||||
sock_addr->family = AF_INET6;
|
||||
ptr = &(net_sin6(sock_addr)->sin6_addr);
|
||||
rc = net_addr_pton(AF_INET6, addr, ptr);
|
||||
#else
|
||||
net_sin(sock_addr)->sin_port = htons(port);
|
||||
sock_addr->family = AF_INET;
|
||||
ptr = &(net_sin(sock_addr)->sin_addr);
|
||||
rc = net_addr_pton(AF_INET, addr, ptr);
|
||||
#endif
|
||||
|
||||
if (rc) {
|
||||
printk("Invalid IP address: %s\n", addr);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int network_setup(struct net_context **net_ctx, const char *local_addr,
|
||||
const char *server_addr, uint16_t server_port)
|
||||
{
|
||||
#ifdef CONFIG_NET_IPV6
|
||||
socklen_t addr_len = sizeof(struct sockaddr_in6);
|
||||
sa_family_t family = AF_INET6;
|
||||
|
||||
#else
|
||||
socklen_t addr_len = sizeof(struct sockaddr_in);
|
||||
sa_family_t family = AF_INET;
|
||||
#endif
|
||||
struct sockaddr server_sock, local_sock;
|
||||
void *p;
|
||||
int rc;
|
||||
|
||||
rc = set_addr(&local_sock, local_addr, 0);
|
||||
if (rc) {
|
||||
printk("set_addr (local) error\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NET_IPV6
|
||||
p = net_if_ipv6_addr_add(net_if_get_default(),
|
||||
&net_sin6(&local_sock)->sin6_addr,
|
||||
NET_ADDR_MANUAL, 0);
|
||||
#else
|
||||
p = net_if_ipv4_addr_add(net_if_get_default(),
|
||||
&net_sin(&local_sock)->sin_addr,
|
||||
NET_ADDR_MANUAL, 0);
|
||||
#endif
|
||||
|
||||
if (!p) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rc = net_context_get(family, SOCK_STREAM, IPPROTO_TCP, net_ctx);
|
||||
if (rc) {
|
||||
printk("net_context_get error\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = net_context_bind(*net_ctx, &local_sock, addr_len);
|
||||
if (rc) {
|
||||
printk("net_context_bind error\n");
|
||||
goto lb_exit;
|
||||
}
|
||||
|
||||
rc = set_addr(&server_sock, server_addr, server_port);
|
||||
if (rc) {
|
||||
printk("set_addr (server) error\n");
|
||||
goto lb_exit;
|
||||
}
|
||||
|
||||
rc = net_context_connect(*net_ctx, &server_sock, addr_len, NULL,
|
||||
APP_SLEEP_MSECS, NULL);
|
||||
if (rc) {
|
||||
printk("net_context_connect error\n"
|
||||
"Is the server (broker) up and running?\n");
|
||||
goto lb_exit;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
lb_exit:
|
||||
net_context_put(*net_ctx);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void test_mqtt_init(void)
|
||||
{
|
||||
assert_true(init_network() == TC_PASS, NULL);
|
||||
}
|
||||
|
||||
void test_mqtt_connect(void)
|
||||
{
|
||||
assert_true(test_connect() == TC_PASS, NULL);
|
||||
}
|
||||
|
||||
void test_mqtt_subscribe(void)
|
||||
{
|
||||
assert_true(test_subscribe() == TC_PASS, NULL);
|
||||
}
|
||||
|
||||
void test_mqtt_unsubscribe(void)
|
||||
{
|
||||
assert_true(test_unsubscribe() == TC_PASS, NULL);
|
||||
}
|
||||
|
||||
void test_mqtt_disconnect(void)
|
||||
{
|
||||
assert_true(test_disconnect() == TC_PASS, NULL);
|
||||
}
|
4
tests/net/mqtt_subscriber/testcase.ini
Normal file
4
tests/net/mqtt_subscriber/testcase.ini
Normal file
|
@ -0,0 +1,4 @@
|
|||
[test]
|
||||
tags = net mqtt
|
||||
build_only = true
|
||||
platform_whitelist = frdm_k64f qemu_x86
|
Loading…
Add table
Add a link
Reference in a new issue