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
This commit is contained in:
Korina Šimičević
2024-02-15 13:57:22 +01:00
parent eb510ae1d4
commit b40ddb3ced
6 changed files with 446 additions and 50 deletions

View File

@ -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);
}
);

View File

@ -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)

View File

@ -0,0 +1,433 @@
#include <boost/test/unit_test.hpp>
#include <chrono>
#include <optional>
#include <boost/asio/io_context.hpp>
#include <boost/asio/steady_timer.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/ssl/stream.hpp>
#include <async_mqtt5/mqtt_client.hpp>
#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<test::test_stream>;
template <typename TestingClientFun>
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<test::test_broker>(
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::ip::tcp::socket>, 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::ip::tcp::socket>, 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> 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::ip::tcp::socket>, 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<std::string> user_properties = std::vector<std::string>{ "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::ip::tcp::socket>, 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::ip::tcp::socket>, 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<std::string> user_properties = std::vector<std::string>{ "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 <typename TestingClientFun>
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<test::test_broker>(
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<decltype(val)>)
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<decltype(val)>)
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::ip::tcp::socket>, 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<decltype(p)>;
[[maybe_unused]] prop::value_type_t<ptype::value> value = ts.connack_property(p);
return true;
});
}
BOOST_AUTO_TEST_SUITE_END();

View File

@ -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);

View File

@ -53,8 +53,6 @@ struct bad_authenticator {
}
};
BOOST_AUTO_TEST_CASE(is_authenticator) {
BOOST_STATIC_ASSERT(detail::is_authenticator<good_authenticator>);
BOOST_STATIC_ASSERT(!detail::is_authenticator<bad_authenticator>);
@ -68,63 +66,32 @@ using tls_layer = asio::ssl::stream<asio::ip::tcp::socket>;
using websocket_tcp_layer = beast::websocket::stream<tcp_layer>;
using websocket_tls_layer = beast::websocket::stream<tls_layer>;
BOOST_AUTO_TEST_CASE(async_traits) {
BOOST_AUTO_TEST_CASE(has_next_layer) {
BOOST_STATIC_ASSERT(!detail::has_next_layer<tcp_layer>);
BOOST_STATIC_ASSERT(detail::has_next_layer<tls_layer>);
BOOST_STATIC_ASSERT(detail::has_next_layer<websocket_tcp_layer>);
BOOST_STATIC_ASSERT(detail::has_next_layer<websocket_tls_layer>);
}
BOOST_AUTO_TEST_CASE(has_tls_layer) {
BOOST_STATIC_ASSERT(!detail::has_tls_layer<tcp_layer>);
BOOST_STATIC_ASSERT(detail::has_tls_layer<tls_layer>);
BOOST_STATIC_ASSERT(!detail::has_tls_layer<websocket_tcp_layer>);
BOOST_STATIC_ASSERT(detail::has_tls_layer<websocket_tls_layer>);
}
BOOST_STATIC_ASSERT(!detail::has_ws_handshake<tcp_layer>);
BOOST_STATIC_ASSERT(!detail::has_ws_handshake<tls_layer>);
BOOST_STATIC_ASSERT(detail::has_ws_handshake<websocket_tcp_layer>);
BOOST_STATIC_ASSERT(detail::has_ws_handshake<websocket_tls_layer>);
BOOST_AUTO_TEST_CASE(has_tls_handshake) {
BOOST_STATIC_ASSERT(!detail::has_tls_handshake<tcp_layer>);
BOOST_STATIC_ASSERT(detail::has_tls_handshake<tls_layer>);
BOOST_STATIC_ASSERT(!detail::has_tls_handshake<websocket_tcp_layer>);
BOOST_STATIC_ASSERT(!detail::has_tls_handshake<websocket_tls_layer>);
}
BOOST_AUTO_TEST_CASE(client_functions) {
asio::io_context ioc;
mqtt_client<tcp_layer> 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<decltype(p)>;
[[maybe_unused]] prop::value_type_t<ptype::value> 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<std::string> { "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<tcp_layer>);
BOOST_STATIC_ASSERT(!detail::has_ws_handshake<tls_layer>);
BOOST_STATIC_ASSERT(detail::has_ws_handshake<websocket_tcp_layer>);
BOOST_STATIC_ASSERT(detail::has_ws_handshake<websocket_tls_layer>);
}
BOOST_AUTO_TEST_SUITE_END();