From b40ddb3ced2eb986f3d4706213037ac3d6fce7d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korina=20=C5=A0imi=C4=8Devi=C4=87?= Date: Thu, 15 Feb 2024 13:57:22 +0100 Subject: [PATCH] Separate tests to compile and run all configuration-related client functions Summary: related to T12015 Reviewers: ivica Reviewed By: ivica Subscribers: miljen, iljazovic Differential Revision: https://repo.mireo.local/D27945 --- include/async_mqtt5/mqtt_client.hpp | 2 +- test/integration/async_sender.cpp | 2 +- test/integration/cancellation.cpp | 2 +- test/integration/client_functions.cpp | 433 ++++++++++++++++++ test/integration/coroutine.cpp | 4 - .../{compilation_checks.cpp => traits.cpp} | 53 +-- 6 files changed, 446 insertions(+), 50 deletions(-) create mode 100644 test/integration/client_functions.cpp rename test/unit/{compilation_checks.cpp => traits.cpp} (64%) diff --git a/include/async_mqtt5/mqtt_client.hpp b/include/async_mqtt5/mqtt_client.hpp index a9a98ef..8936023 100644 --- a/include/async_mqtt5/mqtt_client.hpp +++ b/include/async_mqtt5/mqtt_client.hpp @@ -349,7 +349,7 @@ public: std::integral_constant prop, prop::value_type_t

value ) { - _svc_ptr->connect_property(prop, std::move(value)); + _impl->connect_property(prop, std::move(value)); return *this; } diff --git a/test/integration/async_sender.cpp b/test/integration/async_sender.cpp index 1888564..7fdbce9 100644 --- a/test/integration/async_sender.cpp +++ b/test/integration/async_sender.cpp @@ -242,7 +242,7 @@ BOOST_FIXTURE_TEST_CASE(prioritize_disconnect, shared_test_data) { ++handlers_called; BOOST_TEST(ec == asio::error::operation_aborted); - BOOST_ASSERT(rcs.size() == 1); + BOOST_TEST_REQUIRE(rcs.size() == 1u); BOOST_TEST(rcs[0] == reason_codes::empty); } ); diff --git a/test/integration/cancellation.cpp b/test/integration/cancellation.cpp index fe421d3..84a5fef 100644 --- a/test/integration/cancellation.cpp +++ b/test/integration/cancellation.cpp @@ -161,7 +161,7 @@ void run_cancel_op_test() { asio::steady_timer timer(c.get_executor()); timer.expires_after(std::chrono::milliseconds(100)); - timer.async_wait([&](auto) { + timer.async_wait([&](error_code) { if constexpr (c_type == client_cancel) c.cancel(); else if constexpr (c_type == signal_emit) diff --git a/test/integration/client_functions.cpp b/test/integration/client_functions.cpp new file mode 100644 index 0000000..8d20fce --- /dev/null +++ b/test/integration/client_functions.cpp @@ -0,0 +1,433 @@ +#include + +#include +#include + +#include +#include + +#include +#include + +#include + +#include "test_common/message_exchange.hpp" +#include "test_common/packet_util.hpp" +#include "test_common/test_authenticators.hpp" +#include "test_common/test_service.hpp" +#include "test_common/test_stream.hpp" + +using namespace async_mqtt5; +using namespace std::chrono_literals; + +BOOST_AUTO_TEST_SUITE(client_functions/*, *boost::unit_test::disabled()*/) + +struct shared_test_data { + error_code success {}; + + const std::string connack = encoders::encode_connack( + false, reason_codes::server_moved.value(), {} + ); +}; + +using client_type = mqtt_client; + +template +void run_test( + test::msg_exchange broker_side, TestingClientFun&& client_fun +) { + asio::io_context ioc; + auto executor = ioc.get_executor(); + auto& broker = asio::make_service( + ioc, executor, std::move(broker_side) + ); + + client_type c(executor); + client_fun(c); + c.brokers("127.0.0.1,127.0.0.1") // to avoid reconnect backoff + .async_run(asio::detached); + + ioc.run_for(5s); + BOOST_TEST(broker.received_all_expected()); +} + +using test::after; + +BOOST_AUTO_TEST_CASE(create_client_with_executor) { + asio::io_context ioc; + client_type c(ioc.get_executor()); + BOOST_CHECK(c.get_executor() == ioc.get_executor()); +} + +BOOST_AUTO_TEST_CASE(create_client_with_execution_context) { + asio::io_context ioc; + client_type c(ioc); + BOOST_CHECK(c.get_executor() == ioc.get_executor()); +} + +BOOST_AUTO_TEST_CASE(assign_tls_context) { + // Tests if the tls_context function compiles + + asio::io_context ioc; + asio::ssl::context ctx(asio::ssl::context::tls_client); + + mqtt_client< + asio::ssl::stream, asio::ssl::context + > tls_client(ioc.get_executor(), std::move(ctx)); + tls_client.tls_context(); +} + +BOOST_FIXTURE_TEST_CASE(assign_credentials, shared_test_data) { + std::string client_id = "client_id"; + std::string username = "username"; + std::string password = "password"; + + auto connect = encoders::encode_connect( + client_id, username, password, 60, false, {}, std::nullopt + ); + + test::msg_exchange broker_side; + broker_side + .expect(connect) + .complete_with(success, after(0ms)) + .reply_with(connack, after(1ms)); + + run_test( + std::move(broker_side), + [&](client_type& c) { + c.credentials(client_id, username, password); + } + ); +} + +BOOST_FIXTURE_TEST_CASE(assign_credentials_tls_client, shared_test_data) { + // Tests if the assign credentials function compiles + + std::string client_id = "client_id"; + std::string username = "username"; + std::string password = "password"; + + asio::io_context ioc; + + asio::ssl::context ctx(asio::ssl::context::tls_client); + mqtt_client< + asio::ssl::stream, asio::ssl::context + > ts(ioc.get_executor(), std::move(ctx)); + + ts.credentials(client_id, username, password); +} + +BOOST_FIXTURE_TEST_CASE(assign_will, shared_test_data) { + will w("topic", "message"); + std::optional will_opt { std::move(w) }; + + auto connect = encoders::encode_connect( + "", std::nullopt, std::nullopt, 60, false, {}, will_opt + ); + + test::msg_exchange broker_side; + broker_side + .expect(connect) + .complete_with(success, after(0ms)) + .reply_with(connack, after(1ms)); + + run_test( + std::move(broker_side), + [](client_type& c) { + // because copying is deleted + will w("topic", "message"); + will w_moved = std::move(w); // move assignment coverage + c.will(std::move(w_moved)); + } + ); +} + +BOOST_AUTO_TEST_CASE(assign_authenticator) { + // Tests if the authenticator function compiles + + asio::io_context ioc; + client_type c(ioc); + c.authenticator(test::test_authenticator()); +} + +BOOST_AUTO_TEST_CASE(assign_authenticator_tls_client) { + // Tests if the authenticator function compiles + + asio::io_context ioc; + + asio::ssl::context ctx(asio::ssl::context::tls_client); + mqtt_client< + asio::ssl::stream, asio::ssl::context + > ts(ioc.get_executor(), std::move(ctx)); + + ts.authenticator(test::test_authenticator()); +} + +BOOST_FIXTURE_TEST_CASE(assign_keep_alive, shared_test_data) { + uint16_t keep_alive = 120; + + auto connect = encoders::encode_connect( + "", std::nullopt, std::nullopt, keep_alive, false, {}, std::nullopt + ); + + test::msg_exchange broker_side; + broker_side + .expect(connect) + .complete_with(success, after(0ms)) + .reply_with(connack, after(1ms)); + + run_test( + std::move(broker_side), + [&](client_type& c) { + c.keep_alive(keep_alive); + } + ); +} + +struct shared_connect_prop_test_data : shared_test_data { + const int session_expiry_interval = 40; + const int16_t receive_maximum = 10123; + const int maximum_packet_size = 1024; + const uint16_t topic_alias_maximum = 12345; + const uint8_t request_response_information = 1; + const uint8_t request_problem_information = 0; + const std::vector user_properties = std::vector{ "key", "val" }; + + connect_props cprops = create_connect_props(); + +private: + connect_props create_connect_props() { + connect_props ret_props; + ret_props[prop::session_expiry_interval] = session_expiry_interval; + ret_props[prop::receive_maximum] = receive_maximum; + ret_props[prop::maximum_packet_size] = maximum_packet_size; + ret_props[prop::topic_alias_maximum] = topic_alias_maximum; + ret_props[prop::request_response_information] = request_response_information; + ret_props[prop::request_problem_information] = request_problem_information; + ret_props[prop::user_property] = user_properties; + return ret_props; + } +}; + +BOOST_FIXTURE_TEST_CASE(connect_properties, shared_connect_prop_test_data) { + auto connect = encoders::encode_connect( + "", std::nullopt, std::nullopt, 60, false, cprops, std::nullopt + ); + + test::msg_exchange broker_side; + broker_side + .expect(connect) + .complete_with(success, after(0ms)) + .reply_with(connack, after(1ms)); + + run_test( + std::move(broker_side), + [&](client_type& c) { + c.connect_properties(cprops); + } + ); +} + +BOOST_FIXTURE_TEST_CASE(connect_property, shared_connect_prop_test_data) { + auto connect = encoders::encode_connect( + "", std::nullopt, std::nullopt, 60, false, cprops, std::nullopt + ); + + test::msg_exchange broker_side; + broker_side + .expect(connect) + .complete_with(success, after(0ms)) + .reply_with(connack, after(1ms)); + + run_test( + std::move(broker_side), + [&](client_type& c) { + c.connect_property(prop::session_expiry_interval, session_expiry_interval); + c.connect_property(prop::receive_maximum, receive_maximum); + c.connect_property(prop::maximum_packet_size, maximum_packet_size); + c.connect_property(prop::topic_alias_maximum, topic_alias_maximum); + c.connect_property(prop::request_response_information, request_response_information); + c.connect_property(prop::request_problem_information, request_problem_information); + c.connect_property(prop::user_property, user_properties); + } + ); +} + +BOOST_FIXTURE_TEST_CASE(connect_properties_tls_client, shared_connect_prop_test_data) { + // Tests if the connect_properties function compiles + + asio::io_context ioc; + + asio::ssl::context ctx(asio::ssl::context::tls_client); + mqtt_client< + asio::ssl::stream, asio::ssl::context + > ts(ioc.get_executor(), std::move(ctx)); + + ts.connect_properties(cprops); +} + +BOOST_FIXTURE_TEST_CASE(connect_property_tls_client, shared_connect_prop_test_data) { + // Tests if the connect_property functions compile + + asio::io_context ioc; + + asio::ssl::context ctx(asio::ssl::context::tls_client); + mqtt_client< + asio::ssl::stream, asio::ssl::context + > ts(ioc.get_executor(), std::move(ctx)); + + ts.connect_property(prop::session_expiry_interval, session_expiry_interval); + ts.connect_property(prop::receive_maximum, receive_maximum); + ts.connect_property(prop::maximum_packet_size, maximum_packet_size); + ts.connect_property(prop::topic_alias_maximum, topic_alias_maximum); + ts.connect_property(prop::request_response_information, request_response_information); + ts.connect_property(prop::request_problem_information, request_problem_information); + ts.connect_property(prop::user_property, user_properties); +} + +struct shared_connack_prop_test_data { + error_code success {}; + + // data + const uint8_t session_present = 1; + const uint8_t reason_code = reason_codes::server_moved.value(); + + const int32_t session_expiry_interval = 20; + const int16_t receive_maximum = 2000; + const uint8_t max_qos = 2; + const uint8_t retain_available = 0; + const int32_t maximum_packet_sz = 1024; + const std::string assigned_client_id = "client_id"; + const uint16_t topic_alias_max = 128; + const std::string reason_string = "reason string"; + const std::vector user_properties = std::vector{ "key", "val" }; + const uint8_t wildcard_sub = 1; + const uint8_t sub_id = 1; + const uint8_t shared_sub = 0; + const int16_t server_keep_alive = 25; + const std::string response_information = "info"; + const std::string server_reference = "server reference"; + const std::string authentication_method = "method"; + const std::string authentication_data = "data"; + + connack_props cprops = create_connack_props(); + + // packets + const std::string connect = encoders::encode_connect( + "", std::nullopt, std::nullopt, 60, false, {}, std::nullopt + ); + const std::string connack = encoders::encode_connack( + false, reason_codes::server_moved.value(), cprops + ); + +private: + connack_props create_connack_props() { + connack_props ret_props; + ret_props[prop::session_expiry_interval] = session_expiry_interval; + ret_props[prop::receive_maximum] = receive_maximum; + ret_props[prop::maximum_qos] = max_qos; + ret_props[prop::retain_available] = retain_available; + ret_props[prop::maximum_packet_size] = maximum_packet_sz; + ret_props[prop::assigned_client_identifier] = assigned_client_id; + ret_props[prop::topic_alias_maximum] = topic_alias_max; + ret_props[prop::reason_string] = reason_string; + ret_props[prop::user_property] = user_properties; + ret_props[prop::wildcard_subscription_available] = wildcard_sub; + ret_props[prop::subscription_identifier_available] = sub_id; + ret_props[prop::shared_subscription_available] = shared_sub; + ret_props[prop::server_keep_alive] = server_keep_alive; + ret_props[prop::response_information] = response_information; + ret_props[prop::server_reference] = server_reference; + ret_props[prop::authentication_method] = authentication_method; + ret_props[prop::authentication_data] = authentication_data; + return ret_props; + } +}; + +template +void run_test_with_post_fun( + test::msg_exchange broker_side, TestingClientFun&& client_fun +) { + asio::io_context ioc; + auto executor = ioc.get_executor(); + auto& broker = asio::make_service( + ioc, executor, std::move(broker_side) + ); + + client_type c(executor); + c.brokers("127.0.0.1,127.0.0.1") // to avoid reconnect backoff + .async_run(asio::detached); + + ioc.run_for(5s); + client_fun(c); + BOOST_TEST(broker.received_all_expected()); +} + + +BOOST_FIXTURE_TEST_CASE(connack_properties, shared_connack_prop_test_data) { + test::msg_exchange broker_side; + broker_side + .expect(connect) + .complete_with(success, after(0ms)) + .reply_with(connack, after(1ms)); + + run_test_with_post_fun( + std::move(broker_side), + [&](client_type& c) { + connack_props cprops_ = c.connack_properties(); + cprops_.visit([&](const auto& p, const auto& val) -> bool { + BOOST_TEST_REQUIRE(p); + if constexpr (is_vector) + BOOST_TEST(val == cprops[p]); + else { + BOOST_TEST_REQUIRE(val.has_value()); + BOOST_TEST(*val == *cprops[p]); + } + return true; + }); + } + ); +} + +BOOST_FIXTURE_TEST_CASE(connack_property, shared_connack_prop_test_data) { + test::msg_exchange broker_side; + broker_side + .expect(connect) + .complete_with(success, after(0ms)) + .reply_with(connack, after(1ms)); + + run_test_with_post_fun( + std::move(broker_side), + [&](client_type& c) { + cprops.visit([&](const auto& p, const auto& val) -> bool{ + if constexpr (is_vector) + BOOST_TEST(val == c.connack_property(p)); + else { + BOOST_TEST_REQUIRE(val.has_value()); + BOOST_TEST(*val == *c.connack_property(p)); + } + return true; + }); + } + ); +} + +BOOST_FIXTURE_TEST_CASE(connack_property_with_tls_client, shared_connack_prop_test_data) { + // Tests if the connack_properties & connack_property functions compile + + asio::io_context ioc; + + asio::ssl::context ctx(asio::ssl::context::tls_client); + mqtt_client< + asio::ssl::stream, asio::ssl::context + > ts(ioc.get_executor(), std::move(ctx)); + + auto cprops_ = ts.connack_properties(); + cprops_.visit([&ts](const auto& p, auto&) -> bool { + using ptype = boost::remove_cv_ref_t; + [[maybe_unused]] prop::value_type_t value = ts.connack_property(p); + return true; + }); +} + +BOOST_AUTO_TEST_SUITE_END(); diff --git a/test/integration/coroutine.cpp b/test/integration/coroutine.cpp index 120ed8e..26d8696 100644 --- a/test/integration/coroutine.cpp +++ b/test/integration/coroutine.cpp @@ -113,7 +113,6 @@ BOOST_AUTO_TEST_CASE(tcp_client_check) { client_type c(ioc); c.brokers("broker.hivemq.com", 1883) - .will({ "test/mqtt-test", "Client disconnected!", qos_e::at_least_once }) .async_run(asio::detached); asio::steady_timer timer(ioc); @@ -148,7 +147,6 @@ BOOST_AUTO_TEST_CASE(websocket_tcp_client_check) { client_type c(ioc); c.brokers("broker.hivemq.com/mqtt", 8000) - .will({ "test/mqtt-test", "Client disconnected!", qos_e::at_least_once }) .async_run(asio::detached); asio::steady_timer timer(ioc); @@ -183,7 +181,6 @@ BOOST_AUTO_TEST_CASE(openssl_tls_client_check) { client_type c(ioc, std::move(tls_context)); c.brokers("broker.hivemq.com", 8883) - .will({ "test/mqtt-test", "Client disconnected!", qos_e::at_least_once }) .async_run(asio::detached); asio::steady_timer timer(ioc); @@ -220,7 +217,6 @@ BOOST_AUTO_TEST_CASE(websocket_tls_client_check) { client_type c(ioc, std::move(tls_context)); c.brokers("broker.hivemq.com/mqtt", 8884) - .will({ "test/mqtt-test", "Client disconnected!", qos_e::at_least_once }) .async_run(asio::detached); asio::steady_timer timer(ioc); diff --git a/test/unit/compilation_checks.cpp b/test/unit/traits.cpp similarity index 64% rename from test/unit/compilation_checks.cpp rename to test/unit/traits.cpp index 42ea8ba..6a432a9 100644 --- a/test/unit/compilation_checks.cpp +++ b/test/unit/traits.cpp @@ -53,8 +53,6 @@ struct bad_authenticator { } }; - - BOOST_AUTO_TEST_CASE(is_authenticator) { BOOST_STATIC_ASSERT(detail::is_authenticator); BOOST_STATIC_ASSERT(!detail::is_authenticator); @@ -68,63 +66,32 @@ using tls_layer = asio::ssl::stream; using websocket_tcp_layer = beast::websocket::stream; using websocket_tls_layer = beast::websocket::stream; -BOOST_AUTO_TEST_CASE(async_traits) { +BOOST_AUTO_TEST_CASE(has_next_layer) { BOOST_STATIC_ASSERT(!detail::has_next_layer); BOOST_STATIC_ASSERT(detail::has_next_layer); BOOST_STATIC_ASSERT(detail::has_next_layer); BOOST_STATIC_ASSERT(detail::has_next_layer); +} +BOOST_AUTO_TEST_CASE(has_tls_layer) { BOOST_STATIC_ASSERT(!detail::has_tls_layer); BOOST_STATIC_ASSERT(detail::has_tls_layer); BOOST_STATIC_ASSERT(!detail::has_tls_layer); BOOST_STATIC_ASSERT(detail::has_tls_layer); +} - BOOST_STATIC_ASSERT(!detail::has_ws_handshake); - BOOST_STATIC_ASSERT(!detail::has_ws_handshake); - BOOST_STATIC_ASSERT(detail::has_ws_handshake); - BOOST_STATIC_ASSERT(detail::has_ws_handshake); - +BOOST_AUTO_TEST_CASE(has_tls_handshake) { BOOST_STATIC_ASSERT(!detail::has_tls_handshake); BOOST_STATIC_ASSERT(detail::has_tls_handshake); BOOST_STATIC_ASSERT(!detail::has_tls_handshake); BOOST_STATIC_ASSERT(!detail::has_tls_handshake); } -BOOST_AUTO_TEST_CASE(client_functions) { - asio::io_context ioc; - - mqtt_client tcp_client(ioc); - tcp_client.authenticator(good_authenticator()); - - connack_props ca_props; - ca_props.visit([&tcp_client](const auto& p, auto&) -> bool { - using ptype = boost::remove_cv_ref_t; - [[maybe_unused]] prop::value_type_t value = tcp_client.connack_property(p); - return true; - }); - - connack_props ret_ca_props = tcp_client.connack_properties(); - - connect_props co_props; - co_props[prop::maximum_packet_size] = 1234; - tcp_client.connect_properties(std::move(co_props)); - - tcp_client.connect_property(prop::session_expiry_interval, 40); - tcp_client.connect_property(prop::receive_maximum, uint16_t(10123)); - tcp_client.connect_property(prop::maximum_packet_size, 103); - tcp_client.connect_property(prop::topic_alias_maximum, uint16_t(12345)); - tcp_client.connect_property(prop::request_response_information, uint8_t(1)); - tcp_client.connect_property(prop::request_problem_information, uint8_t(0)); - tcp_client.connect_property(prop::user_property, std::vector { "prop", "prop" }); - tcp_client.connect_property(prop::authentication_method, "method"); - tcp_client.connect_property(prop::authentication_data, "data"); - - asio::ssl::context ctx(asio::ssl::context::tls_client); - mqtt_client< - tls_layer, asio::ssl::context - > tls_client(ioc.get_executor(), std::move(ctx)); - tls_client.tls_context(); +BOOST_AUTO_TEST_CASE(has_ws_handskae) { + BOOST_STATIC_ASSERT(!detail::has_ws_handshake); + BOOST_STATIC_ASSERT(!detail::has_ws_handshake); + BOOST_STATIC_ASSERT(detail::has_ws_handshake); + BOOST_STATIC_ASSERT(detail::has_ws_handshake); } - BOOST_AUTO_TEST_SUITE_END();