/* * Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"). * You may not use this file except in compliance with the License. * A copy of the License is located at * * http://aws.amazon.com/apache2.0 * * or in the "license" file accompanying this file. This file is distributed * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either * express or implied. See the License for the specific language governing * permissions and limitations under the License. */ /** * @file ShadowTests.cpp * @brief * */ #include <chrono> #include <gtest/gtest.h> #include "TestHelper.hpp" #include "MockNetworkConnection.hpp" #include "mqtt/NetworkRead.hpp" #include "mqtt/GreengrassMqttClient.hpp" #include "shadow/Shadow.hpp" #define CONNECT_FIXED_HEADER_VAL 0x10 #define DISCONNECT_FIXED_HEADER_VAL 0xE0 #define KEEP_ALIVE_TIMEOUT_SECS 30 #define SUBSCRIPTION_SETTING_TIME_SECS 2 #define KEEP_ALIVE_TIMEOUT_SECS 30 #define MQTT_COMMAND_TIMEOUT_MSECS 20000 #define SHADOW_REQUEST_TYPE_GET_STRING "get" #define SHADOW_REQUEST_TYPE_UPDATE_STRING "update" #define SHADOW_REQUEST_TYPE_DELETE_STRING "delete" #define SHADOW_REQUEST_TYPE_DELTA_STRING "delta" #define SHADOW_RESPONSE_TYPE_ACCEPTED_STRING "accepted" #define SHADOW_RESPONSE_TYPE_REJECTED_STRING "rejected" #define SHADOW_RESPONSE_TYPE_DELTA_STRING "delta" #define SHADOW_TOPIC_PREFIX "$aws/things/" #define SHADOW_TOPIC_MIDDLE "/shadow/" #define SHADOW_DOCUMENT_EMPTY_TEMPLATE "{" \ " \"state\" : {" \ " \"desired\" : {" \ " }," \ " \"reported\" : {" \ " }" \ " }," \ " \"version\" : 0," \ " \"clientToken\" : \"empty\"," \ " \"timestamp\": 0" \ "}" #define SHADOW_DOCUMENT_EMPTY_STRING "{" \ " \"state\" : {" \ " \"desired\" : {" \ " \"cur_msg_count\" : 0" \ " }," \ " \"reported\" : {" \ " \"cur_msg_count\" : 0" \ " }" \ " }" \ "}" #define SHADOW_DOCUMENT_MODIFIED_VALUE_STRING "{" \ " \"state\" : {" \ " \"desired\" : {" \ " \"cur_msg_count\" : 5" \ " }," \ " \"reported\" : {" \ " \"cur_msg_count\" : 10" \ " }" \ " }," \ " \"version\" : 12," \ " \"clientToken\" : \"shadow_test_client\"," \ " \"timestamp\": 12345" \ "}" #define MODIFIED_VALUE_VERSION 12 #define SHADOW_DOCUMENT_MODIFIED_VALUE_STRING_V2 "{" \ " \"state\" : {" \ " \"desired\" : {" \ " \"cur_msg_count\" : 7" \ " }," \ " \"reported\" : {" \ " \"cur_msg_count\" : 11" \ " }" \ " }," \ " \"version\" : 15," \ " \"clientToken\" : \"shadow_test_client\"," \ " \"timestamp\": 12345" \ "}" #define SHADOW_DOCUMENT_MODIFIED_VALUE_STRING_V3 "{" \ " \"state\" : {" \ " \"desired\" : {" \ " \"cur_msg_count\" : 10" \ " }," \ " \"reported\" : {" \ " \"cur_msg_count\" : 13" \ " }" \ " }," \ " \"version\" : 18," \ " \"clientToken\" : \"shadow_test_client\"," \ " \"timestamp\": 12345" \ "}" #define BROKEN_SHADOW_DOCUMENT_WITH_INVALID_VERSION_KEY "{" \ " \"state\" : {" \ " \"desired\" : {" \ " \"cur_msg_count\" : 5" \ " }," \ " \"reported\" : {" \ " \"cur_msg_count\" : 10" \ " }" \ " }," \ " \"version\" : \"weird_version\"," \ " \"clientToken\" : \"shadow_test_client\"," \ " \"timestamp\": 12345" \ "}" #define BROKEN_SHADOW_DOCUMENT_WITH_NO_VERSION_KEY "{" \ " \"state\" : {" \ " \"desired\" : {" \ " \"cur_msg_count\" : 5" \ " }," \ " \"reported\" : {" \ " \"cur_msg_count\" : 10" \ " }" \ " }," \ " \"clientToken\" : \"shadow_test_client\"," \ " \"timestamp\": 12345" \ "}" #define BROKEN_SHADOW_DOCUMENT_WITH_NO_STATE_KEY "{" \ " \"version\" : 12," \ " \"clientToken\" : \"shadow_test_client\"," \ " \"timestamp\": 12345" \ "}" #define SHADOW_REPORTED_DOC "{" \ " \"cur_msg_count\" : 10" \ "}" #define SHADOW_DESIRED_DOC "{" \ " \"cur_msg_count\" : 5" \ "}" #define SHADOW_DOCUMENT_STATE_KEY "state" #define SHADOW_DOCUMENT_REPORTED_KEY "reported" #define SHADOW_DOCUMENT_DESIRED_KEY "desired" #define SHADOW_DOCUMENT_CLIENT_TOKEN_KEY "clientToken" #define SHADOW_DOCUMENT_VERSION_KEY "version" #define SHADOW_DOCUMENT_TIMESTAMP_KEY "timestamp" #define SHADOW_REQUEST_TYPE_GET_STRING "get" #define SHADOW_REQUEST_TYPE_UPDATE_STRING "update" #define SHADOW_REQUEST_TYPE_DELETE_STRING "delete" #define SHADOW_REQUEST_TYPE_DELTA_STRING "delta" #define SHADOW_RESPONSE_TYPE_ACCEPTED_STRING "accepted" #define SHADOW_RESPONSE_TYPE_REJECTED_STRING "rejected" #define SHADOW_RESPONSE_TYPE_DELTA_STRING "delta" #define SHADOW_LOG_TAG "[Shadow]" namespace awsiotsdk { namespace tests { namespace unit { class ShadowTester : public ::testing::Test { protected: std::shared_ptr<mqtt::ClientState> p_core_state_; std::shared_ptr<tests::mocks::MockNetworkConnection> p_network_connection_; tests::mocks::MockNetworkConnection *p_network_mock_; static const util::String test_client_id_; static const std::chrono::seconds keep_alive_timeout_; std::shared_ptr<GreengrassMqttClient> p_iot_greengrass_client_; util::String p_thing_name_; static const std::chrono::milliseconds mqtt_command_timeout_; std::unique_ptr<Shadow> p_test_shadow; static const util::String test_topic_name_; ShadowTester() { p_core_state_ = mqtt::ClientState::Create(std::chrono::milliseconds(200)); p_network_connection_ = std::make_shared<tests::mocks::MockNetworkConnection>(); p_network_mock_ = p_network_connection_.get(); p_iot_greengrass_client_ = std::shared_ptr<GreengrassMqttClient>(GreengrassMqttClient::Create(p_network_connection_, std::chrono::milliseconds( 2000))); p_thing_name_ = "ShadowUnitTestThing"; } }; const util::String ShadowTester::test_client_id_ = "CppSdkTestClient"; const util::String ShadowTester::test_topic_name_ = "SdkTest"; const std::chrono::seconds ShadowTester::keep_alive_timeout_ = std::chrono::seconds(KEEP_ALIVE_TIMEOUT_SECS); const std::chrono::milliseconds ShadowTester::mqtt_command_timeout_ = std::chrono::milliseconds(MQTT_COMMAND_TIMEOUT_MSECS); TEST_F(ShadowTester, ShadowCreateTest) { EXPECT_NE(nullptr, p_iot_greengrass_client_); std::unique_ptr<Shadow> test_shadow = Shadow::Create(nullptr, mqtt_command_timeout_, p_thing_name_, p_thing_name_); EXPECT_EQ(nullptr, test_shadow); util::String empty_thing_name = ""; test_shadow = Shadow::Create(p_iot_greengrass_client_, mqtt_command_timeout_, empty_thing_name, empty_thing_name); EXPECT_EQ(nullptr, test_shadow); test_shadow = Shadow::Create(p_iot_greengrass_client_, mqtt_command_timeout_, p_thing_name_, p_thing_name_); EXPECT_NE(nullptr, test_shadow); test_shadow = Shadow::Create(p_iot_greengrass_client_, mqtt_command_timeout_, p_thing_name_, empty_thing_name); EXPECT_NE(nullptr, test_shadow); } TEST_F(ShadowTester, TestShadowHandleGetResponseErrors) { EXPECT_NE(nullptr, p_iot_greengrass_client_); std::unique_ptr<Shadow> test_shadow = Shadow::Create(p_iot_greengrass_client_, mqtt_command_timeout_, p_thing_name_, p_thing_name_); EXPECT_NE(nullptr, test_shadow); util::JsonDocument test_empty_document; ResponseCode rc = test_shadow->HandleGetResponse(ShadowResponseType::Delta, test_empty_document); EXPECT_EQ(ResponseCode::SHADOW_UNEXPECTED_RESPONSE_TYPE, rc); rc = test_shadow->HandleGetResponse(ShadowResponseType::Accepted, test_empty_document); EXPECT_EQ(ResponseCode::SHADOW_UNEXPECTED_RESPONSE_PAYLOAD, rc); } TEST_F(ShadowTester, TestShadowUpdateDeviceShadowErrorCases) { EXPECT_NE(nullptr, p_iot_greengrass_client_); std::unique_ptr<Shadow> test_shadow = Shadow::Create(p_iot_greengrass_client_, mqtt_command_timeout_, p_thing_name_, p_thing_name_); EXPECT_NE(nullptr, test_shadow); util::JsonDocument test_empty_document; ResponseCode rc = test_shadow->UpdateDeviceShadow(test_empty_document); EXPECT_EQ(ResponseCode::SHADOW_JSON_EMPTY_ERROR, rc); } TEST_F(ShadowTester, TestShadowSubscriptionHandlerError) { EXPECT_NE(nullptr, p_iot_greengrass_client_); std::unique_ptr<Shadow> test_shadow = Shadow::Create(p_iot_greengrass_client_, mqtt_command_timeout_, p_thing_name_, p_thing_name_); EXPECT_NE(nullptr, test_shadow); util::String non_json_payload = "Not a json"; ResponseCode rc = test_shadow->SubscriptionHandler("Some random topic", non_json_payload, nullptr); EXPECT_NE(ResponseCode::SUCCESS, rc); util::String json_payload(SHADOW_DOCUMENT_EMPTY_STRING); util::String non_shadow_topic = "Non shadow topic"; rc = test_shadow->SubscriptionHandler(non_shadow_topic, json_payload, nullptr); EXPECT_EQ(ResponseCode::SHADOW_UNEXPECTED_RESPONSE_TYPE, rc); } TEST_F(ShadowTester, TestShadowSubscriptionHandlerForValidTopics) { EXPECT_NE(nullptr, p_iot_greengrass_client_); std::unique_ptr<Shadow> test_shadow = Shadow::Create(p_iot_greengrass_client_, mqtt_command_timeout_, p_thing_name_, p_thing_name_); EXPECT_NE(nullptr, test_shadow); util::String get_base_topic = SHADOW_TOPIC_PREFIX + p_thing_name_ + SHADOW_TOPIC_MIDDLE + SHADOW_REQUEST_TYPE_GET_STRING + "/"; util::String get_rejected_topic = get_base_topic + SHADOW_RESPONSE_TYPE_REJECTED_STRING; util::String get_accepted_topic = get_base_topic + SHADOW_RESPONSE_TYPE_ACCEPTED_STRING; util::String get_delta_topic = get_base_topic + SHADOW_RESPONSE_TYPE_DELTA_STRING; ResponseCode rc = test_shadow->SubscriptionHandler(get_accepted_topic, SHADOW_DOCUMENT_MODIFIED_VALUE_STRING, nullptr); EXPECT_EQ(ResponseCode::SHADOW_REQUEST_ACCEPTED, rc); rc = test_shadow->SubscriptionHandler(get_rejected_topic, SHADOW_DOCUMENT_MODIFIED_VALUE_STRING, nullptr); EXPECT_EQ(ResponseCode::SHADOW_REQUEST_REJECTED, rc); rc = test_shadow->SubscriptionHandler(get_delta_topic, SHADOW_DOCUMENT_MODIFIED_VALUE_STRING, nullptr); EXPECT_EQ(ResponseCode::SHADOW_UNEXPECTED_RESPONSE_TYPE, rc); util::String update_base_topic = SHADOW_TOPIC_PREFIX + p_thing_name_ + SHADOW_TOPIC_MIDDLE + SHADOW_REQUEST_TYPE_UPDATE_STRING + "/"; util::String udpate_rejected_topic = update_base_topic + SHADOW_RESPONSE_TYPE_REJECTED_STRING; util::String update_accepted_topic = update_base_topic + SHADOW_RESPONSE_TYPE_ACCEPTED_STRING; util::String update_delta_topic = update_base_topic + SHADOW_RESPONSE_TYPE_DELTA_STRING; rc = test_shadow->SubscriptionHandler(update_accepted_topic, SHADOW_DOCUMENT_MODIFIED_VALUE_STRING_V2, nullptr); EXPECT_EQ(ResponseCode::SHADOW_REQUEST_ACCEPTED, rc); rc = test_shadow->SubscriptionHandler(udpate_rejected_topic, SHADOW_DOCUMENT_MODIFIED_VALUE_STRING, nullptr); EXPECT_EQ(ResponseCode::SHADOW_REQUEST_REJECTED, rc); rc = test_shadow->SubscriptionHandler(update_delta_topic, SHADOW_DOCUMENT_MODIFIED_VALUE_STRING_V3, nullptr); EXPECT_EQ(ResponseCode::SHADOW_RECEIVED_DELTA, rc); util::String delete_base_topic = SHADOW_TOPIC_PREFIX + p_thing_name_ + SHADOW_TOPIC_MIDDLE + SHADOW_REQUEST_TYPE_DELETE_STRING + "/"; util::String delete_rejected_topic = delete_base_topic + SHADOW_RESPONSE_TYPE_REJECTED_STRING; util::String delete_accepted_topic = delete_base_topic + SHADOW_RESPONSE_TYPE_ACCEPTED_STRING; util::String delete_delta_topic = delete_base_topic + SHADOW_RESPONSE_TYPE_DELTA_STRING; rc = test_shadow->SubscriptionHandler(delete_accepted_topic, SHADOW_DOCUMENT_MODIFIED_VALUE_STRING_V2, nullptr); EXPECT_EQ(ResponseCode::SHADOW_REQUEST_ACCEPTED, rc); rc = test_shadow->SubscriptionHandler(delete_rejected_topic, SHADOW_DOCUMENT_MODIFIED_VALUE_STRING, nullptr); EXPECT_EQ(ResponseCode::SHADOW_REQUEST_REJECTED, rc); rc = test_shadow->SubscriptionHandler(delete_delta_topic, SHADOW_DOCUMENT_MODIFIED_VALUE_STRING_V3, nullptr); EXPECT_EQ(ResponseCode::SHADOW_UNEXPECTED_RESPONSE_TYPE, rc); } TEST_F(ShadowTester, TestShadowHandleGetResponseWithValidPayload) { EXPECT_NE(nullptr, p_iot_greengrass_client_); std::unique_ptr<Shadow> test_shadow = Shadow::Create(p_iot_greengrass_client_, mqtt_command_timeout_, p_thing_name_, p_thing_name_); EXPECT_NE(nullptr, test_shadow); util::JsonDocument test_payload; ResponseCode rc = util::JsonParser::InitializeFromJsonString(test_payload, SHADOW_DOCUMENT_MODIFIED_VALUE_STRING); EXPECT_EQ(ResponseCode::SUCCESS, rc); rc = test_shadow->HandleGetResponse(ShadowResponseType::Accepted, test_payload); EXPECT_EQ(ResponseCode::SHADOW_REQUEST_ACCEPTED, rc); rc = util::JsonParser::InitializeFromJsonString(test_payload, BROKEN_SHADOW_DOCUMENT_WITH_NO_VERSION_KEY); EXPECT_EQ(ResponseCode::SUCCESS, rc); rc = test_shadow->HandleGetResponse(ShadowResponseType::Accepted, test_payload); EXPECT_NE(ResponseCode::SHADOW_REQUEST_ACCEPTED, rc); rc = test_shadow->HandleGetResponse(ShadowResponseType::Rejected, test_payload); EXPECT_EQ(ResponseCode::SHADOW_REQUEST_REJECTED, rc); } TEST_F(ShadowTester, TestShadowHandleUpdateResponse) { EXPECT_NE(nullptr, p_iot_greengrass_client_); std::unique_ptr<Shadow> test_shadow = Shadow::Create(p_iot_greengrass_client_, mqtt_command_timeout_, p_thing_name_, p_thing_name_); EXPECT_NE(nullptr, test_shadow); util::JsonDocument test_payload; ResponseCode rc = test_shadow->HandleUpdateResponse(ShadowResponseType::Rejected, test_payload); EXPECT_EQ(ResponseCode::SHADOW_REQUEST_REJECTED, rc); util::JsonDocument invalid_payload; rc = test_shadow->HandleUpdateResponse(ShadowResponseType::Accepted, invalid_payload); EXPECT_EQ(ResponseCode::SHADOW_UNEXPECTED_RESPONSE_PAYLOAD, rc); rc = util::JsonParser::InitializeFromJsonString(invalid_payload, BROKEN_SHADOW_DOCUMENT_WITH_NO_STATE_KEY); EXPECT_EQ(ResponseCode::SUCCESS, rc); rc = test_shadow->HandleUpdateResponse(ShadowResponseType::Accepted, invalid_payload); EXPECT_EQ(ResponseCode::SHADOW_UNEXPECTED_RESPONSE_PAYLOAD, rc); rc = util::JsonParser::InitializeFromJsonString(test_payload, BROKEN_SHADOW_DOCUMENT_WITH_INVALID_VERSION_KEY); EXPECT_EQ(ResponseCode::SUCCESS, rc); rc = test_shadow->HandleUpdateResponse(ShadowResponseType::Accepted, test_payload); EXPECT_NE(ResponseCode::SHADOW_REQUEST_ACCEPTED, rc); rc = util::JsonParser::InitializeFromJsonString(test_payload, SHADOW_DOCUMENT_MODIFIED_VALUE_STRING); EXPECT_EQ(ResponseCode::SUCCESS, rc); rc = test_shadow->HandleUpdateResponse(ShadowResponseType::Accepted, test_payload); EXPECT_EQ(ResponseCode::SHADOW_REQUEST_ACCEPTED, rc); rc = test_shadow->HandleUpdateResponse(ShadowResponseType::Accepted, test_payload); EXPECT_EQ(ResponseCode::SHADOW_RECEIVED_OLD_VERSION_UPDATE, rc); rc = test_shadow->HandleUpdateResponse(ShadowResponseType::Accepted, test_payload); EXPECT_NE(ResponseCode::SHADOW_REQUEST_ACCEPTED, rc); rc = util::JsonParser::InitializeFromJsonString(test_payload, SHADOW_DOCUMENT_MODIFIED_VALUE_STRING_V2); EXPECT_EQ(ResponseCode::SUCCESS, rc); rc = test_shadow->HandleUpdateResponse(ShadowResponseType::Delta, test_payload); EXPECT_EQ(ResponseCode::SHADOW_RECEIVED_DELTA, rc); } TEST_F(ShadowTester, TestShadowHandleDeleteResponse) { EXPECT_NE(nullptr, p_iot_greengrass_client_); std::unique_ptr<Shadow> test_shadow = Shadow::Create(p_iot_greengrass_client_, mqtt_command_timeout_, p_thing_name_, p_thing_name_); EXPECT_NE(nullptr, test_shadow); util::JsonDocument test_payload; ResponseCode rc = util::JsonParser::InitializeFromJsonString(test_payload, SHADOW_DOCUMENT_MODIFIED_VALUE_STRING); EXPECT_EQ(ResponseCode::SUCCESS, rc); rc = test_shadow->HandleDeleteResponse(ShadowResponseType::Delta, test_payload); EXPECT_EQ(ResponseCode::SHADOW_UNEXPECTED_RESPONSE_TYPE, rc); rc = test_shadow->HandleDeleteResponse(ShadowResponseType::Rejected, test_payload); EXPECT_EQ(ResponseCode::SHADOW_REQUEST_REJECTED, rc); rc = test_shadow->HandleDeleteResponse(ShadowResponseType::Accepted, test_payload); EXPECT_EQ(ResponseCode::SHADOW_REQUEST_ACCEPTED, rc); } TEST_F(ShadowTester, TestShadowUpdateDeviceShadow) { EXPECT_NE(nullptr, p_iot_greengrass_client_); std::unique_ptr<Shadow> test_shadow = Shadow::Create(p_iot_greengrass_client_, mqtt_command_timeout_, p_thing_name_, p_thing_name_); EXPECT_NE(nullptr, test_shadow); util::JsonDocument test_payload; ResponseCode rc = test_shadow->UpdateDeviceShadow(test_payload); EXPECT_EQ(ResponseCode::SHADOW_JSON_EMPTY_ERROR, rc); rc = util::JsonParser::InitializeFromJsonString(test_payload, SHADOW_DOCUMENT_MODIFIED_VALUE_STRING); EXPECT_EQ(ResponseCode::SUCCESS, rc); rc = test_shadow->UpdateDeviceShadow(test_payload); EXPECT_EQ(ResponseCode::SUCCESS, rc); } TEST_F(ShadowTester, TestShadowGetFunctions) { EXPECT_NE(nullptr, p_iot_greengrass_client_); std::unique_ptr<Shadow> test_shadow = Shadow::Create(p_iot_greengrass_client_, mqtt_command_timeout_, p_thing_name_, p_thing_name_); EXPECT_NE(nullptr, test_shadow); util::JsonDocument test_payload; ResponseCode rc = util::JsonParser::InitializeFromJsonString(test_payload, SHADOW_DOCUMENT_MODIFIED_VALUE_STRING); EXPECT_EQ(ResponseCode::SUCCESS, rc); rc = test_shadow->UpdateDeviceShadow(test_payload); EXPECT_EQ(ResponseCode::SUCCESS, rc); util::JsonDocument expected_doc; util::JsonDocument shadow_doc; rc = util::JsonParser::InitializeFromJsonString(expected_doc, SHADOW_DESIRED_DOC); EXPECT_EQ(ResponseCode::SUCCESS, rc); shadow_doc = test_shadow->GetDeviceDesired(); EXPECT_EQ(shadow_doc, expected_doc); rc = util::JsonParser::InitializeFromJsonString(expected_doc, SHADOW_REPORTED_DOC); EXPECT_EQ(ResponseCode::SUCCESS, rc); shadow_doc = test_shadow->GetDeviceReported(); EXPECT_EQ(shadow_doc, expected_doc); rc = util::JsonParser::InitializeFromJsonString(expected_doc, SHADOW_DOCUMENT_MODIFIED_VALUE_STRING); EXPECT_EQ(ResponseCode::SUCCESS, rc); shadow_doc = test_shadow->GetDeviceDocument(); EXPECT_EQ(shadow_doc, expected_doc); rc = util::JsonParser::InitializeFromJsonString(expected_doc, "{}"); EXPECT_EQ(ResponseCode::SUCCESS, rc); shadow_doc = test_shadow->GetServerDocument(); EXPECT_EQ(shadow_doc, expected_doc); } TEST_F(ShadowTester, TestShadowResetClientTokenSuffix) { EXPECT_NE(nullptr, p_iot_greengrass_client_); std::unique_ptr<Shadow> test_shadow = Shadow::Create(p_iot_greengrass_client_, mqtt_command_timeout_, p_thing_name_, p_thing_name_); EXPECT_NE(nullptr, test_shadow); test_shadow->ResetClientTokenSuffix(); } TEST_F(ShadowTester, TestShadowGetCurrrentVersionNumber) { EXPECT_NE(nullptr, p_iot_greengrass_client_); std::unique_ptr<Shadow> test_shadow = Shadow::Create(p_iot_greengrass_client_, mqtt_command_timeout_, p_thing_name_, p_thing_name_); EXPECT_NE(nullptr, test_shadow); uint32_t shadow_version = test_shadow->GetCurrentVersionNumber(); EXPECT_EQ(uint32_t(0), shadow_version); } TEST_F(ShadowTester, TestShadowIsInSyncFail) { EXPECT_NE(nullptr, p_iot_greengrass_client_); std::unique_ptr<Shadow> test_shadow = Shadow::Create(p_iot_greengrass_client_, mqtt_command_timeout_, p_thing_name_, p_thing_name_); EXPECT_NE(nullptr, test_shadow); EXPECT_FALSE(test_shadow->IsInSync()); } TEST_F(ShadowTester, TestShadowPerformAsyncOperationsDisconnected) { EXPECT_NE(nullptr, p_iot_greengrass_client_); std::unique_ptr<Shadow> test_shadow = Shadow::Create(p_iot_greengrass_client_, mqtt_command_timeout_, p_thing_name_, p_thing_name_); EXPECT_NE(nullptr, test_shadow); ResponseCode rc = test_shadow->PerformDeleteAsync(); EXPECT_EQ(ResponseCode::SHADOW_MQTT_DISCONNECTED_ERROR, rc); rc = test_shadow->PerformUpdateAsync(); EXPECT_EQ(ResponseCode::SHADOW_MQTT_DISCONNECTED_ERROR, rc); rc = test_shadow->PerformGetAsync(); EXPECT_EQ(ResponseCode::SHADOW_MQTT_DISCONNECTED_ERROR, rc); } TEST_F(ShadowTester, TestShadowConstructorAndNullClientCases) { EXPECT_NE(nullptr, p_iot_greengrass_client_); Shadow test_shadow(nullptr, mqtt_command_timeout_, p_thing_name_, p_thing_name_); util::Map<ShadowRequestType , Shadow::RequestHandlerPtr> mapping; ResponseCode rc = test_shadow.AddShadowSubscription(mapping); EXPECT_EQ(ResponseCode::SHADOW_MQTT_CLIENT_NOT_SET_ERROR, rc); rc = test_shadow.PerformGetAsync(); EXPECT_EQ(ResponseCode::SHADOW_MQTT_CLIENT_NOT_SET_ERROR, rc); rc = test_shadow.PerformUpdateAsync(); EXPECT_EQ(ResponseCode::SHADOW_MQTT_CLIENT_NOT_SET_ERROR, rc); rc = test_shadow.PerformDeleteAsync(); EXPECT_EQ(ResponseCode::SHADOW_MQTT_CLIENT_NOT_SET_ERROR, rc); } TEST_F(ShadowTester, TestAddShadowSubscriptionWithDisconnectedClient) { EXPECT_NE(nullptr, p_iot_greengrass_client_); std::unique_ptr<Shadow> test_shadow = Shadow::Create(p_iot_greengrass_client_, mqtt_command_timeout_, p_thing_name_, p_thing_name_); EXPECT_NE(nullptr, test_shadow); util::Map<ShadowRequestType, Shadow::RequestHandlerPtr> request_mapping; request_mapping.insert(std::make_pair(ShadowRequestType::Get, nullptr)); ResponseCode rc = test_shadow->AddShadowSubscription(request_mapping); EXPECT_EQ(ResponseCode::SHADOW_MQTT_DISCONNECTED_ERROR, rc); } } } }