Files
mqtt5/test/unit/test/serialization.cpp

333 lines
12 KiB
C++
Raw Normal View History

#include <boost/test/unit_test.hpp>
#include <async_mqtt5/types.hpp>
#include <async_mqtt5/impl/codecs/message_decoders.hpp>
#include <async_mqtt5/impl/codecs/message_encoders.hpp>
using namespace async_mqtt5;
using byte_citer = detail::byte_citer;
BOOST_AUTO_TEST_SUITE(serialization/*, *boost::unit_test::disabled()*/)
BOOST_AUTO_TEST_CASE(test_connect) {
// testing variables
std::string_view client_id = "async_mqtt_client_id";
std::string_view uname = "username";
std::optional<std::string_view> password = std::nullopt;
uint16_t keep_alive = 60;
bool clean_start = true;
std::string will_topic = "will_topic";
std::string will_message = "will_message";
connect_props cprops;
cprops[prop::session_expiry_interval] = 29;
cprops[prop::user_property].emplace_back("connect user prop");
will w{ will_topic, will_message };
w[prop::content_type] = "will content type";
w[prop::response_topic] = "will response topic";
w[prop::user_property].emplace_back("first user prop");
w[prop::user_property].emplace_back("second user prop");
std::optional<will> will_opt { std::move(w) };
auto msg = encoders::encode_connect(
client_id, uname, password, keep_alive, clean_start, cprops, will_opt
);
byte_citer it = msg.cbegin(), last = msg.cend();
auto header = decoders::decode_fixed_header(it, last);
BOOST_CHECK_MESSAGE(header, "Parsing CONNECT fixed header failed.");
const auto& [control_byte, remain_length] = *header;
auto rv = decoders::decode_connect(remain_length, it);
BOOST_CHECK_MESSAGE(rv, "Parsing CONNECT failed.");
const auto& [client_id_, uname_, password_, keep_alive_, clean_start_, _, w_] = *rv;
BOOST_CHECK_EQUAL(client_id_, client_id);
BOOST_CHECK(uname_);
BOOST_CHECK_EQUAL(*uname_, uname);
BOOST_CHECK(password_ == password);
BOOST_CHECK_EQUAL(keep_alive_, keep_alive);
BOOST_CHECK_EQUAL(clean_start_, clean_start);
BOOST_CHECK(w_);
BOOST_CHECK_EQUAL((*w_).topic(), will_topic);
BOOST_CHECK_EQUAL((*w_).message(), will_message);
}
BOOST_AUTO_TEST_CASE(test_connack) {
// testing variables
uint8_t session_present = 1;
uint8_t reason_code = 0x89;
uint8_t wildcard_sub = 1;
connack_props cap;
cap[prop::wildcard_subscription_available] = wildcard_sub;
auto msg = encoders::encode_connack(session_present, reason_code, cap);
byte_citer it = msg.cbegin(), last = msg.cend();
auto header = decoders::decode_fixed_header(it, last);
BOOST_CHECK_MESSAGE(header, "Parsing CONNACK fixed header failed.");
const auto& [control_byte, remain_length] = *header;
auto rv = decoders::decode_connack(remain_length, it);
BOOST_CHECK_MESSAGE(rv, "Parsing CONNACK failed.");
const auto& [session_present_, reason_code_, caprops] = *rv;
BOOST_CHECK_EQUAL(session_present_, session_present);
BOOST_CHECK_EQUAL(reason_code_, reason_code);
BOOST_CHECK_EQUAL(*caprops[prop::wildcard_subscription_available], wildcard_sub);
}
BOOST_AUTO_TEST_CASE(test_publish) {
// testing variables
uint16_t packet_id = 31283;
std::string_view topic = "publish_topic";
std::string_view payload = "This is some payload I am publishing!";
uint8_t message_expiry = 70;
std::string content_type = "application/octet-stream";
std::string publish_prop_1 = "first publish prop";
std::string publish_prop_2 = "second publish prop";
publish_props pp;
pp[prop::message_expiry_interval] = message_expiry;
pp[prop::content_type] = content_type;
pp[prop::user_property].emplace_back(publish_prop_1);
pp[prop::user_property].emplace_back(publish_prop_2);
auto msg = encoders::encode_publish(
packet_id, topic, payload,
qos_e::at_least_once, retain_e::yes, dup_e::no,
pp
);
byte_citer it = msg.cbegin(), last = msg.cend();
auto header = decoders::decode_fixed_header(it, last);
BOOST_CHECK_MESSAGE(header, "Parsing PUBLISH fixed header failed.");
const auto& [control_byte, remain_length] = *header;
auto rv = decoders::decode_publish(control_byte, remain_length, it);
BOOST_CHECK_MESSAGE(rv, "Parsing PUBLISH failed.");
const auto& [topic_, packet_id_, flags, pprops, payload_] = *rv;
BOOST_CHECK(packet_id);
BOOST_CHECK_EQUAL(*packet_id_, packet_id);
BOOST_CHECK_EQUAL(topic_, topic);
BOOST_CHECK_EQUAL(payload_, payload);
BOOST_CHECK_EQUAL(*pprops[prop::message_expiry_interval], message_expiry);
BOOST_CHECK_EQUAL(*pprops[prop::content_type], content_type);
BOOST_CHECK_EQUAL(pprops[prop::user_property][0], publish_prop_1);
BOOST_CHECK_EQUAL(pprops[prop::user_property][1], publish_prop_2);
}
BOOST_AUTO_TEST_CASE(test_large_publish) {
// testing variables
uint16_t packet_id = 40001;
std::string_view topic = "publish_topic";
std::string large_payload(1'000'000, 'a');
auto msg = encoders::encode_publish(
packet_id, topic, large_payload,
qos_e::at_least_once, retain_e::yes, dup_e::no,
publish_props{}
);
byte_citer it = msg.cbegin(), last = msg.cend();
auto header = decoders::decode_fixed_header(it, last);
BOOST_CHECK_MESSAGE(header, "Parsing PUBLISH fixed header failed.");
const auto& [control_byte, remain_length] = *header;
auto rv = decoders::decode_publish(control_byte, remain_length, it);
BOOST_CHECK_MESSAGE(rv, "Parsing PUBLISH failed.");
const auto& [topic_, packet_id_, flags, pprops, payload_] = *rv;
BOOST_CHECK(packet_id);
BOOST_CHECK_EQUAL(*packet_id_, packet_id);
BOOST_CHECK_EQUAL(topic_, topic);
BOOST_CHECK_EQUAL(payload_, large_payload);
}
BOOST_AUTO_TEST_CASE(test_puback) {
// testing variables
uint16_t packet_id = 9199;
uint8_t reason_code = 0x93;
std::string reason_string = "PUBACK reason string";
std::string user_prop = "PUBACK user prop";
puback_props pp;
pp[prop::reason_string] = reason_string;
pp[prop::user_property].emplace_back(user_prop);
auto msg = encoders::encode_puback(packet_id, reason_code, pp);
byte_citer it = msg.cbegin(), last = msg.cend();
auto header = decoders::decode_fixed_header(it, last);
BOOST_CHECK_MESSAGE(header, "Parsing PUBACK fixed header failed.");
auto packet_id_ = decoders::decode_packet_id(it);
BOOST_CHECK(packet_id);
BOOST_CHECK_EQUAL(*packet_id_, packet_id);
const auto& [control_byte, remain_length] = *header;
auto rv = decoders::decode_puback(remain_length - sizeof(uint16_t), it);
BOOST_CHECK_MESSAGE(rv, "Parsing PUBACK failed.");
const auto& [reason_code_, pprops] = *rv;
BOOST_CHECK_EQUAL(reason_code_, reason_code);
BOOST_CHECK_EQUAL(*pprops[prop::reason_string], reason_string);
BOOST_CHECK_EQUAL(pprops[prop::user_property][0], user_prop);
}
BOOST_AUTO_TEST_CASE(test_subscribe) {
//testing variables
uint32_t sub_id = 1'234'567;
subscribe_props sp;
sp[prop::subscription_identifier] = sub_id;
std::vector<subscribe_topic> filters {
{ "subscribe topic", { qos_e::at_least_once } }
};
uint16_t packet_id = 65535;
auto msg = encoders::encode_subscribe(packet_id, filters, sp);
byte_citer it = msg.cbegin(), last = msg.cend();
auto header = decoders::decode_fixed_header(it, last);
BOOST_CHECK_MESSAGE(header, "Parsing SUBSCRIBE fixed header failed.");
const auto& [control_byte, remain_length] = *header;
auto packet_id_ = decoders::decode_packet_id(it);
BOOST_CHECK(packet_id);
BOOST_CHECK_EQUAL(*packet_id_, packet_id);
auto rv = decoders::decode_subscribe(remain_length - sizeof(uint16_t), it);
BOOST_CHECK_MESSAGE(rv, "Parsing SUBSCRIBE failed.");
const auto& [props_, filters_] = *rv;
BOOST_CHECK_EQUAL(std::get<0>(filters_[0]), filters[0].topic_filter);
BOOST_CHECK_EQUAL(*props_[prop::subscription_identifier], sub_id);
//TODO: sub options
}
BOOST_AUTO_TEST_CASE(test_suback) {
//testing variables
suback_props sp;
std::vector<uint8_t> reason_codes { 48, 28 };
uint16_t packet_id = 142;
auto msg = encoders::encode_suback(packet_id, reason_codes, sp);
byte_citer it = msg.cbegin(), last = msg.cend();
auto header = decoders::decode_fixed_header(it, last);
BOOST_CHECK_MESSAGE(header, "Parsing SUBACK fixed header failed.");
const auto& [control_byte, remain_length] = *header;
auto packet_id_ = decoders::decode_packet_id(it);
BOOST_CHECK(packet_id);
BOOST_CHECK_EQUAL(*packet_id_, packet_id);
auto rv = decoders::decode_suback(remain_length - sizeof(uint16_t), it);
BOOST_CHECK_MESSAGE(rv, "Parsing SUBACK failed.");
const auto& [sp_, reason_codes_] = *rv;
BOOST_CHECK(reason_codes_ == reason_codes);
}
BOOST_AUTO_TEST_CASE(test_unsubscribe) {
// testing variables
unsubscribe_props sp;
std::vector<std::string> topics { "first topic", "second/topic" };
uint16_t packet_id = 14423;
auto msg = encoders::encode_unsubscribe(packet_id, topics, sp);
byte_citer it = msg.cbegin(), last = msg.cend();
auto header = decoders::decode_fixed_header(it, last);
BOOST_CHECK_MESSAGE(header, "Parsing UNSUBSCRIBE fixed header failed.");
const auto& [control_byte, remain_length] = *header;
auto packet_id_ = decoders::decode_packet_id(it);
BOOST_CHECK(packet_id);
BOOST_CHECK_EQUAL(*packet_id_, packet_id);
auto rv = decoders::decode_unsubscribe(remain_length - sizeof(uint16_t), it);
BOOST_CHECK_MESSAGE(rv, "Parsing UNSUBSCRIBE failed.");
const auto& [props_, topics_] = *rv;
BOOST_CHECK(topics_ == topics);
}
BOOST_AUTO_TEST_CASE(test_unsuback) {
// testing variables
std::string reason_string = "some unsuback reason string";
unsuback_props sp;
sp[prop::reason_string] = reason_string;
std::vector<uint8_t> reason_codes { 48, 28 };
uint16_t packet_id = 42;
auto msg = encoders::encode_unsuback(packet_id, reason_codes, sp);
byte_citer it = msg.cbegin(), last = msg.cend();
auto header = decoders::decode_fixed_header(it, last);
BOOST_CHECK_MESSAGE(header, "Parsing UNSUBACK fixed header failed.");
const auto& [control_byte, remain_length] = *header;
auto packet_id_ = decoders::decode_packet_id(it);
BOOST_CHECK(packet_id);
BOOST_CHECK_EQUAL(*packet_id_, packet_id);
auto rv = decoders::decode_unsuback(remain_length - sizeof(uint16_t), it);
BOOST_CHECK_MESSAGE(header, "Parsing UNSUBACK failed.");
const auto& [props_, reason_codes_] = *rv;
BOOST_CHECK(reason_codes_ == reason_codes);
BOOST_CHECK_EQUAL(*props_[prop::reason_string], reason_string);
}
BOOST_AUTO_TEST_CASE(test_disconnect) {
// testing variables
uint8_t reason_code = 0;
std::string user_property = "DISCONNECT user property";
disconnect_props sp;
sp[prop::user_property].emplace_back(user_property);
auto msg = encoders::encode_disconnect(reason_code, sp);
byte_citer it = msg.cbegin(), last = msg.cend();
auto header = decoders::decode_fixed_header(it, last);
BOOST_CHECK_MESSAGE(header, "Parsing DISCONNECT fixed header failed.");
const auto& [control_byte, remain_length] = *header;
auto rv = decoders::decode_disconnect(remain_length, it);
BOOST_CHECK_MESSAGE(header, "Parsing DISCONNECT failed.");
const auto& [reason_code_, props_] = *rv;
BOOST_CHECK_EQUAL(reason_code_, reason_code);
BOOST_CHECK_EQUAL(props_[prop::user_property][0], user_property);
}
BOOST_AUTO_TEST_CASE(test_auth) {
// testing variables
uint8_t reason_code = 0x18;
std::string reason_string = "AUTH reason";
std::string user_property = "AUTH user propety";
auth_props sp;
sp[prop::reason_string] = reason_string;
sp[prop::user_property].emplace_back(user_property);
auto msg = encoders::encode_auth(reason_code, sp);
byte_citer it = msg.cbegin(), last = msg.cend();
auto header = decoders::decode_fixed_header(it, last);
BOOST_CHECK_MESSAGE(header, "Parsing AUTH fixed header failed.");
const auto& [control_byte, remain_length] = *header;
auto rv = decoders::decode_auth(remain_length, it);
BOOST_CHECK_MESSAGE(rv, "Parsing AUTH failed.");
const auto& [reason_code_, props_] = *rv;
BOOST_CHECK_EQUAL(reason_code_, reason_code);
BOOST_CHECK_EQUAL(*props_[prop::reason_string], reason_string);
BOOST_CHECK_EQUAL(props_[prop::user_property][0], user_property);
}
BOOST_AUTO_TEST_SUITE_END()