diff --git a/src/mqtt/token.h b/src/mqtt/token.h index efb1659..9b36491 100644 --- a/src/mqtt/token.h +++ b/src/mqtt/token.h @@ -118,7 +118,7 @@ private: /** Client and token-related options have special access */ friend class async_client; - friend class token_test; + friend class mock_async_client; friend class connect_options; friend class response_options; diff --git a/test/cppunit/test.cpp b/test/cppunit/test.cpp index 05d9ce9..2e3aac3 100644 --- a/test/cppunit/test.cpp +++ b/test/cppunit/test.cpp @@ -21,7 +21,6 @@ #include "async_client_v3_test.h" #include "client_test.h" #include "iclient_persistence_test.h" -#include "token_test.h" using namespace CppUnit; @@ -30,7 +29,6 @@ using namespace CppUnit; int main(int argc, char* argv[]) { CPPUNIT_TEST_SUITE_REGISTRATION( mqtt::iclient_persistence_test ); - CPPUNIT_TEST_SUITE_REGISTRATION( mqtt::token_test ); CPPUNIT_TEST_SUITE_REGISTRATION( mqtt::async_client_test ); CPPUNIT_TEST_SUITE_REGISTRATION( mqtt::async_client_v3_test ); diff --git a/test/cppunit/token_test.h b/test/cppunit/token_test.h deleted file mode 100644 index dd4d0a5..0000000 --- a/test/cppunit/token_test.h +++ /dev/null @@ -1,379 +0,0 @@ -// token_test.h -// Unit tests for the token class in the Paho MQTT C++ library. - -/******************************************************************************* - * Copyright (c) 2016 Guilherme M. Ferreira - * Copyright (c) 2016-2019 Frank Pagliughi - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v1.0 which accompany this distribution. - * - * The Eclipse Public License is available at - * http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * Contributors: - * Guilherme M. Ferreira - initial implementation and documentation - * Frank Pagliughi - additional tests. Made this test a friend of token. - * Frank Pagliughi - Updated for token::Type - *******************************************************************************/ - -#ifndef __mqtt_token_test_h -#define __mqtt_token_test_h - -#include -#include -#include - -#include -#include - -#include "mqtt/token.h" -#include "dummy_async_client.h" -#include "dummy_action_listener.h" - -namespace mqtt { - -///////////////////////////////////////////////////////////////////////////// - -class token_test : public CppUnit::TestFixture -{ - CPPUNIT_TEST_SUITE( token_test ); - - CPPUNIT_TEST( test_user_constructor_client ); - CPPUNIT_TEST( test_user_constructor_client_token ); - CPPUNIT_TEST( test_user_constructor_client_string ); - CPPUNIT_TEST( test_user_constructor_client_vector ); - CPPUNIT_TEST( test_on_success_with_data ); - CPPUNIT_TEST( test_on_success_without_data ); - CPPUNIT_TEST( test_on_failure_with_data ); - CPPUNIT_TEST( test_on_failure_without_data ); - CPPUNIT_TEST( test_action_callback ); - CPPUNIT_TEST( test_wait_success ); - CPPUNIT_TEST( test_wait_failure ); - CPPUNIT_TEST( test_wait_for_timeout ); - - CPPUNIT_TEST_SUITE_END(); - - using milliseconds = std::chrono::milliseconds; - using steady_clock = std::chrono::steady_clock; - - mqtt::test::dummy_async_client cli; - - static constexpr token::Type TYPE = token::Type::CONNECT; - -public: - void setUp() {} - void tearDown() {} - -// ---------------------------------------------------------------------- -// Test user constructor (iasync_client) -// ---------------------------------------------------------------------- - - void test_user_constructor_client() { - mqtt::token tok{ TYPE, cli }; - CPPUNIT_ASSERT_EQUAL(0, tok.get_message_id()); - CPPUNIT_ASSERT_EQUAL(dynamic_cast(&cli), tok.get_client()); - CPPUNIT_ASSERT(nullptr == tok.get_user_context()); - CPPUNIT_ASSERT(nullptr == tok.get_action_callback()); - CPPUNIT_ASSERT_EQUAL(false, tok.is_complete()); - CPPUNIT_ASSERT(nullptr == tok.get_topics()); - } - -// ---------------------------------------------------------------------- -// Test user constructor (iasync_client, MQTTAsync_token) -// ---------------------------------------------------------------------- - - void test_user_constructor_client_token() { - MQTTAsync_token id {2}; - mqtt::token tok{ TYPE, cli, id }; - CPPUNIT_ASSERT_EQUAL(id, tok.get_message_id()); - CPPUNIT_ASSERT_EQUAL(dynamic_cast(&cli), tok.get_client()); - CPPUNIT_ASSERT(nullptr == tok.get_user_context()); - CPPUNIT_ASSERT(nullptr == tok.get_action_callback()); - CPPUNIT_ASSERT_EQUAL(false, tok.is_complete()); - CPPUNIT_ASSERT(nullptr == tok.get_topics()); - } - -// ---------------------------------------------------------------------- -// Test user constructor (iasync_client, string) -// ---------------------------------------------------------------------- - - void test_user_constructor_client_string() { - std::string topic { "topic" }; - mqtt::token tok{ TYPE, cli, topic }; - CPPUNIT_ASSERT_EQUAL(0, tok.get_message_id()); - CPPUNIT_ASSERT_EQUAL(dynamic_cast(&cli), tok.get_client()); - CPPUNIT_ASSERT(nullptr == tok.get_user_context()); - CPPUNIT_ASSERT(nullptr == tok.get_action_callback()); - CPPUNIT_ASSERT_EQUAL(false, tok.is_complete()); - CPPUNIT_ASSERT(nullptr != tok.get_topics()); - CPPUNIT_ASSERT_EQUAL(size_t(1), tok.get_topics()->size()); - CPPUNIT_ASSERT_EQUAL(topic, (*tok.get_topics())[0]); - } - -// ---------------------------------------------------------------------- -// Test user constructor (iasync_client, vector) -// ---------------------------------------------------------------------- - - void test_user_constructor_client_vector() { - auto topics = string_collection::create({ "topic1", "topic2" }); - mqtt::token tok{ TYPE, cli, topics }; - CPPUNIT_ASSERT_EQUAL(0, tok.get_message_id()); - CPPUNIT_ASSERT_EQUAL(dynamic_cast(&cli), tok.get_client()); - CPPUNIT_ASSERT_EQUAL(static_cast(nullptr), tok.get_user_context()); - CPPUNIT_ASSERT_EQUAL(static_cast(nullptr), tok.get_action_callback()); - CPPUNIT_ASSERT_EQUAL(false, tok.is_complete()); - CPPUNIT_ASSERT(nullptr != tok.get_topics()); - CPPUNIT_ASSERT_EQUAL(size_t(2), tok.get_topics()->size()); - CPPUNIT_ASSERT_EQUAL((*topics)[0], (*tok.get_topics())[0]); - CPPUNIT_ASSERT_EQUAL((*topics)[1], (*tok.get_topics())[1]); - } - -// ---------------------------------------------------------------------- -// Test on success with data -// ---------------------------------------------------------------------- - - void test_on_success_with_data() { - mqtt::token tok{ TYPE, cli }; - - constexpr int MESSAGE_ID = 12; - MQTTAsync_successData data = { - .token = MESSAGE_ID, - }; - data.alt.connect.serverURI = const_cast("tcp://some_server.com"); - - CPPUNIT_ASSERT_EQUAL(false, tok.is_complete()); - token::on_success(&tok, &data); - CPPUNIT_ASSERT_EQUAL(true, tok.is_complete()); - CPPUNIT_ASSERT_EQUAL(MESSAGE_ID, tok.get_message_id()); - } - -// ---------------------------------------------------------------------- -// Test on success without data -// ---------------------------------------------------------------------- - - void test_on_success_without_data() { - mqtt::token tok{ TYPE, cli }; - - CPPUNIT_ASSERT_EQUAL(false, tok.is_complete()); - token::on_success(&tok, nullptr); - CPPUNIT_ASSERT_EQUAL(true, tok.is_complete()); - } - -// ---------------------------------------------------------------------- -// Test on failure with data -// ---------------------------------------------------------------------- - - void test_on_failure_with_data() { - mqtt::token tok{ TYPE, cli }; - - CPPUNIT_ASSERT_EQUAL(false, tok.is_complete()); - constexpr int MESSAGE_ID = 12; - MQTTAsync_failureData data = { - .token = MESSAGE_ID, - .code = 13, - .message = nullptr, - }; - token::on_failure(&tok, &data); - CPPUNIT_ASSERT_EQUAL(true, tok.is_complete()); - CPPUNIT_ASSERT_EQUAL(MESSAGE_ID, tok.get_message_id()); - } - -// ---------------------------------------------------------------------- -// Test on failure without data -// ---------------------------------------------------------------------- - - void test_on_failure_without_data() { - mqtt::token tok{ TYPE, cli }; - - CPPUNIT_ASSERT_EQUAL(false, tok.is_complete()); - token::on_failure(&tok, nullptr); - CPPUNIT_ASSERT_EQUAL(true, tok.is_complete()); - CPPUNIT_ASSERT_EQUAL(0, tok.get_message_id()); - } - -// ---------------------------------------------------------------------- -// Test set callbacks -// ---------------------------------------------------------------------- - - void test_action_callback() { - mqtt::test::dummy_action_listener listener; - mqtt::token tok{ TYPE, cli }; - tok.set_action_callback(listener); - CPPUNIT_ASSERT_EQUAL(dynamic_cast(&listener), tok.get_action_callback()); - - CPPUNIT_ASSERT_EQUAL(false, listener.on_success_called); - token::on_success(&tok, nullptr); - CPPUNIT_ASSERT_EQUAL(true, listener.on_success_called); - - CPPUNIT_ASSERT_EQUAL(false, listener.on_failure_called); - token::on_failure(&tok, nullptr); - CPPUNIT_ASSERT_EQUAL(true, listener.on_failure_called); - } - -// ---------------------------------------------------------------------- -// Test wait for completion on success case -// All wait's should succeed immediately on successful completion. -// ---------------------------------------------------------------------- - - void test_wait_success() { - const auto TIMEOUT = milliseconds(10); - - mqtt::token tok{ TYPE, cli }; - - // NOTE: Make sure the complete flag is already true and the return - // code (rc) is MQTTASYNC_SUCCESS, so the token::wait() - // returns immediately. Otherwise we will get stuck in a single thread - // that can't change the complete flag. - token::on_success(&tok, nullptr); - CPPUNIT_ASSERT_EQUAL(true, tok.is_complete()); - - // A wait does not reset the "complete" flag. - - try { - tok.wait(); - CPPUNIT_ASSERT_EQUAL(true, tok.is_complete()); - } - catch (...) { - CPPUNIT_FAIL("token::wait() should not throw on success"); - } - - // try_wait() - try { - CPPUNIT_ASSERT_EQUAL(true, tok.try_wait()); - CPPUNIT_ASSERT_EQUAL(true, tok.is_complete()); - } - catch (...) { - CPPUNIT_FAIL("token::wait() should not throw on success"); - } - - // wait_for() - try { - CPPUNIT_ASSERT_EQUAL(true, tok.wait_for(TIMEOUT)); - CPPUNIT_ASSERT_EQUAL(true, tok.is_complete()); - } - catch (...) { - CPPUNIT_FAIL("token::wait_for() should not throw on success"); - } - - // wait_until() - const auto TO = steady_clock::now() + TIMEOUT; - try { - CPPUNIT_ASSERT_EQUAL(true, tok.wait_until(TO)); - CPPUNIT_ASSERT_EQUAL(true, tok.is_complete()); - } - catch (...) { - CPPUNIT_FAIL("token::wait_until() should not throw on success"); - } - } - -// ---------------------------------------------------------------------- -// Test wait for completion on failure case -// All wait's should throw if the action failed -// ---------------------------------------------------------------------- - - void test_wait_failure() { - const auto TIMEOUT = milliseconds(10); - - mqtt::token tok{ TYPE, cli }; - - // NOTE: Make sure the complete flag is already true and the return - // code (rc) is MQTTASYNC_FAILURE, so the token::wait() - // returns immediately. Otherwise we will get stuck in a single thread - // that can't change the complete flag. - constexpr int MESSAGE_ID = 12; - MQTTAsync_failureData data = { - .token = MESSAGE_ID, - .code = MQTTASYNC_FAILURE, - .message = nullptr, - }; - token::on_failure(&tok, &data); - - CPPUNIT_ASSERT_EQUAL(true, tok.is_complete()); - CPPUNIT_ASSERT_EQUAL(MESSAGE_ID, tok.get_message_id()); - CPPUNIT_ASSERT_EQUAL(MQTTASYNC_FAILURE, tok.get_return_code()); - - try { - tok.wait(); - CPPUNIT_FAIL("token::wait() should throw on failure"); - } - catch (mqtt::exception& ex) { - CPPUNIT_ASSERT_EQUAL(MQTTASYNC_FAILURE, ex.get_return_code()); - } - - try { - tok.try_wait(); - CPPUNIT_FAIL("token::try_wait() should throw on failure"); - } - catch (mqtt::exception& ex) { - CPPUNIT_ASSERT_EQUAL(MQTTASYNC_FAILURE, ex.get_return_code()); - } - - try { - tok.wait_for(TIMEOUT); - CPPUNIT_FAIL("token::wait_for() should throw on failure"); - } - catch (mqtt::exception& ex) { - CPPUNIT_ASSERT_EQUAL(MQTTASYNC_FAILURE, ex.get_return_code()); - } - - try { - tok.wait_until(steady_clock::now() + TIMEOUT); - CPPUNIT_FAIL("token::wait_until() should throw on failure"); - } - catch (mqtt::exception& ex) { - CPPUNIT_ASSERT_EQUAL(MQTTASYNC_FAILURE, ex.get_return_code()); - } - } - -// ---------------------------------------------------------------------- -// Test wait for completion on failure due timeout case -// All waits should return false, but not throw, on a timeout -// ---------------------------------------------------------------------- - - void test_wait_for_timeout() { - const auto TIMEOUT = milliseconds(10); - - mqtt::token tok{ TYPE, cli }; - - // Test for timeout on non-signaled token. - CPPUNIT_ASSERT_EQUAL(false, tok.is_complete()); - - // try_wait() - try { - CPPUNIT_ASSERT_EQUAL(false, tok.try_wait()); - } - catch (...) { - CPPUNIT_FAIL("token::try_wait() should not throw"); - } - - // wait_for() - CPPUNIT_ASSERT_EQUAL(false, tok.is_complete()); - try { - CPPUNIT_ASSERT_EQUAL(false, tok.wait_for(TIMEOUT)); - } - catch (...) { - CPPUNIT_FAIL("token::wait_for() should not throw on timeout"); - } - - // wait_until() - const auto TO = steady_clock::now() + TIMEOUT; - CPPUNIT_ASSERT_EQUAL(false, tok.is_complete()); - try { - CPPUNIT_ASSERT_EQUAL(false, tok.wait_until(TO)); - } - catch (...) { - CPPUNIT_FAIL("token::wait_until() should not throw on timeout"); - } - } -}; - -///////////////////////////////////////////////////////////////////////////// -// end namespace mqtt -} - -#endif // __mqtt_token_test_h - diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt index 6fdbc2d..57e291f 100644 --- a/test/unit/CMakeLists.txt +++ b/test/unit/CMakeLists.txt @@ -38,6 +38,7 @@ add_executable(unit_tests unit_tests.cpp test_properties.cpp test_response_options.cpp test_string_collection.cpp + test_token.cpp test_topic.cpp test_will_options.cpp ) diff --git a/test/unit/mock_async_client.h b/test/unit/mock_async_client.h index ea5885d..ce75bb4 100644 --- a/test/unit/mock_async_client.h +++ b/test/unit/mock_async_client.h @@ -30,7 +30,6 @@ #include "mqtt/connect_options.h" namespace mqtt { -namespace test { ///////////////////////////////////////////////////////////////////////////// @@ -39,6 +38,25 @@ class mock_async_client : public mqtt::iasync_client public: void remove_token(mqtt::token* tok) override {} + + static void succeed(mqtt::token* tok, MQTTAsync_successData* rsp) { + token::on_success(tok, rsp); + } + + static void succeed5(mqtt::token* tok, MQTTAsync_successData5* rsp) { + token::on_success5(tok, rsp); + } + + static void fail(mqtt::token* tok, MQTTAsync_failureData* rsp) { + token::on_failure(tok, rsp); + } + + static void fail5(mqtt::token* tok, MQTTAsync_failureData5* rsp) { + token::on_failure5(tok, rsp); + } + + // iface + mqtt::token_ptr connect() override { return mqtt::token_ptr{}; } @@ -185,10 +203,6 @@ public: } }; -///////////////////////////////////////////////////////////////////////////// -// end namespace test -} - ///////////////////////////////////////////////////////////////////////////// // end namespace mqtt } diff --git a/test/unit/test_connect_options.cpp b/test/unit/test_connect_options.cpp index 2ab9349..9281ab2 100644 --- a/test/unit/test_connect_options.cpp +++ b/test/unit/test_connect_options.cpp @@ -356,7 +356,7 @@ TEST_CASE("set_token", "[options]") REQUIRE(nullptr == c_struct.context); SECTION("set token") { - mqtt::test::mock_async_client ac; + mock_async_client ac; auto tok = token::create(TOKEN_TYPE, ac); opts.set_token(tok); REQUIRE(tok == opts.get_token()); diff --git a/test/unit/test_disconnect_options.cpp b/test/unit/test_disconnect_options.cpp index 4e9c2ba..e7c29a9 100644 --- a/test/unit/test_disconnect_options.cpp +++ b/test/unit/test_disconnect_options.cpp @@ -34,7 +34,7 @@ static const std::string EMPTY_STR; static constexpr token::Type TOKEN_TYPE = token::Type::DISCONNECT; -static mqtt::test::mock_async_client cli; +static mock_async_client cli; // ---------------------------------------------------------------------- // Test default constructor diff --git a/test/unit/test_response_options.cpp b/test/unit/test_response_options.cpp index 9558e62..1265398 100644 --- a/test/unit/test_response_options.cpp +++ b/test/unit/test_response_options.cpp @@ -37,7 +37,7 @@ using namespace mqtt; static constexpr token::Type TOKEN_TYPE = token::Type::CONNECT; -static mqtt::test::mock_async_client cli; +static mock_async_client cli; // ---------------------------------------------------------------------- // Test default constructor @@ -113,7 +113,7 @@ TEST_CASE("delivery_response_options dflt constructor", "[options]") TEST_CASE("delivery_response_options user constructor", "[options]") { - mqtt::test::mock_async_client cli; + mock_async_client cli; mqtt::delivery_token_ptr token { new mqtt::delivery_token{ cli } }; mqtt::delivery_response_options opts { token }; @@ -137,7 +137,7 @@ TEST_CASE("delivery_response_options set token", "[options]") REQUIRE(c_struct.context == nullptr); - mqtt::test::mock_async_client cli; + mock_async_client cli; mqtt::delivery_token_ptr token { new mqtt::delivery_token{ cli } }; opts.set_token( token ); REQUIRE(c_struct.context == token.get()); diff --git a/test/unit/test_token.cpp b/test/unit/test_token.cpp new file mode 100644 index 0000000..e4d1dfc --- /dev/null +++ b/test/unit/test_token.cpp @@ -0,0 +1,358 @@ +// test_token.h +// +// Unit tests for the token class in the Paho MQTT C++ library. +// + +/******************************************************************************* + * Copyright (c) 2016 Guilherme M. Ferreira + * Copyright (c) 2016-2020 Frank Pagliughi + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v1.0 which accompany this distribution. + * + * The Eclipse Public License is available at + * http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * Guilherme M. Ferreira + * - initial implementation and documentation + * Frank Pagliughi + * - additional tests. Made this test a friend of token. + * - updated for token::Type + * - Converted to use Catch2 + *******************************************************************************/ + +#define UNIT_TESTS + +#include +#include "catch2/catch.hpp" +#include "mqtt/token.h" +#include "mock_async_client.h" +#include "mock_action_listener.h" + +using namespace mqtt; + +using milliseconds = std::chrono::milliseconds; +using steady_clock = std::chrono::steady_clock; + +static mock_async_client cli; + +static constexpr token::Type TYPE = token::Type::CONNECT; + +// ---------------------------------------------------------------------- +// Test user constructor (iasync_client) +// ---------------------------------------------------------------------- + +TEST_CASE("token user constructor client", "[token]") +{ + mqtt::token tok{TYPE, cli}; + REQUIRE(0 == tok.get_message_id()); + REQUIRE(dynamic_cast(&cli) == tok.get_client()); + REQUIRE(nullptr == tok.get_user_context()); + REQUIRE(nullptr == tok.get_action_callback()); + REQUIRE(!tok.is_complete()); + REQUIRE(nullptr == tok.get_topics()); +} + +// ---------------------------------------------------------------------- +// Test user constructor (iasync_client, MQTTAsync_token) +// ---------------------------------------------------------------------- + +TEST_CASE("token user constructor client token", "[token]") +{ + MQTTAsync_token id{2}; + mqtt::token tok{TYPE, cli, id}; + REQUIRE(id == tok.get_message_id()); + REQUIRE(dynamic_cast(&cli) == tok.get_client()); + REQUIRE(nullptr == tok.get_user_context()); + REQUIRE(nullptr == tok.get_action_callback()); + REQUIRE(!tok.is_complete()); + REQUIRE(nullptr == tok.get_topics()); +} + +// ---------------------------------------------------------------------- +// Test user constructor (iasync_client, string) +// ---------------------------------------------------------------------- + +TEST_CASE("token user constructor client string", "[token]") +{ + std::string topic{"topic"}; + mqtt::token tok{TYPE, cli, topic}; + REQUIRE(0 == tok.get_message_id()); + REQUIRE(dynamic_cast(&cli) == tok.get_client()); + REQUIRE(nullptr == tok.get_user_context()); + REQUIRE(nullptr == tok.get_action_callback()); + REQUIRE(!tok.is_complete()); + REQUIRE(nullptr != tok.get_topics()); + REQUIRE(size_t(1) == tok.get_topics()->size()); + REQUIRE(topic == (*tok.get_topics())[0]); +} + +// ---------------------------------------------------------------------- +// Test user constructor (iasync_client, vector) +// ---------------------------------------------------------------------- + +TEST_CASE("token user constructor client vector", "[token]") +{ + auto topics = string_collection::create({ "topic1", "topic2" }); + mqtt::token tok{TYPE, cli, topics}; + REQUIRE(0 == tok.get_message_id()); + REQUIRE(dynamic_cast(&cli) == tok.get_client()); + REQUIRE(static_cast(nullptr) == tok.get_user_context()); + REQUIRE(static_cast(nullptr) == tok.get_action_callback()); + REQUIRE(!tok.is_complete()); + REQUIRE(nullptr != tok.get_topics()); + REQUIRE(size_t(2) == tok.get_topics()->size()); + REQUIRE((*topics)[0] == (*tok.get_topics())[0]); + REQUIRE((*topics)[1] == (*tok.get_topics())[1]); +} + +// ---------------------------------------------------------------------- +// Test on success with data +// ---------------------------------------------------------------------- + +TEST_CASE("token on success with data", "[token]") +{ + mqtt::token tok{TYPE, cli}; + + constexpr int MESSAGE_ID = 12; + MQTTAsync_successData data = { + .token = MESSAGE_ID, + }; + data.alt.connect.serverURI = const_cast("tcp://some_server.com"); + + REQUIRE(!tok.is_complete()); + mock_async_client::succeed(&tok, &data); + REQUIRE(tok.is_complete()); + REQUIRE(MESSAGE_ID == tok.get_message_id()); +} + +// ---------------------------------------------------------------------- +// Test on success without data +// ---------------------------------------------------------------------- + +TEST_CASE("token on success without data", "[token]") +{ + mqtt::token tok{TYPE, cli}; + + REQUIRE(!tok.is_complete()); + mock_async_client::succeed(&tok, nullptr); + REQUIRE(tok.is_complete()); +} + +// ---------------------------------------------------------------------- +// Test on failure with data +// ---------------------------------------------------------------------- + +TEST_CASE("token on failure with data", "[token]") +{ + mqtt::token tok{TYPE, cli}; + + REQUIRE(!tok.is_complete()); + constexpr int MESSAGE_ID = 12; + MQTTAsync_failureData data = { + .token = MESSAGE_ID, + .code = 13, + .message = nullptr, + }; + mock_async_client::fail(&tok, &data); + REQUIRE(tok.is_complete()); + REQUIRE(MESSAGE_ID == tok.get_message_id()); +} + +// ---------------------------------------------------------------------- +// Test on failure without data +// ---------------------------------------------------------------------- + +TEST_CASE("token on failure without data", "[token]") +{ + mqtt::token tok{TYPE, cli}; + + REQUIRE(!tok.is_complete()); + mock_async_client::fail(&tok, nullptr); + REQUIRE(tok.is_complete()); + REQUIRE(0 == tok.get_message_id()); +} + +// ---------------------------------------------------------------------- +// Test set callbacks +// ---------------------------------------------------------------------- + +TEST_CASE("token action callback", "[token]") +{ + mock_action_listener listener; + mqtt::token tok{TYPE, cli}; + tok.set_action_callback(listener); + REQUIRE(dynamic_cast(&listener) == tok.get_action_callback()); + + REQUIRE(!listener.on_success_called); + mock_async_client::succeed(&tok, nullptr); + REQUIRE(listener.on_success_called); + + REQUIRE(!listener.on_failure_called); + mock_async_client::fail(&tok, nullptr); + REQUIRE(listener.on_failure_called); +} + +// ---------------------------------------------------------------------- +// Test wait for completion on success case +// All wait's should succeed immediately on successful completion. +// ---------------------------------------------------------------------- + +TEST_CASE("token wait success", "[token]") +{ + const auto TIMEOUT = milliseconds(10); + + mqtt::token tok{TYPE, cli}; + + // NOTE: Make sure the complete flag is already true and the return + // code (rc) is MQTTASYNC_SUCCESS, so the token::wait() + // returns immediately. Otherwise we will get stuck in a single thread + // that can't change the complete flag. + mock_async_client::succeed(&tok, nullptr); + REQUIRE(tok.is_complete()); + + // A wait does not reset the "complete" flag. + + try { + tok.wait(); + REQUIRE(tok.is_complete()); + } + catch (...) { + FAIL("token::wait() should not throw on success"); + } + + // try_wait() + try { + REQUIRE(tok.try_wait()); + REQUIRE(tok.is_complete()); + } + catch (...) { + FAIL("token::wait() should not throw on success"); + } + + // wait_for() + try { + REQUIRE(tok.wait_for(TIMEOUT)); + REQUIRE(tok.is_complete()); + } + catch (...) { + FAIL("token::wait_for() should not throw on success"); + } + + // wait_until() + const auto TO = steady_clock::now() + TIMEOUT; + try { + REQUIRE(tok.wait_until(TO)); + REQUIRE(tok.is_complete()); + } + catch (...) { + FAIL("token::wait_until() should not throw on success"); + } +} + +// ---------------------------------------------------------------------- +// Test wait for completion on failure case +// All wait's should throw if the action failed +// ---------------------------------------------------------------------- + +TEST_CASE("token wait failure", "[token]") +{ + const auto TIMEOUT = milliseconds(10); + + mqtt::token tok{TYPE, cli}; + + // NOTE: Make sure the complete flag is already true and the return + // code (rc) is MQTTASYNC_FAILURE, so the token::wait() + // returns immediately. Otherwise we will get stuck in a single thread + // that can't change the complete flag. + constexpr int MESSAGE_ID = 12; + MQTTAsync_failureData data = { + .token = MESSAGE_ID, + .code = MQTTASYNC_FAILURE, + .message = nullptr, + }; + mock_async_client::fail(&tok, &data); + + REQUIRE(tok.is_complete()); + REQUIRE(MESSAGE_ID == tok.get_message_id()); + REQUIRE(MQTTASYNC_FAILURE == tok.get_return_code()); + + try { + tok.wait(); + FAIL("token::wait() should throw on failure"); + } + catch (mqtt::exception& ex) { + REQUIRE(MQTTASYNC_FAILURE == ex.get_return_code()); + } + + try { + tok.try_wait(); + FAIL("token::try_wait() should throw on failure"); + } + catch (mqtt::exception& ex) { + REQUIRE(MQTTASYNC_FAILURE == ex.get_return_code()); + } + + try { + tok.wait_for(TIMEOUT); + FAIL("token::wait_for() should throw on failure"); + } + catch (mqtt::exception& ex) { + REQUIRE(MQTTASYNC_FAILURE == ex.get_return_code()); + } + + try { + tok.wait_until(steady_clock::now() + TIMEOUT); + FAIL("token::wait_until() should throw on failure"); + } + catch (mqtt::exception& ex) { + REQUIRE(MQTTASYNC_FAILURE == ex.get_return_code()); + } +} + +// ---------------------------------------------------------------------- +// Test wait for completion on failure due timeout case +// All waits should return false, but not throw, on a timeout +// ---------------------------------------------------------------------- + +TEST_CASE("token wait for timeout", "[token]") +{ + const auto TIMEOUT = milliseconds(10); + + mqtt::token tok{TYPE, cli}; + + // Test for timeout on non-signaled token. + REQUIRE(!tok.is_complete()); + + // try_wait() + try { + REQUIRE(!tok.try_wait()); + } + catch (...) { + FAIL("token::try_wait() should not throw"); + } + + // wait_for() + REQUIRE(!tok.is_complete()); + try { + REQUIRE(!tok.wait_for(TIMEOUT)); + } + catch (...) { + FAIL("token::wait_for() should not throw on timeout"); + } + + // wait_until() + const auto TO = steady_clock::now() + TIMEOUT; + REQUIRE(!tok.is_complete()); + try { + REQUIRE(!tok.wait_until(TO)); + } + catch (...) { + FAIL("token::wait_until() should not throw on timeout"); + } +} + diff --git a/test/unit/test_topic.cpp b/test/unit/test_topic.cpp index 0b19768..005b9e9 100644 --- a/test/unit/test_topic.cpp +++ b/test/unit/test_topic.cpp @@ -44,7 +44,7 @@ static const char* BUF = "Hello there"; static const size_t N = std::strlen(BUF); static const binary PAYLOAD { BUF }; -static mqtt::test::mock_async_client cli; +static mqtt::mock_async_client cli; // ---------------------------------------------------------------------- // Constructors diff --git a/test/unit/test_will_options.cpp b/test/unit/test_will_options.cpp index 9ae3647..793f413 100644 --- a/test/unit/test_will_options.cpp +++ b/test/unit/test_will_options.cpp @@ -73,7 +73,7 @@ TEST_CASE("will_options default ctor", "[options]") TEST_CASE("will_options string buf ctor", "[options]") { - test::mock_async_client cli; + mock_async_client cli; mqtt::topic topic { cli, TOPIC }; mqtt::will_options opts(topic, BUF, N, QOS, true);