Separate tests into unit & integration

Summary:
- Separate tests into unit & integration

- Update paths in workflows

- Cut test execution time

Reviewers: ivica

Reviewed By: ivica

Subscribers: miljen, iljazovic

Differential Revision: https://repo.mireo.local/D27374
This commit is contained in:
Korina Šimičević
2024-01-16 10:25:05 +01:00
parent e3eb408c98
commit 2f6751d162
27 changed files with 884 additions and 855 deletions

View File

@ -96,15 +96,15 @@ jobs:
- name: Build tests
run: |
cmake -S test\\unit -B test\\unit\\build -A ${{ matrix.architecture }} ^
cmake -S test -B test\\build -A ${{ matrix.architecture }} ^
-DCMAKE_CXX_FLAGS="${{ env.CXXFLAGS }}" -DCMAKE_EXE_LINKER_FLAGS="${{ env.LDFLAGS }}" ^
-DCMAKE_CXX_STANDARD="${{ matrix.cxxstd }}" -DCMAKE_BUILD_TYPE="${{ matrix.build-type }}" ^
-DBoost_INCLUDE_DIR="${{ github.workspace }}\\boost_${{ env.BOOST_DIR_VER_NAME }}"
cmake --build test\\unit\\build -j 4
cmake --build test\\build -j 4
- name: Run tests
run: |
.\\test\\unit\\build\\${{ matrix.build-type }}\\mqtt-test.exe --log_level=test_suite
.\\test\\build\\${{ matrix.build-type }}\\mqtt-test.exe --log_level=test_suite
posix:
name: "${{ matrix.toolset }} std=c++${{ matrix.cxxstd }} ${{ matrix.build-type }}"
@ -193,11 +193,11 @@ jobs:
- name: Build tests
run: |
cmake -S test/unit -B test/unit/build \
cmake -S test -B test/build \
-DCMAKE_CXX_COMPILER="${{ matrix.compiler }}" -DCMAKE_CXX_FLAGS="${{ env.CXXFLAGS }}" \
-DCMAKE_CXX_STANDARD="${{ matrix.cxxstd }}" -DCMAKE_EXE_LINKER_FLAGS="${{ env.LDFLAGS }}" -DCMAKE_BUILD_TYPE="${{ matrix.build-type }}" \
-DBoost_INCLUDE_DIR="/usr/local/boost_${{ env.BOOST_DIR_VER_NAME }}"
cmake --build test/unit/build -j 4
cmake --build test/build -j 4
- name: Run tests
run: ./test/unit/build/mqtt-test --log_level=test_suite
run: ./test/build/mqtt-test --log_level=test_suite

View File

@ -60,17 +60,17 @@ jobs:
- name: Build tests
run: |
cmake -S test/unit -B test/unit/build -DCMAKE_CXX_COMPILER="${{ matrix.compiler }}" -DCMAKE_CXX_FLAGS="${{ matrix.cxxflags }}" \
cmake -S test -B test/build -DCMAKE_CXX_COMPILER="${{ matrix.compiler }}" -DCMAKE_CXX_FLAGS="${{ matrix.cxxflags }}" \
-DCMAKE_EXE_LINKER_FLAGS="${{ matrix.ldflags }}" -DCMAKE_BUILD_TYPE="Coverage" \
-DBoost_INCLUDE_DIR="/usr/local/boost_${{ env.BOOST_DIR_VER_NAME }}"
cmake --build test/unit/build -j 4
cmake --build test/build -j 4
- name: Run tests
run: ./test/unit/build/mqtt-test --log_level=test_suite
run: ./test/build/mqtt-test --log_level=test_suite
- name: Generate Coverage Report
run: |
lcov --capture --output-file coverage.info --directory test/unit/build
lcov --capture --output-file coverage.info --directory test/build
lcov --remove coverage.info '/usr/include/*' --output-file coverage.info
lcov --remove coverage.info '**/test/*' --output-file coverage.info
lcov --remove coverage.info '**/boost/*' --output-file coverage.info

23
test/CMakeLists.txt Normal file
View File

@ -0,0 +1,23 @@
cmake_minimum_required(VERSION 3.15)
project(async-mqtt5-tests CXX)
include(../cmake/project-is-top-level.cmake)
if(PROJECT_IS_TOP_LEVEL)
find_package(async-mqtt5 REQUIRED)
enable_testing()
endif()
file(GLOB integration_tests "integration/*.cpp")
file(GLOB unit_tests "unit/*.cpp")
add_executable(mqtt-test src/run_tests.cpp ${integration_tests} ${unit_tests})
target_include_directories(mqtt-test PRIVATE include)
target_compile_definitions(mqtt-test PRIVATE BOOST_TEST_NO_MAIN=1)
find_package(OpenSSL REQUIRED)
target_link_libraries(mqtt-test PRIVATE Async::MQTT5 OpenSSL::SSL)
add_test(NAME mqtt-test COMMAND mqtt-test)

View File

@ -288,61 +288,4 @@ private:
} // end namespace async_mqtt5::test
// Funs temporarily moved out of network service
//
//void process_packet(const std::string& packet) {
// using enum control_code_e;
//
// auto code = extract_code(uint8_t(*packet.data()));
// if (code == connack)
// determine_network_properties(packet);
// else if (code == puback || code == pubcomp)
// _num_outgoing_publishes--;
//}
//
//void determine_network_properties(const std::string& connack) {
// auto begin = connack.cbegin() + 1 /* fixed header */;
// auto _ = decoders::type_parse(begin, connack.cend(), decoders::basic::varint_);
// auto rv = decoders::decode_connack(connack.size(), begin);
// const auto& [session_present, reason_code, ca_props] = *rv;
//
// if (ca_props[prop::receive_maximum])
// _max_receive = *ca_props[prop::receive_maximum];
// else
// _max_receive = MAX_LIMIT;
//}
//
//void count_outgoing_publishes(
// const std::vector<std::string>& packets
//) {
// for (const auto& packet : packets) {
// auto code = extract_code(uint8_t(*packet.data()));
// if (code == control_code_e::publish) {
// auto flags = *packet.data() & 0b00001111;
// auto qos = extract_qos(flags);
//
// if (qos != qos_e::at_most_once)
// _num_outgoing_publishes++;
//
// BOOST_ASIO_CHECK_MESSAGE(
// _num_outgoing_publishes <= _max_receive,
// "There are more outgoing PUBLISH packets than\
// it is allowed by the Maxmimum Receive Limit!"
// );
// }
// }
//}
// write_to_network stuff
//auto packets = to_packets(buffers);
//count_outgoing_publishes(packets);
//// TODO: this is just for debug right now
//if (!write_ec)
// for (const auto& packet : packets)
// test::log(to_readable_packet(packet, write_ec, false));
#endif // ASYNC_MQTT5_TEST_TEST_BROKER_HPP

View File

@ -190,8 +190,7 @@ BOOST_AUTO_TEST_CASE(rerunning_the_client) {
using client_type = mqtt_client<stream_type>;
client_type c(ioc, "");
c.brokers("broker.hivemq.com", 1883)
.credentials("test-cli", "", "")
c.brokers("broker.hivemq.com,broker.hivemq.com", 1883) // to avoid reconnect backoff
.run();
auto [ec] = co_await c.async_publish<qos_e::at_most_once>(

View File

@ -149,8 +149,7 @@ BOOST_AUTO_TEST_CASE(websocket_tcp_client_check) {
using client_type = mqtt_client<stream_type>;
client_type c(ioc, "");
c.credentials("websocket-tcp-tester", "", "")
.brokers("broker.hivemq.com/mqtt", 8000)
c.brokers("broker.hivemq.com/mqtt", 8000)
.will({ "test/mqtt-test", "Client disconnected!", qos_e::at_least_once })
.run();
@ -186,8 +185,7 @@ BOOST_AUTO_TEST_CASE(openssl_tls_client_check) {
using client_type = mqtt_client<stream_type, decltype(tls_context)>;
client_type c(ioc, "", std::move(tls_context));
c.credentials("openssl-tls-tester", "", "")
.brokers("broker.hivemq.com", 8883)
c.brokers("broker.hivemq.com", 8883)
.will({ "test/mqtt-test", "Client disconnected!", qos_e::at_least_once })
.run();
@ -225,8 +223,7 @@ BOOST_AUTO_TEST_CASE(websocket_tls_client_check) {
using client_type = mqtt_client<stream_type, decltype(tls_context)>;
client_type c(ioc, "", std::move(tls_context));
c.credentials("websocket-tls-tester", "", "")
.brokers("broker.hivemq.com/mqtt", 8884)
c.brokers("broker.hivemq.com/mqtt", 8884)
.will({ "test/mqtt-test", "Client disconnected!", qos_e::at_least_once })
.run();

View File

@ -1,193 +1,14 @@
#include <boost/test/unit_test.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/steady_timer.hpp>
#include <async_mqtt5/mqtt_client.hpp>
#include <async_mqtt5/impl/publish_rec_op.hpp>
#include "test_common/message_exchange.hpp"
#include "test_common/test_service.hpp"
#include "test_common/test_stream.hpp"
using namespace async_mqtt5;
BOOST_AUTO_TEST_SUITE(publish_rec_op/*, *boost::unit_test::disabled()*/)
template <qos_e qos>
void receive_publish() {
using test::after;
using std::chrono_literals::operator ""ms;
constexpr int expected_handlers_called = 1;
int handlers_called = 0;
std::string topic = "topic";
std::string payload = "payload";
// packets
auto connect = encoders::encode_connect(
"", std::nullopt, std::nullopt, 10, false, {}, std::nullopt
);
auto connack = encoders::encode_connack(
false, reason_codes::success.value(), {}
);
auto publish = encoders::encode_publish(
1, topic, payload, qos, retain_e::no, dup_e::no, {}
);
auto puback = encoders::encode_puback(1, reason_codes::success.value(), {});
auto pubrec = encoders::encode_pubrec(1, reason_codes::success.value(), {});
auto pubrel = encoders::encode_pubrel(1, reason_codes::success.value(), {});
auto pubcomp = encoders::encode_pubcomp(1, reason_codes::success.value(), {});
test::msg_exchange broker_side;
error_code success {};
broker_side
.expect(connect)
.complete_with(success, after(0ms))
.reply_with(connack, after(0ms))
.send(publish, after(10ms));
if constexpr (qos == qos_e::at_least_once) {
broker_side
.expect(puback)
.complete_with(success, after(1ms));
} else if constexpr (qos == qos_e::exactly_once) {
broker_side
.expect(pubrec)
.complete_with(success, after(1ms))
.reply_with(pubrel, after(2ms))
.expect(pubcomp)
.complete_with(success, after(1ms));
}
asio::io_context ioc;
auto executor = ioc.get_executor();
auto& broker = asio::make_service<test::test_broker>(
ioc, executor, std::move(broker_side)
);
using client_type = mqtt_client<test::test_stream>;
client_type c(executor, "");
c.brokers("127.0.0.1")
.run();
c.async_receive(
[&](
error_code ec,
std::string rec_topic, std::string rec_payload,
publish_props
) {
++handlers_called;
BOOST_CHECK_MESSAGE(!ec, ec.message());
BOOST_CHECK_EQUAL(topic, rec_topic);
BOOST_CHECK_EQUAL(payload, rec_payload);
c.cancel();
}
);
ioc.run_for(std::chrono::seconds(10));
BOOST_CHECK_EQUAL(handlers_called, expected_handlers_called);
BOOST_CHECK(broker.received_all_expected());
}
BOOST_AUTO_TEST_CASE(receive_publish_qos0) {
receive_publish<qos_e::at_most_once>();
}
BOOST_AUTO_TEST_CASE(receive_publish_qos1) {
receive_publish<qos_e::at_least_once>();
}
BOOST_AUTO_TEST_CASE(receive_publish_qos2) {
receive_publish<qos_e::exactly_once>();
}
BOOST_AUTO_TEST_CASE(test_reconnect) {
using test::after;
using std::chrono_literals::operator ""ms;
constexpr int expected_handlers_called = 1;
int handlers_called = 0;
std::string topic = "topic";
std::string payload = "payload";
// packets
auto connect = encoders::encode_connect(
"", std::nullopt, std::nullopt, 10, false, {}, std::nullopt
);
auto connack = encoders::encode_connack(
false, reason_codes::success.value(), {}
);
auto publish = encoders::encode_publish(
1, topic, payload, qos_e::exactly_once, retain_e::yes, dup_e::no, {}
);
auto pubrec = encoders::encode_pubrec(1, reason_codes::success.value(), {});
auto pubrel = encoders::encode_pubrel(1, reason_codes::success.value(), {});
auto pubcomp = encoders::encode_pubcomp(1, reason_codes::success.value(), {});
test::msg_exchange broker_side;
error_code success {};
error_code fail = asio::error::not_connected;
broker_side
.expect(connect)
.complete_with(success, after(0ms))
.reply_with(connack, after(0ms))
.send(publish, after(10ms))
.expect(pubrec)
.complete_with(success, after(1ms))
.reply_with(pubrel, after(2ms))
.expect(pubcomp)
.complete_with(fail, after(1ms))
.expect(connect)
.complete_with(success, after(0ms))
.reply_with(connack, after(0ms))
.send(pubrel, after(10ms))
.expect(pubcomp)
.complete_with(success, after(1ms));
asio::io_context ioc;
auto executor = ioc.get_executor();
auto& broker = asio::make_service<test::test_broker>(
ioc, executor, std::move(broker_side)
);
using client_type = mqtt_client<test::test_stream>;
client_type c(executor, "");
c.brokers("127.0.0.1")
.run();
c.async_receive(
[&](
error_code ec,
std::string rec_topic, std::string rec_payload,
publish_props
) {
++handlers_called;
BOOST_CHECK_MESSAGE(!ec, ec.message());
BOOST_CHECK_EQUAL(topic, rec_topic);
BOOST_CHECK_EQUAL(payload, rec_payload);
c.cancel();
}
);
ioc.run_for(std::chrono::seconds(10));
BOOST_CHECK_EQUAL(handlers_called, expected_handlers_called);
BOOST_CHECK(broker.received_all_expected());
}
BOOST_AUTO_TEST_SUITE(malformed_packet/* , *boost::unit_test::disabled()*/)
BOOST_AUTO_TEST_CASE(test_malformed_publish) {
using test::after;
@ -230,11 +51,11 @@ BOOST_AUTO_TEST_CASE(test_malformed_publish) {
using client_type = mqtt_client<test::test_stream>;
client_type c(executor, "");
c.brokers("127.0.0.1")
c.brokers("127.0.0.1,127.0.0.1") // to avoid reconnect backoff
.run();
asio::steady_timer timer(c.get_executor());
timer.expires_after(std::chrono::seconds(4));
timer.expires_after(std::chrono::seconds(2));
timer.async_wait([&](auto) { c.cancel(); });
ioc.run();
@ -303,7 +124,7 @@ BOOST_AUTO_TEST_CASE(test_malformed_pubrel, *boost::unit_test::disabled()) {
using client_type = mqtt_client<test::test_stream>;
client_type c(executor, "");
c.brokers("127.0.0.1")
c.brokers("127.0.0.1,127.0.0.1") // to avoid reconnect backoff
.run();
c.async_receive(
@ -322,7 +143,180 @@ BOOST_AUTO_TEST_CASE(test_malformed_pubrel, *boost::unit_test::disabled()) {
}
);
ioc.run_for(std::chrono::seconds(10));
ioc.run_for(std::chrono::seconds(2));
BOOST_CHECK_EQUAL(handlers_called, expected_handlers_called);
BOOST_CHECK(broker.received_all_expected());
}
BOOST_AUTO_TEST_CASE(malformed_puback) {
using test::after;
using std::chrono_literals::operator ""ms;
constexpr int expected_handlers_called = 1;
int handlers_called = 0;
// packets
auto connect = encoders::encode_connect(
"", std::nullopt, std::nullopt, 10, false, {}, std::nullopt
);
auto connack = encoders::encode_connack(false, reason_codes::success.value(), {});
auto publish = encoders::encode_publish(
1, "t", "p", qos_e::at_least_once, retain_e::no, dup_e::no, {}
);
auto malformed_puback = encoders::encode_puback(1, uint8_t(0x04), {});
auto publish_dup = encoders::encode_publish(
1, "t", "p", qos_e::at_least_once, retain_e::no, dup_e::yes, {}
);
auto puback = encoders::encode_puback(1, reason_codes::success.value(), {});
disconnect_props dc_props;
dc_props[prop::reason_string] = "Malformed PUBACK: invalid Reason Code";
auto disconnect = encoders::encode_disconnect(
reason_codes::malformed_packet.value(), dc_props
);
test::msg_exchange broker_side;
error_code success {};
broker_side
.expect(connect)
.complete_with(success, after(0ms))
.reply_with(connack, after(0ms))
.expect(publish)
.complete_with(success, after(0ms))
.reply_with(malformed_puback, after(0ms))
.expect(disconnect)
.complete_with(success, after(0ms))
.expect(connect)
.complete_with(success, after(0ms))
.reply_with(connack, after(0ms))
.expect(publish_dup)
.complete_with(success, after(0ms))
.reply_with(puback, after(0ms));
asio::io_context ioc;
auto executor = ioc.get_executor();
auto& broker = asio::make_service<test::test_broker>(
ioc, executor, std::move(broker_side)
);
using client_type = mqtt_client<test::test_stream>;
client_type c(executor, "");
c.brokers("127.0.0.1,127.0.0.1") // to avoid reconnect backoff
.run();
c.async_publish<qos_e::at_least_once>(
"t", "p", retain_e::no, publish_props {},
[&](error_code ec, reason_code rc, auto) {
++handlers_called;
BOOST_CHECK(!ec);
BOOST_CHECK_EQUAL(rc, reason_codes::success);
c.cancel();
}
);
ioc.run_for(std::chrono::seconds(2));
BOOST_CHECK_EQUAL(handlers_called, expected_handlers_called);
BOOST_CHECK(broker.received_all_expected());
}
BOOST_AUTO_TEST_CASE(malformed_pubrec_pubcomp) {
using test::after;
using std::chrono_literals::operator ""ms;
constexpr int expected_handlers_called = 1;
int handlers_called = 0;
// packets
auto connect = encoders::encode_connect(
"", std::nullopt, std::nullopt, 10, false, {}, std::nullopt
);
auto connack = encoders::encode_connack(false, reason_codes::success.value(), {});
auto publish = encoders::encode_publish(
1, "t", "p", qos_e::exactly_once, retain_e::no, dup_e::no, {}
);
auto malformed_pubrec = encoders::encode_pubrec(1, uint8_t(0x04), {});
auto publish_dup = encoders::encode_publish(
1, "t", "p", qos_e::exactly_once, retain_e::no, dup_e::yes, {}
);
auto pubrec = encoders::encode_pubrec(1, reason_codes::success.value(), {});
auto pubrel = encoders::encode_pubrel(1, reason_codes::success.value(), {});
auto malformed_pubcomp = encoders::encode_pubcomp(1, uint8_t(0x04), {});
auto pubcomp = encoders::encode_pubcomp(1, reason_codes::success.value(), {});
disconnect_props dc_props;
dc_props[prop::reason_string] = "Malformed PUBREC: invalid Reason Code";
auto disconnect_on_pubrec = encoders::encode_disconnect(
reason_codes::malformed_packet.value(), dc_props
);
dc_props[prop::reason_string] = "Malformed PUBCOMP: invalid Reason Code";
auto disconnect_on_pubcomp = encoders::encode_disconnect(
reason_codes::malformed_packet.value(), dc_props
);
test::msg_exchange broker_side;
error_code success {};
broker_side
.expect(connect)
.complete_with(success, after(0ms))
.reply_with(connack, after(0ms))
.expect(publish)
.complete_with(success, after(0ms))
.reply_with(malformed_pubrec, after(0ms))
.expect(disconnect_on_pubrec)
.complete_with(success, after(0ms))
.expect(connect)
.complete_with(success, after(0ms))
.reply_with(connack, after(0ms))
.expect(publish_dup)
.complete_with(success, after(0ms))
.reply_with(pubrec, after(0ms))
.expect(pubrel)
.complete_with(success, after(0ms))
.reply_with(malformed_pubcomp, after(0ms))
.expect(disconnect_on_pubcomp)
.complete_with(success, after(0ms))
.expect(connect)
.complete_with(success, after(0ms))
.reply_with(connack, after(0ms))
.expect(pubrel)
.complete_with(success, after(0ms))
.reply_with(pubcomp, after(0ms));
asio::io_context ioc;
auto executor = ioc.get_executor();
auto& broker = asio::make_service<test::test_broker>(
ioc, executor, std::move(broker_side)
);
using client_type = mqtt_client<test::test_stream>;
client_type c(executor, "");
c.brokers("127.0.0.1,127.0.0.1") // to avoid reconnect backoff
.run();
c.async_publish<qos_e::exactly_once>(
"t", "p", retain_e::no, publish_props {},
[&](error_code ec, reason_code rc, auto) {
++handlers_called;
BOOST_CHECK(!ec);
BOOST_CHECK_EQUAL(rc, reason_codes::success);
c.cancel();
}
);
ioc.run_for(std::chrono::seconds(6));
BOOST_CHECK_EQUAL(handlers_called, expected_handlers_called);
BOOST_CHECK(broker.received_all_expected());
}

View File

@ -0,0 +1,190 @@
#include <boost/test/unit_test.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/steady_timer.hpp>
#include <async_mqtt5/mqtt_client.hpp>
#include "test_common/message_exchange.hpp"
#include "test_common/test_service.hpp"
#include "test_common/test_stream.hpp"
using namespace async_mqtt5;
BOOST_AUTO_TEST_SUITE(publish_receive/*, *boost::unit_test::disabled()*/)
template <qos_e qos>
void receive_publish() {
using test::after;
using std::chrono_literals::operator ""ms;
constexpr int expected_handlers_called = 1;
int handlers_called = 0;
std::string topic = "topic";
std::string payload = "payload";
// packets
auto connect = encoders::encode_connect(
"", std::nullopt, std::nullopt, 10, false, {}, std::nullopt
);
auto connack = encoders::encode_connack(
false, reason_codes::success.value(), {}
);
auto publish = encoders::encode_publish(
1, topic, payload, qos, retain_e::no, dup_e::no, {}
);
auto puback = encoders::encode_puback(1, reason_codes::success.value(), {});
auto pubrec = encoders::encode_pubrec(1, reason_codes::success.value(), {});
auto pubrel = encoders::encode_pubrel(1, reason_codes::success.value(), {});
auto pubcomp = encoders::encode_pubcomp(1, reason_codes::success.value(), {});
test::msg_exchange broker_side;
error_code success {};
broker_side
.expect(connect)
.complete_with(success, after(0ms))
.reply_with(connack, after(0ms))
.send(publish, after(10ms));
if constexpr (qos == qos_e::at_least_once) {
broker_side
.expect(puback)
.complete_with(success, after(1ms));
} else if constexpr (qos == qos_e::exactly_once) {
broker_side
.expect(pubrec)
.complete_with(success, after(1ms))
.reply_with(pubrel, after(2ms))
.expect(pubcomp)
.complete_with(success, after(1ms));
}
asio::io_context ioc;
auto executor = ioc.get_executor();
auto& broker = asio::make_service<test::test_broker>(
ioc, executor, std::move(broker_side)
);
using client_type = mqtt_client<test::test_stream>;
client_type c(executor, "");
c.brokers("127.0.0.1")
.run();
c.async_receive(
[&](
error_code ec,
std::string rec_topic, std::string rec_payload,
publish_props
) {
++handlers_called;
BOOST_CHECK_MESSAGE(!ec, ec.message());
BOOST_CHECK_EQUAL(topic, rec_topic);
BOOST_CHECK_EQUAL(payload, rec_payload);
c.cancel();
}
);
ioc.run_for(std::chrono::seconds(10));
BOOST_CHECK_EQUAL(handlers_called, expected_handlers_called);
BOOST_CHECK(broker.received_all_expected());
}
BOOST_AUTO_TEST_CASE(test_receive_publish_qos0) {
receive_publish<qos_e::at_most_once>();
}
BOOST_AUTO_TEST_CASE(test_receive_publish_qos1) {
receive_publish<qos_e::at_least_once>();
}
BOOST_AUTO_TEST_CASE(test_receive_publish_qos2) {
receive_publish<qos_e::exactly_once>();
}
BOOST_AUTO_TEST_CASE(test_waiting_on_pubrel) {
using test::after;
using std::chrono_literals::operator ""ms;
constexpr int expected_handlers_called = 1;
int handlers_called = 0;
std::string topic = "topic";
std::string payload = "payload";
// packets
auto connect = encoders::encode_connect(
"", std::nullopt, std::nullopt, 10, false, {}, std::nullopt
);
auto connack = encoders::encode_connack(
false, reason_codes::success.value(), {}
);
auto publish = encoders::encode_publish(
1, topic, payload, qos_e::exactly_once, retain_e::yes, dup_e::no, {}
);
auto pubrec = encoders::encode_pubrec(1, reason_codes::success.value(), {});
auto pubrel = encoders::encode_pubrel(1, reason_codes::success.value(), {});
auto pubcomp = encoders::encode_pubcomp(1, reason_codes::success.value(), {});
test::msg_exchange broker_side;
error_code success {};
error_code fail = asio::error::not_connected;
broker_side
.expect(connect)
.complete_with(success, after(0ms))
.reply_with(connack, after(0ms))
.send(publish, after(10ms))
.expect(pubrec)
.complete_with(success, after(1ms))
.reply_with(pubrel, after(2ms))
.expect(pubcomp)
.complete_with(fail, after(1ms))
.expect(connect)
.complete_with(success, after(0ms))
.reply_with(connack, after(0ms))
.send(pubrel, after(10ms))
.expect(pubcomp)
.complete_with(success, after(1ms));
asio::io_context ioc;
auto executor = ioc.get_executor();
auto& broker = asio::make_service<test::test_broker>(
ioc, executor, std::move(broker_side)
);
using client_type = mqtt_client<test::test_stream>;
client_type c(executor, "");
c.brokers("127.0.0.1,127.0.0.1") // to avoid reconnect backoff
.run();
c.async_receive(
[&](
error_code ec,
std::string rec_topic, std::string rec_payload,
publish_props
) {
++handlers_called;
BOOST_CHECK_MESSAGE(!ec, ec.message());
BOOST_CHECK_EQUAL(topic, rec_topic);
BOOST_CHECK_EQUAL(payload, rec_payload);
c.cancel();
}
);
ioc.run_for(std::chrono::seconds(10));
BOOST_CHECK_EQUAL(handlers_called, expected_handlers_called);
BOOST_CHECK(broker.received_all_expected());
}
BOOST_AUTO_TEST_SUITE_END();

View File

@ -1,240 +1,19 @@
#include <boost/test/unit_test.hpp>
#include <chrono>
#include <boost/asio/io_context.hpp>
#include <boost/asio/steady_timer.hpp>
#include <async_mqtt5/impl/codecs/message_encoders.hpp>
#include <async_mqtt5.hpp>
#include <async_mqtt5/mqtt_client.hpp>
#include "test_common/message_exchange.hpp"
#include "test_common/test_service.hpp"
#include "test_common/test_stream.hpp"
using namespace async_mqtt5;
BOOST_AUTO_TEST_SUITE(framework/*, *boost::unit_test::disabled()*/)
BOOST_AUTO_TEST_SUITE(publish_send/*, *boost::unit_test::disabled()*/)
BOOST_AUTO_TEST_CASE(publish_qos_0) {
using test::after;
using std::chrono_literals::operator ""ms;
constexpr int expected_handlers_called = 1;
int handlers_called = 0;
// packets
auto connect = encoders::encode_connect(
"", std::nullopt, std::nullopt, 10, false, {}, std::nullopt
);
auto connack = encoders::encode_connack(
false, reason_codes::success.value(), {}
);
auto publish_1 = encoders::encode_publish(
1, "t", "p_1", qos_e::at_most_once, retain_e::no, dup_e::no, {}
);
test::msg_exchange broker_side;
error_code success {};
broker_side
.expect(connect)
.complete_with(success, after(10ms))
.reply_with(connack, after(20ms))
.expect(publish_1);
asio::io_context ioc;
auto executor = ioc.get_executor();
auto& broker = asio::make_service<test::test_broker>(
ioc, executor, std::move(broker_side)
);
using client_type = mqtt_client<test::test_stream>;
client_type c(executor, "");
c.brokers("127.0.0.1")
.run();
c.async_publish<qos_e::at_most_once>(
"t", "p_1", retain_e::no, publish_props{},
[&](error_code ec) {
BOOST_CHECK_MESSAGE(!ec, ec.message());
++handlers_called;
}
);
asio::steady_timer timer(c.get_executor());
timer.expires_after(std::chrono::seconds(1));
timer.async_wait([&](auto) { c.cancel(); });
ioc.run();
BOOST_CHECK_EQUAL(handlers_called, expected_handlers_called);
BOOST_CHECK(broker.received_all_expected());
}
BOOST_AUTO_TEST_CASE(two_publishes_qos_1_with_fail_on_write) {
using test::after;
using std::chrono_literals::operator ""ms;
constexpr int expected_handlers_called = 2;
int handlers_called = 0;
// packets
auto connect = encoders::encode_connect(
"", std::nullopt, std::nullopt, 10, false, {}, std::nullopt
);
auto connack = encoders::encode_connack(
false, reason_codes::success.value(), {}
);
auto publish_1 = encoders::encode_publish(
1, "t", "p_1", qos_e::at_least_once, retain_e::no, dup_e::no, {}
);
auto puback_1 = encoders::encode_puback(
1, reason_codes::success.value(), {}
);
auto publish_2 = encoders::encode_publish(
2, "t", "p_2", qos_e::at_least_once, retain_e::no, dup_e::no, {}
);
auto puback_2 = encoders::encode_puback(
2, reason_codes::success.value(), {}
);
test::msg_exchange broker_side;
error_code success {};
error_code fail = asio::error::not_connected;
broker_side
.expect(connect)
.complete_with(success, after(10ms))
.reply_with(connack, after(10ms))
.expect(publish_1, publish_2)
.complete_with(fail, after(10ms))
.expect(connect)
.complete_with(success, after(10ms))
.reply_with(connack, after(10ms))
.expect(publish_1, publish_2)
.complete_with(success, after(10ms))
.reply_with(puback_1, puback_2, after(20ms));
asio::io_context ioc;
auto executor = ioc.get_executor();
auto& broker = asio::make_service<test::test_broker>(
ioc, executor, std::move(broker_side)
);
using client_type = mqtt_client<test::test_stream>;
client_type c(executor, "");
c.brokers("127.0.0.1")
.run();
c.async_publish<qos_e::at_least_once>(
"t", "p_1", retain_e::no, publish_props{},
[&](error_code ec, reason_code rc, auto) {
BOOST_CHECK_MESSAGE(!ec, ec.message());
BOOST_CHECK_MESSAGE(!rc, rc.message());
++handlers_called;
}
);
c.async_publish<qos_e::at_least_once>(
"t", "p_2", retain_e::no, publish_props{},
[&](error_code ec, reason_code rc, auto) {
BOOST_CHECK_MESSAGE(!ec, ec.message());
BOOST_CHECK_MESSAGE(!rc, rc.message());
++handlers_called;
}
);
asio::steady_timer timer(c.get_executor());
timer.expires_after(std::chrono::seconds(6));
timer.async_wait([&](auto) { c.cancel(); });
ioc.run();
BOOST_CHECK_EQUAL(handlers_called, expected_handlers_called);
BOOST_CHECK(broker.received_all_expected());
}
BOOST_AUTO_TEST_CASE(send_publish_qos_2_with_fail_on_read) {
using test::after;
using std::chrono_literals::operator ""ms;
constexpr int expected_handlers_called = 1;
int handlers_called = 0;
// packets
auto connect = encoders::encode_connect(
"", std::nullopt, std::nullopt, 10, false, {}, std::nullopt
);
auto connack = encoders::encode_connack(
false, reason_codes::success.value(), {}
);
auto publish = encoders::encode_publish(
1, "t_1", "p_1", qos_e::exactly_once, retain_e::no, dup_e::no, {}
);
auto pubrec = encoders::encode_pubrec(
1, reason_codes::success.value(), {}
);
auto pubrel = encoders::encode_pubrel(
1, reason_codes::success.value(), {}
);
auto pubcomp = encoders::encode_pubcomp(
1, reason_codes::success.value(), {}
);
test::msg_exchange broker_side;
error_code success {};
error_code fail = asio::error::not_connected;
broker_side
.expect(connect)
.complete_with(success, after(10ms))
.reply_with(connack, after(20ms))
.expect(publish)
.complete_with(success, after(10ms))
.reply_with(pubrec, after(25ms))
.expect(pubrel)
.complete_with(success, after(10ms))
.reply_with(fail, after(10ms))
.expect(connect)
.complete_with(success, after(10ms))
.reply_with(connack, after(20ms))
.expect(pubrel)
.complete_with(success, after(10ms))
.reply_with(pubcomp, after(20ms));
asio::io_context ioc;
auto executor = ioc.get_executor();
auto& broker = asio::make_service<test::test_broker>(
ioc, executor, std::move(broker_side)
);
using client_type = mqtt_client<test::test_stream>;
client_type c(executor, "");
c.brokers("127.0.0.1")
.run();
c.async_publish<qos_e::exactly_once>(
"t_1", "p_1", retain_e::no, publish_props{},
[&](error_code ec, reason_code rc, auto) {
BOOST_CHECK_MESSAGE(!ec, ec.message());
BOOST_CHECK_MESSAGE(!rc, rc.message());
++handlers_called;
}
);
asio::steady_timer timer(c.get_executor());
timer.expires_after(std::chrono::seconds(7));
timer.async_wait([&](auto) { c.cancel(); });
ioc.run();
BOOST_CHECK_EQUAL(handlers_called, expected_handlers_called);
BOOST_CHECK(broker.received_all_expected());
}
BOOST_AUTO_TEST_CASE(test_ordering_after_reconnect) {
BOOST_AUTO_TEST_CASE(ordering_after_reconnect) {
using test::after;
using std::chrono_literals::operator ""ms;
@ -299,7 +78,7 @@ BOOST_AUTO_TEST_CASE(test_ordering_after_reconnect) {
using client_type = mqtt_client<test::test_stream>;
client_type c(executor, "");
c.brokers("127.0.0.1")
c.brokers("127.0.0.1,127.0.0.1") // to avoid reconnect backoff
.run();
c.async_publish<qos_e::at_least_once>(
@ -308,6 +87,9 @@ BOOST_AUTO_TEST_CASE(test_ordering_after_reconnect) {
BOOST_CHECK_MESSAGE(!ec, ec.message());
BOOST_CHECK_MESSAGE(!rc, rc.message());
++handlers_called;
if (handlers_called == expected_handlers_called)
c.cancel();
}
);
@ -317,14 +99,13 @@ BOOST_AUTO_TEST_CASE(test_ordering_after_reconnect) {
BOOST_CHECK_MESSAGE(!ec, ec.message());
BOOST_CHECK_MESSAGE(!rc, rc.message());
++handlers_called;
if (handlers_called == expected_handlers_called)
c.cancel();
}
);
asio::steady_timer timer(c.get_executor());
timer.expires_after(std::chrono::seconds(7));
timer.async_wait([&](auto) { c.cancel(); });
ioc.run();
ioc.run_for(std::chrono::seconds(1));
BOOST_CHECK_EQUAL(handlers_called, expected_handlers_called);
BOOST_CHECK(broker.received_all_expected());
}
@ -421,14 +202,12 @@ BOOST_AUTO_TEST_CASE(throttling) {
BOOST_CHECK_MESSAGE(!rc, rc.message());
BOOST_CHECK_EQUAL(handlers_called, 2);
++handlers_called;
c.cancel();
}
);
asio::steady_timer timer(c.get_executor());
timer.expires_after(std::chrono::seconds(2));
timer.async_wait([&](auto) { c.cancel(); });
ioc.run();
ioc.run_for(std::chrono::seconds(1));
BOOST_CHECK_EQUAL(handlers_called, expected_handlers_called);
BOOST_CHECK(broker.received_all_expected());
}
@ -519,4 +298,5 @@ BOOST_AUTO_TEST_CASE(cancel_multiple_ops) {
BOOST_CHECK(broker.received_all_expected());
}
BOOST_AUTO_TEST_SUITE_END()
BOOST_AUTO_TEST_SUITE_END();

View File

@ -0,0 +1,150 @@
#include <boost/test/unit_test.hpp>
#include <boost/asio/prepend.hpp>
#include <boost/asio/post.hpp>
#include <async_mqtt5/mqtt_client.hpp>
#include "test_common/message_exchange.hpp"
#include "test_common/test_service.hpp"
#include "test_common/test_stream.hpp"
using namespace async_mqtt5;
BOOST_AUTO_TEST_SUITE(read_message/*, *boost::unit_test::disabled()*/)
void test_receive_malformed_packet(
std::string malformed_packet, std::string reason_string
) {
using test::after;
using std::chrono_literals::operator ""ms;
// packets
auto connect = encoders::encode_connect(
"", std::nullopt, std::nullopt, 10, false, {}, std::nullopt
);
connack_props co_props;
co_props[prop::maximum_packet_size] = 2000;
auto connack = encoders::encode_connack(false, reason_codes::success.value(), co_props);
disconnect_props dc_props;
dc_props[prop::reason_string] = reason_string;
auto disconnect = encoders::encode_disconnect(
reason_codes::malformed_packet.value(), dc_props
);
test::msg_exchange broker_side;
error_code success {};
broker_side
.expect(connect)
.complete_with(success, after(0ms))
.reply_with(connack, after(0ms))
.send(malformed_packet, after(5ms))
.expect(disconnect)
.complete_with(success, after(0ms))
.expect(connect)
.complete_with(success, after(0ms))
.reply_with(connack, after(0ms));
asio::io_context ioc;
auto executor = ioc.get_executor();
auto& broker = asio::make_service<test::test_broker>(
ioc, executor, std::move(broker_side)
);
using client_type = mqtt_client<test::test_stream>;
client_type c(executor, "");
c.brokers("127.0.0.1,127.0.0.1") // to avoid reconnect backoff
.run();
asio::steady_timer timer(c.get_executor());
timer.expires_after(std::chrono::milliseconds(100));
timer.async_wait([&](auto) { c.cancel(); });
ioc.run();
BOOST_CHECK(broker.received_all_expected());
}
BOOST_AUTO_TEST_CASE(forbidden_packet_type) {
test_receive_malformed_packet(
std::string({ 0x00 }),
"Malformed Packet received from the Server"
);
}
BOOST_AUTO_TEST_CASE(malformed_varint) {
test_receive_malformed_packet(
std::string({ 0x10, -1 /* 0xFF */, -1, -1, -1 }),
"Malformed Packet received from the Server"
);
}
BOOST_AUTO_TEST_CASE(malformed_fixed_header) {
test_receive_malformed_packet(
std::string({ 0x60, 1, 0 }),
"Malformed Packet received from the Server"
);
}
BOOST_AUTO_TEST_CASE(packet_larger_than_allowed) {
test_receive_malformed_packet(
std::string({ 0x10, -1, -1, -1, 0 }),
"Malformed Packet received from the Server"
);
}
BOOST_AUTO_TEST_CASE(receive_malformed_publish) {
test_receive_malformed_packet(
std::string({ 0x30, 1, -1 }),
"Malformed PUBLISH received: cannot decode"
);
}
BOOST_AUTO_TEST_CASE(receive_disconnect) {
using test::after;
using std::chrono_literals::operator ""ms;
// packets
auto connect = encoders::encode_connect(
"", std::nullopt, std::nullopt, 10, false, {}, std::nullopt
);
auto connack = encoders::encode_connack(false, reason_codes::success.value(), {});
auto disconnect = encoders::encode_disconnect(0x00, {});
test::msg_exchange broker_side;
error_code success {};
broker_side
.expect(connect)
.complete_with(success, after(0ms))
.reply_with(connack, after(0ms))
.send(disconnect, after(5ms))
.expect(connect)
.complete_with(success, after(0ms))
.reply_with(connack, after(0ms));
asio::io_context ioc;
auto executor = ioc.get_executor();
auto& broker = asio::make_service<test::test_broker>(
ioc, executor, std::move(broker_side)
);
using client_type = mqtt_client<test::test_stream>;
client_type c(executor, "");
c.brokers("127.0.0.1,127.0.0.1") // to avoid reconnect backoff
.run();
asio::steady_timer timer(c.get_executor());
timer.expires_after(std::chrono::milliseconds(100));
timer.async_wait([&](auto) { c.cancel(); });
ioc.run();
BOOST_CHECK(broker.received_all_expected());
}
BOOST_AUTO_TEST_SUITE_END();

View File

@ -0,0 +1,312 @@
#include <boost/test/unit_test.hpp>
#include <async_mqtt5/mqtt_client.hpp>
#include "test_common/message_exchange.hpp"
#include "test_common/test_service.hpp"
#include "test_common/test_stream.hpp"
using namespace async_mqtt5;
BOOST_AUTO_TEST_SUITE(resending/* , *boost::unit_test::disabled()*/)
BOOST_AUTO_TEST_CASE(resend_multiple_publishes) {
using test::after;
using std::chrono_literals::operator ""ms;
constexpr int expected_handlers_called = 2;
int handlers_called = 0;
// packets
auto connect = encoders::encode_connect(
"", std::nullopt, std::nullopt, 10, false, {}, std::nullopt
);
auto connack = encoders::encode_connack(
false, reason_codes::success.value(), {}
);
auto publish_1 = encoders::encode_publish(
1, "t", "p_1", qos_e::at_least_once, retain_e::no, dup_e::no, {}
);
auto puback_1 = encoders::encode_puback(
1, reason_codes::success.value(), {}
);
auto publish_2 = encoders::encode_publish(
2, "t", "p_2", qos_e::at_least_once, retain_e::no, dup_e::no, {}
);
auto puback_2 = encoders::encode_puback(
2, reason_codes::success.value(), {}
);
test::msg_exchange broker_side;
error_code success {};
error_code fail = asio::error::not_connected;
broker_side
.expect(connect)
.complete_with(success, after(10ms))
.reply_with(connack, after(10ms))
.expect(publish_1, publish_2)
.complete_with(fail, after(10ms))
.expect(connect)
.complete_with(success, after(10ms))
.reply_with(connack, after(10ms))
.expect(publish_1, publish_2)
.complete_with(success, after(10ms))
.reply_with(puback_1, puback_2, after(20ms));
asio::io_context ioc;
auto executor = ioc.get_executor();
auto& broker = asio::make_service<test::test_broker>(
ioc, executor, std::move(broker_side)
);
using client_type = mqtt_client<test::test_stream>;
client_type c(executor, "");
c.brokers("127.0.0.1,127.0.0.1") // to avoid reconnect backoff
.run();
c.async_publish<qos_e::at_least_once>(
"t", "p_1", retain_e::no, publish_props{},
[&](error_code ec, reason_code rc, auto) {
BOOST_CHECK_MESSAGE(!ec, ec.message());
BOOST_CHECK_MESSAGE(!rc, rc.message());
++handlers_called;
if (handlers_called == expected_handlers_called)
c.cancel();
}
);
c.async_publish<qos_e::at_least_once>(
"t", "p_2", retain_e::no, publish_props{},
[&](error_code ec, reason_code rc, auto) {
BOOST_CHECK_MESSAGE(!ec, ec.message());
BOOST_CHECK_MESSAGE(!rc, rc.message());
++handlers_called;
if (handlers_called == expected_handlers_called)
c.cancel();
}
);
ioc.run_for(std::chrono::seconds(6));
BOOST_CHECK_EQUAL(handlers_called, expected_handlers_called);
BOOST_CHECK(broker.received_all_expected());
}
BOOST_AUTO_TEST_CASE(resend_pubrel) {
using test::after;
using std::chrono_literals::operator ""ms;
constexpr int expected_handlers_called = 1;
int handlers_called = 0;
// packets
auto connect = encoders::encode_connect(
"", std::nullopt, std::nullopt, 10, false, {}, std::nullopt
);
auto connack = encoders::encode_connack(
false, reason_codes::success.value(), {}
);
auto publish = encoders::encode_publish(
1, "t_1", "p_1", qos_e::exactly_once, retain_e::no, dup_e::no, {}
);
auto pubrec = encoders::encode_pubrec(
1, reason_codes::success.value(), {}
);
auto pubrel = encoders::encode_pubrel(
1, reason_codes::success.value(), {}
);
auto pubcomp = encoders::encode_pubcomp(
1, reason_codes::success.value(), {}
);
test::msg_exchange broker_side;
error_code success {};
error_code fail = asio::error::not_connected;
broker_side
.expect(connect)
.complete_with(success, after(10ms))
.reply_with(connack, after(20ms))
.expect(publish)
.complete_with(success, after(10ms))
.reply_with(pubrec, after(25ms))
.expect(pubrel)
.complete_with(success, after(10ms))
.reply_with(fail, after(10ms))
.expect(connect)
.complete_with(success, after(10ms))
.reply_with(connack, after(20ms))
.expect(pubrel)
.complete_with(success, after(10ms))
.reply_with(pubcomp, after(20ms));
asio::io_context ioc;
auto executor = ioc.get_executor();
auto& broker = asio::make_service<test::test_broker>(
ioc, executor, std::move(broker_side)
);
using client_type = mqtt_client<test::test_stream>;
client_type c(executor, "");
c.brokers("127.0.0.1,127.0.0.1") // to avoid reconnect backoff
.run();
c.async_publish<qos_e::exactly_once>(
"t_1", "p_1", retain_e::no, publish_props{},
[&](error_code ec, reason_code rc, auto) {
BOOST_CHECK_MESSAGE(!ec, ec.message());
BOOST_CHECK_MESSAGE(!rc, rc.message());
++handlers_called;
c.cancel();
}
);
ioc.run_for(std::chrono::seconds(6));
BOOST_CHECK_EQUAL(handlers_called, expected_handlers_called);
BOOST_CHECK(broker.received_all_expected());
}
BOOST_AUTO_TEST_CASE(resend_subscribe) {
using test::after;
using std::chrono_literals::operator ""ms;
constexpr int expected_handlers_called = 1;
int handlers_called = 0;
// data
std::vector<subscribe_topic> topics = {
subscribe_topic { "topic", subscribe_options {} }
};
subscribe_props subscribe_props;
std::vector<uint8_t> rcs = { reason_codes::granted_qos_0.value() };
suback_props suback_props;
// packets
auto connect = encoders::encode_connect(
"", std::nullopt, std::nullopt, 10, false, {}, std::nullopt
);
auto connack = encoders::encode_connack(false, reason_codes::success.value(), {});
auto subscribe = encoders::encode_subscribe(1, topics, subscribe_props);
auto suback = encoders::encode_suback(1, rcs, suback_props);
test::msg_exchange broker_side;
error_code success {};
error_code fail = asio::error::not_connected;
broker_side
.expect(connect)
.complete_with(success, after(0ms))
.reply_with(connack, after(0ms))
.expect(subscribe)
.complete_with(fail, after(0ms))
.expect(connect)
.complete_with(success, after(0ms))
.reply_with(connack, after(0ms))
.expect(subscribe)
.complete_with(success, after(0ms))
.reply_with(suback, after(0ms));
asio::io_context ioc;
auto executor = ioc.get_executor();
auto& broker = asio::make_service<test::test_broker>(
ioc, executor, std::move(broker_side)
);
using client_type = mqtt_client<test::test_stream>;
client_type c(executor, "");
c.brokers("127.0.0.1,127.0.0.1") // to avoid reconnect backoff
.run();
c.async_subscribe(
topics, subscribe_props,
[&](error_code ec, std::vector<reason_code> rcs, auto) {
handlers_called++;
BOOST_CHECK(!ec);
BOOST_ASSERT(rcs.size() == 1);
BOOST_CHECK_EQUAL(rcs[0], reason_codes::granted_qos_0);
c.cancel();
}
);
ioc.run_for(std::chrono::seconds(10));
BOOST_CHECK_EQUAL(handlers_called, expected_handlers_called);
BOOST_CHECK(broker.received_all_expected());
}
BOOST_AUTO_TEST_CASE(resend_unsubscribe) {
using test::after;
using std::chrono_literals::operator ""ms;
constexpr int expected_handlers_called = 1;
int handlers_called = 0;
// data
std::vector<std::string> topics = { "topic" };
unsubscribe_props unsubscribe_props;
std::vector<uint8_t> rcs = { reason_codes::success.value() };
unsuback_props unsuback_props;
// packets
auto connect = encoders::encode_connect(
"", std::nullopt, std::nullopt, 10, false, {}, std::nullopt
);
auto connack = encoders::encode_connack(false, reason_codes::success.value(), {});
auto unsubscribe = encoders::encode_unsubscribe(1, topics, unsubscribe_props);
auto unsuback = encoders::encode_unsuback(1, rcs, unsuback_props);
test::msg_exchange broker_side;
error_code success {};
error_code fail = asio::error::not_connected;
broker_side
.expect(connect)
.complete_with(success, after(0ms))
.reply_with(connack, after(0ms))
.expect(unsubscribe)
.complete_with(fail, after(0ms))
.expect(connect)
.complete_with(success, after(0ms))
.reply_with(connack, after(0ms))
.expect(unsubscribe)
.complete_with(success, after(0ms))
.reply_with(unsuback, after(0ms));
asio::io_context ioc;
auto executor = ioc.get_executor();
auto& broker = asio::make_service<test::test_broker>(
ioc, executor, std::move(broker_side)
);
using client_type = mqtt_client<test::test_stream>;
client_type c(executor, "");
c.brokers("127.0.0.1,127.0.0.1") // to avoid reconnect backoff
.run();
c.async_unsubscribe(
topics, unsubscribe_props,
[&](error_code ec, std::vector<reason_code> rcs, auto) {
handlers_called++;
BOOST_CHECK(!ec);
BOOST_ASSERT(rcs.size() == 1);
BOOST_CHECK_EQUAL(rcs[0], reason_codes::success);
c.cancel();
}
);
ioc.run_for(std::chrono::seconds(10));
BOOST_CHECK_EQUAL(handlers_called, expected_handlers_called);
BOOST_CHECK(broker.received_all_expected());
}
BOOST_AUTO_TEST_SUITE_END();

View File

@ -1,35 +0,0 @@
cmake_minimum_required(VERSION 3.15)
project(async-mqtt5-tests CXX)
include(../../cmake/project-is-top-level.cmake)
if(PROJECT_IS_TOP_LEVEL)
find_package(async-mqtt5 REQUIRED)
enable_testing()
endif()
add_executable(
mqtt-test
src/run_tests.cpp
test/cancellation.cpp
test/client_broker.cpp
test/compilation_checks.cpp
test/coroutine.cpp
test/disconnect_op.cpp
test/publish_rec_op.cpp
test/publish_send_op.cpp
test/serialization.cpp
test/session.cpp
test/string_validation.cpp
test/subscribe_op.cpp
test/unsubscribe_op.cpp
)
target_include_directories(mqtt-test PRIVATE include)
target_compile_definitions(mqtt-test PRIVATE BOOST_TEST_NO_MAIN=1)
find_package(OpenSSL REQUIRED)
target_link_libraries(mqtt-test PRIVATE Async::MQTT5 OpenSSL::SSL)
add_test(NAME mqtt-test COMMAND mqtt-test)

View File

@ -5,14 +5,10 @@
#include <boost/asio/io_context.hpp>
#include <boost/asio/steady_timer.hpp>
#include <async_mqtt5/mqtt_client.hpp>
#include <async_mqtt5/impl/client_service.hpp>
#include <async_mqtt5/impl/publish_send_op.hpp>
#include "test_common/message_exchange.hpp"
#include "test_common/test_service.hpp"
#include "test_common/test_stream.hpp"
using namespace async_mqtt5;
@ -304,177 +300,5 @@ BOOST_AUTO_TEST_CASE(test_publish_cancellation) {
BOOST_CHECK_EQUAL(handlers_called, expected_handlers_called);
}
BOOST_AUTO_TEST_CASE(test_malformed_puback) {
using test::after;
using std::chrono_literals::operator ""ms;
constexpr int expected_handlers_called = 1;
int handlers_called = 0;
// packets
auto connect = encoders::encode_connect(
"", std::nullopt, std::nullopt, 10, false, {}, std::nullopt
);
auto connack = encoders::encode_connack(false, reason_codes::success.value(), {});
auto publish = encoders::encode_publish(
1, "t", "p", qos_e::at_least_once, retain_e::no, dup_e::no, {}
);
auto malformed_puback = encoders::encode_puback(1, uint8_t(0x04), {});
auto publish_dup = encoders::encode_publish(
1, "t", "p", qos_e::at_least_once, retain_e::no, dup_e::yes, {}
);
auto puback = encoders::encode_puback(1, reason_codes::success.value(), {});
disconnect_props dc_props;
dc_props[prop::reason_string] = "Malformed PUBACK: invalid Reason Code";
auto disconnect = encoders::encode_disconnect(
reason_codes::malformed_packet.value(), dc_props
);
test::msg_exchange broker_side;
error_code success {};
broker_side
.expect(connect)
.complete_with(success, after(0ms))
.reply_with(connack, after(0ms))
.expect(publish)
.complete_with(success, after(0ms))
.reply_with(malformed_puback, after(0ms))
.expect(disconnect)
.complete_with(success, after(0ms))
.expect(connect)
.complete_with(success, after(0ms))
.reply_with(connack, after(0ms))
.expect(publish_dup)
.complete_with(success, after(0ms))
.reply_with(puback, after(0ms));
asio::io_context ioc;
auto executor = ioc.get_executor();
auto& broker = asio::make_service<test::test_broker>(
ioc, executor, std::move(broker_side)
);
using client_type = mqtt_client<test::test_stream>;
client_type c(executor, "");
c.brokers("127.0.0.1")
.run();
c.async_publish<qos_e::at_least_once>(
"t", "p", retain_e::no, publish_props {},
[&](error_code ec, reason_code rc, auto) {
++handlers_called;
BOOST_CHECK(!ec);
BOOST_CHECK_EQUAL(rc, reason_codes::success);
c.cancel();
}
);
ioc.run_for(std::chrono::seconds(10));
BOOST_CHECK_EQUAL(handlers_called, expected_handlers_called);
BOOST_CHECK(broker.received_all_expected());
}
BOOST_AUTO_TEST_CASE(test_malformed_pubrec_pubcomp) {
using test::after;
using std::chrono_literals::operator ""ms;
constexpr int expected_handlers_called = 1;
int handlers_called = 0;
// packets
auto connect = encoders::encode_connect(
"", std::nullopt, std::nullopt, 10, false, {}, std::nullopt
);
auto connack = encoders::encode_connack(false, reason_codes::success.value(), {});
auto publish = encoders::encode_publish(
1, "t", "p", qos_e::exactly_once, retain_e::no, dup_e::no, {}
);
auto malformed_pubrec = encoders::encode_pubrec(1, uint8_t(0x04), {});
auto publish_dup = encoders::encode_publish(
1, "t", "p", qos_e::exactly_once, retain_e::no, dup_e::yes, {}
);
auto pubrec = encoders::encode_pubrec(1, reason_codes::success.value(), {});
auto pubrel = encoders::encode_pubrel(1, reason_codes::success.value(), {});
auto malformed_pubcomp = encoders::encode_pubcomp(1, uint8_t(0x04), {});
auto pubcomp = encoders::encode_pubcomp(1, reason_codes::success.value(), {});
disconnect_props dc_props;
dc_props[prop::reason_string] = "Malformed PUBREC: invalid Reason Code";
auto disconnect_on_pubrec = encoders::encode_disconnect(
reason_codes::malformed_packet.value(), dc_props
);
dc_props[prop::reason_string] = "Malformed PUBCOMP: invalid Reason Code";
auto disconnect_on_pubcomp = encoders::encode_disconnect(
reason_codes::malformed_packet.value(), dc_props
);
test::msg_exchange broker_side;
error_code success {};
broker_side
.expect(connect)
.complete_with(success, after(0ms))
.reply_with(connack, after(0ms))
.expect(publish)
.complete_with(success, after(0ms))
.reply_with(malformed_pubrec, after(0ms))
.expect(disconnect_on_pubrec)
.complete_with(success, after(0ms))
.expect(connect)
.complete_with(success, after(0ms))
.reply_with(connack, after(0ms))
.expect(publish_dup)
.complete_with(success, after(0ms))
.reply_with(pubrec, after(0ms))
.expect(pubrel)
.complete_with(success, after(0ms))
.reply_with(malformed_pubcomp, after(0ms))
.expect(disconnect_on_pubcomp)
.complete_with(success, after(0ms))
.expect(connect)
.complete_with(success, after(0ms))
.reply_with(connack, after(0ms))
.expect(pubrel)
.complete_with(success, after(0ms))
.reply_with(pubcomp, after(0ms));
asio::io_context ioc;
auto executor = ioc.get_executor();
auto& broker = asio::make_service<test::test_broker>(
ioc, executor, std::move(broker_side)
);
using client_type = mqtt_client<test::test_stream>;
client_type c(executor, "");
c.brokers("127.0.0.1")
.run();
c.async_publish<qos_e::exactly_once>(
"t", "p", retain_e::no, publish_props {},
[&](error_code ec, reason_code rc, auto) {
++handlers_called;
BOOST_CHECK(!ec);
BOOST_CHECK_EQUAL(rc, reason_codes::success);
c.cancel();
}
);
ioc.run_for(std::chrono::seconds(15));
BOOST_CHECK_EQUAL(handlers_called, expected_handlers_called);
BOOST_CHECK(broker.received_all_expected());
}
BOOST_AUTO_TEST_SUITE_END()

View File

@ -2,13 +2,9 @@
#include <boost/asio/io_context.hpp>
#include <async_mqtt5/mqtt_client.hpp>
#include <async_mqtt5/impl/subscribe_op.hpp>
#include "test_common/message_exchange.hpp"
#include "test_common/test_service.hpp"
#include "test_common/test_stream.hpp"
using namespace async_mqtt5;
@ -282,75 +278,4 @@ BOOST_AUTO_TEST_CASE(test_packet_too_large) {
BOOST_CHECK_EQUAL(handlers_called, expected_handlers_called);
}
BOOST_AUTO_TEST_CASE(test_resending) {
using test::after;
using std::chrono_literals::operator ""ms;
constexpr int expected_handlers_called = 1;
int handlers_called = 0;
// data
std::vector<subscribe_topic> topics = {
subscribe_topic { "topic", subscribe_options {} }
};
subscribe_props subscribe_props;
std::vector<uint8_t> rcs = { reason_codes::granted_qos_0.value() };
suback_props suback_props;
// packets
auto connect = encoders::encode_connect(
"", std::nullopt, std::nullopt, 10, false, {}, std::nullopt
);
auto connack = encoders::encode_connack(false, reason_codes::success.value(), {});
auto subscribe = encoders::encode_subscribe(1, topics, subscribe_props);
auto suback = encoders::encode_suback(1, rcs, suback_props);
test::msg_exchange broker_side;
error_code success {};
error_code fail = asio::error::not_connected;
broker_side
.expect(connect)
.complete_with(success, after(0ms))
.reply_with(connack, after(0ms))
.expect(subscribe)
.complete_with(fail, after(0ms))
.expect(connect)
.complete_with(success, after(0ms))
.reply_with(connack, after(0ms))
.expect(subscribe)
.complete_with(success, after(0ms))
.reply_with(suback, after(0ms));
asio::io_context ioc;
auto executor = ioc.get_executor();
auto& broker = asio::make_service<test::test_broker>(
ioc, executor, std::move(broker_side)
);
using client_type = mqtt_client<test::test_stream>;
client_type c(executor, "");
c.brokers("127.0.0.1")
.run();
c.async_subscribe(
topics, subscribe_props,
[&](error_code ec, std::vector<reason_code> rcs, auto) {
handlers_called++;
BOOST_CHECK(!ec);
BOOST_ASSERT(rcs.size() == 1);
BOOST_CHECK_EQUAL(rcs[0], reason_codes::granted_qos_0);
c.cancel();
}
);
ioc.run_for(std::chrono::seconds(10));
BOOST_CHECK_EQUAL(handlers_called, expected_handlers_called);
BOOST_CHECK(broker.received_all_expected());
}
BOOST_AUTO_TEST_SUITE_END()

View File

@ -2,13 +2,9 @@
#include <boost/asio/io_context.hpp>
#include <async_mqtt5/mqtt_client.hpp>
#include <async_mqtt5/impl/unsubscribe_op.hpp>
#include "test_common/message_exchange.hpp"
#include "test_common/test_service.hpp"
#include "test_common/test_stream.hpp"
using namespace async_mqtt5;
@ -133,73 +129,4 @@ BOOST_AUTO_TEST_CASE(test_packet_too_large) {
BOOST_CHECK_EQUAL(handlers_called, expected_handlers_called);
}
BOOST_AUTO_TEST_CASE(test_resending) {
using test::after;
using std::chrono_literals::operator ""ms;
constexpr int expected_handlers_called = 1;
int handlers_called = 0;
// data
std::vector<std::string> topics = { "topic " };
unsubscribe_props unsubscribe_props;
std::vector<uint8_t> rcs = { reason_codes::success.value() };
unsuback_props unsuback_props;
// packets
auto connect = encoders::encode_connect(
"", std::nullopt, std::nullopt, 10, false, {}, std::nullopt
);
auto connack = encoders::encode_connack(false, reason_codes::success.value(), {});
auto unsubscribe = encoders::encode_unsubscribe(1, topics, unsubscribe_props);
auto unsuback = encoders::encode_unsuback(1, rcs, unsuback_props);
test::msg_exchange broker_side;
error_code success {};
error_code fail = asio::error::not_connected;
broker_side
.expect(connect)
.complete_with(success, after(0ms))
.reply_with(connack, after(0ms))
.expect(unsubscribe)
.complete_with(fail, after(0ms))
.expect(connect)
.complete_with(success, after(0ms))
.reply_with(connack, after(0ms))
.expect(unsubscribe)
.complete_with(success, after(0ms))
.reply_with(unsuback, after(0ms));
asio::io_context ioc;
auto executor = ioc.get_executor();
auto& broker = asio::make_service<test::test_broker>(
ioc, executor, std::move(broker_side)
);
using client_type = mqtt_client<test::test_stream>;
client_type c(executor, "");
c.brokers("127.0.0.1")
.run();
c.async_unsubscribe(
topics, unsubscribe_props,
[&](error_code ec, std::vector<reason_code> rcs, auto) {
handlers_called++;
BOOST_CHECK(!ec);
BOOST_ASSERT(rcs.size() == 1);
BOOST_CHECK_EQUAL(rcs[0], reason_codes::success);
c.cancel();
}
);
ioc.run_for(std::chrono::seconds(10));
BOOST_CHECK_EQUAL(handlers_called, expected_handlers_called);
BOOST_CHECK(broker.received_all_expected());
}
BOOST_AUTO_TEST_SUITE_END()