From f416c47429dd9a495c15ea6d078ea30ee2971b4a Mon Sep 17 00:00:00 2001 From: "Alexander Kutsan (GitHub)" Date: Thu, 27 Feb 2020 17:36:08 +0200 Subject: Feature/Web Engine support (#3221) * Add ini file parameters for WebEngineSupport Issue : #3197 * Add Server WebSocket transport * Policy changes for Web Engine support Issue : #3197 * Changes in HMI_API for WebEngineSupport Issue : #3197 * Add application manager implementation for WebEngineSupport Add appropriate commands Make changes in application manager Issue : #3197 * Bug fix : Do not override message params if request setups it * Update SDD * fixup! Add application manager implementation for WebEngineSupport * fixup! Add Server WebSocket transport * Rename websocket dir to websocket_server * Rename WebSocketTransport adapter to WebSocketServerTransportAdapter * fixup! Update SDD * Fix/update app list after unregistration (#3252) * fixup! Rename WebSocketTransport adapter to WebSocketServerTransportAdapter * fixup! Rename websocket dir to websocket_server * Don't remove enabled WebEngine apps from pending apps * Rework WebEngine device ID generation * Fix build after back merge * Fix get app properties (#3258) Co-authored-by: Maksym Ked (GitHub) <41471947+mked-luxoft@users.noreply.github.com> * Remove unused vin_code variable Co-authored-by: Maksym Ked (GitHub) <41471947+mked-luxoft@users.noreply.github.com> Co-authored-by: Andriy Byzhynar (GitHub) Co-authored-by: Ira Lytvynenko (GitHub) Co-authored-by: Andrii Kalinich (GitHub) --- CMakeLists.txt | 13 + Doxyfile | 3 +- src/appMain/smartDeviceLink.ini | 9 + .../application_manager/application_manager_impl.h | 8 +- .../include/application_manager/message_helper.h | 9 + .../application_manager/policies/policy_handler.h | 49 +- .../commands/hmi/bc_get_app_properties_request.h | 80 ++++ .../commands/hmi/bc_get_app_properties_response.h | 78 ++++ .../commands/hmi/bc_set_app_properties_request.h | 77 ++++ .../commands/hmi/bc_set_app_properties_response.h | 78 ++++ .../hmi/on_app_properties_change_notification.h | 79 ++++ .../commands/hmi/bc_get_app_properties_request.cc | 144 ++++++ .../commands/hmi/bc_get_app_properties_response.cc | 60 +++ .../commands/hmi/bc_set_app_properties_request.cc | 114 +++++ .../commands/hmi/bc_set_app_properties_response.cc | 62 +++ .../hmi/on_app_properties_change_notification.cc | 59 +++ .../mobile/get_cloud_app_properties_request.cc | 37 +- .../mobile/set_cloud_app_properties_request.cc | 23 +- .../sdl_rpc_plugin/src/hmi_command_factory.cc | 19 + .../hmi/bc_get_app_properties_request_test.cc | 367 +++++++++++++++ .../hmi/bc_get_app_properties_response_test.cc | 66 +++ .../hmi/bc_set_app_properties_request_test.cc | 304 +++++++++++++ .../hmi/bc_set_app_properties_response_test.cc | 66 +++ .../on_app_properties_change_notification_test.cc | 92 ++++ .../src/application_manager_impl.cc | 250 ++++++---- .../src/commands/request_from_hmi.cc | 5 +- .../src/message_helper/message_helper.cc | 57 ++- .../src/policies/policy_handler.cc | 239 ++++++++-- .../test/application_manager_impl_test.cc | 158 +++++-- .../application_manager/commands/commands_test.h | 15 + .../application_manager/mock_message_helper.h | 3 + .../test/mock_message_helper.cc | 7 + .../test/policy_handler_test.cc | 416 +++++++++++++++-- .../include/config_profile/profile.h | 44 ++ src/components/config_profile/src/profile.cc | 95 ++++ .../connection_handler/connection_handler_impl.h | 6 +- .../src/connection_handler_impl.cc | 106 +++-- .../application_manager/application_manager.h | 21 + .../policies/policy_handler_interface.h | 92 +++- .../connection_handler/connection_handler.h | 13 + .../connection_handler_observer.h | 5 + .../policy_external/policy/policy_listener.h | 8 + .../policy/policy_external/policy/policy_manager.h | 61 ++- .../policy/policy_regular/policy/policy_listener.h | 7 + .../policy/policy_regular/policy/policy_manager.h | 63 ++- .../application_manager/mock_application_manager.h | 6 + .../policies/mock_policy_handler_interface.h | 22 +- .../connection_handler/mock_connection_handler.h | 2 + .../mock_connection_handler_observer.h | 1 + .../policy_external/policy/mock_cache_manager.h | 10 +- .../policy_external/policy/mock_policy_listener.h | 2 + .../policy_external/policy/mock_policy_manager.h | 14 +- .../policy_regular/policy/mock_cache_manager.h | 10 +- .../policy_regular/policy/mock_policy_listener.h | 2 + .../policy_regular/policy/mock_policy_manager.h | 14 +- .../transport_manager/mock_transport_manager.h | 2 + .../mock_transport_manager_settings.h | 6 + .../transport_adapter/mock_transport_adapter.h | 4 + src/components/include/transport_manager/common.h | 5 + .../transport_adapter/transport_adapter.h | 11 + .../include/transport_manager/transport_manager.h | 12 + .../transport_manager/transport_manager_settings.h | 17 + src/components/interfaces/HMI_API.xml | 103 +++++ .../policy_external/include/policy/cache_manager.h | 34 +- .../include/policy/cache_manager_interface.h | 36 +- .../policy_external/include/policy/policy_helper.h | 4 + .../include/policy/policy_manager_impl.h | 46 +- .../policy_external/include/policy/policy_types.h | 70 ++- .../policy/policy_external/src/cache_manager.cc | 60 ++- .../policy/policy_external/src/policy_helper.cc | 78 ++++ .../policy_external/src/policy_manager_impl.cc | 59 ++- .../test/policy_manager_impl_ptu_test.cc | 17 +- .../test/policy_manager_impl_test_base.cc | 4 + .../policy_regular/include/policy/cache_manager.h | 31 +- .../include/policy/cache_manager_interface.h | 36 +- .../policy_regular/include/policy/policy_helper.h | 4 + .../include/policy/policy_manager_impl.h | 50 +- .../policy_regular/include/policy/policy_types.h | 72 ++- .../policy/policy_regular/src/cache_manager.cc | 60 ++- .../policy/policy_regular/src/policy_helper.cc | 78 +++- .../policy_regular/src/policy_manager_impl.cc | 60 ++- .../test/policy_manager_impl_test.cc | 6 + src/components/transport_manager/CMakeLists.txt | 12 + .../docs/SDL.SDD.WebEngineSupport.dox | 127 ++++++ .../transport_manager/docs/assets/WES_classes.png | Bin 0 -> 55856 bytes .../transport_manager/docs/assets/WES_sequence.png | Bin 0 -> 77759 bytes .../transport_adapter_controller.h | 2 + .../transport_adapter/transport_adapter_impl.h | 13 +- .../transport_manager/transport_manager_default.h | 4 + .../transport_manager/transport_manager_impl.h | 6 + .../websocket_server/websocket_connection.h | 126 ++++++ .../websocket_server/websocket_device.h | 75 +++ .../websocket_server/websocket_listener.h | 120 +++++ .../websocket_server/websocket_secure_session.h | 64 +++ .../websocket_server_transport_adapter.h | 136 ++++++ .../websocket_server/websocket_session.h | 107 +++++ .../transport_adapter/transport_adapter_impl.cc | 38 +- .../src/transport_manager_default.cc | 26 ++ .../src/transport_manager_impl.cc | 76 +++- .../src/websocket_server/websocket_connection.cc | 218 +++++++++ .../src/websocket_server/websocket_device.cc | 94 ++++ .../src/websocket_server/websocket_listener.cc | 299 ++++++++++++ .../websocket_server/websocket_secure_session.cc | 79 ++++ .../websocket_server_transport_adapter.cc | 141 ++++++ .../src/websocket_server/websocket_session.cc | 162 +++++++ .../transport_manager/test/CMakeLists.txt | 10 +- .../mock_transport_adapter_controller.h | 82 ++-- .../websocket_server/websocket_sample_client.h | 117 +++++ .../test/tcp_client_listener_test.cc | 62 +-- .../transport_manager/test/test_certs/ca-cert.pem | 23 + .../test/test_certs/client-cert.pem | 21 + .../test/test_certs/client-key.pem | 28 ++ .../test/test_certs/invalid_cert.pem | 22 + .../test/test_certs/invalid_key.pem | 28 ++ .../test/test_certs/server-cert.pem | 21 + .../test/test_certs/server-key.pem | 28 ++ .../test/transport_manager_default_test.cc | 21 +- .../test/websocket_client_connection_test.cc | 482 ++++++++++++++++++++ .../test/websocket_connection_test.cc | 504 ++++----------------- .../websocket_sample_client.cc | 193 ++++++++ .../test/websocket_server_listener_test.cc | 260 +++++++++++ 121 files changed, 7307 insertions(+), 1135 deletions(-) create mode 100644 src/components/application_manager/rpc_plugins/sdl_rpc_plugin/include/sdl_rpc_plugin/commands/hmi/bc_get_app_properties_request.h create mode 100644 src/components/application_manager/rpc_plugins/sdl_rpc_plugin/include/sdl_rpc_plugin/commands/hmi/bc_get_app_properties_response.h create mode 100644 src/components/application_manager/rpc_plugins/sdl_rpc_plugin/include/sdl_rpc_plugin/commands/hmi/bc_set_app_properties_request.h create mode 100644 src/components/application_manager/rpc_plugins/sdl_rpc_plugin/include/sdl_rpc_plugin/commands/hmi/bc_set_app_properties_response.h create mode 100644 src/components/application_manager/rpc_plugins/sdl_rpc_plugin/include/sdl_rpc_plugin/commands/hmi/on_app_properties_change_notification.h create mode 100644 src/components/application_manager/rpc_plugins/sdl_rpc_plugin/src/commands/hmi/bc_get_app_properties_request.cc create mode 100644 src/components/application_manager/rpc_plugins/sdl_rpc_plugin/src/commands/hmi/bc_get_app_properties_response.cc create mode 100644 src/components/application_manager/rpc_plugins/sdl_rpc_plugin/src/commands/hmi/bc_set_app_properties_request.cc create mode 100644 src/components/application_manager/rpc_plugins/sdl_rpc_plugin/src/commands/hmi/bc_set_app_properties_response.cc create mode 100644 src/components/application_manager/rpc_plugins/sdl_rpc_plugin/src/commands/hmi/on_app_properties_change_notification.cc create mode 100644 src/components/application_manager/rpc_plugins/sdl_rpc_plugin/test/commands/hmi/bc_get_app_properties_request_test.cc create mode 100644 src/components/application_manager/rpc_plugins/sdl_rpc_plugin/test/commands/hmi/bc_get_app_properties_response_test.cc create mode 100644 src/components/application_manager/rpc_plugins/sdl_rpc_plugin/test/commands/hmi/bc_set_app_properties_request_test.cc create mode 100644 src/components/application_manager/rpc_plugins/sdl_rpc_plugin/test/commands/hmi/bc_set_app_properties_response_test.cc create mode 100644 src/components/application_manager/rpc_plugins/sdl_rpc_plugin/test/commands/hmi/on_app_properties_change_notification_test.cc mode change 100755 => 100644 src/components/application_manager/test/mock_message_helper.cc create mode 100644 src/components/transport_manager/docs/SDL.SDD.WebEngineSupport.dox create mode 100644 src/components/transport_manager/docs/assets/WES_classes.png create mode 100644 src/components/transport_manager/docs/assets/WES_sequence.png create mode 100644 src/components/transport_manager/include/transport_manager/websocket_server/websocket_connection.h create mode 100644 src/components/transport_manager/include/transport_manager/websocket_server/websocket_device.h create mode 100644 src/components/transport_manager/include/transport_manager/websocket_server/websocket_listener.h create mode 100644 src/components/transport_manager/include/transport_manager/websocket_server/websocket_secure_session.h create mode 100644 src/components/transport_manager/include/transport_manager/websocket_server/websocket_server_transport_adapter.h create mode 100644 src/components/transport_manager/include/transport_manager/websocket_server/websocket_session.h create mode 100644 src/components/transport_manager/src/websocket_server/websocket_connection.cc create mode 100644 src/components/transport_manager/src/websocket_server/websocket_device.cc create mode 100644 src/components/transport_manager/src/websocket_server/websocket_listener.cc create mode 100644 src/components/transport_manager/src/websocket_server/websocket_secure_session.cc create mode 100644 src/components/transport_manager/src/websocket_server/websocket_server_transport_adapter.cc create mode 100644 src/components/transport_manager/src/websocket_server/websocket_session.cc create mode 100644 src/components/transport_manager/test/include/transport_manager/websocket_server/websocket_sample_client.h create mode 100644 src/components/transport_manager/test/test_certs/ca-cert.pem create mode 100644 src/components/transport_manager/test/test_certs/client-cert.pem create mode 100644 src/components/transport_manager/test/test_certs/client-key.pem create mode 100644 src/components/transport_manager/test/test_certs/invalid_cert.pem create mode 100644 src/components/transport_manager/test/test_certs/invalid_key.pem create mode 100644 src/components/transport_manager/test/test_certs/server-cert.pem create mode 100644 src/components/transport_manager/test/test_certs/server-key.pem create mode 100644 src/components/transport_manager/test/websocket_client_connection_test.cc create mode 100644 src/components/transport_manager/test/websocket_sample_client/websocket_sample_client.cc create mode 100644 src/components/transport_manager/test/websocket_server_listener_test.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index b344f91342..764a050b91 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,6 +44,7 @@ option(BUILD_SHARED_LIBS "Build all libraries as shared (if ON) or static (if OF option(BUILD_BT_SUPPORT "Bluetooth support" ON) option(BUILD_USB_SUPPORT "libusb support" ON) option(BUILD_CLOUD_APP_SUPPORT "Cloud App Transport Support" ON) +option(BUILD_WEBSOCKET_SERVER_SUPPORT "Web Engine App Transport Support" ON) option(BUILD_BACKTRACE_SUPPORT "backtrace support" ON) option(BUILD_TESTS "Possibility to build and run tests" OFF) option(TELEMETRY_MONITOR "Enable profiling time test util" ON) @@ -209,6 +210,13 @@ get_property(cValue CACHE ENABLE_HMI_PTU_DECRYPTION PROPERTY VALUE) file(APPEND "${build_config_path}" "//${cHelpString}\n") file(APPEND "${build_config_path}" "ENABLE_HMI_PTU_DECRYPTION:${cType}=${cValue}\n") +get_property(cHelpString CACHE BUILD_WEBSOCKET_SERVER_SUPPORT PROPERTY HELPSTRING) +get_property(cType CACHE BUILD_WEBSOCKET_SERVER_SUPPORT PROPERTY TYPE) +get_property(cValue CACHE BUILD_WEBSOCKET_SERVER_SUPPORT PROPERTY VALUE) +file(APPEND "${build_config_path}" "//${cHelpString}\n") +file(APPEND "${build_config_path}" "BUILD_WEBSOCKET_SERVER_SUPPORT:${cType}=${cValue}\n") + + add_custom_target(pasa-tarball COMMAND ${CMAKE_SOURCE_DIR}/tools/Utils/export-customer-specific.sh ${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} pasa COMMAND tar -cz -C /tmp/PASA -f ${CMAKE_BINARY_DIR}/pasa.tar.gz . @@ -323,6 +331,11 @@ if (BUILD_CLOUD_APP_SUPPORT) message(STATUS "Cloud app websocket support enabled") endif() +if (BUILD_WEBSOCKET_SERVER_SUPPORT) + add_definitions(-DWEBSOCKET_SERVER_TRANSPORT_SUPPORT) + message(STATUS "Web engine app websocket support enabled") +endif() + if (BUILD_BACKTRACE_SUPPORT) add_definitions(-DBACKTRACE_SUPPORT) message(STATUS "Backtrace support enabled") diff --git a/Doxyfile b/Doxyfile index 8674bd3114..79f0c3510e 100644 --- a/Doxyfile +++ b/Doxyfile @@ -900,7 +900,8 @@ EXAMPLE_RECURSIVE = NO IMAGE_PATH = \ src/components/security_manager/docs/assets \ - src/components/protocol_handler/docs/assets + src/components/protocol_handler/docs/assets \ + src/components/transport_manager/docs/assets # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program diff --git a/src/appMain/smartDeviceLink.ini b/src/appMain/smartDeviceLink.ini index baf8cf6073..31302f24c6 100644 --- a/src/appMain/smartDeviceLink.ini +++ b/src/appMain/smartDeviceLink.ini @@ -202,6 +202,15 @@ TCPAdapterPort = 12345 ; If the name is omitted, Core will listen on all network interfaces by binding to INADDR_ANY. TCPAdapterNetworkInterface = +; WebSocket connection address used for incoming connections +WebSocketServerAddress = 0.0.0.0 +; Listening port for incoming connection to websocket server +WebSocketServerPort = 2020 +; WS Server Certificate +; WSServerCertificatePath = server-cert.pem +; WSServerKeyPath = server-key.pem +; WSServerCACertificatePath = ca-cert.pem + ; 128 bit uuid for bluetooth device discovery. Please format as 16 seperate bytes. ;BluetoothUUID = 0x93, 0x6D, 0xA0, 0x1F, 0x9A, 0xBD, 0x4D, 0x9D, 0x80, 0xC7, 0x02, 0xAF, 0x85, 0xC8, 0x22, 0xA8 diff --git a/src/components/application_manager/include/application_manager/application_manager_impl.h b/src/components/application_manager/include/application_manager/application_manager_impl.h index ab7cf95139..1e361a75c9 100644 --- a/src/components/application_manager/include/application_manager/application_manager_impl.h +++ b/src/components/application_manager/include/application_manager/application_manager_impl.h @@ -409,7 +409,13 @@ class ApplicationManagerImpl void CreatePendingApplication( const transport_manager::ConnectionUID connection_id, const transport_manager::DeviceInfo& device_info, - connection_handler::DeviceHandle device_id); + connection_handler::DeviceHandle device_id) OVERRIDE; + + void OnWebEngineDeviceCreated() OVERRIDE; + + void CreatePendingLocalApplication(const std::string& policy_app_id) OVERRIDE; + + void RemovePendingApplication(const std::string& policy_app_id) OVERRIDE; void SetPendingApplicationState( const transport_manager::ConnectionUID connection_id, diff --git a/src/components/application_manager/include/application_manager/message_helper.h b/src/components/application_manager/include/application_manager/message_helper.h index aff4659323..5d95a2468d 100644 --- a/src/components/application_manager/include/application_manager/message_helper.h +++ b/src/components/application_manager/include/application_manager/message_helper.h @@ -380,6 +380,15 @@ class MessageHelper { static void SendOnAppUnregNotificationToHMI(ApplicationConstSharedPtr app, bool is_unexpected_disconnect, ApplicationManager& app_mngr); + /** + * @brief Creates BasicCommunication.OnAppPropertiesChange + * notification to the HMI + * @param policy_app_id unique policy app id + * @param app_mngr application manager + * @return smart object with BC.OnAppPropertiesChange notification + */ + static smart_objects::SmartObjectSPtr CreateOnAppPropertiesChangeNotification( + const std::string& policy_app_id, ApplicationManager& app_mngr); static smart_objects::SmartObjectSPtr GetBCActivateAppRequestToHMI( ApplicationConstSharedPtr app, diff --git a/src/components/application_manager/include/application_manager/policies/policy_handler.h b/src/components/application_manager/include/application_manager/policies/policy_handler.h index a03288f9a9..b517a7d82c 100644 --- a/src/components/application_manager/include/application_manager/policies/policy_handler.h +++ b/src/components/application_manager/include/application_manager/policies/policy_handler.h @@ -427,6 +427,8 @@ class PolicyHandler : public PolicyHandlerInterface, custom_str::CustomString GetAppName( const std::string& policy_app_id) OVERRIDE; + std::vector GetApplicationPolicyIDs() const OVERRIDE; + /** * @brief Get a list of enabled cloud applications * @param enabled_apps List filled with the policy app id of each enabled @@ -435,6 +437,13 @@ class PolicyHandler : public PolicyHandlerInterface, void GetEnabledCloudApps( std::vector& enabled_apps) const OVERRIDE; + /** + * @brief Get a list of enabled local applications + * @return enabled_apps List filled with the policy app id of each enabled + * local application + */ + std::vector GetEnabledLocalApps() const OVERRIDE; + /** * @brief Checks if a given application is an enabled cloud application * @param policy_app_id Unique application id @@ -444,33 +453,24 @@ class PolicyHandler : public PolicyHandlerInterface, const bool CheckCloudAppEnabled( const std::string& policy_app_id) const OVERRIDE; - /** - * @brief Get cloud app policy information, all fields that aren't set for a - * given app will be filled with empty strings - * @param policy_app_id Unique application id - * @param enabled Whether or not the app is enabled - * @param endpoint Filled with the endpoint used to connect to the cloud - * application - * @param certificate Filled with the certificate used to for creating a - * secure connection to the cloud application - * @param auth_token Filled with the token used for authentication when - * reconnecting to the cloud app - * @param cloud_transport_type Filled with the transport type used by the - * cloud application (ex. "WSS") - * @param hybrid_app_preference Filled with the hybrid app preference for the - * cloud application set by the user - */ - bool GetCloudAppParameters(const std::string& policy_app_id, - bool& enabled, - std::string& endpoint, - std::string& certificate, - std::string& auth_token, - std::string& cloud_transport_type, - std::string& hybrid_app_preference) const OVERRIDE; + bool GetAppProperties( + const std::string& policy_app_id, + policy::AppProperties& out_app_properties) const OVERRIDE; void OnAuthTokenUpdated(const std::string& policy_app_id, const std::string& auth_token) OVERRIDE; + void OnSetAppProperties( + const smart_objects::SmartObject& properties) OVERRIDE; + + AppPropertiesState GetAppPropertiesStatus( + const smart_objects::SmartObject& properties, + const std::string& app_id) const OVERRIDE; + + bool IsNewApplication(const std::string& policy_app_id) const OVERRIDE; + + void OnLocalAppAdded() OVERRIDE; + /** * @brief Callback for when a SetCloudAppProperties message is received * from a mobile app @@ -533,6 +533,9 @@ class PolicyHandler : public PolicyHandlerInterface, const std::string& device_id, const std::string& policy_app_id) const OVERRIDE; + void SendOnAppPropertiesChangeNotification( + const std::string& policy_app_id) const OVERRIDE; + virtual void OnPTExchangeNeeded() OVERRIDE; virtual void GetAvailableApps(std::queue& apps) OVERRIDE; diff --git a/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/include/sdl_rpc_plugin/commands/hmi/bc_get_app_properties_request.h b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/include/sdl_rpc_plugin/commands/hmi/bc_get_app_properties_request.h new file mode 100644 index 0000000000..484a82ca4c --- /dev/null +++ b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/include/sdl_rpc_plugin/commands/hmi/bc_get_app_properties_request.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2020, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SRC_COMPONENTS_APPLICATION_MANAGER_RPC_PLUGINS_SDL_RPC_PLUGIN_INCLUDE_SDL_RPC_PLUGIN_COMMANDS_HMI_BC_GET_APP_PROPERTIES_REQUEST_H_ +#define SRC_COMPONENTS_APPLICATION_MANAGER_RPC_PLUGINS_SDL_RPC_PLUGIN_INCLUDE_SDL_RPC_PLUGIN_COMMANDS_HMI_BC_GET_APP_PROPERTIES_REQUEST_H_ + +#include "application_manager/commands/request_from_hmi.h" + +namespace sdl_rpc_plugin { +namespace app_mngr = application_manager; + +namespace commands { + +/** + * @brief BCGetAppPropertiesRequest command class + **/ +class BCGetAppPropertiesRequest : public app_mngr::commands::RequestFromHMI { + public: + /** + * @brief BCGetAppPropertiesRequest class constructor + * + * @param message Incoming SmartObject message + **/ + BCGetAppPropertiesRequest(const app_mngr::commands::MessageSharedPtr& message, + app_mngr::ApplicationManager& application_manager, + app_mngr::rpc_service::RPCService& rpc_service, + app_mngr::HMICapabilities& hmi_capabilities, + policy::PolicyHandlerInterface& policy_handler); + + /** + * @brief BCGetAppPropertiesRequest class destructor + **/ + virtual ~BCGetAppPropertiesRequest() = default; + + /** + * @brief Execute command + **/ + void Run() FINAL; + + private: + void FillAppProperties(const std::string& policy_app_id, + smart_objects::SmartObject& out_properties) const; + + DISALLOW_COPY_AND_ASSIGN(BCGetAppPropertiesRequest); +}; + +} // namespace commands + +} // namespace sdl_rpc_plugin + +#endif // SRC_COMPONENTS_APPLICATION_MANAGER_RPC_PLUGINS_SDL_RPC_PLUGIN_INCLUDE_SDL_RPC_PLUGIN_COMMANDS_HMI_BC_GET_APP_PROPERTIES_REQUEST_H_ diff --git a/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/include/sdl_rpc_plugin/commands/hmi/bc_get_app_properties_response.h b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/include/sdl_rpc_plugin/commands/hmi/bc_get_app_properties_response.h new file mode 100644 index 0000000000..5634663254 --- /dev/null +++ b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/include/sdl_rpc_plugin/commands/hmi/bc_get_app_properties_response.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2020, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SRC_COMPONENTS_APPLICATION_MANAGER_RPC_PLUGINS_SDL_RPC_PLUGIN_INCLUDE_SDL_RPC_PLUGIN_COMMANDS_HMI_BC_GET_APP_PROPERTIES_RESPONSE_H_ +#define SRC_COMPONENTS_APPLICATION_MANAGER_RPC_PLUGINS_SDL_RPC_PLUGIN_INCLUDE_SDL_RPC_PLUGIN_COMMANDS_HMI_BC_GET_APP_PROPERTIES_RESPONSE_H_ + +#include "application_manager/commands/response_to_hmi.h" + +namespace sdl_rpc_plugin { +namespace app_mngr = application_manager; + +namespace commands { + +/** + * @brief BCGetAppPropertiesResponse command class + **/ +class BCGetAppPropertiesResponse : public app_mngr::commands::ResponseToHMI { + public: + /** + * @brief BCGetAppPropertiesResponse class constructor + * + * @param message Incoming SmartObject message + **/ + BCGetAppPropertiesResponse( + const app_mngr::commands::MessageSharedPtr& message, + app_mngr::ApplicationManager& application_manager, + app_mngr::rpc_service::RPCService& rpc_service, + app_mngr::HMICapabilities& hmi_capabilities, + policy::PolicyHandlerInterface& policy_handler); + + /** + * @brief BCGetAppPropertiesResponse class destructor + **/ + virtual ~BCGetAppPropertiesResponse() = default; + + /** + * @brief Execute command + **/ + void Run() FINAL; + + private: + DISALLOW_COPY_AND_ASSIGN(BCGetAppPropertiesResponse); +}; + +} // namespace commands + +} // namespace sdl_rpc_plugin + +#endif // SRC_COMPONENTS_APPLICATION_MANAGER_RPC_PLUGINS_SDL_RPC_PLUGIN_INCLUDE_SDL_RPC_PLUGIN_COMMANDS_HMI_BC_GET_APP_PROPERTIES_RESPONSE_H_ diff --git a/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/include/sdl_rpc_plugin/commands/hmi/bc_set_app_properties_request.h b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/include/sdl_rpc_plugin/commands/hmi/bc_set_app_properties_request.h new file mode 100644 index 0000000000..491d2196e5 --- /dev/null +++ b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/include/sdl_rpc_plugin/commands/hmi/bc_set_app_properties_request.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2020, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SRC_COMPONENTS_APPLICATION_MANAGER_RPC_PLUGINS_SDL_RPC_PLUGIN_INCLUDE_SDL_RPC_PLUGIN_COMMANDS_HMI_BC_SET_APP_PROPERTIES_REQUEST_H_ +#define SRC_COMPONENTS_APPLICATION_MANAGER_RPC_PLUGINS_SDL_RPC_PLUGIN_INCLUDE_SDL_RPC_PLUGIN_COMMANDS_HMI_BC_SET_APP_PROPERTIES_REQUEST_H_ + +#include "application_manager/commands/request_from_hmi.h" + +namespace sdl_rpc_plugin { +namespace app_mngr = application_manager; + +namespace commands { + +/** + * @brief BCSetAppPropertiesRequest command class + **/ +class BCSetAppPropertiesRequest : public app_mngr::commands::RequestFromHMI { + public: + /** + * @brief BCSetAppPropertiesRequest class constructor + * + * @param message Incoming SmartObject message + **/ + BCSetAppPropertiesRequest(const app_mngr::commands::MessageSharedPtr& message, + app_mngr::ApplicationManager& application_manager, + app_mngr::rpc_service::RPCService& rpc_service, + app_mngr::HMICapabilities& hmi_capabilities, + policy::PolicyHandlerInterface& policy_handler); + + /** + * @brief BCSetAppPropertiesRequest class destructor + **/ + virtual ~BCSetAppPropertiesRequest() = default; + + /** + * @brief Execute command + **/ + void Run() FINAL; + + private: + DISALLOW_COPY_AND_ASSIGN(BCSetAppPropertiesRequest); +}; + +} // namespace commands + +} // namespace sdl_rpc_plugin + +#endif // SRC_COMPONENTS_APPLICATION_MANAGER_RPC_PLUGINS_SDL_RPC_PLUGIN_INCLUDE_SDL_RPC_PLUGIN_COMMANDS_HMI_BC_SET_APP_PROPERTIES_REQUEST_H_ diff --git a/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/include/sdl_rpc_plugin/commands/hmi/bc_set_app_properties_response.h b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/include/sdl_rpc_plugin/commands/hmi/bc_set_app_properties_response.h new file mode 100644 index 0000000000..e9872196c9 --- /dev/null +++ b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/include/sdl_rpc_plugin/commands/hmi/bc_set_app_properties_response.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2020, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SRC_COMPONENTS_APPLICATION_MANAGER_RPC_PLUGINS_SDL_RPC_PLUGIN_INCLUDE_SDL_RPC_PLUGIN_COMMANDS_HMI_BC_SET_APP_PROPERTIES_RESPONSE_H_ +#define SRC_COMPONENTS_APPLICATION_MANAGER_RPC_PLUGINS_SDL_RPC_PLUGIN_INCLUDE_SDL_RPC_PLUGIN_COMMANDS_HMI_BC_SET_APP_PROPERTIES_RESPONSE_H_ + +#include "application_manager/commands/response_to_hmi.h" + +namespace sdl_rpc_plugin { +namespace app_mngr = application_manager; + +namespace commands { + +/** + * @brief BCSetAppPropertiesResponse command class + **/ +class BCSetAppPropertiesResponse : public app_mngr::commands::ResponseToHMI { + public: + /** + * @brief BCSetAppPropertiesResponse class constructor + * + * @param message Incoming SmartObject message + **/ + BCSetAppPropertiesResponse( + const app_mngr::commands::MessageSharedPtr& message, + app_mngr::ApplicationManager& application_manager, + app_mngr::rpc_service::RPCService& rpc_service, + app_mngr::HMICapabilities& hmi_capabilities, + policy::PolicyHandlerInterface& policy_handler); + + /** + * @brief BCSetAppPropertiesResponse class destructor + **/ + virtual ~BCSetAppPropertiesResponse() = default; + + /** + * @brief Execute command + **/ + void Run() FINAL; + + private: + DISALLOW_COPY_AND_ASSIGN(BCSetAppPropertiesResponse); +}; + +} // namespace commands + +} // namespace sdl_rpc_plugin + +#endif // SRC_COMPONENTS_APPLICATION_MANAGER_RPC_PLUGINS_SDL_RPC_PLUGIN_INCLUDE_SDL_RPC_PLUGIN_COMMANDS_HMI_BC_SET_APP_PROPERTIES_RESPONSE_H_ diff --git a/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/include/sdl_rpc_plugin/commands/hmi/on_app_properties_change_notification.h b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/include/sdl_rpc_plugin/commands/hmi/on_app_properties_change_notification.h new file mode 100644 index 0000000000..7feb2ef85e --- /dev/null +++ b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/include/sdl_rpc_plugin/commands/hmi/on_app_properties_change_notification.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2020, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SRC_COMPONENTS_APPLICATION_MANAGER_RPC_PLUGINS_SDL_RPC_PLUGIN_INCLUDE_SDL_RPC_PLUGIN_COMMANDS_HMI_ON_APP_PROPERTIES_CHANGE_NOTIFICATION_H_ +#define SRC_COMPONENTS_APPLICATION_MANAGER_RPC_PLUGINS_SDL_RPC_PLUGIN_INCLUDE_SDL_RPC_PLUGIN_COMMANDS_HMI_ON_APP_PROPERTIES_CHANGE_NOTIFICATION_H_ + +#include "application_manager/commands/notification_to_hmi.h" + +namespace sdl_rpc_plugin { +namespace app_mngr = application_manager; + +namespace commands { + +/** + * @brief OnAppPropertiesChangeNotification command class + **/ +class OnAppPropertiesChangeNotification + : public app_mngr::commands::NotificationToHMI { + public: + /** + * @brief OnAppPropertiesChangeNotification class constructor + * + * @param message Incoming SmartObject message + **/ + OnAppPropertiesChangeNotification( + const app_mngr::commands::MessageSharedPtr& message, + app_mngr::ApplicationManager& application_manager, + app_mngr::rpc_service::RPCService& rpc_service, + app_mngr::HMICapabilities& hmi_capabilities, + policy::PolicyHandlerInterface& policy_handle); + + /** + * @brief OnAppPropertiesChangeNotification class destructor + **/ + virtual ~OnAppPropertiesChangeNotification() = default; + + /** + * @brief Execute command + **/ + void Run() FINAL; + + private: + DISALLOW_COPY_AND_ASSIGN(OnAppPropertiesChangeNotification); +}; + +} // namespace commands + +} // namespace sdl_rpc_plugin + +#endif // SRC_COMPONENTS_APPLICATION_MANAGER_RPC_PLUGINS_SDL_RPC_PLUGIN_INCLUDE_SDL_RPC_PLUGIN_COMMANDS_HMI_ON_APP_PROPERTIES_CHANGE_NOTIFICATION_H_ diff --git a/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/src/commands/hmi/bc_get_app_properties_request.cc b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/src/commands/hmi/bc_get_app_properties_request.cc new file mode 100644 index 0000000000..0dafa21e33 --- /dev/null +++ b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/src/commands/hmi/bc_get_app_properties_request.cc @@ -0,0 +1,144 @@ +/* + Copyright (c) 2020, Ford Motor Company, Livio + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following + disclaimer in the documentation and/or other materials provided with the + distribution. + + Neither the name of the the copyright holders nor the names of their + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + */ + +#include "sdl_rpc_plugin/commands/hmi/bc_get_app_properties_request.h" +#include "application_manager/policies/policy_handler_interface.h" +#include "application_manager/rpc_service.h" +#include "interfaces/MOBILE_API.h" + +namespace sdl_rpc_plugin { +using namespace application_manager; +namespace commands { + +BCGetAppPropertiesRequest::BCGetAppPropertiesRequest( + const application_manager::commands::MessageSharedPtr& message, + ApplicationManager& application_manager, + app_mngr::rpc_service::RPCService& rpc_service, + app_mngr::HMICapabilities& hmi_capabilities, + policy::PolicyHandlerInterface& policy_handler) + : RequestFromHMI(message, + application_manager, + rpc_service, + hmi_capabilities, + policy_handler) {} + +void BCGetAppPropertiesRequest::FillAppProperties( + const std::string& policy_app_id, + smart_objects::SmartObject& out_properties) const { + LOG4CXX_AUTO_TRACE(logger_); + + policy::AppProperties app_properties; + const bool result = + policy_handler_.GetAppProperties(policy_app_id, app_properties); + + if (!result) { + LOG4CXX_DEBUG( + logger_, + "Failed to get app parameters for policy_app_id: " << policy_app_id); + return; + } + + out_properties[strings::policy_app_id] = policy_app_id; + out_properties[strings::enabled] = app_properties.enabled; + + policy::StringArray nicknames; + policy::StringArray app_hmi_types; + + policy_handler_.GetInitialAppData(policy_app_id, &nicknames, &app_hmi_types); + + smart_objects::SmartObject nicknames_array(smart_objects::SmartType_Array); + size_t i = 0; + for (const auto& nickname : nicknames) { + nicknames_array[i++] = nickname; + } + out_properties[strings::nicknames] = nicknames_array; + + if (!app_properties.auth_token.empty()) { + out_properties[strings::auth_token] = app_properties.auth_token; + } + if (!app_properties.transport_type.empty()) { + out_properties[strings::transport_type] = app_properties.transport_type; + } + if (!app_properties.hybrid_app_preference.empty()) { + out_properties[strings::hybrid_app_preference] = + app_properties.hybrid_app_preference; + } + if (!app_properties.endpoint.empty()) { + out_properties[strings::endpoint] = app_properties.endpoint; + } +} + +void BCGetAppPropertiesRequest::Run() { + LOG4CXX_AUTO_TRACE(logger_); + + const auto& msg_params = (*message_)[strings::msg_params]; + smart_objects::SmartObject response_params(smart_objects::SmartType_Map); + + if (msg_params.keyExists(strings::policy_app_id)) { + const auto policy_app_id = msg_params[strings::policy_app_id].asString(); + smart_objects::SmartObject properties(smart_objects::SmartType_Map); + FillAppProperties(policy_app_id, properties); + if (!properties.empty()) { + response_params[strings::properties][0] = properties; + } + } else { + LOG4CXX_DEBUG(logger_, + "policyAppID was absent in request, all apps properties " + "will be returned."); + const auto app_ids = policy_handler_.GetApplicationPolicyIDs(); + int i = 0; + for (auto& app_id : app_ids) { + smart_objects::SmartObject properties(smart_objects::SmartType_Map); + FillAppProperties(app_id, properties); + response_params[strings::properties][i++] = properties; + } + } + + if (response_params[strings::properties].empty()) { + SendErrorResponse( + (*message_)[strings::params][strings::correlation_id].asUInt(), + hmi_apis::FunctionID::BasicCommunication_GetAppProperties, + hmi_apis::Common_Result::DATA_NOT_AVAILABLE, + "Requested data not available", + application_manager::commands::Command::SOURCE_SDL_TO_HMI); + return; + } + + SendResponse(true, + (*message_)[strings::params][strings::correlation_id].asUInt(), + hmi_apis::FunctionID::BasicCommunication_GetAppProperties, + hmi_apis::Common_Result::SUCCESS, + &response_params); +} + +} // namespace commands +} // namespace sdl_rpc_plugin diff --git a/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/src/commands/hmi/bc_get_app_properties_response.cc b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/src/commands/hmi/bc_get_app_properties_response.cc new file mode 100644 index 0000000000..57949a949b --- /dev/null +++ b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/src/commands/hmi/bc_get_app_properties_response.cc @@ -0,0 +1,60 @@ +/* + Copyright (c) 2020, Ford Motor Company, Livio + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following + disclaimer in the documentation and/or other materials provided with the + distribution. + + Neither the name of the the copyright holders nor the names of their + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + */ + +#include "sdl_rpc_plugin/commands/hmi/bc_get_app_properties_response.h" +#include "application_manager/application_impl.h" +#include "application_manager/event_engine/event.h" +#include "application_manager/rpc_service.h" +#include "interfaces/MOBILE_API.h" + +namespace sdl_rpc_plugin { +using namespace application_manager; +namespace commands { + +BCGetAppPropertiesResponse::BCGetAppPropertiesResponse( + const application_manager::commands::MessageSharedPtr& message, + ApplicationManager& application_manager, + app_mngr::rpc_service::RPCService& rpc_service, + app_mngr::HMICapabilities& hmi_capabilities, + policy::PolicyHandlerInterface& policy_handler) + : ResponseToHMI(message, + application_manager, + rpc_service, + hmi_capabilities, + policy_handler) {} + +void BCGetAppPropertiesResponse::Run() { + LOG4CXX_AUTO_TRACE(logger_); + rpc_service_.SendMessageToHMI(message_); +} +} // namespace commands +} // namespace sdl_rpc_plugin diff --git a/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/src/commands/hmi/bc_set_app_properties_request.cc b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/src/commands/hmi/bc_set_app_properties_request.cc new file mode 100644 index 0000000000..a4c5d6b1b4 --- /dev/null +++ b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/src/commands/hmi/bc_set_app_properties_request.cc @@ -0,0 +1,114 @@ +/* + Copyright (c) 2020, Ford Motor Company, Livio + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following + disclaimer in the documentation and/or other materials provided with the + distribution. + + Neither the name of the the copyright holders nor the names of their + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + */ + +#include "sdl_rpc_plugin/commands/hmi/bc_set_app_properties_request.h" +#include "application_manager/message_helper.h" +#include "application_manager/policies/policy_handler_interface.h" +#include "application_manager/rpc_service.h" +#include "interfaces/MOBILE_API.h" + +namespace sdl_rpc_plugin { +using namespace application_manager; +namespace commands { + +BCSetAppPropertiesRequest::BCSetAppPropertiesRequest( + const application_manager::commands::MessageSharedPtr& message, + ApplicationManager& application_manager, + app_mngr::rpc_service::RPCService& rpc_service, + app_mngr::HMICapabilities& hmi_capabilities, + policy::PolicyHandlerInterface& policy_handler) + : RequestFromHMI(message, + application_manager, + rpc_service, + hmi_capabilities, + policy_handler) {} + +void BCSetAppPropertiesRequest::Run() { + LOG4CXX_AUTO_TRACE(logger_); + const auto& properties = + (*message_)[strings::msg_params][strings::properties]; + + const auto policy_app_id(properties[strings::policy_app_id].asString()); + + const auto properties_change_status = + policy_handler_.GetAppPropertiesStatus(properties, policy_app_id); + + using AppPropertiesState = policy::PolicyHandlerInterface::AppPropertiesState; + const bool are_properties_changed = + AppPropertiesState::NO_CHANGES != properties_change_status; + + const bool is_new_app = policy_handler_.IsNewApplication(policy_app_id); + + policy_handler_.OnSetAppProperties(properties); + SendResponse(true, + (*message_)[strings::params][strings::correlation_id].asUInt(), + hmi_apis::FunctionID::BasicCommunication_SetAppProperties, + hmi_apis::Common_Result::SUCCESS); + + if (are_properties_changed || is_new_app) { + const auto notification = + MessageHelper::CreateOnAppPropertiesChangeNotification( + policy_app_id, application_manager_); + application_manager_.GetRPCService().ManageHMICommand(notification); + } + if (is_new_app) { + LOG4CXX_ERROR(logger_, + "Message contains unknow policyAppId: " + << policy_app_id << ", PTU will be triggered"); + policy_handler_.OnLocalAppAdded(); + } + + auto app_enabled = [this]() -> bool { + auto& properties = (*message_)[strings::msg_params][strings::properties]; + if (properties.keyExists(strings::enabled)) { + return properties[strings::enabled].asBool(); + } + return false; + }; + + const bool enable_flag_switch = + AppPropertiesState::ENABLED_FLAG_SWITCH == properties_change_status; + + if (app_enabled() && (enable_flag_switch || is_new_app)) { + application_manager_.CreatePendingLocalApplication(policy_app_id); + application_manager_.SendUpdateAppList(); + return; + } + + if (enable_flag_switch) { + application_manager_.RemovePendingApplication(policy_app_id); + application_manager_.SendUpdateAppList(); + } +} + +} // namespace commands +} // namespace sdl_rpc_plugin diff --git a/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/src/commands/hmi/bc_set_app_properties_response.cc b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/src/commands/hmi/bc_set_app_properties_response.cc new file mode 100644 index 0000000000..928a17d0f8 --- /dev/null +++ b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/src/commands/hmi/bc_set_app_properties_response.cc @@ -0,0 +1,62 @@ +/* + Copyright (c) 2020, Ford Motor Company, Livio + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following + disclaimer in the documentation and/or other materials provided with the + distribution. + + Neither the name of the the copyright holders nor the names of their + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + */ + +#include "sdl_rpc_plugin/commands/hmi/bc_set_app_properties_response.h" +#include "application_manager/application_impl.h" +#include "application_manager/event_engine/event.h" +#include "application_manager/policies/policy_handler_interface.h" +#include "application_manager/rpc_service.h" +#include "interfaces/MOBILE_API.h" + +namespace sdl_rpc_plugin { +using namespace application_manager; +namespace commands { + +BCSetAppPropertiesResponse::BCSetAppPropertiesResponse( + const application_manager::commands::MessageSharedPtr& message, + ApplicationManager& application_manager, + app_mngr::rpc_service::RPCService& rpc_service, + app_mngr::HMICapabilities& hmi_capabilities, + policy::PolicyHandlerInterface& policy_handler) + : ResponseToHMI(message, + application_manager, + rpc_service, + hmi_capabilities, + policy_handler) {} + +void BCSetAppPropertiesResponse::Run() { + LOG4CXX_AUTO_TRACE(logger_); + rpc_service_.SendMessageToHMI(message_); +} + +} // namespace commands +} // namespace sdl_rpc_plugin diff --git a/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/src/commands/hmi/on_app_properties_change_notification.cc b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/src/commands/hmi/on_app_properties_change_notification.cc new file mode 100644 index 0000000000..f1fa703bbb --- /dev/null +++ b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/src/commands/hmi/on_app_properties_change_notification.cc @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2020, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "sdl_rpc_plugin/commands/hmi/on_app_properties_change_notification.h" + +namespace sdl_rpc_plugin { +using namespace application_manager; + +namespace commands { + +OnAppPropertiesChangeNotification::OnAppPropertiesChangeNotification( + const application_manager::commands::MessageSharedPtr& message, + ApplicationManager& application_manager, + rpc_service::RPCService& rpc_service, + HMICapabilities& hmi_capabilities, + policy::PolicyHandlerInterface& policy_handle) + : NotificationToHMI(message, + application_manager, + rpc_service, + hmi_capabilities, + policy_handle) {} + +void OnAppPropertiesChangeNotification::Run() { + LOG4CXX_AUTO_TRACE(logger_); + SendNotification(); +} + +} // namespace commands + +} // namespace sdl_rpc_plugin diff --git a/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/src/commands/mobile/get_cloud_app_properties_request.cc b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/src/commands/mobile/get_cloud_app_properties_request.cc index 0b7e611e59..c5e94da378 100644 --- a/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/src/commands/mobile/get_cloud_app_properties_request.cc +++ b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/src/commands/mobile/get_cloud_app_properties_request.cc @@ -33,20 +33,10 @@ void GetCloudAppPropertiesRequest::Run() { std::string policy_app_id = (*message_)[strings::msg_params][strings::app_id].asString(); - bool enabled = true; - std::string endpoint; - std::string auth_token; - std::string certificate; - std::string cloud_transport_type; - std::string hybrid_app_preference; - - bool result = policy_handler_.GetCloudAppParameters(policy_app_id, - enabled, - endpoint, - certificate, - auth_token, - cloud_transport_type, - hybrid_app_preference); + policy::AppProperties app_properties; + + const bool result = + policy_handler_.GetAppProperties(policy_app_id, app_properties); if (!result) { SendResponse(false, @@ -70,19 +60,20 @@ void GetCloudAppPropertiesRequest::Run() { } properties[strings::nicknames] = nicknames_array; properties[strings::app_id] = policy_app_id; - properties[strings::enabled] = enabled; + properties[strings::enabled] = app_properties.enabled; - if (!auth_token.empty()) { - properties[strings::auth_token] = auth_token; + if (!app_properties.auth_token.empty()) { + properties[strings::auth_token] = app_properties.auth_token; } - if (!cloud_transport_type.empty()) { - properties[strings::cloud_transport_type] = cloud_transport_type; + if (!app_properties.transport_type.empty()) { + properties[strings::cloud_transport_type] = app_properties.transport_type; } - if (!hybrid_app_preference.empty()) { - properties[strings::hybrid_app_preference] = hybrid_app_preference; + if (!app_properties.hybrid_app_preference.empty()) { + properties[strings::hybrid_app_preference] = + app_properties.hybrid_app_preference; } - if (!endpoint.empty()) { - properties[strings::endpoint] = endpoint; + if (!app_properties.endpoint.empty()) { + properties[strings::endpoint] = app_properties.endpoint; } response_params[strings::properties] = properties; diff --git a/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/src/commands/mobile/set_cloud_app_properties_request.cc b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/src/commands/mobile/set_cloud_app_properties_request.cc index 3bb1e1c107..680429d3b6 100644 --- a/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/src/commands/mobile/set_cloud_app_properties_request.cc +++ b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/src/commands/mobile/set_cloud_app_properties_request.cc @@ -1,4 +1,5 @@ #include "sdl_rpc_plugin/commands/mobile/set_cloud_app_properties_request.h" +#include "application_manager/message_helper.h" #include "application_manager/policies/policy_handler_interface.h" namespace sdl_rpc_plugin { @@ -30,9 +31,29 @@ void SetCloudAppPropertiesRequest::Run() { return; } - policy_handler_.OnSetCloudAppProperties(*message_); + const auto& properties = + (*message_)[strings::msg_params][strings::properties]; + + const auto app_id(properties[strings::app_id].asString()); + + const auto properties_change_status = + policy_handler_.GetAppPropertiesStatus(properties, app_id); + + using AppPropertiesState = policy::PolicyHandlerInterface::AppPropertiesState; + const bool is_properties_changed = + AppPropertiesState::NO_CHANGES != properties_change_status; + const bool is_new_app = policy_handler_.IsNewApplication(app_id); + + policy_handler_.OnSetCloudAppProperties(*message_); SendResponse(true, mobile_apis::Result::SUCCESS); + + if (is_properties_changed || is_new_app) { + const auto notification = + MessageHelper::CreateOnAppPropertiesChangeNotification( + app_id, application_manager_); + application_manager_.GetRPCService().ManageHMICommand(notification); + } } void SetCloudAppPropertiesRequest::on_event( diff --git a/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/src/hmi_command_factory.cc b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/src/hmi_command_factory.cc index 6a231f8e35..b89a8dbd68 100644 --- a/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/src/hmi_command_factory.cc +++ b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/src/hmi_command_factory.cc @@ -256,6 +256,12 @@ #include "sdl_rpc_plugin/commands/hmi/on_bc_system_capability_updated_notification.h" #include "sdl_rpc_plugin/commands/hmi/on_bc_system_capability_updated_notification_from_hmi.h" +#include "sdl_rpc_plugin/commands/hmi/bc_get_app_properties_request.h" +#include "sdl_rpc_plugin/commands/hmi/bc_get_app_properties_response.h" +#include "sdl_rpc_plugin/commands/hmi/bc_set_app_properties_request.h" +#include "sdl_rpc_plugin/commands/hmi/bc_set_app_properties_response.h" +#include "sdl_rpc_plugin/commands/hmi/on_app_properties_change_notification.h" + namespace sdl_rpc_plugin { using namespace application_manager; @@ -904,6 +910,19 @@ CommandCreator& HMICommandFactory::get_creator_factory( : factory.GetCreator< commands::OnBCSystemCapabilityUpdatedNotification>(); } + case hmi_apis::FunctionID::BasicCommunication_GetAppProperties: { + return hmi_apis::messageType::request == message_type + ? factory.GetCreator() + : factory.GetCreator(); + } + case hmi_apis::FunctionID::BasicCommunication_SetAppProperties: { + return hmi_apis::messageType::request == message_type + ? factory.GetCreator() + : factory.GetCreator(); + } + case hmi_apis::FunctionID::BasicCommunication_OnAppPropertiesChange: { + return factory.GetCreator(); + } default: { return factory.GetCreator(); } } } diff --git a/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/test/commands/hmi/bc_get_app_properties_request_test.cc b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/test/commands/hmi/bc_get_app_properties_request_test.cc new file mode 100644 index 0000000000..0d70226645 --- /dev/null +++ b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/test/commands/hmi/bc_get_app_properties_request_test.cc @@ -0,0 +1,367 @@ +/* + * Copyright (c) 2020, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "gtest/gtest.h" + +#include "application_manager/commands/command_impl.h" +#include "application_manager/commands/command_request_test.h" +#include "application_manager/mock_application.h" +#include "hmi/bc_get_app_properties_request.h" + +namespace test { +namespace components { +namespace commands_test { +namespace hmi_commands_test { +namespace bc_get_app_properties_request_test { + +namespace am = ::application_manager; +namespace strings = ::application_manager::strings; + +using am::commands::CommandImpl; +using am::commands::MessageSharedPtr; +using sdl_rpc_plugin::commands::BCGetAppPropertiesRequest; + +using testing::DoAll; +using testing::Return; +using testing::ReturnRef; +using testing::SaveArg; + +namespace { +const std::string kPolicyAppId = "00001"; +const uint32_t kCorrelationId = 1u; +const auto kSource = am::commands::Command::SOURCE_HMI; + +const std::string kAuthToken = "auth_token"; +const std::string kCertificate = "certificate"; +const std::string kTransportType = "WS"; +const std::string kHybridAppPreference = "local_app"; +const bool kEnabled = true; + +const std::string kNickname1 = "nickname1"; +const std::string kNickname2 = "nickname2"; +} // namespace + +bool CompareAppProperties(const smart_objects::SmartObject& app_propersties_so, + const policy::AppProperties& app_properties) { + return (app_propersties_so[strings::auth_token].asString() == + app_properties.auth_token) && + (app_propersties_so[strings::transport_type].asString() == + app_properties.transport_type) && + (app_propersties_so[strings::hybrid_app_preference].asString() == + app_properties.hybrid_app_preference); +} + +bool CompareNicknames(const smart_objects::SmartObject& nicknames_so, + const policy::StringArray& nicknames) { + if (nicknames_so.length() != nicknames.size()) { + return false; + } + + for (size_t i = 0; i < nicknames_so.length(); ++i) { + if (nicknames_so[i].asString() != nicknames[i]) { + return false; + } + } + return true; +} + +ACTION_P(SetTestAppProperties, app_properties) { + arg1 = app_properties; +} + +ACTION_P(SetTestNickNames, nicknames) { + *arg1 = nicknames; +} + +class BCGetAppPropertiesRequestTest + : public CommandRequestTest { + public: + BCGetAppPropertiesRequestTest() : mock_app_(CreateMockApp()) { + ON_CALL(app_mngr_, GetRPCService()) + .WillByDefault(ReturnRef(mock_rpc_service_)); + } + + MockAppPtr mock_app_; +}; + +TEST_F(BCGetAppPropertiesRequestTest, Run_PolicyAppId_Exist_SUCCESS) { + auto msg = CreateMessage(); + + (*msg)[strings::params][strings::correlation_id] = kCorrelationId; + (*msg)[strings::msg_params][strings::policy_app_id] = kPolicyAppId; + auto command = CreateCommand(msg); + + // Fills app properties with default test values + EXPECT_CALL(mock_policy_handler_, GetAppProperties(kPolicyAppId, _)) + .WillOnce(DoAll( + SetTestAppProperties(policy::AppProperties("", + kCertificate, + kEnabled, + kAuthToken, + kTransportType, + kHybridAppPreference)), + Return(true))); + + // Fills app nicknames with default test values + EXPECT_CALL(mock_policy_handler_, GetInitialAppData(kPolicyAppId, _, _)) + .WillOnce( + DoAll(SetTestNickNames(policy::StringArray{kNickname1, kNickname2}), + Return(true))); + + auto message_to_hmi = CreateMessage(); + + EXPECT_CALL(mock_rpc_service_, + ManageHMICommand( + HMIMessageParametersAre( + kCorrelationId, + hmi_apis::FunctionID::BasicCommunication_GetAppProperties, + hmi_apis::Common_Result::SUCCESS), + kSource)) + .WillOnce(DoAll(SaveArg<0>(&message_to_hmi), Return(true))); + + ASSERT_TRUE(command->Init()); + command->Run(); + + const smart_objects::SmartObject& sent_app_properties = + (*message_to_hmi)[strings::msg_params][strings::properties][0]; + + EXPECT_FALSE(sent_app_properties.empty()); + + const std::string auth_token = + sent_app_properties[strings::auth_token].asString(); + const std::string transport_type = + sent_app_properties[strings::transport_type].asString(); + const std::string hybrid_app_preference = + sent_app_properties[strings::hybrid_app_preference].asString(); + // ENDPOINT should be omitted for local application properties. + EXPECT_FALSE(sent_app_properties.keyExists(strings::endpoint)); + + EXPECT_EQ(kAuthToken, auth_token); + EXPECT_EQ(kTransportType, transport_type); + EXPECT_EQ(kHybridAppPreference, hybrid_app_preference); + + EXPECT_TRUE(sent_app_properties.keyExists(strings::nicknames)); + + const auto nick_names = sent_app_properties[strings::nicknames]; + EXPECT_EQ(kNickname1, nick_names[0].asString()); + EXPECT_EQ(kNickname2, nick_names[1].asString()); +} + +TEST_F(BCGetAppPropertiesRequestTest, + PolicyAppIdExistsInMessage_GetAppPropertiesFailed_UNSUCCESS) { + auto msg = CreateMessage(); + + (*msg)[strings::params][strings::correlation_id] = kCorrelationId; + (*msg)[strings::msg_params][strings::policy_app_id] = kPolicyAppId; + auto command = CreateCommand(msg); + + EXPECT_CALL(mock_policy_handler_, GetAppProperties(kPolicyAppId, _)) + .WillOnce(Return(false)); + + EXPECT_CALL(mock_rpc_service_, + ManageHMICommand( + HMIMessageParametersAre( + kCorrelationId, + hmi_apis::FunctionID::BasicCommunication_GetAppProperties, + hmi_apis::Common_Result::DATA_NOT_AVAILABLE), + application_manager::commands::Command::SOURCE_SDL_TO_HMI)) + .WillOnce(Return(true)); + + ASSERT_TRUE(command->Init()); + command->Run(); +} + +TEST_F( + BCGetAppPropertiesRequestTest, + Run_PolicyAppIdIsAbsentInMessage_AppParametersAreAbsent_NickNamesAreAbsent_UNSUCCESS) { + auto msg = CreateMessage(); + + (*msg)[strings::params][strings::correlation_id] = kCorrelationId; + auto command = CreateCommand(msg); + + EXPECT_CALL(mock_policy_handler_, GetApplicationPolicyIDs()) + .WillOnce(Return(policy::StringArray())); + + EXPECT_CALL(mock_policy_handler_, GetAppProperties(_, _)).Times(0); + EXPECT_CALL(mock_policy_handler_, GetInitialAppData(_, _, _)).Times(0); + + auto message_to_hmi = CreateMessage(); + + EXPECT_CALL(mock_rpc_service_, + ManageHMICommand( + HMIMessageParametersAre( + kCorrelationId, + hmi_apis::FunctionID::BasicCommunication_GetAppProperties, + hmi_apis::Common_Result::DATA_NOT_AVAILABLE), + Command::SOURCE_SDL_TO_HMI)) + .WillOnce(DoAll(SaveArg<0>(&message_to_hmi), Return(true))); + + ASSERT_TRUE(command->Init()); + command->Run(); + + EXPECT_FALSE( + (*message_to_hmi)[strings::msg_params].keyExists(strings::properties)); +} + +TEST_F(BCGetAppPropertiesRequestTest, + Run_PolicyAppIdIsAbsentInMessage_ReturnsAllAppProperties_SUCCESS) { + auto msg = CreateMessage(); + + (*msg)[strings::params][strings::correlation_id] = kCorrelationId; + auto command = CreateCommand(msg); + + const std::string test_policy_app_id1 = "test_policy_app_id1"; + const policy::AppProperties test_app1_properties("", + "cert1", + true, + "auth_token1", + "transport_type1", + "hybrid_app_preference1"); + const policy::StringArray test_nicknames1{"nickname1", "nickname2"}; + + const std::string test_policy_app_id2 = "test_policy_app_id2"; + const policy::AppProperties test_app2_properties("", + "cert2", + false, + "auth_token2", + "transport_type2", + "hybrid_app_preference2"); + const policy::StringArray test_nicknames2{"nickname3", "nickname4"}; + + EXPECT_CALL(mock_policy_handler_, GetApplicationPolicyIDs()) + .WillOnce(Return( + policy::StringArray{test_policy_app_id1, test_policy_app_id2})); + + EXPECT_CALL(mock_policy_handler_, GetAppProperties(test_policy_app_id1, _)) + .WillOnce( + DoAll(SetTestAppProperties(test_app1_properties), Return(true))); + EXPECT_CALL(mock_policy_handler_, + GetInitialAppData(test_policy_app_id1, _, _)) + .WillOnce(DoAll(SetTestNickNames(test_nicknames1), Return(true))); + + EXPECT_CALL(mock_policy_handler_, GetAppProperties(test_policy_app_id2, _)) + .WillOnce( + DoAll(SetTestAppProperties(test_app2_properties), Return(true))); + EXPECT_CALL(mock_policy_handler_, + GetInitialAppData(test_policy_app_id2, _, _)) + .WillOnce(DoAll(SetTestNickNames(test_nicknames2), Return(true))); + + auto message_to_hmi = CreateMessage(); + + EXPECT_CALL(mock_rpc_service_, + ManageHMICommand( + HMIMessageParametersAre( + kCorrelationId, + hmi_apis::FunctionID::BasicCommunication_GetAppProperties, + hmi_apis::Common_Result::SUCCESS), + kSource)) + .WillOnce(DoAll(SaveArg<0>(&message_to_hmi), Return(true))); + + ASSERT_TRUE(command->Init()); + command->Run(); + + const auto& sent_app_properties = + (*message_to_hmi)[strings::msg_params][strings::properties]; + + EXPECT_EQ(2u, sent_app_properties.length()); + + // Compare test_app1 app_properties with sent app properties + const auto& sent_test_app1_properties = sent_app_properties[0]; + EXPECT_FALSE(sent_test_app1_properties.keyExists(strings::endpoint)); + EXPECT_TRUE( + CompareAppProperties(sent_test_app1_properties, test_app1_properties)); + + const auto& sent_test_app1_nicknames = + sent_app_properties[0][strings::nicknames]; + EXPECT_TRUE(CompareNicknames(sent_test_app1_nicknames, test_nicknames1)); + + // Compare test_app2 app_properties with sent app properties + const auto& sent_test_app2_properties = sent_app_properties[1]; + EXPECT_FALSE(sent_test_app2_properties.keyExists(strings::endpoint)); + EXPECT_TRUE( + CompareAppProperties(sent_test_app2_properties, test_app2_properties)); + + const auto& sent_test_app2_nicknames = + sent_app_properties[1][strings::nicknames]; + EXPECT_TRUE(CompareNicknames(sent_test_app2_nicknames, test_nicknames2)); +} + +TEST_F(BCGetAppPropertiesRequestTest, + Run_PolicyAppIdExist_NickNamesAreAbsent_SendEmptyArray_SUCCESS) { + auto msg = CreateMessage(); + + (*msg)[strings::params][strings::correlation_id] = kCorrelationId; + (*msg)[strings::msg_params][strings::policy_app_id] = kPolicyAppId; + auto command = CreateCommand(msg); + + // Fills app properties with default test values + EXPECT_CALL(mock_policy_handler_, GetAppProperties(kPolicyAppId, _)) + .WillOnce(DoAll( + SetTestAppProperties(policy::AppProperties("", + kCertificate, + kEnabled, + kAuthToken, + kTransportType, + kHybridAppPreference)), + Return(true))); + + // In the case when nicknames array is empty, SDL should forward the empty + // array to HMI in the app properties + EXPECT_CALL(mock_policy_handler_, GetInitialAppData(kPolicyAppId, _, _)) + .WillOnce(DoAll(SetTestNickNames(policy::StringArray{}), Return(true))); + + auto message_to_hmi = CreateMessage(); + + EXPECT_CALL(mock_rpc_service_, + ManageHMICommand( + HMIMessageParametersAre( + kCorrelationId, + hmi_apis::FunctionID::BasicCommunication_GetAppProperties, + hmi_apis::Common_Result::SUCCESS), + kSource)) + .WillOnce(DoAll(SaveArg<0>(&message_to_hmi), Return(true))); + + ASSERT_TRUE(command->Init()); + command->Run(); + + const auto& sent_app_properties = + (*message_to_hmi)[strings::msg_params][strings::properties]; + + EXPECT_TRUE(sent_app_properties[0].keyExists(strings::nicknames)); + EXPECT_TRUE(sent_app_properties[0][strings::nicknames].empty()); +} + +} // namespace bc_get_app_properties_request_test +} // namespace hmi_commands_test +} // namespace commands_test +} // namespace components +} // namespace test diff --git a/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/test/commands/hmi/bc_get_app_properties_response_test.cc b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/test/commands/hmi/bc_get_app_properties_response_test.cc new file mode 100644 index 0000000000..f9df8db1e3 --- /dev/null +++ b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/test/commands/hmi/bc_get_app_properties_response_test.cc @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2020 Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the names of the copyright holders nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "hmi/bc_get_app_properties_response.h" +#include "application_manager/commands/command_impl.h" +#include "application_manager/commands/commands_test.h" +#include "gtest/gtest.h" +#include "smart_objects/smart_object.h" + +namespace test { +namespace components { +namespace commands_test { +namespace hmi_commands_test { +namespace bc_get_app_properties_response { + +using sdl_rpc_plugin::commands::BCGetAppPropertiesResponse; + +class BCGetAppPropertiesResponseTest + : public CommandsTest {}; + +TEST_F(BCGetAppPropertiesResponseTest, RUN_SUCCESS) { + MessageSharedPtr msg = CreateMessage(); + + std::shared_ptr command( + CreateCommand(msg)); + + EXPECT_CALL(mock_rpc_service_, SendMessageToHMI(msg)); + + ASSERT_TRUE(command->Init()); + command->Run(); +} + +} // namespace bc_get_app_properties_response +} // namespace hmi_commands_test +} // namespace commands_test +} // namespace components +} // namespace test diff --git a/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/test/commands/hmi/bc_set_app_properties_request_test.cc b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/test/commands/hmi/bc_set_app_properties_request_test.cc new file mode 100644 index 0000000000..5804476649 --- /dev/null +++ b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/test/commands/hmi/bc_set_app_properties_request_test.cc @@ -0,0 +1,304 @@ +/* + * Copyright (c) 2020 Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the names of the copyright holders nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "gtest/gtest.h" + +#include "application_manager/policies/policy_handler.h" +#include "hmi/bc_set_app_properties_request.h" + +#include "application_manager/commands/command_request_test.h" +#include "application_manager/policies/policy_handler.h" + +namespace test { +namespace components { +namespace commands_test { +namespace hmi_commands_test { +namespace bc_set_app_properties_request { + +namespace am = ::application_manager; +namespace strings = am::strings; + +using sdl_rpc_plugin::commands::BCSetAppPropertiesRequest; +using ::testing::_; +using ::testing::ReturnRef; + +namespace { +const uint32_t kAppId = 1u; +const std::string kPolicyAppId = "00001"; +const std::string kToken = "TOKEN"; +const uint32_t kHmiAppId = 13u; +const uint32_t kCorrelationId = 1u; +const auto kSource = am::commands::Command::SOURCE_HMI; +} // namespace + +typedef std::shared_ptr BCSetAppPropertiesRequestPtr; + +class BCSetAppPropertiesRequestTest + : public CommandRequestTest { + public: + BCSetAppPropertiesRequestTest() : mock_app_(CreateMockApp()) { + ON_CALL((*mock_app_), app_id()).WillByDefault(Return(kAppId)); + ON_CALL(app_mngr_, event_dispatcher()) + .WillByDefault(ReturnRef(event_dispatcher_)); + ON_CALL(app_mngr_, application(_)).WillByDefault(Return(mock_app_)); + ON_CALL(app_mngr_, application_by_hmi_app(_)) + .WillByDefault(Return(mock_app_)); + ON_CALL(app_mngr_, GetRPCService()) + .WillByDefault(ReturnRef(mock_rpc_service_)); + ON_CALL(mock_rpc_service_, ManageHMICommand(_, _)) + .WillByDefault(Return(true)); + } + + MessageSharedPtr CreateMessageWithCustomProperties( + const smart_objects::SmartObject& properties) { + MessageSharedPtr msg = CreateMessage(); + (*msg)[strings::params][strings::correlation_id] = kCorrelationId; + (*msg)[strings::msg_params][strings::app_id] = kAppId; + (*msg)[strings::msg_params][strings::properties] = properties; + return msg; + } + + MockAppPtr mock_app_; +}; + +TEST_F(BCSetAppPropertiesRequestTest, + Run_NoAppPropertyChanges_AppIsSame_FailToUpdateAppList) { + smart_objects::SmartObject properties(smart_objects::SmartType_Map); + properties[strings::policy_app_id] = kPolicyAppId; + + MessageSharedPtr msg = CreateMessageWithCustomProperties(properties); + auto command = CreateCommand(msg); + + const auto change_status = + policy::PolicyHandler::AppPropertiesState::NO_CHANGES; + ON_CALL(mock_policy_handler_, + GetAppPropertiesStatus(properties, kPolicyAppId)) + .WillByDefault(Return(change_status)); + ON_CALL(mock_policy_handler_, IsNewApplication(kPolicyAppId)) + .WillByDefault(Return(false)); + + MessageSharedPtr notification = CreateMessage(); + ON_CALL(mock_message_helper_, + CreateOnAppPropertiesChangeNotification(kPolicyAppId, _)) + .WillByDefault(Return(notification)); + + EXPECT_CALL(mock_message_helper_, + CreateOnAppPropertiesChangeNotification(_, _)) + .Times(0); + EXPECT_CALL(mock_policy_handler_, + GetAppPropertiesStatus(properties, kPolicyAppId)); + EXPECT_CALL(mock_policy_handler_, OnSetAppProperties(properties)); + EXPECT_CALL( + mock_rpc_service_, + ManageHMICommand( + HMIResultCodeIs( + hmi_apis::FunctionID::BasicCommunication_SetAppProperties), + kSource)); + EXPECT_CALL(mock_rpc_service_, ManageHMICommand(notification, kSource)) + .Times(0); + EXPECT_CALL(app_mngr_, CreatePendingLocalApplication(kPolicyAppId)).Times(0); + EXPECT_CALL(app_mngr_, SendUpdateAppList()).Times(0); + + ASSERT_TRUE(command->Init()); + command->Run(); +} + +TEST_F(BCSetAppPropertiesRequestTest, + Run_AppAuthTokenChanged_AppIsSame_NoUpdateAppList) { + smart_objects::SmartObject properties(smart_objects::SmartType_Map); + properties[strings::auth_token] = kToken; + properties[strings::policy_app_id] = kPolicyAppId; + + MessageSharedPtr msg = CreateMessageWithCustomProperties(properties); + auto command = CreateCommand(msg); + + const auto change_status = + policy::PolicyHandler::AppPropertiesState::AUTH_TOKEN_CHANGED; + ON_CALL(mock_policy_handler_, + GetAppPropertiesStatus(properties, kPolicyAppId)) + .WillByDefault(Return(change_status)); + ON_CALL(mock_policy_handler_, IsNewApplication(kPolicyAppId)) + .WillByDefault(Return(false)); + + MessageSharedPtr notification = CreateMessage(); + ON_CALL(mock_message_helper_, + CreateOnAppPropertiesChangeNotification(kPolicyAppId, _)) + .WillByDefault(Return(notification)); + + EXPECT_CALL(mock_message_helper_, + CreateOnAppPropertiesChangeNotification(kPolicyAppId, _)); + EXPECT_CALL(mock_policy_handler_, + GetAppPropertiesStatus(properties, kPolicyAppId)); + EXPECT_CALL(mock_policy_handler_, OnSetAppProperties(properties)); + EXPECT_CALL( + mock_rpc_service_, + ManageHMICommand( + HMIResultCodeIs( + hmi_apis::FunctionID::BasicCommunication_SetAppProperties), + kSource)); + EXPECT_CALL(mock_rpc_service_, ManageHMICommand(notification, kSource)); + EXPECT_CALL(app_mngr_, CreatePendingLocalApplication(kPolicyAppId)).Times(0); + EXPECT_CALL(app_mngr_, SendUpdateAppList()).Times(0); + + ASSERT_TRUE(command->Init()); + command->Run(); +} + +TEST_F(BCSetAppPropertiesRequestTest, + Run_NoAppPropetiesChanged_AppIsNewAndEnabled_AppListUpdated) { + smart_objects::SmartObject properties(smart_objects::SmartType_Map); + properties[strings::policy_app_id] = kPolicyAppId; + properties[strings::enabled] = true; + + MessageSharedPtr msg = CreateMessageWithCustomProperties(properties); + auto command = CreateCommand(msg); + + const auto change_status = + policy::PolicyHandler::AppPropertiesState::NO_CHANGES; + ON_CALL(mock_policy_handler_, + GetAppPropertiesStatus(properties, kPolicyAppId)) + .WillByDefault(Return(change_status)); + ON_CALL(mock_policy_handler_, IsNewApplication(kPolicyAppId)) + .WillByDefault(Return(true)); + + MessageSharedPtr notification = CreateMessage(); + ON_CALL(mock_message_helper_, + CreateOnAppPropertiesChangeNotification(kPolicyAppId, _)) + .WillByDefault(Return(notification)); + + EXPECT_CALL(mock_message_helper_, + CreateOnAppPropertiesChangeNotification(kPolicyAppId, _)); + EXPECT_CALL(mock_policy_handler_, + GetAppPropertiesStatus(properties, kPolicyAppId)); + EXPECT_CALL(mock_policy_handler_, OnSetAppProperties(properties)); + EXPECT_CALL( + mock_rpc_service_, + ManageHMICommand( + HMIResultCodeIs( + hmi_apis::FunctionID::BasicCommunication_SetAppProperties), + kSource)); + EXPECT_CALL(mock_rpc_service_, ManageHMICommand(notification, kSource)); + EXPECT_CALL(app_mngr_, CreatePendingLocalApplication(kPolicyAppId)); + EXPECT_CALL(app_mngr_, SendUpdateAppList()); + + ASSERT_TRUE(command->Init()); + command->Run(); +} + +TEST_F(BCSetAppPropertiesRequestTest, + Run_AppEnabledFlagChanged_AppListUpdated) { + smart_objects::SmartObject properties(smart_objects::SmartType_Map); + properties[strings::policy_app_id] = kPolicyAppId; + properties[strings::enabled] = true; + + MessageSharedPtr msg = CreateMessageWithCustomProperties(properties); + auto command = CreateCommand(msg); + + const auto change_status = + policy::PolicyHandler::AppPropertiesState::ENABLED_FLAG_SWITCH; + ON_CALL(mock_policy_handler_, + GetAppPropertiesStatus(properties, kPolicyAppId)) + .WillByDefault(Return(change_status)); + ON_CALL(mock_policy_handler_, IsNewApplication(kPolicyAppId)) + .WillByDefault(Return(false)); + + MessageSharedPtr notification = CreateMessage(); + ON_CALL(mock_message_helper_, + CreateOnAppPropertiesChangeNotification(kPolicyAppId, _)) + .WillByDefault(Return(notification)); + + EXPECT_CALL(mock_message_helper_, + CreateOnAppPropertiesChangeNotification(kPolicyAppId, _)); + EXPECT_CALL(mock_policy_handler_, + GetAppPropertiesStatus(properties, kPolicyAppId)); + EXPECT_CALL(mock_policy_handler_, OnSetAppProperties(properties)); + EXPECT_CALL( + mock_rpc_service_, + ManageHMICommand( + HMIResultCodeIs( + hmi_apis::FunctionID::BasicCommunication_SetAppProperties), + kSource)); + EXPECT_CALL(mock_rpc_service_, ManageHMICommand(notification, kSource)); + EXPECT_CALL(app_mngr_, CreatePendingLocalApplication(kPolicyAppId)); + EXPECT_CALL(app_mngr_, SendUpdateAppList()); + + ASSERT_TRUE(command->Init()); + command->Run(); +} + +TEST_F(BCSetAppPropertiesRequestTest, + Run_AppEnabledFlagChangedToFalse_AppRemoveFromList_AppListUpdated) { + smart_objects::SmartObject properties(smart_objects::SmartType_Map); + properties[strings::policy_app_id] = kPolicyAppId; + properties[strings::enabled] = false; + + MessageSharedPtr msg = CreateMessageWithCustomProperties(properties); + auto command = CreateCommand(msg); + + const auto change_status = + policy::PolicyHandler::AppPropertiesState::ENABLED_FLAG_SWITCH; + ON_CALL(mock_policy_handler_, + GetAppPropertiesStatus(properties, kPolicyAppId)) + .WillByDefault(Return(change_status)); + ON_CALL(mock_policy_handler_, IsNewApplication(kPolicyAppId)) + .WillByDefault(Return(false)); + + MessageSharedPtr notification = CreateMessage(); + ON_CALL(mock_message_helper_, + CreateOnAppPropertiesChangeNotification(kPolicyAppId, _)) + .WillByDefault(Return(notification)); + + EXPECT_CALL(mock_message_helper_, + CreateOnAppPropertiesChangeNotification(kPolicyAppId, _)); + EXPECT_CALL(mock_policy_handler_, + GetAppPropertiesStatus(properties, kPolicyAppId)); + EXPECT_CALL(mock_policy_handler_, OnSetAppProperties(properties)); + EXPECT_CALL( + mock_rpc_service_, + ManageHMICommand( + HMIResultCodeIs( + hmi_apis::FunctionID::BasicCommunication_SetAppProperties), + kSource)); + EXPECT_CALL(mock_rpc_service_, ManageHMICommand(notification, kSource)); + EXPECT_CALL(app_mngr_, CreatePendingLocalApplication(kPolicyAppId)).Times(0); + EXPECT_CALL(app_mngr_, RemovePendingApplication(kPolicyAppId)); + EXPECT_CALL(app_mngr_, SendUpdateAppList()); + + ASSERT_TRUE(command->Init()); + command->Run(); +} + +} // namespace bc_set_app_properties_request +} // namespace hmi_commands_test +} // namespace commands_test +} // namespace components +} // namespace test diff --git a/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/test/commands/hmi/bc_set_app_properties_response_test.cc b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/test/commands/hmi/bc_set_app_properties_response_test.cc new file mode 100644 index 0000000000..d4b7447d0d --- /dev/null +++ b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/test/commands/hmi/bc_set_app_properties_response_test.cc @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2020 Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the names of the copyright holders nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "gtest/gtest.h" + +#include "hmi/bc_set_app_properties_response.h" + +#include "application_manager/commands/commands_test.h" + +namespace test { +namespace components { +namespace commands_test { +namespace hmi_commands_test { +namespace bc_set_app_properties_response { + +using sdl_rpc_plugin::commands::BCSetAppPropertiesResponse; + +class BCSetAppPropertiesResponseTest + : public CommandsTest {}; + +TEST_F(BCSetAppPropertiesResponseTest, RUN_SUCCESS) { + MessageSharedPtr msg = CreateMessage(); + + std::shared_ptr command( + CreateCommand(msg)); + + EXPECT_CALL(mock_rpc_service_, SendMessageToHMI(msg)); + + ASSERT_TRUE(command->Init()); + command->Run(); +} + +} // namespace bc_set_app_properties_response +} // namespace hmi_commands_test +} // namespace commands_test +} // namespace components +} // namespace test diff --git a/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/test/commands/hmi/on_app_properties_change_notification_test.cc b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/test/commands/hmi/on_app_properties_change_notification_test.cc new file mode 100644 index 0000000000..0ab0bc5a35 --- /dev/null +++ b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/test/commands/hmi/on_app_properties_change_notification_test.cc @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2020, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include + +#include "application_manager/commands/commands_test.h" +#include "application_manager/mock_application.h" +#include "application_manager/mock_application_manager.h" +#include "application_manager/smart_object_keys.h" +#include "gtest/gtest.h" +#include "hmi/on_app_properties_change_notification.h" +#include "smart_objects/smart_object.h" + +namespace test { +namespace components { +namespace commands_test { +namespace hmi_commands_test { +namespace on_app_properties_change_notification { + +using namespace application_manager; +using sdl_rpc_plugin::commands::OnAppPropertiesChangeNotification; + +typedef std::shared_ptr NotificationPtr; +typedef hmi_apis::Common_ServiceType::eType ServiceType; +typedef hmi_apis::Common_ServiceEvent::eType ServiceEvent; + +namespace { +const uint32_t kConnectionKey = 1232u; +const uint32_t kHmiAppId = 321u; +} // namespace + +class OnAppPropertiesChangeNotificationTest + : public CommandsTest { + public: + OnAppPropertiesChangeNotificationTest() + : message_(CreateMessage(smart_objects::SmartType_Map)) {} + + protected: + MessageSharedPtr message_; + NotificationPtr command_; +}; + +TEST_F(OnAppPropertiesChangeNotificationTest, SendNotificationToHMI) { + (*message_)[strings::msg_params][strings::app_id] = kConnectionKey; + command_ = CreateCommand(message_); + + EXPECT_CALL(mock_rpc_service_, SendMessageToHMI(message_)).Times(1); + + auto mock_app = std::make_shared >(); + + ON_CALL(app_mngr_, application(kConnectionKey)) + .WillByDefault(Return(mock_app)); + + ON_CALL(*mock_app, hmi_app_id()).WillByDefault(Return(kHmiAppId)); + + ASSERT_TRUE(command_->Init()); + command_->Run(); +} + +} // namespace on_app_properties_change_notification +} // namespace hmi_commands_test +} // namespace commands_test +} // namespace components +} // namespace test diff --git a/src/components/application_manager/src/application_manager_impl.cc b/src/components/application_manager/src/application_manager_impl.cc index 7d7e2b30df..3b586dd5e7 100644 --- a/src/components/application_manager/src/application_manager_impl.cc +++ b/src/components/application_manager/src/application_manager_impl.cc @@ -66,6 +66,7 @@ #include #include #include "application_manager/application_impl.h" +#include "encryption/hashing.h" #include "interfaces/HMI_API_schema.h" #include "media_manager/media_manager.h" #include "policy/usage_statistics/counter.h" @@ -102,7 +103,9 @@ DeviceTypes devicesType = { std::make_pair(std::string("CARPLAY_WIRELESS_IOS"), hmi_apis::Common_TransportType::WIFI), std::make_pair(std::string("CLOUD_WEBSOCKET"), - hmi_apis::Common_TransportType::CLOUD_WEBSOCKET)}; + hmi_apis::Common_TransportType::CLOUD_WEBSOCKET), + std::make_pair(std::string("WEBENGINE_WEBSOCKET"), + hmi_apis::Common_TransportType::WEBENGINE_WEBSOCKET)}; } /** @@ -840,6 +843,11 @@ void ApplicationManagerImpl::ConnectToDevice(const std::string& device_mac) { void ApplicationManagerImpl::OnHMIStartedCooperation() { LOG4CXX_AUTO_TRACE(logger_); hmi_cooperating_ = true; + +#ifdef WEBSOCKET_SERVER_TRANSPORT_SUPPORT + connection_handler_->CreateWebEngineDevice(); +#endif // WEBSOCKET_SERVER_TRANSPORT_SUPPORT + MessageHelper::SendGetSystemInfoRequest(*this); std::shared_ptr is_vr_ready( @@ -946,20 +954,9 @@ void ApplicationManagerImpl::DisconnectCloudApp(ApplicationSharedPtr app) { LOG4CXX_TRACE(logger_, "Cloud app support is disabled. Exiting function"); return; #else - std::string endpoint; - std::string certificate; - std::string auth_token; - std::string cloud_transport_type; - std::string hybrid_app_preference; - bool enabled = true; std::string policy_app_id = app->policy_app_id(); - GetPolicyHandler().GetCloudAppParameters(policy_app_id, - enabled, - endpoint, - certificate, - auth_token, - cloud_transport_type, - hybrid_app_preference); + policy::AppProperties app_properties; + GetPolicyHandler().GetAppProperties(policy_app_id, app_properties); if (app->IsRegistered() && app->is_cloud_app()) { LOG4CXX_DEBUG(logger_, "Disabled app is registered, unregistering now"); GetRPCService().ManageMobileCommand( @@ -974,12 +971,12 @@ void ApplicationManagerImpl::DisconnectCloudApp(ApplicationSharedPtr app) { connection_handler().RemoveCloudAppDevice(app->device()); transport_manager::transport_adapter::CloudAppProperties properties{ - endpoint, - certificate, - enabled, - auth_token, - cloud_transport_type, - hybrid_app_preference}; + app_properties.endpoint, + app_properties.certificate, + app_properties.enabled, + app_properties.auth_token, + app_properties.transport_type, + app_properties.hybrid_app_preference}; // Create device in pending state LOG4CXX_DEBUG(logger_, "Re-adding the cloud app device"); connection_handler().AddCloudAppDevice(policy_app_id, properties); @@ -999,12 +996,6 @@ void ApplicationManagerImpl::RefreshCloudAppInformation() { GetPolicyHandler().GetEnabledCloudApps(enabled_apps); std::vector::iterator enabled_it = enabled_apps.begin(); std::vector::iterator enabled_end = enabled_apps.end(); - std::string endpoint; - std::string certificate; - std::string auth_token; - std::string cloud_transport_type; - std::string hybrid_app_preference_str; - bool enabled = true; // Store old device map and clear the current map pending_device_map_lock_ptr_->Acquire(); @@ -1012,20 +1003,20 @@ void ApplicationManagerImpl::RefreshCloudAppInformation() { std::map old_device_map = pending_device_map_; pending_device_map_ = std::map(); // Create a device for each newly enabled cloud app + policy::AppProperties app_properties; for (; enabled_it != enabled_end; ++enabled_it) { - GetPolicyHandler().GetCloudAppParameters(*enabled_it, - enabled, - endpoint, - certificate, - auth_token, - cloud_transport_type, - hybrid_app_preference_str); + GetPolicyHandler().GetAppProperties(*enabled_it, app_properties); + + if (app_properties.endpoint.empty()) { + continue; + } mobile_apis::HybridAppPreference::eType hybrid_app_preference = mobile_apis::HybridAppPreference::INVALID_ENUM; smart_objects::EnumConversionHelper< mobile_apis::HybridAppPreference::eType>:: - StringToEnum(hybrid_app_preference_str, &hybrid_app_preference); + StringToEnum(app_properties.hybrid_app_preference, + &hybrid_app_preference); auto policy_id = *enabled_it; policy::StringArray nicknames; @@ -1057,22 +1048,22 @@ void ApplicationManagerImpl::RefreshCloudAppInformation() { } } - pending_device_map_.insert( - std::pair(endpoint, policy_id)); + pending_device_map_.insert(std::pair( + app_properties.endpoint, policy_id)); // Determine which endpoints were disabled by erasing all enabled apps from // the old device list - auto old_device_it = old_device_map.find(endpoint); + auto old_device_it = old_device_map.find(app_properties.endpoint); if (old_device_it != old_device_map.end()) { old_device_map.erase(old_device_it); } transport_manager::transport_adapter::CloudAppProperties properties{ - endpoint, - certificate, - enabled, - auth_token, - cloud_transport_type, - hybrid_app_preference_str}; + app_properties.endpoint, + app_properties.certificate, + app_properties.enabled, + app_properties.auth_token, + app_properties.transport_type, + app_properties.hybrid_app_preference}; // If the device was disconnected, this will reinitialize the device connection_handler().AddCloudAppDevice(policy_id, properties); @@ -1094,7 +1085,7 @@ void ApplicationManagerImpl::RefreshCloudAppInformation() { const std::string app_icon_dir(settings_.app_icons_folder()); const std::string full_icon_path(app_icon_dir + "/" + policy_id); if (!file_system::FileExists(full_icon_path)) { - AppIconInfo icon_info(endpoint, false); + AppIconInfo icon_info(app_properties.endpoint, false); LOG4CXX_DEBUG( logger_, "Inserting cloud app into icon map: " << app_icon_map_.size()); @@ -1158,12 +1149,6 @@ void ApplicationManagerImpl::CreatePendingApplication( connection_handler::DeviceHandle device_id) { LOG4CXX_AUTO_TRACE(logger_); - std::string endpoint; - std::string certificate; - std::string auth_token; - std::string cloud_transport_type; - std::string hybrid_app_preference_str; - bool enabled = true; std::string name = device_info.name(); pending_device_map_lock_ptr_->Acquire(); auto it = pending_device_map_.find(name); @@ -1207,34 +1192,29 @@ void ApplicationManagerImpl::CreatePendingApplication( if (file_system::FileExists(full_icon_path)) { application->set_app_icon_path(full_icon_path); } - - GetPolicyHandler().GetCloudAppParameters(policy_app_id, - enabled, - endpoint, - certificate, - auth_token, - cloud_transport_type, - hybrid_app_preference_str); + policy::AppProperties app_properties; + GetPolicyHandler().GetAppProperties(policy_app_id, app_properties); mobile_apis::HybridAppPreference::eType hybrid_app_preference_enum; - bool convert_result = smart_objects::EnumConversionHelper< + const bool convert_result = smart_objects::EnumConversionHelper< mobile_apis::HybridAppPreference::eType>:: - StringToEnum(hybrid_app_preference_str, &hybrid_app_preference_enum); + StringToEnum(app_properties.hybrid_app_preference, + &hybrid_app_preference_enum); - if (!hybrid_app_preference_str.empty() && !convert_result) { - LOG4CXX_ERROR( - logger_, - "Could not convert string to enum: " << hybrid_app_preference_str); + if (!app_properties.hybrid_app_preference.empty() && !convert_result) { + LOG4CXX_ERROR(logger_, + "Could not convert string to enum: " + << app_properties.hybrid_app_preference); return; } application->set_hmi_application_id(GenerateNewHMIAppID()); - application->set_cloud_app_endpoint(endpoint); - application->set_auth_token(auth_token); - application->set_cloud_app_transport_type(cloud_transport_type); + application->set_cloud_app_endpoint(app_properties.endpoint); + application->set_auth_token(app_properties.auth_token); + application->set_cloud_app_transport_type(app_properties.transport_type); application->set_hybrid_app_preference(hybrid_app_preference_enum); - application->set_cloud_app_certificate(certificate); + application->set_cloud_app_certificate(app_properties.certificate); sync_primitives::AutoLock lock(apps_to_register_list_lock_ptr_); LOG4CXX_DEBUG(logger_, @@ -1246,6 +1226,106 @@ void ApplicationManagerImpl::CreatePendingApplication( SendUpdateAppList(); } +void ApplicationManagerImpl::RemovePendingApplication( + const std::string& policy_app_id) { + LOG4CXX_AUTO_TRACE(logger_); + sync_primitives::AutoLock lock(apps_to_register_list_lock_ptr_); + PolicyAppIdPredicate finder(policy_app_id); + auto app_it = + std::find_if(apps_to_register_.begin(), apps_to_register_.end(), finder); + + if (apps_to_register_.end() == app_it) { + LOG4CXX_WARN( + logger_, + "Unable to find app to remove (" << policy_app_id << "), skipping"); + return; + } + + apps_to_register_.erase(app_it); + LOG4CXX_DEBUG(logger_, + "Remove " << policy_app_id + << " from apps_to_register_. new size = " + << apps_to_register_.size()); +} + +void ApplicationManagerImpl::CreatePendingLocalApplication( + const std::string& policy_app_id) { + policy::StringArray nicknames; + policy::StringArray app_hmi_types; + + GetPolicyHandler().GetInitialAppData( + policy_app_id, &nicknames, &app_hmi_types); + + if (nicknames.empty()) { + LOG4CXX_ERROR(logger_, + "Cloud/Web App " << policy_app_id << "missing nickname"); + return; + } + + const std::string display_name = nicknames[0]; + + const auto web_engine_device = connection_handler_->GetWebEngineDeviceInfo(); + + ApplicationSharedPtr application( + new ApplicationImpl(0, + policy_app_id, + web_engine_device.mac_address(), + web_engine_device.device_handle(), + custom_str::CustomString(display_name), + GetPolicyHandler().GetStatisticManager(), + *this)); + + const std::string app_icon_dir(settings_.app_icons_folder()); + const std::string full_icon_path(app_icon_dir + "/" + policy_app_id); + if (file_system::FileExists(full_icon_path)) { + application->set_app_icon_path(full_icon_path); + } + policy::AppProperties app_properties; + GetPolicyHandler().GetAppProperties(policy_app_id, app_properties); + + mobile_apis::HybridAppPreference::eType hybrid_app_preference_enum; + const bool convert_result = smart_objects::EnumConversionHelper< + mobile_apis::HybridAppPreference::eType>:: + StringToEnum(app_properties.hybrid_app_preference, + &hybrid_app_preference_enum); + + if (!app_properties.hybrid_app_preference.empty() && !convert_result) { + LOG4CXX_ERROR(logger_, + "Could not convert string to enum: " + << app_properties.hybrid_app_preference); + return; + } + + application->set_hmi_application_id(GenerateNewHMIAppID()); + application->set_cloud_app_endpoint(app_properties.endpoint); + application->set_auth_token(app_properties.auth_token); + application->set_cloud_app_transport_type(app_properties.transport_type); + application->set_hybrid_app_preference(hybrid_app_preference_enum); + application->set_cloud_app_certificate(app_properties.certificate); + + sync_primitives::AutoLock lock(apps_to_register_list_lock_ptr_); + apps_to_register_.insert(application); + LOG4CXX_DEBUG(logger_, + "Insert " << application->name().c_str() + << " to apps_to_register_. new size = " + << apps_to_register_.size()); +} + +void ApplicationManagerImpl::OnWebEngineDeviceCreated() { + LOG4CXX_AUTO_TRACE(logger_); + const auto enabled_local_apps = policy_handler_->GetEnabledLocalApps(); + + if (enabled_local_apps.empty()) { + LOG4CXX_DEBUG(logger_, "No enabled local apps present"); + return; + } + + for (auto policy_app_id : enabled_local_apps) { + CreatePendingLocalApplication(policy_app_id); + } + SendUpdateAppList(); +} + void ApplicationManagerImpl::SetPendingApplicationState( const transport_manager::ConnectionUID connection_id, const transport_manager::DeviceInfo& device_info) { @@ -3061,18 +3141,24 @@ void ApplicationManagerImpl::UnregisterAllApplications() { void ApplicationManagerImpl::RemoveAppsWaitingForRegistration( const connection_handler::DeviceHandle handle) { + LOG4CXX_AUTO_TRACE(logger_); DevicePredicate device_finder(handle); apps_to_register_list_lock_ptr_->Acquire(); - AppsWaitRegistrationSet::iterator it_app = std::find_if( - apps_to_register_.begin(), apps_to_register_.end(), device_finder); - - while (apps_to_register_.end() != it_app) { - LOG4CXX_DEBUG( - logger_, - "Waiting app: " << (*it_app)->name().c_str() << " is removed."); - apps_to_register_.erase(it_app); - it_app = std::find_if( - apps_to_register_.begin(), apps_to_register_.end(), device_finder); + std::vector apps_to_remove; + std::copy_if(apps_to_register_.begin(), + apps_to_register_.end(), + std::back_inserter(apps_to_remove), + device_finder); + + const auto enabled_local_apps = policy_handler_->GetEnabledLocalApps(); + for (auto app : apps_to_remove) { + const bool is_app_enabled = + helpers::in_range(enabled_local_apps, app->policy_app_id()); + if (!is_app_enabled) { + LOG4CXX_DEBUG(logger_, + "Waiting app: " << app->name().c_str() << " is removed."); + apps_to_register_.erase(app); + } } apps_to_register_list_lock_ptr_->Release(); @@ -3191,6 +3277,14 @@ void ApplicationManagerImpl::UnregisterApplication( RemoveAppsWaitingForRegistration(handle); } } + const auto enabled_local_apps = policy_handler_->GetEnabledLocalApps(); + if (helpers::in_range(enabled_local_apps, app_to_remove->policy_app_id())) { + LOG4CXX_DEBUG(logger_, + "Enabled local app has been unregistered. Re-create " + "pending application"); + CreatePendingLocalApplication(app_to_remove->policy_app_id()); + } + RefreshCloudAppInformation(); SendUpdateAppList(); } diff --git a/src/components/application_manager/src/commands/request_from_hmi.cc b/src/components/application_manager/src/commands/request_from_hmi.cc index 576287286f..1cf5c50cdd 100644 --- a/src/components/application_manager/src/commands/request_from_hmi.cc +++ b/src/components/application_manager/src/commands/request_from_hmi.cc @@ -90,13 +90,14 @@ void RequestFromHMI::SendResponse( FillCommonParametersOfSO(*message, correlation_id, function_id); (*message)[strings::params][strings::message_type] = MessageType::kResponse; (*message)[strings::params][hmi_response::code] = result_code; - (*message)[strings::msg_params][strings::success] = success; - (*message)[strings::msg_params][strings::result_code] = result_code; if (response_params) { (*message)[strings::msg_params] = *response_params; } + (*message)[strings::msg_params][strings::success] = success; + (*message)[strings::msg_params][strings::result_code] = result_code; + rpc_service_.ManageHMICommand(message, source); } diff --git a/src/components/application_manager/src/message_helper/message_helper.cc b/src/components/application_manager/src/message_helper/message_helper.cc index 48cf1460f9..4a64fdb128 100644 --- a/src/components/application_manager/src/message_helper/message_helper.cc +++ b/src/components/application_manager/src/message_helper/message_helper.cc @@ -1817,8 +1817,10 @@ bool MessageHelper::CreateHMIApplicationStruct( &secondary_device_info); } - message[strings::is_cloud_application] = app->is_cloud_app(); - if (app->is_cloud_app()) { + const bool is_cloud_app = app->is_cloud_app(); + message[strings::is_cloud_application] = is_cloud_app; + + if (is_cloud_app) { message[strings::cloud_connection_status] = app_mngr.GetCloudAppConnectionStatus(app); } @@ -1903,6 +1905,57 @@ void MessageHelper::SendOnAppUnregNotificationToHMI( app_mngr.GetRPCService().ManageHMICommand(notification); } +smart_objects::SmartObjectSPtr +MessageHelper::CreateOnAppPropertiesChangeNotification( + const std::string& policy_app_id, ApplicationManager& app_mngr) { + LOG4CXX_AUTO_TRACE(logger_); + smart_objects::SmartObjectSPtr notification = + std::make_shared( + smart_objects::SmartType_Map); + + smart_objects::SmartObject& message = *notification; + message[strings::params][strings::function_id] = + hmi_apis::FunctionID::BasicCommunication_OnAppPropertiesChange; + message[strings::params][strings::message_type] = MessageType::kNotification; + + policy::AppProperties app_properties; + app_mngr.GetPolicyHandler().GetAppProperties(policy_app_id, app_properties); + + policy::StringArray nicknames; + policy::StringArray app_hmi_types; + + app_mngr.GetPolicyHandler().GetInitialAppData( + policy_app_id, &nicknames, &app_hmi_types); + + smart_objects::SmartObject properties(smart_objects::SmartType_Map); + properties[strings::policy_app_id] = policy_app_id; + properties[strings::enabled] = app_properties.enabled; + + smart_objects::SmartObject nicknames_array(smart_objects::SmartType_Array); + size_t i = 0; + for (const auto& nickname : nicknames) { + nicknames_array[i++] = nickname; + } + properties[strings::nicknames] = nicknames_array; + + if (!app_properties.auth_token.empty()) { + properties[strings::auth_token] = app_properties.auth_token; + } + if (!app_properties.transport_type.empty()) { + properties[strings::transport_type] = app_properties.transport_type; + } + if (!app_properties.hybrid_app_preference.empty()) { + properties[strings::hybrid_app_preference] = + app_properties.hybrid_app_preference; + } + if (!app_properties.endpoint.empty()) { + properties[strings::endpoint] = app_properties.endpoint; + } + + message[strings::msg_params][strings::properties] = properties; + return notification; +} + smart_objects::SmartObjectSPtr MessageHelper::GetBCActivateAppRequestToHMI( ApplicationConstSharedPtr app, const policy::PolicyHandlerInterface& policy_handler, diff --git a/src/components/application_manager/src/policies/policy_handler.cc b/src/components/application_manager/src/policies/policy_handler.cc index b70fcfef86..e43281c448 100644 --- a/src/components/application_manager/src/policies/policy_handler.cc +++ b/src/components/application_manager/src/policies/policy_handler.cc @@ -548,6 +548,15 @@ void PolicyHandler::SendOnAppPermissionsChanged( app->app_id(), permissions, application_manager_); } +void PolicyHandler::SendOnAppPropertiesChangeNotification( + const std::string& policy_app_id) const { + LOG4CXX_AUTO_TRACE(logger_); + const auto notification = + MessageHelper::CreateOnAppPropertiesChangeNotification( + policy_app_id, application_manager_); + application_manager_.GetRPCService().ManageHMICommand(notification); +} + void PolicyHandler::OnPTExchangeNeeded() { LOG4CXX_AUTO_TRACE(logger_); POLICY_LIB_CHECK_VOID(); @@ -1984,47 +1993,205 @@ bool PolicyHandler::CheckSystemAction( return false; } +std::vector PolicyHandler::GetApplicationPolicyIDs() const { + POLICY_LIB_CHECK(std::vector()); + const auto all_policy_ids = policy_manager_->GetApplicationPolicyIDs(); + std::vector policy_app_ids; + + std::copy_if( + all_policy_ids.begin(), + all_policy_ids.end(), + std::back_inserter(policy_app_ids), + [](std::string id) { + return helpers::Compare( + id, kDefaultId, kPreDataConsentId, kDeviceId); + }); + + return policy_app_ids; +} + void PolicyHandler::GetEnabledCloudApps( std::vector& enabled_apps) const { POLICY_LIB_CHECK_VOID(); policy_manager_->GetEnabledCloudApps(enabled_apps); } -bool PolicyHandler::GetCloudAppParameters( - const std::string& policy_app_id, - bool& enabled, - std::string& endpoint, - std::string& certificate, - std::string& auth_token, - std::string& cloud_transport_type, - std::string& hybrid_app_preference) const { +bool PolicyHandler::GetAppProperties(const std::string& policy_app_id, + AppProperties& out_app_properties) const { POLICY_LIB_CHECK(false); - return policy_manager_->GetCloudAppParameters(policy_app_id, - enabled, - endpoint, - certificate, - auth_token, - cloud_transport_type, - hybrid_app_preference); + return policy_manager_->GetAppProperties(policy_app_id, out_app_properties); +} + +std::vector PolicyHandler::GetEnabledLocalApps() const { + POLICY_LIB_CHECK(std::vector()); + return policy_manager_->GetEnabledLocalApps(); } const bool PolicyHandler::CheckCloudAppEnabled( const std::string& policy_app_id) const { POLICY_LIB_CHECK(false); - bool enabled = false; - std::string endpoint; - std::string auth_token; - std::string certificate; - std::string cloud_transport_type; - std::string hybrid_app_preference; - policy_manager_->GetCloudAppParameters(policy_app_id, - enabled, - endpoint, - certificate, - auth_token, - cloud_transport_type, - hybrid_app_preference); - return enabled; + AppProperties out_app_properties; + policy_manager_->GetAppProperties(policy_app_id, out_app_properties); + return out_app_properties.enabled; +} + +PolicyHandler::AppPropertiesState PolicyHandler::GetAppPropertiesStatus( + const smart_objects::SmartObject& properties, + const std::string& app_id) const { + LOG4CXX_AUTO_TRACE(logger_); + + AppProperties app_properties; + policy_manager_->GetAppProperties(app_id, app_properties); + + policy::StringArray nicknames; + policy::StringArray app_hmi_types; + policy_manager_->GetInitialAppData(app_id, &nicknames, &app_hmi_types); + + if (properties.keyExists(strings::enabled) && + app_properties.enabled != properties[strings::enabled].asBool()) { + LOG4CXX_DEBUG(logger_, + "\"enabled\" was changed from: " + << app_properties.enabled + << " to: " << properties[strings::enabled].asBool()); + return AppPropertiesState::ENABLED_FLAG_SWITCH; + } + if (properties.keyExists(strings::auth_token) && + app_properties.auth_token != properties[strings::auth_token].asString()) { + LOG4CXX_DEBUG(logger_, + "\"auth_token\" was changed from: " + << app_properties.auth_token + << " to: " << properties[strings::auth_token].asString()); + return AppPropertiesState::AUTH_TOKEN_CHANGED; + } + if (properties.keyExists(strings::transport_type) && + app_properties.transport_type != + properties[strings::transport_type].asString()) { + LOG4CXX_DEBUG(logger_, + "\"transport_type\" was changed from: " + << app_properties.transport_type << " to: " + << properties[strings::transport_type].asString()); + return AppPropertiesState::TRANSPORT_TYPE_CHANGED; + } + + if (properties.keyExists(strings::cloud_transport_type) && + app_properties.transport_type != + properties[strings::cloud_transport_type].asString()) { + LOG4CXX_DEBUG(logger_, + "\"transport_type\" was changed from: " + << app_properties.transport_type << " to: " + << properties[strings::cloud_transport_type].asString()); + return AppPropertiesState::TRANSPORT_TYPE_CHANGED; + } + + if (properties.keyExists(strings::endpoint) && + app_properties.endpoint != properties[strings::endpoint].asString()) { + LOG4CXX_DEBUG(logger_, + "\"endpoint\" was changed from: " + << app_properties.endpoint + << " to: " << properties[strings::endpoint].asString()); + return AppPropertiesState::ENDPOINT_CHANGED; + } + if (properties.keyExists(strings::nicknames)) { + const smart_objects::SmartArray* nicknames_array = + properties[strings::nicknames].asArray(); + + if (nicknames_array->empty() && !nicknames.empty()) { + return AppPropertiesState::NICKNAMES_CHANGED; + } + + smart_objects::SmartArray::const_iterator it_begin = + nicknames_array->begin(); + smart_objects::SmartArray::const_iterator it_end = nicknames_array->end(); + for (; it_begin != it_end; ++it_begin) { + const auto result = + std::find(nicknames.begin(), nicknames.end(), (*it_begin).asString()); + if (nicknames.end() == result) { + LOG4CXX_DEBUG(logger_, + "\"nicknames\" were changed, new value: " + << (*it_begin).asString()); + return AppPropertiesState::NICKNAMES_CHANGED; + } + } + } + if (properties.keyExists(strings::hybrid_app_preference)) { + auto value = static_cast( + properties[strings::hybrid_app_preference].asUInt()); + std::string hybrid_app_preference_str; + smart_objects::EnumConversionHelper< + mobile_apis::HybridAppPreference::eType>:: + EnumToString(value, &hybrid_app_preference_str); + if (app_properties.hybrid_app_preference != hybrid_app_preference_str) { + LOG4CXX_DEBUG( + logger_, + "\"hybrid_app_preference\" was changed from: " + << app_properties.hybrid_app_preference << " to: " + << properties[strings::hybrid_app_preference].asString()); + return AppPropertiesState::HYBRYD_APP_PROPERTIES_CHANGED; + } + } + return AppPropertiesState::NO_CHANGES; +} + +bool PolicyHandler::IsNewApplication(const std::string& policy_app_id) const { + return policy_manager_->IsNewApplication(policy_app_id); +} + +void PolicyHandler::OnSetAppProperties( + const smart_objects::SmartObject& properties) { + POLICY_LIB_CHECK_VOID(); + + const auto policy_app_id(properties[strings::policy_app_id].asString()); + policy_manager_->InitCloudApp(policy_app_id); + + bool auth_token_update = false; + if (properties.keyExists(strings::enabled)) { + const bool enabled = properties[strings::enabled].asBool(); + policy_manager_->SetCloudAppEnabled(policy_app_id, enabled); + } + if (properties.keyExists(strings::auth_token)) { + const std::string auth_token = properties[strings::auth_token].asString(); + policy_manager_->SetAppAuthToken(policy_app_id, auth_token); + auth_token_update = true; + } + if (properties.keyExists(strings::transport_type)) { + policy_manager_->SetAppCloudTransportType( + policy_app_id, properties[strings::transport_type].asString()); + } + if (properties.keyExists(strings::endpoint)) { + policy_manager_->SetAppEndpoint(policy_app_id, + properties[strings::endpoint].asString()); + } + if (properties.keyExists(strings::nicknames)) { + StringArray nicknames; + const smart_objects::SmartObject& nicknames_array = + properties[strings::nicknames]; + for (size_t i = 0; i < nicknames_array.length(); ++i) { + nicknames.push_back(nicknames_array[i].asString()); + } + policy_manager_->SetAppNicknames(policy_app_id, nicknames); + } + if (properties.keyExists(strings::hybrid_app_preference)) { + std::string hybrid_app_preference; + + auto value = static_cast( + properties[strings::hybrid_app_preference].asUInt()); + smart_objects::EnumConversionHelper< + mobile_apis::HybridAppPreference::eType>:: + EnumToString(value, &hybrid_app_preference); + policy_manager_->SetHybridAppPreference(policy_app_id, + hybrid_app_preference); + } + + if (auth_token_update) { + AppProperties app_properties; + if (policy_manager_->GetAppProperties(policy_app_id, app_properties)) { + OnAuthTokenUpdated(policy_app_id, app_properties.auth_token); + } + } +} + +void PolicyHandler::OnLocalAppAdded() { + policy_manager_->OnLocalAppAdded(); } void PolicyHandler::OnSetCloudAppProperties( @@ -2087,9 +2254,8 @@ void PolicyHandler::OnSetCloudAppProperties( if (properties.keyExists(strings::hybrid_app_preference)) { std::string hybrid_app_preference; - mobile_apis::HybridAppPreference::eType value = - static_cast( - properties[strings::hybrid_app_preference].asUInt()); + auto value = static_cast( + properties[strings::hybrid_app_preference].asUInt()); smart_objects::EnumConversionHelper< mobile_apis::HybridAppPreference::eType>:: EnumToString(value, &hybrid_app_preference); @@ -2098,13 +2264,10 @@ void PolicyHandler::OnSetCloudAppProperties( } if (auth_token_update) { - bool enabled; - std::string end, cert, ctt, hap; - std::string auth_token; + AppProperties app_properties; - policy_manager_->GetCloudAppParameters( - policy_app_id, enabled, end, cert, auth_token, ctt, hap); - OnAuthTokenUpdated(policy_app_id, auth_token); + policy_manager_->GetAppProperties(policy_app_id, app_properties); + OnAuthTokenUpdated(policy_app_id, app_properties.auth_token); } } diff --git a/src/components/application_manager/test/application_manager_impl_test.cc b/src/components/application_manager/test/application_manager_impl_test.cc index b5fba2cc54..2c16048e97 100644 --- a/src/components/application_manager/test/application_manager_impl_test.cc +++ b/src/components/application_manager/test/application_manager_impl_test.cc @@ -112,6 +112,7 @@ const uint32_t kConnectionKey = 1232u; const std::string kAppName = "appName"; const WindowID kDefaultWindowId = mobile_apis::PredefinedWindows::DEFAULT_WINDOW; +const std::vector kEnabledLocalApps = {"localAppId"}; typedef hmi_apis::Common_ServiceStatusUpdateReason::eType ServiceStatusUpdateReason; @@ -119,6 +120,12 @@ typedef hmi_apis::Common_ServiceType::eType ServiceType; typedef hmi_apis::Common_ServiceEvent::eType ServiceEvent; typedef utils::Optional UpdateReasonOptional; +const std::string kPolicyAppID = "test policy id"; +transport_manager::DeviceInfo kDeviceInfo(1, + "mac", + "name", + "WEB_ENGINE_DEVICE"); + #if defined(CLOUD_APP_WEBSOCKET_TRANSPORT_SUPPORT) // Cloud application params const std::string kEndpoint = "endpoint"; @@ -130,6 +137,12 @@ const mobile_api::HybridAppPreference::eType kHybridAppPreference = mobile_api::HybridAppPreference::CLOUD; const std::string kHybridAppPreferenceStr = "CLOUD"; const bool kEnabled = true; +const policy::AppProperties app_properties(kEndpoint2, + kCertificate, + kEnabled, + kAuthToken, + kTransportType, + kHybridAppPreferenceStr); #endif // CLOUD_APP_WEBSOCKET_TRANSPORT_SUPPORT } // namespace @@ -222,6 +235,8 @@ class ApplicationManagerImplTest smart_objects::SmartType_Map))); ON_CALL(*mock_policy_handler_, GetStatisticManager()) .WillByDefault(Return(mock_statistics_manager_)); + ON_CALL(*mock_policy_handler_, GetEnabledLocalApps()) + .WillByDefault(Return(kEnabledLocalApps)); } void CreateAppManager() { @@ -311,6 +326,9 @@ class ApplicationManagerImplTest void AddCloudAppToPendingDeviceMap(); void CreatePendingApplication(); #endif + + void CreatePendingLocalApplication(const std::string& policy_app_id); + uint32_t app_id_; NiceMock mock_policy_settings_; std::shared_ptr > mock_storage_; @@ -1249,7 +1267,9 @@ TEST_F(ApplicationManagerImplTest, UnregisterAnotherAppDuringAudioPassThru) { EXPECT_CALL(*mock_app_2, device()).WillRepeatedly(Return(0)); EXPECT_CALL(*mock_app_2, mac_address()) .WillRepeatedly(ReturnRef(dummy_mac_address)); - EXPECT_CALL(*mock_app_2, policy_app_id()).WillRepeatedly(Return("")); + const std::string app2_policy_id = "app2_policy_id"; + EXPECT_CALL(*mock_app_2, policy_app_id()) + .WillRepeatedly(Return(app2_policy_id)); EXPECT_CALL(*mock_app_2, protocol_version()) .WillRepeatedly( Return(protocol_handler::MajorProtocolVersion::PROTOCOL_VERSION_4)); @@ -1286,6 +1306,9 @@ TEST_F(ApplicationManagerImplTest, UnregisterAnotherAppDuringAudioPassThru) { audio_type); } + std::vector enabled_apps = {app2_policy_id}; + EXPECT_CALL(*mock_rpc_service_, ManageHMICommand(_, _)).Times(1); + // while running APT, app 1 is unregistered app_manager_impl_->UnregisterApplication( app_id_1, mobile_apis::Result::SUCCESS, false, true); @@ -1668,14 +1691,8 @@ void ApplicationManagerImplTest::AddCloudAppToPendingDeviceMap() { std::vector enabled_apps{"1234"}; EXPECT_CALL(*mock_policy_handler_, GetEnabledCloudApps(_)) .WillOnce(SetArgReferee<0>(enabled_apps)); - EXPECT_CALL(*mock_policy_handler_, GetCloudAppParameters(_, _, _, _, _, _, _)) - .WillOnce(DoAll(SetArgReferee<1>(kEnabled), - SetArgReferee<2>(kEndpoint2), - SetArgReferee<3>(kCertificate), - SetArgReferee<4>(kAuthToken), - SetArgReferee<5>(kTransportType), - SetArgReferee<6>(kHybridAppPreferenceStr), - Return(true))); + EXPECT_CALL(*mock_policy_handler_, GetAppProperties(_, _)) + .WillOnce(DoAll(SetArgReferee<1>(app_properties), Return(true))); std::vector nicknames{"CloudApp"}; EXPECT_CALL(*mock_policy_handler_, GetInitialAppData(_, _, _)) @@ -1700,14 +1717,8 @@ void ApplicationManagerImplTest::CreatePendingApplication() { EXPECT_CALL(*mock_policy_handler_, GetStatisticManager()) .WillOnce(Return(std::shared_ptr( new usage_statistics_test::MockStatisticsManager()))); - EXPECT_CALL(*mock_policy_handler_, GetCloudAppParameters(_, _, _, _, _, _, _)) - .WillOnce(DoAll(SetArgReferee<1>(kEnabled), - SetArgReferee<2>(kEndpoint2), - SetArgReferee<3>(kCertificate), - SetArgReferee<4>(kAuthToken), - SetArgReferee<5>(kTransportType), - SetArgReferee<6>(kHybridAppPreferenceStr), - Return(true))); + EXPECT_CALL(*mock_policy_handler_, GetAppProperties(_, _)) + .WillOnce(DoAll(SetArgReferee<1>(app_properties), Return(true))); // Expect Update app list EXPECT_CALL(*mock_rpc_service_, ManageHMICommand(_, _)).Times(1); app_manager_impl_->CreatePendingApplication(1, device_info, 1); @@ -1737,14 +1748,8 @@ TEST_F(ApplicationManagerImplTest, SetPendingState) { EXPECT_CALL(*mock_policy_handler_, GetEnabledCloudApps(_)) .WillOnce(SetArgReferee<0>(enabled_apps)); - EXPECT_CALL(*mock_policy_handler_, GetCloudAppParameters(_, _, _, _, _, _, _)) - .WillOnce(DoAll(SetArgReferee<1>(kEnabled), - SetArgReferee<2>(kEndpoint2), - SetArgReferee<3>(kCertificate), - SetArgReferee<4>(kAuthToken), - SetArgReferee<5>(kTransportType), - SetArgReferee<6>(kHybridAppPreferenceStr), - Return(true))); + EXPECT_CALL(*mock_policy_handler_, GetAppProperties(_, _)) + .WillOnce(DoAll(SetArgReferee<1>(app_properties), Return(true))); std::vector nicknames{"CloudApp"}; EXPECT_CALL(*mock_policy_handler_, GetInitialAppData(_, _, _)) @@ -1887,14 +1892,8 @@ TEST_F(ApplicationManagerImplTest, PolicyIDByIconUrl_Success) { std::vector enabled_apps{"1234"}; EXPECT_CALL(*mock_policy_handler_, GetEnabledCloudApps(_)) .WillOnce(SetArgReferee<0>(enabled_apps)); - EXPECT_CALL(*mock_policy_handler_, GetCloudAppParameters(_, _, _, _, _, _, _)) - .WillOnce(DoAll(SetArgReferee<1>(kEnabled), - SetArgReferee<2>(kEndpoint2), - SetArgReferee<3>(kCertificate), - SetArgReferee<4>(kAuthToken), - SetArgReferee<5>(kTransportType), - SetArgReferee<6>(kHybridAppPreferenceStr), - Return(true))); + EXPECT_CALL(*mock_policy_handler_, GetAppProperties(_, _)) + .WillOnce(DoAll(SetArgReferee<1>(app_properties), Return(true))); std::vector nicknames{"CloudApp"}; EXPECT_CALL(*mock_policy_handler_, GetInitialAppData(_, _, _)) @@ -1936,8 +1935,99 @@ TEST_F(ApplicationManagerImplTest, SetIconFileFromSystemRequest_Success) { app_manager_impl_->SetIconFileFromSystemRequest("1234"); EXPECT_TRUE(file_system::RemoveDirectory(kDirectoryName, true)); } - #endif // CLOUD_APP_WEBSOCKET_TRANSPORT_SUPPORT + +void ApplicationManagerImplTest::CreatePendingLocalApplication( + const std::string& policy_app_id) { + // CreatePendingApplication + std::vector nicknames{"PendingApplication"}; + EXPECT_CALL(*mock_policy_handler_, GetInitialAppData(policy_app_id, _, _)) + .WillOnce(DoAll(SetArgPointee<1>(nicknames), Return(true))); + EXPECT_CALL(mock_connection_handler_, GetWebEngineDeviceInfo()) + .WillOnce(ReturnRef(kDeviceInfo)); + EXPECT_CALL(*mock_policy_handler_, GetStatisticManager()) + .WillOnce(Return(std::shared_ptr( + new usage_statistics_test::MockStatisticsManager()))); + EXPECT_CALL(*mock_policy_handler_, GetAppProperties(_, _)) + .WillOnce(DoAll(SetArgReferee<1>(app_properties), Return(true))); + // Expect NO Update app list + EXPECT_CALL(*mock_rpc_service_, ManageHMICommand(_, _)).Times(0); + app_manager_impl_->CreatePendingLocalApplication(policy_app_id); + AppsWaitRegistrationSet app_list = + app_manager_impl_->AppsWaitingForRegistration().GetData(); + EXPECT_EQ(1u, app_list.size()); +} + +TEST_F(ApplicationManagerImplTest, CreatePendingApplicationByPolicyAppID) { + CreatePendingLocalApplication(kPolicyAppID); +} + +TEST_F(ApplicationManagerImplTest, RemoveExistingPendingApplication_SUCCESS) { + CreatePendingLocalApplication(kPolicyAppID); + auto app_list = app_manager_impl_->AppsWaitingForRegistration().GetData(); + ASSERT_EQ(1u, app_list.size()); + + app_manager_impl_->RemovePendingApplication(kPolicyAppID); + app_list = app_manager_impl_->AppsWaitingForRegistration().GetData(); + EXPECT_TRUE(app_list.empty()); +} + +TEST_F(ApplicationManagerImplTest, + RemovePendingApplicationFromEmptyList_NoAppRemoved_SUCCESS) { + auto app_list = app_manager_impl_->AppsWaitingForRegistration().GetData(); + ASSERT_TRUE(app_list.empty()); + + app_manager_impl_->RemovePendingApplication(kPolicyAppID); + app_list = app_manager_impl_->AppsWaitingForRegistration().GetData(); + EXPECT_TRUE(app_list.empty()); +} + +TEST_F( + ApplicationManagerImplTest, + OnWebEngineDeviceCreated_NoEnabledLocalApps_PendingApplicationNotCreatedAndNoUpdateAppList) { + std::vector enabled_apps; + EXPECT_CALL(*mock_policy_handler_, GetEnabledLocalApps()) + .WillOnce(Return(enabled_apps)); + EXPECT_CALL(*mock_rpc_service_, ManageHMICommand(_, _)).Times(0); + + app_manager_impl_->OnWebEngineDeviceCreated(); + + auto app_list = app_manager_impl_->AppsWaitingForRegistration().GetData(); + EXPECT_TRUE(app_list.empty()); +} + +TEST_F( + ApplicationManagerImplTest, + OnWebEngineDeviceCreated_PendingApplicationCreatedAndUpdateAppListSentToHMI) { + std::vector enabled_apps = {"app1"}; + std::vector nicknames{"PendingApplication"}; + + EXPECT_CALL(*mock_policy_handler_, GetEnabledLocalApps()) + .WillOnce(Return(enabled_apps)); + EXPECT_CALL(*mock_rpc_service_, ManageHMICommand(_, _)).Times(1); + EXPECT_CALL(*mock_policy_handler_, GetAppProperties(_, _)) + .WillOnce(DoAll(SetArgReferee<1>(app_properties), Return(true))); + EXPECT_CALL(*mock_policy_handler_, GetInitialAppData(_, _, _)) + .WillOnce(DoAll(SetArgPointee<1>(nicknames), Return(true))); + EXPECT_CALL(mock_connection_handler_, GetWebEngineDeviceInfo()) + .WillOnce(ReturnRef(kDeviceInfo)); + + app_manager_impl_->OnWebEngineDeviceCreated(); + + auto app_list = app_manager_impl_->AppsWaitingForRegistration().GetData(); + EXPECT_EQ(1u, app_list.size()); +} + +TEST_F(ApplicationManagerImplTest, AddAndRemoveQueryAppDevice_SUCCESS) { + const connection_handler::DeviceHandle device_handle = 1u; + ASSERT_FALSE(app_manager_impl_->IsAppsQueriedFrom(device_handle)); + + app_manager_impl_->OnQueryAppsRequest(device_handle); + EXPECT_TRUE(app_manager_impl_->IsAppsQueriedFrom(device_handle)); + app_manager_impl_->RemoveDevice(device_handle); + EXPECT_FALSE(app_manager_impl_->IsAppsQueriedFrom(device_handle)); +} + } // namespace application_manager_test } // namespace components } // namespace test diff --git a/src/components/application_manager/test/include/application_manager/commands/commands_test.h b/src/components/application_manager/test/include/application_manager/commands/commands_test.h index a047de81b9..fdaef2c716 100644 --- a/src/components/application_manager/test/include/application_manager/commands/commands_test.h +++ b/src/components/application_manager/test/include/application_manager/commands/commands_test.h @@ -245,6 +245,21 @@ MATCHER_P(HMIResultCodeIs, result_code, "") { .asInt()); } +MATCHER_P3( + HMIMessageParametersAre, correlation_id, function_id, result_code, "") { + using namespace application_manager; + + const bool corr_ids_eq = + correlation_id == + (*arg)[strings::params][strings::correlation_id].asInt(); + const bool func_ids_eq = + (*arg)[strings::params][strings::function_id].asInt() == function_id; + const bool res_codes_eq = + (*arg)[strings::params][hmi_response::code].asInt() == result_code; + + return corr_ids_eq && func_ids_eq && res_codes_eq; +} + MATCHER_P3(MobileResponseIs, result_code, result_info, result_success, "") { mobile_apis::Result::eType code = static_cast( (*arg)[am::strings::msg_params][am::strings::result_code].asInt()); diff --git a/src/components/application_manager/test/include/application_manager/mock_message_helper.h b/src/components/application_manager/test/include/application_manager/mock_message_helper.h index 072199082e..eb3c97bfff 100644 --- a/src/components/application_manager/test/include/application_manager/mock_message_helper.h +++ b/src/components/application_manager/test/include/application_manager/mock_message_helper.h @@ -269,6 +269,9 @@ class MockMessageHelper { void(ApplicationConstSharedPtr app, const bool is_unexpected_disconnect, ApplicationManager& app_mngr)); + MOCK_METHOD2(CreateOnAppPropertiesChangeNotification, + smart_objects::SmartObjectSPtr(const std::string& policy_app_id, + ApplicationManager& app_mngr)); MOCK_METHOD4(SendLaunchApp, void(const uint32_t connection_key, const std::string& urlSchema, diff --git a/src/components/application_manager/test/mock_message_helper.cc b/src/components/application_manager/test/mock_message_helper.cc old mode 100755 new mode 100644 index 628fd97ae8..959bbf5bd0 --- a/src/components/application_manager/test/mock_message_helper.cc +++ b/src/components/application_manager/test/mock_message_helper.cc @@ -485,6 +485,13 @@ bool MessageHelper::CreateHMIApplicationStruct( app, session_observer, policy_handler, output, app_mngr); } +smart_objects::SmartObjectSPtr +MessageHelper::CreateOnAppPropertiesChangeNotification( + const std::string& policy_app_id, ApplicationManager& app_mngr) { + return MockMessageHelper::message_helper_mock() + ->CreateOnAppPropertiesChangeNotification(policy_app_id, app_mngr); +} + void MessageHelper::SendOnAppUnregNotificationToHMI( ApplicationConstSharedPtr app, const bool is_unexpected_disconnect, diff --git a/src/components/application_manager/test/policy_handler_test.cc b/src/components/application_manager/test/policy_handler_test.cc index 961f338ca4..3f37cec657 100644 --- a/src/components/application_manager/test/policy_handler_test.cc +++ b/src/components/application_manager/test/policy_handler_test.cc @@ -72,6 +72,8 @@ #include "policy/usage_statistics/mock_statistics_manager.h" #include "protocol_handler/mock_session_observer.h" +#include "smart_objects/enum_schema_item.h" + namespace test { namespace components { namespace policy_handler_test { @@ -272,6 +274,19 @@ class PolicyHandlerTest : public ::testing::Test { hmi_types.push_back(hmi_type); return hmi_types; } + + void SetExpectationsAndCheckCloudAppPropertiesStatus( + const policy::AppProperties& app_properties, + const smart_objects::SmartObject& properties, + const policy::PolicyHandlerInterface::AppPropertiesState& + app_properties_state) { + EXPECT_CALL(*mock_policy_manager_, GetAppProperties(kPolicyAppId_, _)) + .WillOnce(DoAll(SetArgReferee<1>(app_properties), Return(true))); + EXPECT_CALL(*mock_policy_manager_, GetInitialAppData(kPolicyAppId_, _, _)); + EXPECT_EQ( + app_properties_state, + policy_handler_.GetAppPropertiesStatus(properties, kPolicyAppId_)); + } }; namespace { @@ -2687,6 +2702,12 @@ TEST_F(PolicyHandlerTest, OnSetCloudAppProperties_AllProperties_SUCCESS) { mobile_apis::HybridAppPreference::CLOUD; std::string hybrid_app_preference_str = "CLOUD"; std::string endpoint = "anEndpoint"; + const policy::AppProperties app_properties(endpoint, + " ", + enabled, + auth_token, + cloud_transport_type, + hybrid_app_preference_str); StringArray nicknames_vec; nicknames_vec.push_back(app_name); @@ -2720,9 +2741,8 @@ TEST_F(PolicyHandlerTest, OnSetCloudAppProperties_AllProperties_SUCCESS) { EXPECT_CALL(*mock_policy_manager_, SetHybridAppPreference(kPolicyAppId_, hybrid_app_preference_str)); EXPECT_CALL(*mock_policy_manager_, SetAppEndpoint(kPolicyAppId_, endpoint)); - EXPECT_CALL(*mock_policy_manager_, - GetCloudAppParameters(kPolicyAppId_, _, _, _, _, _, _)) - .WillOnce(DoAll(SetArgReferee<4>(auth_token), Return(true))); + EXPECT_CALL(*mock_policy_manager_, GetAppProperties(kPolicyAppId_, _)) + .WillOnce(DoAll(SetArgReferee<1>(app_properties), Return(true))); EXPECT_CALL(app_manager_, RefreshCloudAppInformation()); EXPECT_CALL(policy_handler_observer, OnAuthTokenUpdated(kPolicyAppId_, auth_token)); @@ -2740,38 +2760,370 @@ TEST_F(PolicyHandlerTest, GetCloudAppParameters_AllProperties_SUCCESS) { std::string hybrid_app_preference_str = "CLOUD"; std::string endpoint = "anEndpoint"; + const policy::AppProperties app_properties(endpoint, + certificate, + enabled, + auth_token, + cloud_transport_type, + hybrid_app_preference_str); + application_manager_test::MockPolicyHandlerObserver policy_handler_observer; policy_handler_.add_listener(&policy_handler_observer); - EXPECT_CALL(*mock_policy_manager_, - GetCloudAppParameters(kPolicyAppId_, _, _, _, _, _, _)) - .WillOnce(DoAll(SetArgReferee<1>(enabled), - SetArgReferee<2>(endpoint), - SetArgReferee<3>(certificate), - SetArgReferee<4>(auth_token), - SetArgReferee<5>(cloud_transport_type), - SetArgReferee<6>(hybrid_app_preference_str), - Return(true))); - - bool enabled_out; - std::string endpoint_out; - std::string cert_out; - std::string auth_token_out; - std::string ctt_out; - std::string hap_out; - EXPECT_TRUE(policy_handler_.GetCloudAppParameters(kPolicyAppId_, - enabled_out, - endpoint_out, - cert_out, - auth_token_out, - ctt_out, - hap_out)); - EXPECT_EQ(enabled, enabled_out); - EXPECT_EQ(endpoint, endpoint_out); - EXPECT_EQ(certificate, cert_out); - EXPECT_EQ(auth_token, auth_token_out); - EXPECT_EQ(cloud_transport_type, ctt_out); - EXPECT_EQ(hybrid_app_preference_str, hap_out); + EXPECT_CALL(*mock_policy_manager_, GetAppProperties(kPolicyAppId_, _)) + .WillOnce(DoAll(SetArgReferee<1>(app_properties), Return(true))); + + policy::AppProperties out_app_properties; + EXPECT_TRUE( + policy_handler_.GetAppProperties(kPolicyAppId_, out_app_properties)); + EXPECT_EQ(app_properties.enabled, out_app_properties.enabled); + EXPECT_EQ(app_properties.endpoint, out_app_properties.endpoint); + EXPECT_EQ(app_properties.certificate, out_app_properties.certificate); + EXPECT_EQ(app_properties.auth_token, out_app_properties.auth_token); + EXPECT_EQ(app_properties.transport_type, out_app_properties.transport_type); + EXPECT_EQ(app_properties.hybrid_app_preference, + out_app_properties.hybrid_app_preference); +} + +TEST_F(PolicyHandlerTest, SendOnAppPropertiesChangeNotification_SUCCESS) { + using namespace smart_objects; + auto notification = std::make_shared(SmartType_Null); + + ON_CALL(app_manager_, GetRPCService()) + .WillByDefault(ReturnRef(mock_rpc_service_)); + + EXPECT_CALL(mock_message_helper_, + CreateOnAppPropertiesChangeNotification(kPolicyAppId_, _)) + .WillOnce(Return(notification)); + EXPECT_CALL(mock_rpc_service_, + ManageHMICommand(notification, commands::Command::SOURCE_HMI)); + + policy_handler_.SendOnAppPropertiesChangeNotification(kPolicyAppId_); +} + +TEST_F(PolicyHandlerTest, GetApplicationPolicyIDs_GetEmptyIDsVector_SUCCESS) { + ChangePolicyManagerToMock(); + + std::vector app_ids_vector; + ON_CALL(*mock_policy_manager_, GetApplicationPolicyIDs()) + .WillByDefault(Return(app_ids_vector)); + + EXPECT_CALL(*mock_policy_manager_, GetApplicationPolicyIDs()); + EXPECT_EQ(app_ids_vector, policy_handler_.GetApplicationPolicyIDs()); +} + +TEST_F(PolicyHandlerTest, + GetApplicationPolicyIDs_GetIDFromAppIDsVectorWithWrongIDs_SUCCESS) { + ChangePolicyManagerToMock(); + + std::vector app_ids_vector = {policy::kDefaultId, + policy::kPreDataConsentId, + policy::kDeviceId, + kPolicyAppId_}; + ON_CALL(*mock_policy_manager_, GetApplicationPolicyIDs()) + .WillByDefault(Return(app_ids_vector)); + + EXPECT_CALL(*mock_policy_manager_, GetApplicationPolicyIDs()); + + auto policy_ids = policy_handler_.GetApplicationPolicyIDs(); + EXPECT_NE(app_ids_vector, policy_ids); + EXPECT_EQ(1u, policy_ids.size()); + EXPECT_EQ(kPolicyAppId_, policy_ids[0]); +} + +TEST_F(PolicyHandlerTest, CheckCloudAppEnabled_SUCCESS) { + ChangePolicyManagerToMock(); + + policy::AppProperties out_app_properties; + out_app_properties.enabled = true; + + EXPECT_CALL(*mock_policy_manager_, GetAppProperties(kPolicyAppId_, _)) + .WillOnce(DoAll(SetArgReferee<1>(out_app_properties), Return(true))); + EXPECT_TRUE(policy_handler_.CheckCloudAppEnabled(kPolicyAppId_)); +} + +TEST_F(PolicyHandlerTest, CheckCloudAppNotEnabled_SUCCESS) { + ChangePolicyManagerToMock(); + EXPECT_CALL(*mock_policy_manager_, GetAppProperties(kPolicyAppId_, _)); + EXPECT_FALSE(policy_handler_.CheckCloudAppEnabled(kPolicyAppId_)); +} + +TEST_F(PolicyHandlerTest, OnLocalAppAdded_SUCCESS) { + ChangePolicyManagerToMock(); + EXPECT_CALL(*mock_policy_manager_, OnLocalAppAdded()); + policy_handler_.OnLocalAppAdded(); +} + +TEST_F(PolicyHandlerTest, GetAppPropertiesStatus_NoPropertiesChanged) { + ChangePolicyManagerToMock(); + + smart_objects::SmartObject properties; + properties[strings::app_id] = kPolicyAppId_; + + EXPECT_CALL(*mock_policy_manager_, GetAppProperties(kPolicyAppId_, _)) + .WillOnce(Return(false)); + EXPECT_CALL(*mock_policy_manager_, GetInitialAppData(kPolicyAppId_, _, _)) + .WillOnce(Return(false)); + EXPECT_EQ(policy::PolicyHandlerInterface::AppPropertiesState::NO_CHANGES, + policy_handler_.GetAppPropertiesStatus(properties, kPolicyAppId_)); +} + +TEST_F(PolicyHandlerTest, + GetAppPropertiesStatus_EnableFlagSwitchChanged_SUCCESS) { + ChangePolicyManagerToMock(); + + policy::AppProperties app_properties; + app_properties.enabled = false; + + smart_objects::SmartObject properties; + properties[strings::app_id] = kPolicyAppId_; + properties[strings::enabled] = !app_properties.enabled; + + SetExpectationsAndCheckCloudAppPropertiesStatus( + app_properties, + properties, + policy::PolicyHandlerInterface::AppPropertiesState::ENABLED_FLAG_SWITCH); +} + +TEST_F(PolicyHandlerTest, + GetAppPropertiesStatus_EnableFlagSwitchNotChanged_SUCCESS) { + ChangePolicyManagerToMock(); + + policy::AppProperties app_properties; + app_properties.enabled = false; + + smart_objects::SmartObject properties; + properties[strings::app_id] = kPolicyAppId_; + properties[strings::enabled] = app_properties.enabled; + + SetExpectationsAndCheckCloudAppPropertiesStatus( + app_properties, + properties, + policy::PolicyHandlerInterface::AppPropertiesState::NO_CHANGES); +} + +TEST_F(PolicyHandlerTest, GetAppPropertiesStatus_AuthTokenChanged_SUCCESS) { + ChangePolicyManagerToMock(); + + const std::string kCurrentToken = "kCurrentToken"; + const std::string kNewToken = "kNewToken"; + + policy::AppProperties app_properties; + app_properties.auth_token = kCurrentToken; + + smart_objects::SmartObject properties; + properties[strings::app_id] = kPolicyAppId_; + properties[strings::auth_token] = kNewToken; + + SetExpectationsAndCheckCloudAppPropertiesStatus( + app_properties, + properties, + policy::PolicyHandlerInterface::AppPropertiesState::AUTH_TOKEN_CHANGED); +} + +TEST_F(PolicyHandlerTest, GetAppPropertiesStatus_AuthTokenNotChanged_SUCCESS) { + ChangePolicyManagerToMock(); + + const std::string kCurrentToken = "kCurrentToken"; + + policy::AppProperties app_properties; + app_properties.auth_token = kCurrentToken; + + smart_objects::SmartObject properties; + properties[strings::app_id] = kPolicyAppId_; + properties[strings::auth_token] = app_properties.auth_token; + + SetExpectationsAndCheckCloudAppPropertiesStatus( + app_properties, + properties, + policy::PolicyHandlerInterface::AppPropertiesState::NO_CHANGES); +} + +TEST_F(PolicyHandlerTest, GetAppPropertiesStatus_TransportTypeChanged_SUCCESS) { + ChangePolicyManagerToMock(); + + const std::string kCurrentTransportType = "kCurrentTransportType"; + const std::string kNewTransportType = "kNewTransportType"; + + policy::AppProperties app_properties; + app_properties.transport_type = kCurrentTransportType; + + smart_objects::SmartObject properties; + properties[strings::app_id] = kPolicyAppId_; + properties[strings::cloud_transport_type] = kNewTransportType; + + SetExpectationsAndCheckCloudAppPropertiesStatus( + app_properties, + properties, + policy::PolicyHandlerInterface::AppPropertiesState:: + TRANSPORT_TYPE_CHANGED); +} + +TEST_F(PolicyHandlerTest, + GetAppPropertiesStatus_TransportTypeNotChanged_SUCCESS) { + ChangePolicyManagerToMock(); + + const std::string kCurrentTransportType = "kCurrentTransportType"; + + policy::AppProperties app_properties; + app_properties.transport_type = kCurrentTransportType; + + smart_objects::SmartObject properties; + properties[strings::app_id] = kPolicyAppId_; + properties[strings::cloud_transport_type] = app_properties.transport_type; + SetExpectationsAndCheckCloudAppPropertiesStatus( + app_properties, + properties, + policy::PolicyHandlerInterface::AppPropertiesState::NO_CHANGES); +} + +TEST_F(PolicyHandlerTest, GetAppPropertiesStatus_EndPointChanged_SUCCESS) { + ChangePolicyManagerToMock(); + + const std::string kCurrentEndPoint = "kCurrentEndPoint"; + const std::string kNewEndPoint = "kNewEndPoint"; + + policy::AppProperties app_properties; + app_properties.endpoint = kCurrentEndPoint; + + smart_objects::SmartObject properties; + properties[strings::app_id] = kPolicyAppId_; + properties[strings::endpoint] = kNewEndPoint; + + SetExpectationsAndCheckCloudAppPropertiesStatus( + app_properties, + properties, + policy::PolicyHandlerInterface::AppPropertiesState::ENDPOINT_CHANGED); +} + +TEST_F(PolicyHandlerTest, GetAppPropertiesStatus_EndPointNotChanged_SUCCESS) { + ChangePolicyManagerToMock(); + + const std::string kCurrentEndPoint = "kCurrentEndPoint"; + + policy::AppProperties app_properties; + app_properties.endpoint = kCurrentEndPoint; + + smart_objects::SmartObject properties; + properties[strings::app_id] = kPolicyAppId_; + properties[strings::endpoint] = app_properties.endpoint; + + SetExpectationsAndCheckCloudAppPropertiesStatus( + app_properties, + properties, + policy::PolicyHandlerInterface::AppPropertiesState::NO_CHANGES); +} + +TEST_F(PolicyHandlerTest, GetAppPropertiesStatus_NicknameChanged_SUCCESS) { + ChangePolicyManagerToMock(); + + const std::string kFakeNickname = "fake_nickname"; + + smart_objects::SmartObject properties; + properties[strings::app_id] = kPolicyAppId_; + properties[strings::nicknames] = + smart_objects::SmartObject(smart_objects::SmartType_Array); + properties[strings::nicknames].asArray()->push_back( + smart_objects::SmartObject(kFakeNickname)); + + std::shared_ptr nicknames = + std::make_shared(); + + const auto expected_app_properties_state = + policy::PolicyHandlerInterface::AppPropertiesState::NICKNAMES_CHANGED; + + EXPECT_CALL(*mock_policy_manager_, GetAppProperties(kPolicyAppId_, _)) + .WillOnce(Return(true)); + EXPECT_CALL(*mock_policy_manager_, GetInitialAppData(kPolicyAppId_, _, _)) + .WillOnce(DoAll(SetArgPointee<1>(*nicknames), Return(true))); + EXPECT_EQ(expected_app_properties_state, + policy_handler_.GetAppPropertiesStatus(properties, kPolicyAppId_)); +} + +TEST_F(PolicyHandlerTest, GetAppPropertiesStatus_NicknameNotChanged_SUCCESS) { + ChangePolicyManagerToMock(); + + const std::string kFakeNickname = "fake_nickname"; + + smart_objects::SmartObject properties; + properties[strings::app_id] = kPolicyAppId_; + properties[strings::nicknames] = + smart_objects::SmartObject(smart_objects::SmartType_Array); + properties[strings::nicknames].asArray()->push_back( + smart_objects::SmartObject(kFakeNickname)); + + std::shared_ptr nicknames = + std::make_shared(); + nicknames->push_back(kFakeNickname); + + const auto expected_app_properties_state = + policy::PolicyHandlerInterface::AppPropertiesState::NO_CHANGES; + + EXPECT_CALL(*mock_policy_manager_, GetAppProperties(kPolicyAppId_, _)) + .WillOnce(Return(true)); + EXPECT_CALL(*mock_policy_manager_, GetInitialAppData(kPolicyAppId_, _, _)) + .WillOnce(DoAll(SetArgPointee<1>(*nicknames), Return(true))); + EXPECT_EQ(expected_app_properties_state, + policy_handler_.GetAppPropertiesStatus(properties, kPolicyAppId_)); +} + +TEST_F(PolicyHandlerTest, GetAppPropertiesStatus_HybridAppChanged_SUCCESS) { + ChangePolicyManagerToMock(); + + const auto kCurrentHybridAppProperties = + mobile_apis::HybridAppPreference::eType::CLOUD; + const auto kNewHybridAppProperties = + mobile_apis::HybridAppPreference::eType::MOBILE; + + policy::AppProperties app_properties; + smart_objects::EnumConversionHelper:: + EnumToString(kCurrentHybridAppProperties, + &app_properties.hybrid_app_preference); + + smart_objects::SmartObject properties; + properties[strings::app_id] = kPolicyAppId_; + properties[strings::hybrid_app_preference] = kNewHybridAppProperties; + + SetExpectationsAndCheckCloudAppPropertiesStatus( + app_properties, + properties, + policy::PolicyHandlerInterface::AppPropertiesState:: + HYBRYD_APP_PROPERTIES_CHANGED); +} + +TEST_F(PolicyHandlerTest, GetAppPropertiesStatus_HybridAppNotChanged_SUCCESS) { + ChangePolicyManagerToMock(); + + const auto kCurrentHybridAppProperties = + mobile_apis::HybridAppPreference::eType::CLOUD; + + policy::AppProperties app_properties; + smart_objects::EnumConversionHelper:: + EnumToString(kCurrentHybridAppProperties, + &app_properties.hybrid_app_preference); + + smart_objects::SmartObject properties; + properties[strings::app_id] = kPolicyAppId_; + properties[strings::hybrid_app_preference] = kCurrentHybridAppProperties; + + SetExpectationsAndCheckCloudAppPropertiesStatus( + app_properties, + properties, + policy::PolicyHandlerInterface::AppPropertiesState::NO_CHANGES); +} + +TEST_F(PolicyHandlerTest, GetEnabledLocalApps_SUCCESS) { + ChangePolicyManagerToMock(); + std::vector enabled_local_apps; + + EXPECT_CALL(*mock_policy_manager_, GetEnabledLocalApps()) + .WillOnce(Return(enabled_local_apps)); + EXPECT_EQ(enabled_local_apps, policy_handler_.GetEnabledLocalApps()); + + enabled_local_apps.push_back("local_app"); + EXPECT_CALL(*mock_policy_manager_, GetEnabledLocalApps()) + .WillOnce(Return(enabled_local_apps)); + EXPECT_EQ(enabled_local_apps, policy_handler_.GetEnabledLocalApps()); } } // namespace policy_handler_test diff --git a/src/components/config_profile/include/config_profile/profile.h b/src/components/config_profile/include/config_profile/profile.h index 5489a962e8..76c66c7c7b 100644 --- a/src/components/config_profile/include/config_profile/profile.h +++ b/src/components/config_profile/include/config_profile/profile.h @@ -413,6 +413,40 @@ class Profile : public protocol_handler::ProtocolHandlerSettings, const std::string& transport_manager_tcp_adapter_network_interface() const OVERRIDE; +#ifdef WEBSOCKET_SERVER_TRANSPORT_SUPPORT + /** + * @brief Returns websocket server address + */ + const std::string& websocket_server_address() const OVERRIDE; + + /** + * @brief Returns port for websocket server + */ + uint16_t websocket_server_port() const OVERRIDE; +#ifdef ENABLE_SECURITY + /** + * @brief Returns ws server certificate path to pem file + */ + const std::string& ws_server_cert_path() const OVERRIDE; + + /** + * @brief Returns ws server CA certificate path to pem file + */ + const std::string& ws_server_ca_cert_path() const OVERRIDE; + + /** + * @brief Returns ws server key path to pem file + */ + const std::string& ws_server_key_path() const OVERRIDE; + + /** + * @brief Returns bool flag indicating whether WSS settings were setup + * correctly + */ + const bool wss_server_supported() const OVERRIDE; +#endif // ENABLE_SECURITY +#endif // WEBSOCKET_SERVER_TRANSPORT_SUPPORT + /** * @brief Returns retry timeout for cloud app connections */ @@ -991,6 +1025,16 @@ class Profile : public protocol_handler::ProtocolHandlerSettings, std::string system_files_path_; uint16_t transport_manager_tcp_adapter_port_; std::string transport_manager_tcp_adapter_network_interface_; +#ifdef WEBSOCKET_SERVER_TRANSPORT_SUPPORT + std::string websocket_server_address_; + uint16_t websocket_server_port_; +#ifdef ENABLE_SECURITY + std::string ws_server_cert_path_; + std::string ws_server_ca_cert_path_; + std::string ws_server_key_path_; + bool is_wss_settings_setup_; +#endif // ENABLE_SECURITY +#endif // WEBSOCKET_SERVER_TRANSPORT_SUPPORT uint32_t cloud_app_retry_timeout_; uint16_t cloud_app_max_retry_attempts_; std::vector bluetooth_uuid_; diff --git a/src/components/config_profile/src/profile.cc b/src/components/config_profile/src/profile.cc index dd0dc50f44..3037b66fdd 100644 --- a/src/components/config_profile/src/profile.cc +++ b/src/components/config_profile/src/profile.cc @@ -157,6 +157,15 @@ const char* kMaxSupportedProtocolVersionKey = "MaxSupportedProtocolVersion"; const char* kUseLastStateKey = "UseLastState"; const char* kTCPAdapterPortKey = "TCPAdapterPort"; const char* kTCPAdapterNetworkInterfaceKey = "TCPAdapterNetworkInterface"; +#ifdef WEBSOCKET_SERVER_TRANSPORT_SUPPORT +const char* kWebSocketServerAddressKey = "WebSocketServerAddress"; +const char* kWebSocketServerPortKey = "WebSocketServerPort"; +#ifdef ENABLE_SECURITY +const char* kWSServerCertificatePathKey = "WSServerCertificatePath"; +const char* kWSServerCACertificaePathKey = "WSServerCACertificatePath"; +const char* kWSServerKeyPathKey = "WSServerKeyPath"; +#endif // ENABLE_SECURITY +#endif // WEBSOCKET_SERVER_TRANSPORT_SUPPORT const char* kCloudAppRetryTimeoutKey = "CloudAppRetryTimeout"; const char* kCloudAppMaxRetryAttemptsKey = "CloudAppMaxRetryAttempts"; const char* kServerPortKey = "ServerPort"; @@ -305,6 +314,7 @@ const char* kDefaultPoliciesSnapshotFileName = "sdl_snapshot.json"; const char* kDefaultHmiCapabilitiesFileName = "hmi_capabilities.json"; const char* kDefaultPreloadedPTFileName = "sdl_preloaded_pt.json"; const char* kDefaultServerAddress = "127.0.0.1"; +const char* kDefaultWebsocketServerAddress = "0.0.0.0"; const char* kDefaultAppInfoFileName = "app_info.dat"; const char* kDefaultSystemFilesPath = "/tmp/fs/mp/images/ivsu_cache"; const char* kDefaultPluginsPath = "plugins"; @@ -334,6 +344,7 @@ const uint32_t kDefaultHubProtocolIndex = 0; const uint32_t kDefaultHeartBeatTimeout = 0; const uint16_t kDefaultMaxSupportedProtocolVersion = 5; const uint16_t kDefautTransportManagerTCPPort = 12345; +const uint16_t kDefaultWebSocketServerPort = 2020; const uint16_t kDefaultCloudAppRetryTimeout = 1000; const uint16_t kDefaultCloudAppMaxRetryAttempts = 5; const uint16_t kDefaultServerPort = 8087; @@ -495,6 +506,10 @@ Profile::Profile() , supported_diag_modes_() , system_files_path_(kDefaultSystemFilesPath) , transport_manager_tcp_adapter_port_(kDefautTransportManagerTCPPort) +#ifdef WEBSOCKET_SERVER_TRANSPORT_SUPPORT + , websocket_server_address_(kDefaultWebsocketServerAddress) + , websocket_server_port_(kDefaultWebSocketServerPort) +#endif , cloud_app_retry_timeout_(kDefaultCloudAppRetryTimeout) , cloud_app_max_retry_attempts_(kDefaultCloudAppMaxRetryAttempts) , tts_delimiter_(kDefaultTtsDelimiter) @@ -831,6 +846,33 @@ const std::string& Profile::transport_manager_tcp_adapter_network_interface() return transport_manager_tcp_adapter_network_interface_; } +#ifdef WEBSOCKET_SERVER_TRANSPORT_SUPPORT +const std::string& Profile::websocket_server_address() const { + return websocket_server_address_; +} + +uint16_t Profile::websocket_server_port() const { + return websocket_server_port_; +} +#ifdef ENABLE_SECURITY +const std::string& Profile::ws_server_cert_path() const { + return ws_server_cert_path_; +} + +const std::string& Profile::ws_server_key_path() const { + return ws_server_key_path_; +} + +const std::string& Profile::ws_server_ca_cert_path() const { + return ws_server_ca_cert_path_; +} + +const bool Profile::wss_server_supported() const { + return is_wss_settings_setup_; +} +#endif // ENABLE_SECURITY +#endif // WEBSOCKET_SERVER_TRANSPORT_SUPPORT + uint32_t Profile::cloud_app_retry_timeout() const { return cloud_app_retry_timeout_; } @@ -1240,6 +1282,7 @@ void Profile::UpdateValues() { ReadStringValue( &cert_path_, "", kSecuritySection, kSecurityCertificatePathKey); + ReadStringValue( &ca_cert_path_, "", kSecuritySection, kSecurityCACertificatePathKey); @@ -1867,6 +1910,58 @@ void Profile::UpdateValues() { LOG_UPDATED_VALUE(transport_manager_tcp_adapter_network_interface_, kTCPAdapterNetworkInterfaceKey, kTransportManagerSection); +#ifdef WEBSOCKET_SERVER_TRANSPORT_SUPPORT + // Websocket server address + ReadStringValue(&websocket_server_address_, + kDefaultWebsocketServerAddress, + kTransportManagerSection, + kWebSocketServerAddressKey); + + LOG_UPDATED_VALUE(websocket_server_address_, + kWebSocketServerAddressKey, + kTransportManagerSection); + + // Websocket non-secured server port + ReadUIntValue(&websocket_server_port_, + kDefaultWebSocketServerPort, + kTransportManagerSection, + kWebSocketServerPortKey); + + LOG_UPDATED_VALUE(websocket_server_port_, + kWebSocketServerPortKey, + kTransportManagerSection); + +#ifdef ENABLE_SECURITY + const bool is_ws_server_cert_setup = + ReadStringValue(&ws_server_cert_path_, + "", + kTransportManagerSection, + kWSServerCertificatePathKey); + + LOG_UPDATED_VALUE(ws_server_cert_path_, + kWSServerCertificatePathKey, + kTransportManagerSection); + + const bool is_ws_server_key_setup = ReadStringValue( + &ws_server_key_path_, "", kTransportManagerSection, kWSServerKeyPathKey); + + LOG_UPDATED_VALUE( + ws_server_key_path_, kWSServerKeyPathKey, kTransportManagerSection); + + const bool is_ws_ca_cert_setup = + ReadStringValue(&ws_server_ca_cert_path_, + "", + kTransportManagerSection, + kWSServerCACertificaePathKey); + + LOG_UPDATED_VALUE(ws_server_ca_cert_path_, + kWSServerCACertificaePathKey, + kTransportManagerSection); + + is_wss_settings_setup_ = + is_ws_server_cert_setup && is_ws_server_key_setup && is_ws_ca_cert_setup; +#endif // ENABLE_SECURITY +#endif // WEBSOCKET_SERVER_TRANSPORT_SUPPORT ReadUIntValue(&cloud_app_retry_timeout_, kDefaultCloudAppRetryTimeout, diff --git a/src/components/connection_handler/include/connection_handler/connection_handler_impl.h b/src/components/connection_handler/include/connection_handler/connection_handler_impl.h index b7b791a5c1..b2b4c5a970 100644 --- a/src/components/connection_handler/include/connection_handler/connection_handler_impl.h +++ b/src/components/connection_handler/include/connection_handler/connection_handler_impl.h @@ -606,6 +606,10 @@ class ConnectionHandlerImpl const transport_manager::ConnectionUID secondary_connection_handle) OVERRIDE; + const transport_manager::DeviceInfo& GetWebEngineDeviceInfo() const OVERRIDE; + + void CreateWebEngineDevice() OVERRIDE; + private: /** * \brief Disconnect application. @@ -646,7 +650,7 @@ class ConnectionHandlerImpl * \brief List of devices */ DeviceMap device_list_; - + mutable sync_primitives::RWLock device_list_lock_; /** * @brief session/connection map */ diff --git a/src/components/connection_handler/src/connection_handler_impl.cc b/src/components/connection_handler/src/connection_handler_impl.cc index 4a51d00558..c8b4268bf0 100644 --- a/src/components/connection_handler/src/connection_handler_impl.cc +++ b/src/components/connection_handler/src/connection_handler_impl.cc @@ -120,6 +120,7 @@ void ConnectionHandlerImpl::OnDeviceListUpdated( const std::vector&) { LOG4CXX_AUTO_TRACE(logger_); sync_primitives::AutoReadLock read_lock(connection_handler_observer_lock_); + sync_primitives::AutoReadLock lock(device_list_lock_); if (connection_handler_observer_) { connection_handler_observer_->OnDeviceListUpdated(device_list_); } @@ -152,14 +153,21 @@ void ConnectionHandlerImpl::OnDeviceAdded( device_info.mac_address(), device_info.connection_type()); - auto result = device_list_.insert(std::make_pair(handle, device)); + { + sync_primitives::AutoWriteLock write_lock(device_list_lock_); + auto result = device_list_.insert(std::make_pair(handle, device)); - if (!result.second) { - LOG4CXX_ERROR(logger_, - "Device with handle " << handle - << " is known already. " - "Information won't be updated."); - return; + if (!result.second) { + LOG4CXX_ERROR(logger_, + "Device with handle " << handle + << " is known already. " + "Information won't be updated."); + return; + } + } + if (device_info.name() == + transport_manager::webengine_constants::kWebEngineDeviceName) { + connection_handler_observer_->OnWebEngineDeviceCreated(); } } @@ -189,7 +197,10 @@ void ConnectionHandlerImpl::OnDeviceRemoved( } sync_primitives::AutoReadLock read_lock(connection_handler_observer_lock_); - device_list_.erase(device_info.device_handle()); + { + sync_primitives::AutoWriteLock lock(device_list_lock_); + device_list_.erase(device_info.device_handle()); + } if (connection_handler_observer_) { connection_handler_observer_->RemoveDevice(device_info.device_handle()); } @@ -219,6 +230,8 @@ struct DeviceFinder { void ConnectionHandlerImpl::OnDeviceSwitchingStart( const std::string& device_uid_from, const std::string& device_uid_to) { + sync_primitives::AutoReadLock lock(device_list_lock_); + auto device_from = std::find_if(device_list_.begin(), device_list_.end(), @@ -260,10 +273,14 @@ void ConnectionHandlerImpl::OnConnectionPending( << device_info.name() << " " << device_info.mac_address() << " " << device_info.connection_type()); - DeviceMap::iterator it = device_list_.find(device_info.device_handle()); - if (device_list_.end() == it) { - LOG4CXX_ERROR(logger_, "Unknown device!"); - return; + { + sync_primitives::AutoReadLock lock(device_list_lock_); + auto it = device_list_.find(device_info.device_handle()); + + if (device_list_.end() == it) { + LOG4CXX_ERROR(logger_, "Unknown device!"); + return; + } } LOG4CXX_DEBUG(logger_, "Add Pending Connection #" << connection_id << " to the list."); @@ -310,11 +327,15 @@ void ConnectionHandlerImpl::OnConnectionEstablished( << device_info.device_handle() << " " << device_info.name() << " " << device_info.mac_address() << " " << device_info.connection_type()); - DeviceMap::iterator it = device_list_.find(device_info.device_handle()); - if (device_list_.end() == it) { - LOG4CXX_ERROR(logger_, "Unknown device!"); - return; + { + sync_primitives::AutoReadLock lock(device_list_lock_); + auto it = device_list_.find(device_info.device_handle()); + if (device_list_.end() == it) { + LOG4CXX_ERROR(logger_, "Unknown device!"); + return; + } } + LOG4CXX_DEBUG(logger_, "Add Connection #" << connection_id << " to the list."); sync_primitives::AutoWriteLock lock(connection_list_lock_); @@ -413,8 +434,9 @@ void ConnectionHandlerImpl::OnSessionStartedCallback( // In case this is a Session running on a Secondary Transport, we need to // find the Sessions's primary transport. In this case, "connection_handle" - // reflects the secondary transport, which we need for the various callbacks, - // so they can send appropriate Ack or NAK messages on the correct transport. + // reflects the secondary transport, which we need for the various + // callbacks, so they can send appropriate Ack or NAK messages on the + // correct transport. transport_manager::ConnectionUID primary_connection_handle = connection_handle; SessionTransports st = GetSessionTransports(session_id); @@ -533,7 +555,8 @@ void ConnectionHandlerImpl::NotifyServiceStartedResult( start_service_context_map_.erase(it); } - // We need the context's primary connection so we can manage its services list + // We need the context's primary connection so we can manage its services + // list Connection* connection = NULL; { sync_primitives::AutoReadLock lock(connection_list_lock_); @@ -646,8 +669,9 @@ uint32_t ConnectionHandlerImpl::OnSessionEndedCallback( // In case this is a Session running on a Secondary Transport, we need to // find the Sessions's primary transport. In this case, "connection_handle" - // reflects the secondary transport, which we need for the various callbacks, - // so they can send appropriate Ack or NAK messages on the correct transport. + // reflects the secondary transport, which we need for the various + // callbacks, so they can send appropriate Ack or NAK messages on the + // correct transport. transport_manager::ConnectionUID primary_connection_handle = connection_handle; if (session_id != 0) { @@ -841,6 +865,15 @@ void ConnectionHandlerImpl::OnSecondaryTransportEnded( } } +const transport_manager::DeviceInfo& +ConnectionHandlerImpl::GetWebEngineDeviceInfo() const { + return transport_manager_.GetWebEngineDeviceInfo(); +} + +void ConnectionHandlerImpl::CreateWebEngineDevice() { + transport_manager_.CreateWebEngineDevice(); +} + const std::string ConnectionHandlerImpl::TransportTypeProfileStringFromConnHandle( transport_manager::ConnectionUID connection_handle) const { @@ -861,11 +894,14 @@ const std::string ConnectionHandlerImpl::TransportTypeProfileStringFromDeviceHandle( DeviceHandle device_handle) const { std::string connection_type; - DeviceMap::const_iterator it = device_list_.find(device_handle); - if (device_list_.end() == it) { - LOG4CXX_ERROR(logger_, "Device not found!"); - } else { - connection_type = it->second.connection_type(); + { + sync_primitives::AutoReadLock lock(device_list_lock_); + auto it = device_list_.find(device_handle); + if (device_list_.end() == it) { + LOG4CXX_ERROR(logger_, "Device not found!"); + } else { + connection_type = it->second.connection_type(); + } } // Caution: this should be in sync with devicesType map in @@ -1067,9 +1103,10 @@ SessionTransports ConnectionHandlerImpl::SetSecondaryTransportID( st = it->second; // The only time we overwrite an existing entry in the map is if the new - // secondary transport ID is kDisabledSecondary, which effectively DISABLES - // the secondary transport feature for the session, or if the new secondary - // transport ID is 0, which means a secondary transport has shut down + // secondary transport ID is kDisabledSecondary, which effectively + // DISABLES the secondary transport feature for the session, or if the new + // secondary transport ID is 0, which means a secondary transport has shut + // down if (st.secondary_transport != 0 && secondary_transport_id != kDisabledSecondary && secondary_transport_id != 0) { @@ -1167,6 +1204,7 @@ struct CompareMAC { bool ConnectionHandlerImpl::GetDeviceID(const std::string& mac_address, DeviceHandle* device_handle) { DCHECK_OR_RETURN(device_handle, false); + sync_primitives::AutoReadLock lock(device_list_lock_); DeviceMap::const_iterator it = std::find_if( device_list_.begin(), device_list_.end(), CompareMAC(mac_address)); if (it != device_list_.end()) { @@ -1185,7 +1223,10 @@ int32_t ConnectionHandlerImpl::GetDataOnDeviceID( LOG4CXX_AUTO_TRACE(logger_); int32_t result = -1; - DeviceMap::const_iterator it = device_list_.find(device_handle); + + sync_primitives::AutoReadLock lock(device_list_lock_); + auto it = device_list_.find(device_handle); + if (device_list_.end() == it) { LOG4CXX_ERROR(logger_, "Device not found for handle " << device_handle); return result; @@ -1231,6 +1272,7 @@ void ConnectionHandlerImpl::GetConnectedDevicesMAC( std::vector& device_macs) const { DeviceMap::const_iterator first = device_list_.begin(); DeviceMap::const_iterator last = device_list_.end(); + sync_primitives::AutoReadLock lock(device_list_lock_); while (first != last) { device_macs.push_back((*first).second.mac_address()); @@ -1328,6 +1370,7 @@ void ConnectionHandlerImpl::StartDevicesDiscovery() { transport_manager_.SearchDevices(); sync_primitives::AutoReadLock read_lock(connection_handler_observer_lock_); + sync_primitives::AutoReadLock lock(device_list_lock_); if (connection_handler_observer_) { connection_handler_observer_->OnDeviceListUpdated(device_list_); } @@ -1336,6 +1379,7 @@ void ConnectionHandlerImpl::StartDevicesDiscovery() { void ConnectionHandlerImpl::ConnectToDevice( connection_handler::DeviceHandle device_handle) { connection_handler::DeviceMap::const_iterator it_in; + sync_primitives::AutoReadLock lock(device_list_lock_); it_in = device_list_.find(device_handle); if (device_list_.end() != it_in) { LOG4CXX_INFO(logger_, "Connecting to device with handle " << device_handle); @@ -1357,6 +1401,7 @@ transport_manager::ConnectionStatus ConnectionHandlerImpl::GetConnectionStatus( void ConnectionHandlerImpl::RunAppOnDevice(const std::string& device_mac, const std::string& bundle_id) const { + sync_primitives::AutoReadLock lock(device_list_lock_); for (DeviceMap::const_iterator i = device_list_.begin(); i != device_list_.end(); ++i) { @@ -1370,6 +1415,7 @@ void ConnectionHandlerImpl::RunAppOnDevice(const std::string& device_mac, } void ConnectionHandlerImpl::ConnectToAllDevices() { + sync_primitives::AutoReadLock lock(device_list_lock_); for (DeviceMap::iterator i = device_list_.begin(); i != device_list_.end(); ++i) { connection_handler::DeviceHandle device_handle = i->first; diff --git a/src/components/include/application_manager/application_manager.h b/src/components/include/application_manager/application_manager.h index 057f38f78e..31729aad75 100644 --- a/src/components/include/application_manager/application_manager.h +++ b/src/components/include/application_manager/application_manager.h @@ -165,6 +165,27 @@ class ApplicationManager { virtual DataAccessor applications() const = 0; virtual DataAccessor pending_applications() const = 0; + + /** + * @brief CreatePendingApplication Add applicaiton to pending state + * All info mandatory for application will be fetched from policy database. + * Application will be stored to internal pending applicaitons list. + * UpdateAppList will not be trigerred + * Application will be created if app exists in policy database and + * nicknames are not empty + * @param policy_app_id app id to store + */ + virtual void CreatePendingLocalApplication( + const std::string& policy_app_id) = 0; + + /** + * @brief RemovePendingApplication Remove applicaiton from pending state + * Application will be removed from the internal pending applicaitons list. + * UpdateAppList will not be trigerred + * @param policy_app_id app id to remove + */ + virtual void RemovePendingApplication(const std::string& policy_app_id) = 0; + virtual DataAccessor reregister_applications() const = 0; virtual ApplicationSharedPtr application(uint32_t app_id) const = 0; diff --git a/src/components/include/application_manager/policies/policy_handler_interface.h b/src/components/include/application_manager/policies/policy_handler_interface.h index 3af3b770aa..1e9f4d51b3 100644 --- a/src/components/include/application_manager/policies/policy_handler_interface.h +++ b/src/components/include/application_manager/policies/policy_handler_interface.h @@ -158,6 +158,13 @@ class PolicyHandlerInterface : public VehicleDataItemProvider { const std::string& device_id, const std::string& policy_app_id) const = 0; + /** + * @brief Send OnAppPropertiesChangeNotification to the HMI + * @param policy_app_id policy app id + */ + virtual void SendOnAppPropertiesChangeNotification( + const std::string& policy_app_id) const = 0; + /** * @brief CheckSystemAction allows to check whether certain system * action is enabled. @@ -477,6 +484,13 @@ class PolicyHandlerInterface : public VehicleDataItemProvider { virtual const std::vector GetAppRequestSubTypes( const std::string& policy_app_id) const = 0; + /** + * @brief Get a list of policy app ids + * @return apps list filled with the policy app ids of each + * application + */ + virtual std::vector GetApplicationPolicyIDs() const = 0; + /** * @brief Get a list of enabled cloud applications * @param enabled_apps List filled with the policy app id of each enabled @@ -495,29 +509,63 @@ class PolicyHandlerInterface : public VehicleDataItemProvider { const std::string& policy_app_id) const = 0; /** - * @brief Get cloud app policy information, all fields that aren't set for a + * @brief Get a list of enabled local applications + * @return enabled_apps List filled with the policy app id of each enabled + * local application + */ + virtual std::vector GetEnabledLocalApps() const = 0; + + /** + * @brief Get app policy information, all fields that aren't set for a * given app will be filled with empty strings - * @param policy_app_id Unique application id - * @param enabled Whether or not the app is enabled - * @param endpoint Filled with the endpoint used to connect to the cloud - * application - * @param certificate Filled with the certificate used to for creating a - * secure connection to the cloud application - * @param auth_token Filled with the token used for authentication when - * reconnecting to the cloud app - * @param cloud_transport_type Filled with the transport type used by the - * cloud application (ex. "WSS") - * @param hybrid_app_preference Filled with the hybrid app preference for the - * cloud application set by the user - */ - virtual bool GetCloudAppParameters( - const std::string& policy_app_id, - bool& enabled, - std::string& endpoint, - std::string& certificate, - std::string& auth_token, - std::string& cloud_transport_type, - std::string& hybrid_app_preference) const = 0; + * @param policy_app_id policy app id + * @param out_app_properties application properties + * @return true if application presents in database, otherwise - false + */ + virtual bool GetAppProperties(const std::string& policy_app_id, + AppProperties& out_app_properties) const = 0; + + /** + * @brief Callback for when a BC.SetAppProperties message is + * received from the HMI + * @param message The BC.SetAppProperties message + */ + virtual void OnSetAppProperties( + const smart_objects::SmartObject& properties) = 0; + + enum class AppPropertiesState { + NO_CHANGES, + ENABLED_FLAG_SWITCH, + AUTH_TOKEN_CHANGED, + TRANSPORT_TYPE_CHANGED, + ENDPOINT_CHANGED, + NICKNAMES_CHANGED, + HYBRYD_APP_PROPERTIES_CHANGED + }; + + /** + * @brief Checks if the application properties were changed. Compares the + * properties received from the HMI with the stored properties in the database + * @param properties new app properties + * @param app_id application id + * @return AppPropertiesState enum value that indicates which property has + * been changed + */ + virtual AppPropertiesState GetAppPropertiesStatus( + const smart_objects::SmartObject& properties, + const std::string& app_id) const = 0; + + /** + * @brief Check if certain application already in policy db. + * @param policy application id. + * @return true if application presents false otherwise. + */ + virtual bool IsNewApplication(const std::string& application_id) const = 0; + + /** + * @brief OnLocalAppAdded triggers PTU + */ + virtual void OnLocalAppAdded() = 0; /** * @brief Callback for when a SetCloudAppProperties message is received from a diff --git a/src/components/include/connection_handler/connection_handler.h b/src/components/include/connection_handler/connection_handler.h index eb92336b4f..e98a78f377 100644 --- a/src/components/include/connection_handler/connection_handler.h +++ b/src/components/include/connection_handler/connection_handler.h @@ -312,6 +312,19 @@ class ConnectionHandler { const transport_manager::ConnectionUID primary_connection_handle, const transport_manager::ConnectionUID secondary_connection_handle) = 0; + /** + * @brief GetWebEngineDeviceInfo + * @return device info for WebEngine device + */ + virtual const transport_manager::DeviceInfo& GetWebEngineDeviceInfo() + const = 0; + + /** + * @brief Called when HMI cooperation is started, + * creates WebSocketDevice for WebEngine + */ + virtual void CreateWebEngineDevice() = 0; + protected: /** * \brief Destructor diff --git a/src/components/include/connection_handler/connection_handler_observer.h b/src/components/include/connection_handler/connection_handler_observer.h index 48e4263959..7d6664a009 100644 --- a/src/components/include/connection_handler/connection_handler_observer.h +++ b/src/components/include/connection_handler/connection_handler_observer.h @@ -172,6 +172,11 @@ class ConnectionHandlerObserver { const transport_manager::ConnectionUID connection_id, const transport_manager::DeviceInfo& device_info) = 0; + /** + *@brief Called when webengine device added + */ + virtual void OnWebEngineDeviceCreated() = 0; + protected: /** * \brief Destructor diff --git a/src/components/include/policy/policy_external/policy/policy_listener.h b/src/components/include/policy/policy_external/policy/policy_listener.h index 8220d05584..c613fdd091 100644 --- a/src/components/include/policy/policy_external/policy/policy_listener.h +++ b/src/components/include/policy/policy_external/policy/policy_listener.h @@ -109,6 +109,14 @@ class PolicyListener { const std::string& device_id, const std::string& policy_app_id) const = 0; + /** + * @brief Send OnAppPropertiesChangeNotification to the HMI + * @param policy_app_id policy app id + */ + + virtual void SendOnAppPropertiesChangeNotification( + const std::string& policy_app_id) const = 0; + /** * @brief GetAvailableApps allows to obtain list of registered applications. */ diff --git a/src/components/include/policy/policy_external/policy/policy_manager.h b/src/components/include/policy/policy_external/policy/policy_manager.h index 22721841aa..935233e92d 100644 --- a/src/components/include/policy/policy_external/policy/policy_manager.h +++ b/src/components/include/policy/policy_external/policy/policy_manager.h @@ -601,6 +601,13 @@ class PolicyManager : public usage_statistics::StatisticsManager, */ virtual Json::Value GetPolicyTableData() const = 0; + /** + * @brief Get a list of policy app ids + * @return apps list filled with the policy app ids of each + * application + */ + virtual const std::vector GetApplicationPolicyIDs() const = 0; + /** * @brief Get a list of enabled cloud applications * @param enabled_apps List filled with the policy app id of each enabled @@ -610,29 +617,21 @@ class PolicyManager : public usage_statistics::StatisticsManager, std::vector& enabled_apps) const = 0; /** - * @brief Get cloud app policy information, all fields that aren't set for a + * @brief Get app policy information, all fields that aren't set for a * given app will be filled with empty strings - * @param policy_app_id Unique application id - * @param enabled Whether or not the app is enabled - * @param endpoint Filled with the endpoint used to connect to the cloud - * application - * @param certificate Filled with the certificate used to for creating a - * secure connection to the cloud application - * @param auth_token Filled with the token used for authentication when - * reconnecting to the cloud app - * @param cloud_transport_type Filled with the transport type used by the - * cloud application (ex. "WSS") - * @param hybrid_app_preference Filled with the hybrid app preference for the - * cloud application set by the user - */ - virtual bool GetCloudAppParameters( - const std::string& policy_app_id, - bool& enabled, - std::string& endpoint, - std::string& certificate, - std::string& auth_token, - std::string& cloud_transport_type, - std::string& hybrid_app_preference) const = 0; + * @param policy_app_id policy app id + * @param out_app_properties application properties + * @return true if application presents in database, otherwise - false + */ + virtual bool GetAppProperties(const std::string& policy_app_id, + AppProperties& out_app_properties) const = 0; + + /** + * @brief Get a list of enabled local applications + * @return enabled_apps List filled with the policy app id of each enabled + * local application + */ + virtual std::vector GetEnabledLocalApps() const = 0; /** * @ brief Initialize new cloud app in the policy table @@ -778,6 +777,12 @@ class PolicyManager : public usage_statistics::StatisticsManager, */ virtual void SendAppPermissionsChanged(const std::string& device_id, const std::string& application_id) = 0; + /** + * @brief Send OnAppPropertiesChangeNotification to the HMI + * @param policy_app_id policy app id + */ + virtual void SendOnAppPropertiesChangeNotification( + const std::string& policy_app_id) const = 0; /** * @brief Gets all allowed module types @@ -830,6 +835,18 @@ class PolicyManager : public usage_statistics::StatisticsManager, */ virtual ExternalConsentStatus GetExternalConsentStatus() = 0; + /** + * @brief OnLocalAppAdded triggers PTU + */ + virtual void OnLocalAppAdded() = 0; + + /** + * @brief Check if certain application already in policy db. + * @param policy application id. + * @return true if application presents false otherwise. + */ + virtual bool IsNewApplication(const std::string& application_id) const = 0; + /** * @brief Restart PTU timeout if PTU in UPDATING state */ diff --git a/src/components/include/policy/policy_regular/policy/policy_listener.h b/src/components/include/policy/policy_regular/policy/policy_listener.h index bbe220060e..5b8245f6a4 100644 --- a/src/components/include/policy/policy_regular/policy/policy_listener.h +++ b/src/components/include/policy/policy_regular/policy/policy_listener.h @@ -107,6 +107,13 @@ class PolicyListener { const std::string& device_id, const std::string& policy_app_id) const = 0; + /** + * @brief Send OnAppPropertiesChangeNotification to the HMI + * @param policy_app_id policy app id + */ + virtual void SendOnAppPropertiesChangeNotification( + const std::string& policy_app_id) const = 0; + /** * @brief GetAvailableApps allows to obtain list of registered applications. */ diff --git a/src/components/include/policy/policy_regular/policy/policy_manager.h b/src/components/include/policy/policy_regular/policy/policy_manager.h index c9143d6bbb..52923a53e2 100644 --- a/src/components/include/policy/policy_regular/policy/policy_manager.h +++ b/src/components/include/policy/policy_regular/policy/policy_manager.h @@ -575,6 +575,14 @@ class PolicyManager : public usage_statistics::StatisticsManager, * @return policy_table as json object */ virtual Json::Value GetPolicyTableData() const = 0; + + /** + * @brief Get a list of policy app ids + * @return apps list filled with the policy app ids of each + * application + */ + virtual const std::vector GetApplicationPolicyIDs() const = 0; + /** * @brief Get a list of enabled cloud applications * @param enabled_apps List filled with the policy app id of each enabled @@ -584,29 +592,21 @@ class PolicyManager : public usage_statistics::StatisticsManager, std::vector& enabled_apps) const = 0; /** - * @brief Get cloud app policy information, all fields that aren't set for a + * @brief Get a list of enabled local applications + * @return enabled_apps List filled with the policy app id of each enabled + * local application + */ + virtual std::vector GetEnabledLocalApps() const = 0; + + /** + * @brief Get app policy information, all fields that aren't set for a * given app will be filled with empty strings - * @param policy_app_id Unique application id - * @param enabled Whether or not the app is enabled - * @param endpoint Filled with the endpoint used to connect to the cloud - * application - * @param certificate Filled with the certificate used to for creating a - * secure connection to the cloud application - * @param auth_token Filled with the token used for authentication when - * reconnecting to the cloud app - * @param cloud_transport_type Filled with the transport type used by the - * cloud application (ex. "WSS") - * @param hybrid_app_preference Filled with the hybrid app preference for the - * cloud application set by the user - */ - virtual bool GetCloudAppParameters( - const std::string& policy_app_id, - bool& enabled, - std::string& endpoint, - std::string& certificate, - std::string& auth_token, - std::string& cloud_transport_type, - std::string& hybrid_app_preference) const = 0; + * @param policy_app_id policy app id + * @param out_app_properties application properties + * @return true if application presents in database, otherwise - false + */ + virtual bool GetAppProperties(const std::string& policy_app_id, + AppProperties& out_app_properties) const = 0; /** * @ brief Initialize new cloud app in the policy table @@ -757,6 +757,13 @@ class PolicyManager : public usage_statistics::StatisticsManager, virtual void SendAppPermissionsChanged(const std::string& device_id, const std::string& application_id) = 0; + /** + * @brief Send OnAppPropertiesChangeNotification to the HMI + * @param policy_app_id policy app id + */ + virtual void SendOnAppPropertiesChangeNotification( + const std::string& policy_app_id) const = 0; + /** * @brief Gets all allowed module types * @param policy_app_id unique identifier of application @@ -785,6 +792,18 @@ class PolicyManager : public usage_statistics::StatisticsManager, virtual AppIdURL RetrySequenceUrl(const struct RetrySequenceURL& rs, const EndpointUrls& urls) const = 0; + /** + * @brief OnLocalAppAdded triggers PTU + */ + virtual void OnLocalAppAdded() = 0; + + /** + * @brief Check if certain application already in policy db. + * @param policy application id. + * @return true if application presents false otherwise. + */ + virtual bool IsNewApplication(const std::string& application_id) const = 0; + /** * @brief Restart PTU timeout if PTU in UPDATING state */ diff --git a/src/components/include/test/application_manager/mock_application_manager.h b/src/components/include/test/application_manager/mock_application_manager.h index b2de63252e..5e9b65fec5 100644 --- a/src/components/include/test/application_manager/mock_application_manager.h +++ b/src/components/include/test/application_manager/mock_application_manager.h @@ -86,6 +86,10 @@ class MockApplicationManager : public application_manager::ApplicationManager { DataAccessor()); MOCK_CONST_METHOD0(reregister_applications, DataAccessor()); + MOCK_METHOD1(CreatePendingLocalApplication, + void(const std::string& policy_app_id)); + MOCK_METHOD1(RemovePendingApplication, + void(const std::string& policy_app_id)); MOCK_CONST_METHOD1( application, application_manager::ApplicationSharedPtr(uint32_t app_id)); MOCK_CONST_METHOD0(active_application, @@ -287,6 +291,8 @@ class MockApplicationManager : public application_manager::ApplicationManager { ApplyFunctorForEachPlugin, void(std::function functor)); + MOCK_METHOD1(SetVINCode, void(const std::string& vin_code)); + MOCK_CONST_METHOD0(GetVINCode, const std::string()); MOCK_METHOD1( GetDeviceTransportType, hmi_apis::Common_TransportType::eType(const std::string& transport_type)); diff --git a/src/components/include/test/application_manager/policies/mock_policy_handler_interface.h b/src/components/include/test/application_manager/policies/mock_policy_handler_interface.h index f6e0b3cb0f..a9cb70354a 100644 --- a/src/components/include/test/application_manager/policies/mock_policy_handler_interface.h +++ b/src/components/include/test/application_manager/policies/mock_policy_handler_interface.h @@ -206,6 +206,8 @@ class MockPolicyHandlerInterface : public policy::PolicyHandlerInterface { void(const policy::AppPermissions& permissions, const std::string& device_id, const std::string& policy_app_id)); + MOCK_CONST_METHOD1(SendOnAppPropertiesChangeNotification, + void(const std::string& policy_app_id)); MOCK_METHOD0(OnPTExchangeNeeded, void()); MOCK_METHOD1(GetAvailableApps, void(std::queue& apps)); MOCK_METHOD3( @@ -242,18 +244,24 @@ class MockPolicyHandlerInterface : public policy::PolicyHandlerInterface { const std::vector( const transport_manager::DeviceHandle& device_handle, const std::string& policy_app_id)); + MOCK_CONST_METHOD0(GetApplicationPolicyIDs, std::vector()); MOCK_CONST_METHOD1(GetEnabledCloudApps, void(std::vector& enabled_apps)); MOCK_CONST_METHOD1(CheckCloudAppEnabled, const bool(const std::string& policy_app_id)); - MOCK_CONST_METHOD7(GetCloudAppParameters, + MOCK_CONST_METHOD0(GetEnabledLocalApps, std::vector()); + MOCK_CONST_METHOD2(GetAppProperties, bool(const std::string& policy_app_id, - bool& enabled, - std::string& endpoint, - std::string& certificate, - std::string& auth_token, - std::string& cloud_transport_type, - std::string& hybrid_app_preference)); + policy::AppProperties& out_app_properties)); + + MOCK_METHOD1(OnSetAppProperties, + void(const smart_objects::SmartObject& message)); + MOCK_CONST_METHOD2( + GetAppPropertiesStatus, + AppPropertiesState(const smart_objects::SmartObject& properties, + const std::string& app_id)); + MOCK_CONST_METHOD1(IsNewApplication, bool(const std::string& application_id)); + MOCK_METHOD0(OnLocalAppAdded, void()); MOCK_METHOD1(OnSetCloudAppProperties, void(const smart_objects::SmartObject& message)); MOCK_CONST_METHOD2( diff --git a/src/components/include/test/connection_handler/mock_connection_handler.h b/src/components/include/test/connection_handler/mock_connection_handler.h index 41c2f04ebb..6acffea0ed 100644 --- a/src/components/include/test/connection_handler/mock_connection_handler.h +++ b/src/components/include/test/connection_handler/mock_connection_handler.h @@ -133,6 +133,8 @@ class MockConnectionHandler : public connection_handler::ConnectionHandler { OnSecondaryTransportEnded, void(const transport_manager::ConnectionUID primary_connection_handle, const transport_manager::ConnectionUID secondary_connection_handle)); + MOCK_METHOD0(CreateWebEngineDevice, void()); + MOCK_CONST_METHOD0(GetWebEngineDeviceInfo, transport_manager::DeviceInfo&()); }; } // namespace connection_handler_test diff --git a/src/components/include/test/connection_handler/mock_connection_handler_observer.h b/src/components/include/test/connection_handler/mock_connection_handler_observer.h index 8f7ec90550..61877daa23 100644 --- a/src/components/include/test/connection_handler/mock_connection_handler_observer.h +++ b/src/components/include/test/connection_handler/mock_connection_handler_observer.h @@ -46,6 +46,7 @@ class MockConnectionHandlerObserver MOCK_METHOD1(OnDeviceListUpdated, void(const connection_handler::DeviceMap& device_list)); MOCK_METHOD0(OnFindNewApplicationsRequest, void()); + MOCK_METHOD0(OnWebEngineDeviceCreated, void()); MOCK_METHOD1(RemoveDevice, void(const connection_handler::DeviceHandle& device_handle)); MOCK_METHOD4(OnServiceStartedCallback, diff --git a/src/components/include/test/policy/policy_external/policy/mock_cache_manager.h b/src/components/include/test/policy/policy_external/policy/mock_cache_manager.h index b74ddbd13c..c6eb3416da 100644 --- a/src/components/include/test/policy/policy_external/policy/mock_cache_manager.h +++ b/src/components/include/test/policy/policy_external/policy/mock_cache_manager.h @@ -61,6 +61,7 @@ class MockCacheManagerInterface : public ::policy::CacheManagerInterface { MOCK_METHOD0(IsPTPreloaded, bool()); MOCK_METHOD0(IgnitionCyclesBeforeExchange, int()); MOCK_METHOD1(KilometersBeforeExchange, int(int current)); + MOCK_CONST_METHOD0(GetEnabledLocalApps, std::vector()); MOCK_CONST_METHOD1(GetPermissionsList, bool(StringArray& perm_list)); MOCK_METHOD2(SetCountersPassedForSuccessfulUpdate, bool(Counters counter, int value)); @@ -83,14 +84,9 @@ class MockCacheManagerInterface : public ::policy::CacheManagerInterface { std::vector()); MOCK_CONST_METHOD1(GetEnabledCloudApps, void(std::vector& enabled_apps)); - MOCK_CONST_METHOD7(GetCloudAppParameters, + MOCK_CONST_METHOD2(GetAppProperties, bool(const std::string& policy_app_id, - bool& enabled, - std::string& endpoint, - std::string& certificate, - std::string& auth_token, - std::string& cloud_transport_type, - std::string& hybrid_app_preference)); + AppProperties& out_app_properties)); MOCK_METHOD1(InitCloudApp, void(const std::string& policy_app_id)); MOCK_METHOD2(SetCloudAppEnabled, void(const std::string& policy_app_id, const bool enabled)); diff --git a/src/components/include/test/policy/policy_external/policy/mock_policy_listener.h b/src/components/include/test/policy/policy_external/policy/mock_policy_listener.h index 2eb5b3300b..0060d2299f 100644 --- a/src/components/include/test/policy/policy_external/policy/mock_policy_listener.h +++ b/src/components/include/test/policy/policy_external/policy/mock_policy_listener.h @@ -94,6 +94,8 @@ class MockPolicyListener : public ::policy::PolicyListener { void(const policy::AppPermissions& permissions, const std::string& device_id, const std::string& policy_app_id)); + MOCK_CONST_METHOD1(SendOnAppPropertiesChangeNotification, + void(const std::string& policy_app_id)); MOCK_CONST_METHOD1( GetDevicesIds, std::vector(const std::string& policy_app_id)); diff --git a/src/components/include/test/policy/policy_external/policy/mock_policy_manager.h b/src/components/include/test/policy/policy_external/policy/mock_policy_manager.h index d2023fd3d4..5adb982410 100644 --- a/src/components/include/test/policy/policy_external/policy/mock_policy_manager.h +++ b/src/components/include/test/policy/policy_external/policy/mock_policy_manager.h @@ -194,6 +194,8 @@ class MockPolicyManager : public PolicyManager { MOCK_METHOD2(SendAppPermissionsChanged, void(const std::string& device_id, const std::string& application_id)); + MOCK_CONST_METHOD1(SendOnAppPropertiesChangeNotification, + void(const std::string& application_id)); MOCK_CONST_METHOD2(GetModuleTypes, bool(const std::string& policy_app_id, std::vector* modules)); @@ -228,14 +230,12 @@ class MockPolicyManager : public PolicyManager { std::vector()); MOCK_CONST_METHOD1(GetEnabledCloudApps, void(std::vector& enabled_apps)); - MOCK_CONST_METHOD7(GetCloudAppParameters, + MOCK_CONST_METHOD2(GetAppProperties, bool(const std::string& policy_app_id, - bool& enabled, - std::string& endpoint, - std::string& certificate, - std::string& auth_token, - std::string& cloud_transport_type, - std::string& hybrid_app_preference)); + AppProperties& out_app_properties)); + MOCK_CONST_METHOD0(GetEnabledLocalApps, std::vector()); + MOCK_CONST_METHOD1(IsNewApplication, bool(const std::string& application_id)); + MOCK_METHOD0(OnLocalAppAdded, void()); MOCK_METHOD1(InitCloudApp, void(const std::string& policy_app_id)); MOCK_METHOD2(SetCloudAppEnabled, void(const std::string& policy_app_id, const bool enabled)); diff --git a/src/components/include/test/policy/policy_regular/policy/mock_cache_manager.h b/src/components/include/test/policy/policy_regular/policy/mock_cache_manager.h index e592caf3bc..7c78eadfc8 100644 --- a/src/components/include/test/policy/policy_regular/policy/mock_cache_manager.h +++ b/src/components/include/test/policy/policy_regular/policy/mock_cache_manager.h @@ -55,6 +55,7 @@ class MockCacheManagerInterface : public CacheManagerInterface { MOCK_METHOD0(IsPTPreloaded, bool()); MOCK_METHOD0(IgnitionCyclesBeforeExchange, int()); MOCK_METHOD1(KilometersBeforeExchange, int(int current)); + MOCK_CONST_METHOD0(GetEnabledLocalApps, std::vector()); MOCK_METHOD2(SetCountersPassedForSuccessfulUpdate, bool(Counters counter, int value)); MOCK_METHOD1(DaysBeforeExchange, int(int current)); @@ -69,14 +70,9 @@ class MockCacheManagerInterface : public CacheManagerInterface { std::vector()); MOCK_CONST_METHOD1(GetEnabledCloudApps, void(std::vector& enabled_apps)); - MOCK_CONST_METHOD7(GetCloudAppParameters, + MOCK_CONST_METHOD2(GetAppProperties, bool(const std::string& policy_app_id, - bool& enabled, - std::string& endpoint, - std::string& certificate, - std::string& auth_token, - std::string& cloud_transport_type, - std::string& hybrid_app_preference)); + AppProperties& out_app_properties)); MOCK_METHOD1(InitCloudApp, void(const std::string& policy_app_id)); MOCK_METHOD2(SetCloudAppEnabled, void(const std::string& policy_app_id, const bool enabled)); diff --git a/src/components/include/test/policy/policy_regular/policy/mock_policy_listener.h b/src/components/include/test/policy/policy_regular/policy/mock_policy_listener.h index 48c549e91b..e5f2321217 100644 --- a/src/components/include/test/policy/policy_regular/policy/mock_policy_listener.h +++ b/src/components/include/test/policy/policy_regular/policy/mock_policy_listener.h @@ -89,6 +89,8 @@ class MockPolicyListener : public ::policy::PolicyListener { void(const policy::AppPermissions& permissions, const std::string& device_id, const std::string& policy_app_id)); + MOCK_CONST_METHOD1(SendOnAppPropertiesChangeNotification, + void(const std::string& policy_app_id)); MOCK_METHOD3(OnUpdateHMILevel, void(const std::string& device_id, const std::string& policy_app_id, diff --git a/src/components/include/test/policy/policy_regular/policy/mock_policy_manager.h b/src/components/include/test/policy/policy_regular/policy/mock_policy_manager.h index da9edb9fe5..a76d61dfe4 100644 --- a/src/components/include/test/policy/policy_regular/policy/mock_policy_manager.h +++ b/src/components/include/test/policy/policy_regular/policy/mock_policy_manager.h @@ -193,6 +193,8 @@ class MockPolicyManager : public PolicyManager { MOCK_METHOD2(SendAppPermissionsChanged, void(const std::string& device_id, const std::string& application_id)); + MOCK_CONST_METHOD1(SendOnAppPropertiesChangeNotification, + void(const std::string& application_id)); MOCK_CONST_METHOD2(GetModuleTypes, bool(const std::string& policy_app_id, std::vector* modules)); @@ -223,14 +225,12 @@ class MockPolicyManager : public PolicyManager { std::vector()); MOCK_CONST_METHOD1(GetEnabledCloudApps, void(std::vector& enabled_apps)); - MOCK_CONST_METHOD7(GetCloudAppParameters, + MOCK_CONST_METHOD2(GetAppProperties, bool(const std::string& policy_app_id, - bool& enabled, - std::string& endpoint, - std::string& certificate, - std::string& auth_token, - std::string& cloud_transport_type, - std::string& hybrid_app_preference)); + AppProperties& out_app_properties)); + MOCK_CONST_METHOD0(GetEnabledLocalApps, std::vector()); + MOCK_CONST_METHOD1(IsNewApplication, bool(const std::string& application_id)); + MOCK_METHOD0(OnLocalAppAdded, void()); MOCK_METHOD1(InitCloudApp, void(const std::string& policy_app_id)); MOCK_METHOD2(SetCloudAppEnabled, void(const std::string& policy_app_id, const bool enabled)); diff --git a/src/components/include/test/transport_manager/mock_transport_manager.h b/src/components/include/test/transport_manager/mock_transport_manager.h index c853ceb512..1920af18a3 100644 --- a/src/components/include/test/transport_manager/mock_transport_manager.h +++ b/src/components/include/test/transport_manager/mock_transport_manager.h @@ -88,6 +88,8 @@ class MockTransportManager : public ::transport_manager::TransportManager, MOCK_METHOD1(SetTelemetryObserver, void(transport_manager::TMTelemetryObserver* observer)); + MOCK_METHOD0(CreateWebEngineDevice, void()); + MOCK_CONST_METHOD0(GetWebEngineDeviceInfo, transport_manager::DeviceInfo&()); }; } // namespace transport_manager_test diff --git a/src/components/include/test/transport_manager/mock_transport_manager_settings.h b/src/components/include/test/transport_manager/mock_transport_manager_settings.h index 6ed4ac5d51..10320d51ab 100644 --- a/src/components/include/test/transport_manager/mock_transport_manager_settings.h +++ b/src/components/include/test/transport_manager/mock_transport_manager_settings.h @@ -63,6 +63,8 @@ class MockTransportManagerSettings MOCK_CONST_METHOD0(app_transport_change_timer_addition, uint32_t()); MOCK_CONST_METHOD0(transport_manager_tcp_adapter_network_interface, std::string&()); + MOCK_CONST_METHOD0(websocket_server_address, const std::string&()); + MOCK_CONST_METHOD0(websocket_server_port, uint16_t()); MOCK_CONST_METHOD0(cloud_app_retry_timeout, uint32_t()); MOCK_CONST_METHOD0(cloud_app_max_retry_attempts, uint16_t()); MOCK_CONST_METHOD0(bluetooth_uuid, const uint8_t*()); @@ -72,6 +74,10 @@ class MockTransportManagerSettings MOCK_CONST_METHOD0(aoa_filter_version, const std::string&()); MOCK_CONST_METHOD0(aoa_filter_uri, const std::string&()); MOCK_CONST_METHOD0(aoa_filter_serial_number, const std::string&()); + MOCK_CONST_METHOD0(ws_server_cert_path, const std::string&()); + MOCK_CONST_METHOD0(ws_server_key_path, const std::string&()); + MOCK_CONST_METHOD0(ws_server_ca_cert_path, const std::string&()); + MOCK_CONST_METHOD0(wss_server_supported, const bool()); }; } // namespace transport_manager_test diff --git a/src/components/include/test/transport_manager/transport_adapter/mock_transport_adapter.h b/src/components/include/test/transport_manager/transport_adapter/mock_transport_adapter.h index a07365f8c0..d4ce0a39c8 100644 --- a/src/components/include/test/transport_manager/transport_adapter/mock_transport_adapter.h +++ b/src/components/include/test/transport_manager/transport_adapter/mock_transport_adapter.h @@ -108,6 +108,10 @@ class MockTransportAdapter transport_manager::transport_adapter::TransportConfig()); MOCK_METHOD1(CreateDevice, void(const std::string& uid)); + MOCK_METHOD1(AddDevice, + transport_manager::transport_adapter::DeviceSptr( + transport_manager::transport_adapter::DeviceSptr device)); + #ifdef TELEMETRY_MONITOR MOCK_METHOD0(GetTelemetryObserver, ::transport_manager::TMTelemetryObserver*()); diff --git a/src/components/include/transport_manager/common.h b/src/components/include/transport_manager/common.h index 08f52ae1d0..f8b0cabe2e 100644 --- a/src/components/include/transport_manager/common.h +++ b/src/components/include/transport_manager/common.h @@ -69,6 +69,11 @@ enum { enum ConnectionStatus { INVALID = -1, PENDING, RETRY, CONNECTED, CLOSING }; +namespace webengine_constants { +const std::string kWebEngineConnectionType("WEBENGINE_WEBSOCKET"); +const std::string kWebEngineDeviceName("Web Engine"); +} // namespace webengine_constants + /** * @brief Type definition for variable that hold handle of device. */ diff --git a/src/components/include/transport_manager/transport_adapter/transport_adapter.h b/src/components/include/transport_manager/transport_adapter/transport_adapter.h index 8b46be253b..e9494b4ced 100644 --- a/src/components/include/transport_manager/transport_adapter/transport_adapter.h +++ b/src/components/include/transport_manager/transport_adapter/transport_adapter.h @@ -68,6 +68,7 @@ enum DeviceType { IOS_USB_HOST_MODE, IOS_USB_DEVICE_MODE, IOS_CARPLAY_WIRELESS, // running on iAP over Carplay wireless transport + WEBENGINE_WEBSOCKET, UNKNOWN }; @@ -224,6 +225,16 @@ class TransportAdapter { virtual ConnectionStatus GetConnectionStatus( const DeviceUID& device_handle) const = 0; + /** + * @brief Add device to the container(map), if container doesn't hold it yet. + * in TransportAdapter is used only to add a WebEngine device + * + * @param device Smart pointer to the device. + * + * @return Smart pointer to the device. + */ + virtual DeviceSptr AddDevice(DeviceSptr device) = 0; + /** * @brief RunAppOnDevice allows to run specific application on the certain *device. diff --git a/src/components/include/transport_manager/transport_manager.h b/src/components/include/transport_manager/transport_manager.h index e370e3e4c6..4697bf9982 100644 --- a/src/components/include/transport_manager/transport_manager.h +++ b/src/components/include/transport_manager/transport_manager.h @@ -215,6 +215,18 @@ class TransportManager { */ virtual int PerformActionOnClients( const TransportAction required_action) const = 0; + + /** + * @brief Called when websocket server transport adapter is available. + * Creates WebSocketDevice for WebEngine and add it to the device list + */ + virtual void CreateWebEngineDevice() = 0; + + /** + * @brief GetWebEngineDeviceInfo + * @return device info for WebEngine device + */ + virtual const DeviceInfo& GetWebEngineDeviceInfo() const = 0; }; } // namespace transport_manager #endif // SRC_COMPONENTS_INCLUDE_TRANSPORT_MANAGER_TRANSPORT_MANAGER_H_ diff --git a/src/components/include/transport_manager/transport_manager_settings.h b/src/components/include/transport_manager/transport_manager_settings.h index 83d0b3e833..fee5b031ed 100644 --- a/src/components/include/transport_manager/transport_manager_settings.h +++ b/src/components/include/transport_manager/transport_manager_settings.h @@ -69,7 +69,24 @@ class TransportManagerSettings : public TransportManagerMMESettings { */ virtual const std::string& transport_manager_tcp_adapter_network_interface() const = 0; +#ifdef WEBSOCKET_SERVER_TRANSPORT_SUPPORT + /** + *@brief Returns websocket server address + */ + virtual const std::string& websocket_server_address() const = 0; + + /** + * @brief Returns port for websocket server + */ + virtual uint16_t websocket_server_port() const = 0; +#ifdef ENABLE_SECURITY + virtual const std::string& ws_server_cert_path() const = 0; + virtual const std::string& ws_server_key_path() const = 0; + virtual const std::string& ws_server_ca_cert_path() const = 0; + virtual const bool wss_server_supported() const = 0; +#endif // ENABLE_SECURITY +#endif // WEBSOCKET_SERVER_TRANSPORT_SUPPORT /** * @brief Returns retry timeout for cloud app connections */ diff --git a/src/components/interfaces/HMI_API.xml b/src/components/interfaces/HMI_API.xml index d105d2e3e8..9e8a32312f 100644 --- a/src/components/interfaces/HMI_API.xml +++ b/src/components/interfaces/HMI_API.xml @@ -95,6 +95,7 @@ + @@ -4122,6 +4123,13 @@ Contains information about the locations of each seat + + + Enumeration for the user's preference of which app type to use when both are available + + + + @@ -4640,7 +4648,102 @@ ID of application that is related to this RPC. + + + + + An array of app names an app is allowed to register with. If included in a SetAppProperties request, this value will overwrite the existing "nicknames" field in the app policies section of the policy table. + + + + If true, the app will be marked as "available" or "installed" and will be included in HMI RPC UpdateAppList. + + + Used to authenticate connection on app activation + + + + Specifies the connection type Core should use. The Core role (server or client) is dependent of "endpoint" being specified. + See "endpoint" for details. + + + + Specifies the user preference to use one specific app type or all available types + + + + If specified, which Core uses a client implementation of the connection type and attempts to connect to the endpoint when this app is selected (activated). + If omitted, Core won't attempt to connect as the app selection (activation) is managed outside of Core. Instead it uses a server implementation of the connection type and expects the app to connect. + + + + + + + HMI >SDL. RPC used to enable/disable an application and set authentication data + + + The new application properties + + + + The response to SetAppProperties + + true if successful; false if failed + + + See Result + + + + + + + + + + + + + + HMI >SDL. RPC used to get the current properties of an application + + + If specified the response will contain the properties of the specified app ID. + Otherwise if omitted all app properties will be returned at once. + + + + + The response to GetAppProperties + + The requested application properties + + + true if successful; false if failed + + + See Result + + + + + + + + + + + + + + SDL >HMI. RPC used to inform HMI about app properties change (such as auth token). + + + The new application properties + + diff --git a/src/components/policy/policy_external/include/policy/cache_manager.h b/src/components/policy/policy_external/include/policy/cache_manager.h index 5e3cf3dde7..b24e05fb6d 100644 --- a/src/components/policy/policy_external/include/policy/cache_manager.h +++ b/src/components/policy/policy_external/include/policy/cache_manager.h @@ -181,32 +181,18 @@ class CacheManager : public CacheManagerInterface { * @param enabled_apps List filled with the policy app id of each enabled * cloud application */ - virtual void GetEnabledCloudApps( - std::vector& enabled_apps) const; + void GetEnabledCloudApps( + std::vector& enabled_apps) const OVERRIDE; /** - * @brief Get cloud app policy information, all fields that aren't set for a - * given app will be filled with empty strings - * @param policy_app_id Unique application id - * @param enabled Whether or not the app is enabled - * @param endpoint Filled with the endpoint used to connect to the cloud - * application - * @param certificate Filled with the certificate used to for creating a - * secure connection to the cloud application - * @param auth_token Filled with the token used for authentication when - * reconnecting to the cloud app - * @param cloud_transport_type Filled with the transport type used by the - * cloud application (ex. "WSS") - * @param hybrid_app_preference Filled with the hybrid app preference for the - * cloud application set by the user - */ - virtual bool GetCloudAppParameters(const std::string& policy_app_id, - bool& enabled, - std::string& endpoint, - std::string& certificate, - std::string& auth_token, - std::string& cloud_transport_type, - std::string& hybrid_app_preference) const; + * @brief Get a list of enabled local applications + * @return enabled_apps List filled with the policy app id + * of each enabled local application + */ + std::vector GetEnabledLocalApps() const OVERRIDE; + + bool GetAppProperties(const std::string& policy_app_id, + AppProperties& out_app_properties) const OVERRIDE; /** * Initializes a new cloud application with default policies diff --git a/src/components/policy/policy_external/include/policy/cache_manager_interface.h b/src/components/policy/policy_external/include/policy/cache_manager_interface.h index 2cb5f8fe33..8e3f90b64f 100644 --- a/src/components/policy/policy_external/include/policy/cache_manager_interface.h +++ b/src/components/policy/policy_external/include/policy/cache_manager_interface.h @@ -190,29 +190,21 @@ class CacheManagerInterface { std::vector& enabled_apps) const = 0; /** - * @brief Get cloud app policy information, all fields that aren't set for a + * @brief Get a list of enabled local applications + * @return enabled_apps List filled with the policy app id of each enabled + * local application + */ + virtual std::vector GetEnabledLocalApps() const = 0; + + /** + * @brief Get app policy information, all fields that aren't set for a * given app will be filled with empty strings - * @param policy_app_id Unique application id - * @param enabled Whether or not the app is enabled - * @param endpoint Filled with the endpoint used to connect to the cloud - * application - * @param certificate Filled with the certificate used to for creating a - * secure connection to the cloud application - * @param auth_token Filled with the token used for authentication when - * reconnecting to the cloud app - * @param cloud_transport_type Filled with the transport type used by the - * cloud application (ex. "WSS") - * @param hybrid_app_preference Filled with the hybrid app preference for the - * cloud application set by the user - */ - virtual bool GetCloudAppParameters( - const std::string& policy_app_id, - bool& enabled, - std::string& endpoint, - std::string& certificate, - std::string& auth_token, - std::string& cloud_transport_type, - std::string& hybrid_app_preference) const = 0; + * @param policy_app_id policy app id + * @param out_app_properties application properties + * @return true if application presents in database, otherwise - false + */ + virtual bool GetAppProperties(const std::string& policy_app_id, + AppProperties& out_app_properties) const = 0; /** * Initializes a new cloud application with default policies diff --git a/src/components/policy/policy_external/include/policy/policy_helper.h b/src/components/policy/policy_external/include/policy/policy_helper.h index 2054485ef5..69ba8806d4 100644 --- a/src/components/policy/policy_external/include/policy/policy_helper.h +++ b/src/components/policy/policy_external/include/policy/policy_helper.h @@ -231,6 +231,10 @@ struct CheckAppPolicy { void InsertPermission(const std::string& app_id, const AppPermissions& permissions_diff); + bool IsAppPropertiesChanged(const AppPoliciesValueType& app_policy) const; + + bool IsAppPropertiesProvided(const AppPoliciesValueType& app_policy) const; + private: PolicyManagerImpl* pm_; const std::shared_ptr update_; diff --git a/src/components/policy/policy_external/include/policy/policy_manager_impl.h b/src/components/policy/policy_external/include/policy/policy_manager_impl.h index ce344d576a..57499131f9 100644 --- a/src/components/policy/policy_external/include/policy/policy_manager_impl.h +++ b/src/components/policy/policy_external/include/policy/policy_manager_impl.h @@ -667,28 +667,14 @@ class PolicyManagerImpl : public PolicyManager { std::vector& enabled_apps) const OVERRIDE; /** - * @brief Get cloud app policy information, all fields that aren't set for a - * given app will be filled with empty strings - * @param policy_app_id Unique application id - * @param enabled Whether or not the app is enabled - * @param endpoint Filled with the endpoint used to connect to the cloud - * application - * @param certificate Filled with the certificate used to for creating a - * secure connection to the cloud application - * @param auth_token Filled with the token used for authentication when - * reconnecting to the cloud app - * @param cloud_transport_type Filled with the transport type used by the - * cloud application (ex. "WSS") - * @param hybrid_app_preference Filled with the hybrid app preference for the - * cloud application set by the user - */ - bool GetCloudAppParameters(const std::string& policy_app_id, - bool& enabled, - std::string& endpoint, - std::string& certificate, - std::string& auth_token, - std::string& cloud_transport_type, - std::string& hybrid_app_preference) const OVERRIDE; + * @brief Get a list of enabled local applications + * @return enabled_apps List filled with the policy app id of each enabled + * local application + */ + std::vector GetEnabledLocalApps() const OVERRIDE; + + bool GetAppProperties(const std::string& policy_app_id, + AppProperties& out_app_properties) const OVERRIDE; /** * @ brief Initialize new cloud app in the policy table @@ -921,6 +907,10 @@ class PolicyManagerImpl : public PolicyManager { */ void OnSystemRequestReceived() OVERRIDE; + void OnLocalAppAdded() OVERRIDE; + + bool IsNewApplication(const std::string& application_id) const OVERRIDE; + protected: /** * @brief Parse policy table content and convert to PT object @@ -1036,13 +1026,6 @@ class PolicyManagerImpl : public PolicyManager { const std::string& application_id, DeviceConsent device_consent); - /** - * @brief Check if certain application already in policy db. - * @param policy application id. - * @return true if application presents false otherwise. - */ - bool IsNewApplication(const std::string& application_id) const; - /** * Checks existing and permissions of AppStorageFolder * @return true if AppStorageFolder exists and has permissions read/write @@ -1124,6 +1107,9 @@ class PolicyManagerImpl : public PolicyManager { void SendAppPermissionsChanged(const std::string& device_id, const std::string& application_id) OVERRIDE; + void SendOnAppPropertiesChangeNotification( + const std::string& policy_app_id) const OVERRIDE; + /** * @brief notify listener of updated auth token for a given policy id * @param policy_app_id the app id that has an updated auth token @@ -1341,6 +1327,8 @@ class PolicyManagerImpl : public PolicyManager { */ bool send_on_update_sent_out_; + std::vector app_properties_changed_list_; + /** * @brief Flag for notifying that invalid PTU should be triggered */ diff --git a/src/components/policy/policy_external/include/policy/policy_types.h b/src/components/policy/policy_external/include/policy/policy_types.h index 879eb0aa9b..7e8abd5989 100644 --- a/src/components/policy/policy_external/include/policy/policy_types.h +++ b/src/components/policy/policy_external/include/policy/policy_types.h @@ -232,8 +232,11 @@ struct DeviceInfo { using namespace helpers; static const std::string bluetooth("BLUETOOTH"); static const std::string wifi("WIFI"); + static const std::string webengine("WEBENGINE_WEBSOCKET"); if (Compare(deviceType, bluetooth, wifi)) { connection_type.assign("BTMAC"); + } else if (Compare(deviceType, webengine)) { + connection_type.assign(""); } } }; @@ -452,11 +455,13 @@ struct ApplicationPolicyActions { ApplicationPolicyActions() : is_notify_system(false) , is_send_permissions_to_app(false) - , is_consent_needed(false) {} + , is_consent_needed(false) + , app_properties_changed(false) {} bool is_notify_system; bool is_send_permissions_to_app; bool is_consent_needed; + bool app_properties_changed; }; /** @@ -517,6 +522,7 @@ enum PermissionsCheckResult { RESULT_REQUEST_TYPE_CHANGED, RESULT_REQUEST_SUBTYPE_CHANGED, RESULT_ENCRYPTION_REQUIRED_FLAG_CHANGED, + RESULT_APP_PROPERTIES_CHANGED }; /** @@ -539,6 +545,68 @@ enum ConsentPriorityType { kUserConsentPrio, kExternalConsentPrio }; */ enum ConsentProcessingPolicy { kTimestampBased, kExternalConsentBased }; +/** + * @brief The AppProperties struct contains application properties + */ +struct AppProperties { + AppProperties() + : endpoint() + , certificate() + , enabled(false) + , auth_token() + , transport_type() + , hybrid_app_preference() {} + + AppProperties(std::string endpoint, + std::string certificate, + bool enabled, + std::string auth_token, + std::string transport_type, + std::string hybrid_app_preference) + : endpoint(endpoint) + , certificate(certificate) + , enabled(enabled) + , auth_token(auth_token) + , transport_type(transport_type) + , hybrid_app_preference(hybrid_app_preference) {} + + /** + * @brief endpoint Filled with the endpoint used to connect to the cloud + * application. + * @note should be absent for local applications + */ + std::string endpoint; + + /** + * @brief certificate Filled with the certificate used for creation + * of a secure connection to the cloud application + */ + std::string certificate; + + /** + * @brief enabled Whether or not the app is enabled + */ + bool enabled; + + /** + * @brief auth_token Filled with the token used for authentication when + * reconnecting to the cloud app + */ + std::string auth_token; + + /** + * @brief transport_type Filled with the transport type used by the + * cloud/local application (ex. "WSS") + */ + std::string transport_type; + + /** + * @brief hybrid_app_preference Filled with the hybrid app preference for the + * application set by the user + */ + std::string hybrid_app_preference; +}; + } // namespace policy #endif // SRC_COMPONENTS_POLICY_POLICY_EXTERNAL_INCLUDE_POLICY_POLICY_TYPES_H_ diff --git a/src/components/policy/policy_external/src/cache_manager.cc b/src/components/policy/policy_external/src/cache_manager.cc index 5bf4bfd658..a49d450a9e 100644 --- a/src/components/policy/policy_external/src/cache_manager.cc +++ b/src/components/policy/policy_external/src/cache_manager.cc @@ -1471,40 +1471,60 @@ void CacheManager::GetEnabledCloudApps( #endif // CLOUD_APP_WEBSOCKET_TRANSPORT_SUPPORT } -bool CacheManager::GetCloudAppParameters( - const std::string& policy_app_id, - bool& enabled, - std::string& endpoint, - std::string& certificate, - std::string& auth_token, - std::string& cloud_transport_type, - std::string& hybrid_app_preference) const { +bool CacheManager::GetAppProperties(const std::string& policy_app_id, + AppProperties& out_app_properties) const { const policy_table::ApplicationPolicies& policies = pt_->policy_table.app_policies_section.apps; policy_table::ApplicationPolicies::const_iterator policy_iter = policies.find(policy_app_id); if (policies.end() != policy_iter) { auto app_policy = (*policy_iter).second; - endpoint = app_policy.endpoint.is_initialized() ? *app_policy.endpoint - : std::string(); - auth_token = app_policy.auth_token.is_initialized() ? *app_policy.auth_token - : std::string(); - cloud_transport_type = app_policy.cloud_transport_type.is_initialized() - ? *app_policy.cloud_transport_type - : std::string(); - certificate = app_policy.certificate.is_initialized() - ? *app_policy.certificate - : std::string(); - hybrid_app_preference = + out_app_properties.endpoint = app_policy.endpoint.is_initialized() + ? *app_policy.endpoint + : std::string(); + out_app_properties.auth_token = app_policy.auth_token.is_initialized() + ? *app_policy.auth_token + : std::string(); + out_app_properties.transport_type = + app_policy.cloud_transport_type.is_initialized() + ? *app_policy.cloud_transport_type + : std::string(); + out_app_properties.certificate = app_policy.certificate.is_initialized() + ? *app_policy.certificate + : std::string(); + out_app_properties.hybrid_app_preference = app_policy.hybrid_app_preference.is_initialized() ? EnumToJsonString(*app_policy.hybrid_app_preference) : std::string(); - enabled = app_policy.enabled.is_initialized() && *app_policy.enabled; + out_app_properties.enabled = + app_policy.enabled.is_initialized() && *app_policy.enabled; return true; } return false; } +std::vector CacheManager::GetEnabledLocalApps() const { +#if !defined(WEBSOCKET_SERVER_TRANSPORT_SUPPORT) + return std::vector(); +#else + std::vector enabled_apps; + const policy_table::ApplicationPolicies& app_policies = + pt_->policy_table.app_policies_section.apps; + for (const auto& app_policies_item : app_policies) { + const auto app_policy = app_policies_item.second; + // Local (WebEngine) applications + // should not have "endpoint" field + if (app_policy.endpoint.is_initialized()) { + continue; + } + if (app_policy.enabled.is_initialized() && *app_policy.enabled) { + enabled_apps.push_back(app_policies_item.first); + } + } + return enabled_apps; +#endif // WEBSOCKET_SERVER_TRANSPORT_SUPPORT +} + void CacheManager::InitCloudApp(const std::string& policy_app_id) { CACHE_MANAGER_CHECK_VOID(); sync_primitives::AutoLock auto_lock(cache_lock_); diff --git a/src/components/policy/policy_external/src/policy_helper.cc b/src/components/policy/policy_external/src/policy_helper.cc index 98e5b5b3c1..b8bbb1682c 100644 --- a/src/components/policy/policy_external/src/policy_helper.cc +++ b/src/components/policy/policy_external/src/policy_helper.cc @@ -434,6 +434,13 @@ void CheckAppPolicy::InsertPermission(const std::string& app_id, bool CheckAppPolicy::operator()(const AppPoliciesValueType& app_policy) { const std::string app_id = app_policy.first; + + const bool app_properties_changed = IsAppPropertiesChanged(app_policy); + const bool is_predefined_app = IsPredefinedApp(app_policy); + if (!is_predefined_app && app_properties_changed) { + AddResult(app_id, RESULT_APP_PROPERTIES_CHANGED); + } + AppPermissions permissions_diff(app_id); if (!IsKnownAppication(app_id)) { LOG4CXX_WARN(logger_, @@ -668,6 +675,74 @@ bool CheckAppPolicy::IsRequestSubTypeChanged( return diff.size(); } +bool CheckAppPolicy::IsAppPropertiesProvided( + const AppPoliciesValueType& app_policy) const { + LOG4CXX_AUTO_TRACE(logger_); + if (app_policy.second.hybrid_app_preference.is_initialized() || + app_policy.second.endpoint.is_initialized() || + app_policy.second.enabled.is_initialized() || + app_policy.second.auth_token.is_initialized() || + app_policy.second.cloud_transport_type.is_initialized() || + app_policy.second.nicknames.is_initialized()) { + return true; + } + return false; +} + +bool CheckAppPolicy::IsAppPropertiesChanged( + const AppPoliciesValueType& app_policy) const { + LOG4CXX_AUTO_TRACE(logger_); + + if (!IsAppPropertiesProvided(app_policy)) { + return false; + } + + if (!IsKnownAppication(app_policy.first)) { + LOG4CXX_DEBUG( + logger_, + "AppProperties provided for new application: " << app_policy.first); + return true; + } + + policy::AppPoliciesConstItr it = + snapshot_->policy_table.app_policies_section.apps.find(app_policy.first); + const auto snapshot_properties = *it; + + if (app_policy.second.enabled.is_initialized() && + app_policy.second.enabled != snapshot_properties.second.enabled) { + LOG4CXX_DEBUG(logger_, "\"enabled\" was changed"); + return true; + } + + if (app_policy.second.endpoint.is_initialized() && + app_policy.second.endpoint != snapshot_properties.second.endpoint) { + LOG4CXX_DEBUG(logger_, "\"endpoint\" was changed"); + return true; + } + + if (app_policy.second.hybrid_app_preference.is_initialized() && + app_policy.second.hybrid_app_preference != + snapshot_properties.second.hybrid_app_preference) { + LOG4CXX_DEBUG(logger_, "\"hybrid_app_preference\" was changed"); + return true; + } + + if (app_policy.second.auth_token.is_initialized() && + app_policy.second.auth_token != snapshot_properties.second.auth_token) { + LOG4CXX_DEBUG(logger_, "\"auth_token\" was changed"); + return true; + } + + if (app_policy.second.cloud_transport_type.is_initialized() && + app_policy.second.cloud_transport_type != + snapshot_properties.second.cloud_transport_type) { + LOG4CXX_DEBUG(logger_, "\"cloud_transport_type\" was changed"); + return true; + } + + return false; +} + bool CheckAppPolicy::IsEncryptionRequiredFlagChanged( const AppPoliciesValueType& app_policy) const { LOG4CXX_AUTO_TRACE(logger_); @@ -778,6 +853,9 @@ void FillActionsForAppPolicies::operator()( case RESULT_PERMISSIONS_REVOKED_AND_CONSENT_NEEDED: actions_[app_id].is_consent_needed = true; break; + case RESULT_APP_PROPERTIES_CHANGED: + actions_[app_id].app_properties_changed = true; + break; case RESULT_CONSENT_NOT_REQUIRED: case RESULT_PERMISSIONS_REVOKED: case RESULT_REQUEST_TYPE_CHANGED: diff --git a/src/components/policy/policy_external/src/policy_manager_impl.cc b/src/components/policy/policy_external/src/policy_manager_impl.cc index 787e65f43a..cd2bd4c2d4 100644 --- a/src/components/policy/policy_external/src/policy_manager_impl.cc +++ b/src/components/policy/policy_external/src/policy_manager_impl.cc @@ -622,6 +622,10 @@ void PolicyManagerImpl::ProcessActionsForAppPolicies( continue; } + if (action.second.app_properties_changed) { + app_properties_changed_list_.push_back(app_policy->first); + } + const auto devices_ids = listener()->GetDevicesIds(app_policy->first); for (const auto& device_id : devices_ids) { if (action.second.is_consent_needed) { @@ -820,21 +824,13 @@ void PolicyManagerImpl::GetEnabledCloudApps( cache_->GetEnabledCloudApps(enabled_apps); } -bool PolicyManagerImpl::GetCloudAppParameters( - const std::string& policy_app_id, - bool& enabled, - std::string& endpoint, - std::string& certificate, - std::string& auth_token, - std::string& cloud_transport_type, - std::string& hybrid_app_preference) const { - return cache_->GetCloudAppParameters(policy_app_id, - enabled, - endpoint, - certificate, - auth_token, - cloud_transport_type, - hybrid_app_preference); +std::vector PolicyManagerImpl::GetEnabledLocalApps() const { + return cache_->GetEnabledLocalApps(); +} + +bool PolicyManagerImpl::GetAppProperties( + const std::string& policy_app_id, AppProperties& out_app_properties) const { + return cache_->GetAppProperties(policy_app_id, out_app_properties); } void PolicyManagerImpl::InitCloudApp(const std::string& policy_app_id) { @@ -1201,6 +1197,12 @@ void PolicyManagerImpl::AddDevice(const std::string& device_id, } } +void PolicyManagerImpl::OnLocalAppAdded() { + LOG4CXX_AUTO_TRACE(logger_); + update_status_manager_.ScheduleUpdate(); + StartPTExchange(); +} + void PolicyManagerImpl::SetDeviceInfo(const std::string& device_id, const DeviceInfo& device_info) { LOG4CXX_AUTO_TRACE(logger_); @@ -1702,6 +1704,12 @@ void PolicyManagerImpl::UpdateAppConsentWithExternalConsent( cache_->SetExternalConsentForApp(updated_external_consent_permissions); } +void PolicyManagerImpl::SendOnAppPropertiesChangeNotification( + const std::string& policy_app_id) const { + LOG4CXX_AUTO_TRACE(logger_); + listener_->SendOnAppPropertiesChangeNotification(policy_app_id); +} + void PolicyManagerImpl::ResumePendingAppPolicyActions() { LOG4CXX_AUTO_TRACE(logger_); @@ -1714,6 +1722,10 @@ void PolicyManagerImpl::ResumePendingAppPolicyActions() { SendPermissionsToApp(send_permissions_params.first, send_permissions_params.second); } + + for (auto& app : app_properties_changed_list_) { + SendOnAppPropertiesChangeNotification(app); + } send_permissions_list_.clear(); } @@ -2318,10 +2330,10 @@ bool PolicyManagerImpl::InitPT(const std::string& file_name, const bool ret = cache_->Init(file_name, settings); if (ret) { RefreshRetrySequence(); - std::vector enabled_apps; - cache_->GetEnabledCloudApps(enabled_apps); - for (auto it = enabled_apps.begin(); it != enabled_apps.end(); ++it) { - SendAuthTokenUpdated(*it); + std::vector enabled_cloud_apps; + cache_->GetEnabledCloudApps(enabled_cloud_apps); + for (auto app : enabled_cloud_apps) { + SendAuthTokenUpdated(app); } } return ret; @@ -2440,12 +2452,9 @@ void PolicyManagerImpl::SendAppPermissionsChanged( } void PolicyManagerImpl::SendAuthTokenUpdated(const std::string policy_app_id) { - bool enabled = false; - std::string end, cert, ctt, hap; - std::string auth_token; - cache_->GetCloudAppParameters( - policy_app_id, enabled, end, cert, auth_token, ctt, hap); - listener_->OnAuthTokenUpdated(policy_app_id, auth_token); + AppProperties app_properties; + cache_->GetAppProperties(policy_app_id, app_properties); + listener_->OnAuthTokenUpdated(policy_app_id, app_properties.auth_token); } void PolicyManagerImpl::OnPrimaryGroupsChanged( diff --git a/src/components/policy/policy_external/test/policy_manager_impl_ptu_test.cc b/src/components/policy/policy_external/test/policy_manager_impl_ptu_test.cc index 4fbbeaa6aa..920d2e1272 100644 --- a/src/components/policy/policy_external/test/policy_manager_impl_ptu_test.cc +++ b/src/components/policy/policy_external/test/policy_manager_impl_ptu_test.cc @@ -146,9 +146,6 @@ TEST_F(PolicyManagerImplTest2, IsAppRevoked_SetRevokedAppID_ExpectAppRevoked) { // Arrange CreateLocalPT(preloaded_pt_filename_); - EXPECT_CALL(listener_, GetDevicesIds(app_id_1_)) - .WillRepeatedly(Return(transport_manager::DeviceList())); - policy_manager_->AddApplication( device_id_1_, app_id_1_, HmiTypes(policy_table::AHT_DEFAULT)); @@ -224,8 +221,10 @@ TEST_F(PolicyManagerImplTest2, EXPECT_CALL(listener_, OnCurrentDeviceIdUpdateRequired(_, app_id_1_)) .Times(0); - EXPECT_CALL(listener_, GetDevicesIds(app_id_1_)) - .WillRepeatedly(Return(transport_manager::DeviceList(1, device_id_1_))); + ON_CALL(listener_, GetDevicesIds(_)) + .WillByDefault(Return(transport_manager::DeviceList())); + ON_CALL(listener_, GetDevicesIds(app_id_1_)) + .WillByDefault(Return(transport_manager::DeviceList(1, device_id_1_))); policy_manager_->SetUserConsentForDevice(device_id_1_, true); // Add app from consented device. App will be assigned with default policies @@ -289,8 +288,12 @@ TEST_F(PolicyManagerImplTest2, "Bluetooth")); EXPECT_CALL(listener_, OnCurrentDeviceIdUpdateRequired(_, application_id_)) .Times(0); - EXPECT_CALL(listener_, GetDevicesIds(application_id_)) - .WillRepeatedly(Return(transport_manager::DeviceList(1, device_id_1_))); + + ON_CALL(listener_, GetDevicesIds(_)) + .WillByDefault(Return(transport_manager::DeviceList())); + ON_CALL(listener_, GetDevicesIds(app_id_1_)) + .WillByDefault(Return(transport_manager::DeviceList(1, device_id_1_))); + policy_manager_->SetUserConsentForDevice(device_id_1_, true); // Add app from consented device. App will be assigned with default policies policy_manager_->AddApplication( diff --git a/src/components/policy/policy_external/test/policy_manager_impl_test_base.cc b/src/components/policy/policy_external/test/policy_manager_impl_test_base.cc index 9f363a223a..dc1d7a06ef 100644 --- a/src/components/policy/policy_external/test/policy_manager_impl_test_base.cc +++ b/src/components/policy/policy_external/test/policy_manager_impl_test_base.cc @@ -257,6 +257,8 @@ void PolicyManagerImplTest2::SetUp() { ON_CALL(listener_, GetRegisteredLinks(_)).WillByDefault(Return()); ON_CALL(listener_, ptu_retry_handler()) .WillByDefault(ReturnRef(ptu_retry_handler_)); + ON_CALL(listener_, GetDevicesIds(_)) + .WillByDefault(Return(transport_manager::DeviceList())); file_system::CreateDirectory(app_storage_folder_); @@ -675,6 +677,8 @@ PolicyManagerImplTest_RequestTypes::PolicyManagerImplTest_RequestTypes() void PolicyManagerImplTest_RequestTypes::SetUp() { ON_CALL(listener_, GetRegisteredLinks(_)).WillByDefault(Return()); + ON_CALL(listener_, GetDevicesIds(_)) + .WillByDefault(Return(transport_manager::DeviceList())); file_system::CreateDirectory(app_storage_folder_); const bool in_memory = true; diff --git a/src/components/policy/policy_regular/include/policy/cache_manager.h b/src/components/policy/policy_regular/include/policy/cache_manager.h index 6bd2c4840b..0ad7634382 100644 --- a/src/components/policy/policy_regular/include/policy/cache_manager.h +++ b/src/components/policy/policy_regular/include/policy/cache_manager.h @@ -161,6 +161,7 @@ class CacheManager : public CacheManagerInterface { const boost::optional LockScreenDismissalWarningMessage( const std::string& language) const OVERRIDE; + /** * @brief Get a list of enabled cloud applications * @param enabled_apps List filled with the policy app id of each enabled @@ -170,28 +171,14 @@ class CacheManager : public CacheManagerInterface { std::vector& enabled_apps) const; /** - * @brief Get cloud app policy information, all fields that aren't set for a - * given app will be filled with empty strings - * @param policy_app_id Unique application id - * @param enabled Whether or not the app is enabled - * @param endpoint Filled with the endpoint used to connect to the cloud - * application - * @param certificate Filled with the certificate used to for creating a - * secure connection to the cloud application - * @param auth_token Filled with the token used for authentication when - * reconnecting to the cloud app - * @param cloud_transport_type Filled with the transport type used by the - * cloud application (ex. "WSS") - * @param hybrid_app_preference Filled with the hybrid app preference for the - * cloud application set by the user - */ - virtual bool GetCloudAppParameters(const std::string& policy_app_id, - bool& enabled, - std::string& endpoint, - std::string& certificate, - std::string& auth_token, - std::string& cloud_transport_type, - std::string& hybrid_app_preference) const; + * @brief Get a list of enabled local applications + * @return enabled_apps List filled with the policy app id of each enabled + * local application + */ + std::vector GetEnabledLocalApps() const OVERRIDE; + + bool GetAppProperties(const std::string& policy_app_id, + AppProperties& out_app_properties) const OVERRIDE; /** * Initializes a new cloud application with default policies diff --git a/src/components/policy/policy_regular/include/policy/cache_manager_interface.h b/src/components/policy/policy_regular/include/policy/cache_manager_interface.h index a1b4af0f39..35a61f6597 100644 --- a/src/components/policy/policy_regular/include/policy/cache_manager_interface.h +++ b/src/components/policy/policy_regular/include/policy/cache_manager_interface.h @@ -177,29 +177,21 @@ class CacheManagerInterface { std::vector& enabled_apps) const = 0; /** - * @brief Get cloud app policy information, all fields that aren't set for a + * @brief Get a list of enabled local applications + * @return enabled_apps List filled with the policy app id of each enabled + * local application + */ + virtual std::vector GetEnabledLocalApps() const = 0; + + /** + * @brief Get app policy information, all fields that aren't set for a * given app will be filled with empty strings - * @param policy_app_id Unique application id - * @param enabled Whether or not the app is enabled - * @param endpoint Filled with the endpoint used to connect to the cloud - * application - * @param certificate Filled with the certificate used to for creating a - * secure connection to the cloud application - * @param auth_token Filled with the token used for authentication when - * reconnecting to the cloud app - * @param cloud_transport_type Filled with the transport type used by the - * cloud application (ex. "WSS") - * @param hybrid_app_preference Filled with the hybrid app preference for the - * cloud application set by the user - */ - virtual bool GetCloudAppParameters( - const std::string& policy_app_id, - bool& enabled, - std::string& endpoint, - std::string& certificate, - std::string& auth_token, - std::string& cloud_transport_type, - std::string& hybrid_app_preference) const = 0; + * @param policy_app_id policy app id + * @param out_app_properties application properties + * @return true if application presents in database, otherwise - false + */ + virtual bool GetAppProperties(const std::string& policy_app_id, + AppProperties& out_app_properties) const = 0; /** * Initializes a new cloud application with default policies diff --git a/src/components/policy/policy_regular/include/policy/policy_helper.h b/src/components/policy/policy_regular/include/policy/policy_helper.h index a8cec41715..d5155cf91b 100644 --- a/src/components/policy/policy_regular/include/policy/policy_helper.h +++ b/src/components/policy/policy_regular/include/policy/policy_helper.h @@ -131,6 +131,10 @@ struct CheckAppPolicy { bool IsEncryptionRequiredFlagChanged( const AppPoliciesValueType& app_policy) const; + bool IsAppPropertiesChanged(const AppPoliciesValueType& app_policy) const; + + bool IsAppPropertiesProvided(const AppPoliciesValueType& app_policy) const; + private: PolicyManagerImpl* pm_; const std::shared_ptr update_; diff --git a/src/components/policy/policy_regular/include/policy/policy_manager_impl.h b/src/components/policy/policy_regular/include/policy/policy_manager_impl.h index 192de6cd34..a1a39ff80b 100644 --- a/src/components/policy/policy_regular/include/policy/policy_manager_impl.h +++ b/src/components/policy/policy_regular/include/policy/policy_manager_impl.h @@ -671,6 +671,7 @@ class PolicyManagerImpl : public PolicyManager { * @return policy_table as json object */ Json::Value GetPolicyTableData() const OVERRIDE; + /** * @brief Get a list of enabled cloud applications * @param enabled_apps List filled with the policy app id of each enabled @@ -680,28 +681,14 @@ class PolicyManagerImpl : public PolicyManager { std::vector& enabled_apps) const OVERRIDE; /** - * @brief Get cloud app policy information, all fields that aren't set for a - * given app will be filled with empty strings - * @param policy_app_id Unique application id - * @param enabled Whether or not the app is enabled - * @param endpoint Filled with the endpoint used to connect to the cloud - * application - * @param certificate Filled with the certificate used to for creating a - * secure connection to the cloud application - * @param auth_token Filled with the token used for authentication when - * reconnecting to the cloud app - * @param cloud_transport_type Filled with the transport type used by the - * cloud application (ex. "WSS") - * @param hybrid_app_preference Filled with the hybrid app preference for the - * cloud application set by the user - */ - bool GetCloudAppParameters(const std::string& policy_app_id, - bool& enabled, - std::string& endpoint, - std::string& certificate, - std::string& auth_token, - std::string& cloud_transport_type, - std::string& hybrid_app_preference) const OVERRIDE; + * @brief Get a list of enabled local applications + * @return enabled_apps List filled with the policy app id of each enabled + * local application + */ + std::vector GetEnabledLocalApps() const OVERRIDE; + + bool GetAppProperties(const std::string& policy_app_id, + AppProperties& out_app_properties) const OVERRIDE; /** * @ brief Initialize new cloud app in the policy table @@ -876,6 +863,10 @@ class PolicyManagerImpl : public PolicyManager { int32_t timespan_seconds) OVERRIDE; // Interface StatisticsManager (end) + void OnLocalAppAdded() OVERRIDE; + + bool IsNewApplication(const std::string& application_id) const OVERRIDE; + void ResetTimeout() OVERRIDE; protected: @@ -983,13 +974,6 @@ class PolicyManagerImpl : public PolicyManager { void PromoteExistedApplication(const std::string& application_id, DeviceConsent device_consent); - /** - * @brief Check if certain application already in policy db. - * @param policy application id. - * @return true if application presents false otherwise. - */ - bool IsNewApplication(const std::string& application_id) const; - /** * Checks existing and permissions of AppStorageFolder * @return true if AppStorageFolder exists and has permissions read/write @@ -1077,6 +1061,9 @@ class PolicyManagerImpl : public PolicyManager { void SendAppPermissionsChanged(const std::string& device_id, const std::string& application_id) OVERRIDE; + void SendOnAppPropertiesChangeNotification( + const std::string& policy_app_id) const OVERRIDE; + /** * @brief notify listener of updated auth token for a given policy id * @param policy_app_id the app id that has an updated auth token @@ -1184,6 +1171,11 @@ class PolicyManagerImpl : public PolicyManager { */ bool send_on_update_sent_out_; + /** + * @brief List of chnaged application properties + */ + std::vector app_properties_changed_list_; + /** * @brief Flag for notifying that invalid PTU should be triggered */ diff --git a/src/components/policy/policy_regular/include/policy/policy_types.h b/src/components/policy/policy_regular/include/policy/policy_types.h index f8d71ecb13..7f95d9132b 100644 --- a/src/components/policy/policy_regular/include/policy/policy_types.h +++ b/src/components/policy/policy_regular/include/policy/policy_types.h @@ -234,8 +234,11 @@ struct DeviceInfo { using namespace helpers; static const std::string bluetooth("BLUETOOTH"); static const std::string wifi("WIFI"); + static const std::string webengine("WEBENGINE_WEBSOCKET"); if (Compare(deviceType, bluetooth, wifi)) { connection_type.assign("BTMAC"); + } else if (Compare(deviceType, webengine)) { + connection_type.assign(""); } } }; @@ -444,11 +447,13 @@ struct ApplicationPolicyActions { ApplicationPolicyActions() : is_notify_system(false) , is_send_permissions_to_app(false) - , is_consent_needed(false) {} + , is_consent_needed(false) + , app_properties_changed(false) {} bool is_notify_system; bool is_send_permissions_to_app; bool is_consent_needed; + bool app_properties_changed; }; /** @@ -508,7 +513,8 @@ enum PermissionsCheckResult { RESULT_PERMISSIONS_REVOKED_AND_CONSENT_NEEDED, RESULT_REQUEST_TYPE_CHANGED, RESULT_REQUEST_SUBTYPE_CHANGED, - RESULT_ENCRYPTION_REQUIRED_FLAG_CHANGED + RESULT_ENCRYPTION_REQUIRED_FLAG_CHANGED, + RESULT_APP_PROPERTIES_CHANGED }; /** @@ -524,6 +530,68 @@ typedef std::set > */ typedef std::pair AppIdURL; +/** + * @brief The AppProperties struct contains application properties + */ +struct AppProperties { + AppProperties() + : endpoint() + , certificate() + , enabled(false) + , auth_token() + , transport_type() + , hybrid_app_preference() {} + + AppProperties(std::string endpoint, + std::string certificate, + bool enabled, + std::string auth_token, + std::string transport_type, + std::string hybrid_app_preference) + : endpoint(endpoint) + , certificate(certificate) + , enabled(enabled) + , auth_token(auth_token) + , transport_type(transport_type) + , hybrid_app_preference(hybrid_app_preference) {} + + /** + * @brief endpoint Filled with the endpoint used to connect to the cloud + * application. + * @note should be absent for local applications + */ + std::string endpoint; + + /** + * @brief certificate Filled with the certificate used for creation + * of a secure connection to the cloud application + */ + std::string certificate; + + /** + * @brief enabled Whether or not the app is enabled + */ + bool enabled; + + /** + * @brief auth_token Filled with the token used for authentication when + * reconnecting to the cloud app + */ + std::string auth_token; + + /** + * @brief transport_type Filled with the transport type used by the + * cloud/local application (ex. "WSS") + */ + std::string transport_type; + + /** + * @brief hybrid_app_preference Filled with the hybrid app preference for the + * application set by the user + */ + std::string hybrid_app_preference; +}; + } // namespace policy #endif // SRC_COMPONENTS_POLICY_POLICY_EXTERNAL_INCLUDE_POLICY_POLICY_TYPES_H_ diff --git a/src/components/policy/policy_regular/src/cache_manager.cc b/src/components/policy/policy_regular/src/cache_manager.cc index 743b9eff6c..7a6f98f536 100644 --- a/src/components/policy/policy_regular/src/cache_manager.cc +++ b/src/components/policy/policy_regular/src/cache_manager.cc @@ -766,35 +766,55 @@ void CacheManager::GetEnabledCloudApps( #endif // CLOUD_APP_WEBSOCKET_TRANSPORT_SUPPORT } -bool CacheManager::GetCloudAppParameters( - const std::string& policy_app_id, - bool& enabled, - std::string& endpoint, - std::string& certificate, - std::string& auth_token, - std::string& cloud_transport_type, - std::string& hybrid_app_preference) const { +std::vector CacheManager::GetEnabledLocalApps() const { +#if !defined(WEBSOCKET_SERVER_TRANSPORT_SUPPORT) + return std::vector(); +#else + std::vector enabled_apps; + const policy_table::ApplicationPolicies& app_policies = + pt_->policy_table.app_policies_section.apps; + for (const auto& app_policies_item : app_policies) { + const auto app_policy = app_policies_item.second; + // Local (WebEngine) applications + // should not have "endpoint" field + if (app_policy.endpoint.is_initialized()) { + continue; + } + if (app_policy.enabled.is_initialized() && *app_policy.enabled) { + enabled_apps.push_back(app_policies_item.first); + } + } + return enabled_apps; +#endif // WEBSOCKET_SERVER_TRANSPORT_SUPPORT +} + +bool CacheManager::GetAppProperties(const std::string& policy_app_id, + AppProperties& out_app_properties) const { const policy_table::ApplicationPolicies& policies = pt_->policy_table.app_policies_section.apps; policy_table::ApplicationPolicies::const_iterator policy_iter = policies.find(policy_app_id); if (policies.end() != policy_iter) { auto app_policy = (*policy_iter).second; - endpoint = app_policy.endpoint.is_initialized() ? *app_policy.endpoint - : std::string(); - auth_token = app_policy.auth_token.is_initialized() ? *app_policy.auth_token - : std::string(); - cloud_transport_type = app_policy.cloud_transport_type.is_initialized() - ? *app_policy.cloud_transport_type - : std::string(); - certificate = app_policy.certificate.is_initialized() - ? *app_policy.certificate - : std::string(); - hybrid_app_preference = + out_app_properties.endpoint = app_policy.endpoint.is_initialized() + ? *app_policy.endpoint + : std::string(); + out_app_properties.auth_token = app_policy.auth_token.is_initialized() + ? *app_policy.auth_token + : std::string(); + out_app_properties.transport_type = + app_policy.cloud_transport_type.is_initialized() + ? *app_policy.cloud_transport_type + : std::string(); + out_app_properties.certificate = app_policy.certificate.is_initialized() + ? *app_policy.certificate + : std::string(); + out_app_properties.hybrid_app_preference = app_policy.hybrid_app_preference.is_initialized() ? EnumToJsonString(*app_policy.hybrid_app_preference) : std::string(); - enabled = app_policy.enabled.is_initialized() && *app_policy.enabled; + out_app_properties.enabled = + app_policy.enabled.is_initialized() && *app_policy.enabled; return true; } return false; diff --git a/src/components/policy/policy_regular/src/policy_helper.cc b/src/components/policy/policy_regular/src/policy_helper.cc index b689ed81ba..08f1fbb177 100644 --- a/src/components/policy/policy_regular/src/policy_helper.cc +++ b/src/components/policy/policy_regular/src/policy_helper.cc @@ -388,6 +388,12 @@ void CheckAppPolicy::AddResult(const std::string& app_id, bool CheckAppPolicy::operator()(const AppPoliciesValueType& app_policy) { const std::string app_id = app_policy.first; + const bool app_properties_changed = IsAppPropertiesChanged(app_policy); + const bool is_predefined_app = IsPredefinedApp(app_policy); + if (!is_predefined_app && app_properties_changed) { + AddResult(app_id, RESULT_APP_PROPERTIES_CHANGED); + } + if (!IsKnownAppication(app_id)) { LOG4CXX_WARN(logger_, "Application:" << app_id << " is not present in snapshot."); @@ -608,6 +614,74 @@ bool CheckAppPolicy::IsRequestSubTypeChanged( return diff.size(); } +bool CheckAppPolicy::IsAppPropertiesProvided( + const AppPoliciesValueType& app_policy) const { + LOG4CXX_AUTO_TRACE(logger_); + if (app_policy.second.hybrid_app_preference.is_initialized() || + app_policy.second.endpoint.is_initialized() || + app_policy.second.enabled.is_initialized() || + app_policy.second.auth_token.is_initialized() || + app_policy.second.cloud_transport_type.is_initialized() || + app_policy.second.nicknames.is_initialized()) { + return true; + } + return false; +} + +bool CheckAppPolicy::IsAppPropertiesChanged( + const AppPoliciesValueType& app_policy) const { + LOG4CXX_AUTO_TRACE(logger_); + + if (!IsAppPropertiesProvided(app_policy)) { + return false; + } + + if (!IsKnownAppication(app_policy.first)) { + LOG4CXX_DEBUG( + logger_, + "AppProperties provided for new application: " << app_policy.first); + return true; + } + + policy::AppPoliciesConstItr it = + snapshot_->policy_table.app_policies_section.apps.find(app_policy.first); + const auto snapshot_properties = *it; + + if (app_policy.second.enabled.is_initialized() && + app_policy.second.enabled != snapshot_properties.second.enabled) { + LOG4CXX_DEBUG(logger_, "\"enabled\" was changed"); + return true; + } + + if (app_policy.second.endpoint.is_initialized() && + app_policy.second.endpoint != snapshot_properties.second.endpoint) { + LOG4CXX_DEBUG(logger_, "\"endpoint\" was changed"); + return true; + } + + if (app_policy.second.hybrid_app_preference.is_initialized() && + app_policy.second.hybrid_app_preference != + snapshot_properties.second.hybrid_app_preference) { + LOG4CXX_DEBUG(logger_, "\"hybrid_app_preference\" was changed"); + return true; + } + + if (app_policy.second.auth_token.is_initialized() && + app_policy.second.auth_token != snapshot_properties.second.auth_token) { + LOG4CXX_DEBUG(logger_, "\"auth_token\" was changed"); + return true; + } + + if (app_policy.second.cloud_transport_type.is_initialized() && + app_policy.second.cloud_transport_type != + snapshot_properties.second.cloud_transport_type) { + LOG4CXX_DEBUG(logger_, "\"cloud_transport_type\" was changed"); + return true; + } + + return false; +} + bool CheckAppPolicy::IsEncryptionRequiredFlagChanged( const AppPoliciesValueType& app_policy) const { auto get_app_encryption_needed = @@ -699,7 +773,6 @@ void FillActionsForAppPolicies::operator()( const policy::CheckAppPolicyResults::value_type& value) { const std::string app_id = value.first; const auto app_policy = app_policies_.find(app_id); - if (app_policies_.end() == app_policy) { return; } @@ -717,6 +790,9 @@ void FillActionsForAppPolicies::operator()( case RESULT_PERMISSIONS_REVOKED_AND_CONSENT_NEEDED: actions_[app_id].is_consent_needed = true; break; + case RESULT_APP_PROPERTIES_CHANGED: + actions_[app_id].app_properties_changed = true; + break; case RESULT_CONSENT_NOT_REQUIRED: case RESULT_PERMISSIONS_REVOKED: case RESULT_REQUEST_TYPE_CHANGED: diff --git a/src/components/policy/policy_regular/src/policy_manager_impl.cc b/src/components/policy/policy_regular/src/policy_manager_impl.cc index b93850f579..94c1009086 100644 --- a/src/components/policy/policy_regular/src/policy_manager_impl.cc +++ b/src/components/policy/policy_regular/src/policy_manager_impl.cc @@ -466,6 +466,10 @@ void PolicyManagerImpl::ProcessActionsForAppPolicies( continue; } + if (it_actions->second.app_properties_changed) { + app_properties_changed_list_.push_back(app_policy->first); + } + const auto devices_ids = listener()->GetDevicesIds(app_policy->first); for (const auto& device_id : devices_ids) { if (it_actions->second.is_consent_needed) { @@ -493,6 +497,12 @@ void PolicyManagerImpl::ProcessActionsForAppPolicies( } } +void PolicyManagerImpl::SendOnAppPropertiesChangeNotification( + const std::string& policy_app_id) const { + LOG4CXX_AUTO_TRACE(logger_); + listener_->SendOnAppPropertiesChangeNotification(policy_app_id); +} + void PolicyManagerImpl::ResumePendingAppPolicyActions() { LOG4CXX_AUTO_TRACE(logger_); @@ -505,6 +515,11 @@ void PolicyManagerImpl::ResumePendingAppPolicyActions() { SendPermissionsToApp(send_permissions_params.first, send_permissions_params.second); } + + for (auto& app : app_properties_changed_list_) { + SendOnAppPropertiesChangeNotification(app); + } + send_permissions_list_.clear(); } @@ -682,6 +697,12 @@ void PolicyManagerImpl::OnAppsSearchCompleted(const bool trigger_ptu) { } } +void PolicyManagerImpl::OnLocalAppAdded() { + LOG4CXX_AUTO_TRACE(logger_); + update_status_manager_.ScheduleUpdate(); + StartPTExchange(); +} + void PolicyManagerImpl::OnAppRegisteredOnMobile( const std::string& device_id, const std::string& application_id) { StartPTExchange(); @@ -738,21 +759,13 @@ void PolicyManagerImpl::GetEnabledCloudApps( cache_->GetEnabledCloudApps(enabled_apps); } -bool PolicyManagerImpl::GetCloudAppParameters( - const std::string& policy_app_id, - bool& enabled, - std::string& endpoint, - std::string& certificate, - std::string& auth_token, - std::string& cloud_transport_type, - std::string& hybrid_app_preference) const { - return cache_->GetCloudAppParameters(policy_app_id, - enabled, - endpoint, - certificate, - auth_token, - cloud_transport_type, - hybrid_app_preference); +std::vector PolicyManagerImpl::GetEnabledLocalApps() const { + return cache_->GetEnabledLocalApps(); +} + +bool PolicyManagerImpl::GetAppProperties( + const std::string& policy_app_id, AppProperties& out_app_properties) const { + return cache_->GetAppProperties(policy_app_id, out_app_properties); } void PolicyManagerImpl::InitCloudApp(const std::string& policy_app_id) { @@ -1581,10 +1594,10 @@ bool PolicyManagerImpl::InitPT(const std::string& file_name, if (!certificate_data.empty()) { listener_->OnCertificateUpdated(certificate_data); } - std::vector enabled_apps; - cache_->GetEnabledCloudApps(enabled_apps); - for (auto it = enabled_apps.begin(); it != enabled_apps.end(); ++it) { - SendAuthTokenUpdated(*it); + std::vector enabled_cloud_apps; + cache_->GetEnabledCloudApps(enabled_cloud_apps); + for (auto app : enabled_cloud_apps) { + SendAuthTokenUpdated(app); } } return ret; @@ -1735,12 +1748,9 @@ void PolicyManagerImpl::SendAppPermissionsChanged( } void PolicyManagerImpl::SendAuthTokenUpdated(const std::string policy_app_id) { - bool enabled = false; - std::string end, cert, ctt, hap; - std::string auth_token; - cache_->GetCloudAppParameters( - policy_app_id, enabled, end, cert, auth_token, ctt, hap); - listener_->OnAuthTokenUpdated(policy_app_id, auth_token); + AppProperties app_properties; + cache_->GetAppProperties(policy_app_id, app_properties); + listener_->OnAuthTokenUpdated(policy_app_id, app_properties.auth_token); } void PolicyManagerImpl::OnPrimaryGroupsChanged( diff --git a/src/components/policy/policy_regular/test/policy_manager_impl_test.cc b/src/components/policy/policy_regular/test/policy_manager_impl_test.cc index abb5901690..08e8dd4023 100644 --- a/src/components/policy/policy_regular/test/policy_manager_impl_test.cc +++ b/src/components/policy/policy_regular/test/policy_manager_impl_test.cc @@ -1328,6 +1328,8 @@ TEST_F( // Arrange CreateLocalPT("sdl_preloaded_pt.json"); EXPECT_EQ("UP_TO_DATE", manager->GetPolicyTableStatus()); + ON_CALL(listener, GetDevicesIds(_)) + .WillByDefault(Return(transport_manager::DeviceList())); GetPTU("valid_sdl_pt_update.json"); EXPECT_EQ("UP_TO_DATE", manager->GetPolicyTableStatus()); // Try to add existing app @@ -1342,6 +1344,8 @@ TEST_F(PolicyManagerImplTest2, UpdateApplication_AppServices) { // Arrange CreateLocalPT("sdl_preloaded_pt.json"); EXPECT_EQ("UP_TO_DATE", manager->GetPolicyTableStatus()); + ON_CALL(listener, GetDevicesIds(_)) + .WillByDefault(Return(transport_manager::DeviceList())); GetPTU("valid_sdl_pt_update.json"); EXPECT_EQ("UP_TO_DATE", manager->GetPolicyTableStatus()); // Try to add existing app @@ -1376,6 +1380,8 @@ TEST_F(PolicyManagerImplTest2, const int kSecondsInDay = 60 * 60 * 24; int days = date_time::getSecs(current_time) / kSecondsInDay; EXPECT_EQ("UP_TO_DATE", manager->GetPolicyTableStatus()); + ON_CALL(listener, GetDevicesIds(_)) + .WillByDefault(Return(transport_manager::DeviceList())); GetPTU("valid_sdl_pt_update.json"); EXPECT_EQ("UP_TO_DATE", manager->GetPolicyTableStatus()); diff --git a/src/components/transport_manager/CMakeLists.txt b/src/components/transport_manager/CMakeLists.txt index a539c64578..82cc00baf2 100644 --- a/src/components/transport_manager/CMakeLists.txt +++ b/src/components/transport_manager/CMakeLists.txt @@ -106,6 +106,18 @@ else() ) endif() +if(NOT BUILD_WEBSOCKET_SERVER_SUPPORT) + list(APPEND EXCLUDE_PATHS + ${CMAKE_CURRENT_SOURCE_DIR}/include/transport_manager/websocket_server + ${CMAKE_CURRENT_SOURCE_DIR}/src/websocket_server + ) +elseif(NOT ENABLE_SECURITY) + list(APPEND EXCLUDE_PATHS + ${CMAKE_CURRENT_SOURCE_DIR}/include/transport_manager/websocket_server/websocket_secure_session.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/websocket_server/websocket_secure_session.cc + ) +endif() + if(NOT ENABLE_IAP2EMULATION) list (APPEND EXCLUDE_PATHS ${CMAKE_CURRENT_SOURCE_DIR}/include/iap2_emulation/iap2_transport_adapter.h diff --git a/src/components/transport_manager/docs/SDL.SDD.WebEngineSupport.dox b/src/components/transport_manager/docs/SDL.SDD.WebEngineSupport.dox new file mode 100644 index 0000000000..77ab46e247 --- /dev/null +++ b/src/components/transport_manager/docs/SDL.SDD.WebEngineSupport.dox @@ -0,0 +1,127 @@ +/** +\page web_engine_support Web Engine Support Detailed Design +## Table of contents +- \subpage wes_intoduction + + \ref wes_rationale "1.1 Rationale" + + \ref wes_scope "1.2 Scope" +- \subpage wes_detail_design + + \ref wes_design_solutions "2.1 Design solutions" + + \ref wes_class_structure "2.2 Class Structure" + + \ref wes_sequence_diagram "2.3 Sequence diagram" +- \subpage wes_data_structures + + \ref wes_data_structure "3.1 Data structures" +- \subpage wes_references_and_history + + \ref wes_history "4.1 References" +*/ +//----------------------------------------------------------- +/** +\page wes_intoduction 1 Introduction +The document is intended to support software developers, +maintenance and integration engineers with sufficient, +detailed information concerning the design, development and +deployment concepts, to accomplish their respective tasks without reliance on the authors. + +\anchor wes_rationale +## 1.1 Rationale +Boost asio libraries were utilized to enable websocket server connection for web engine. +To split responsibilities, the following entities were introduces to enable server connections: +- WebSocketListener +- WebSocketConnection +- WebSocketSession +- WebSocketSecureSession + + +\anchor wes_scope +## 1.2 Scope +All aforementioned entities are part of transport_manager namespace + +*/ +//----------------------------------------------------------- +/** +\page wes_detail_design 2 Component detail design +\anchor wes_design_solutions +### 2.1 Design solutions + +- WebSocket server was implemented using several layers (e.g. WebSocketConnection, WebSocketSession, WebSocketSecureSession). +- Utilizing boost::asio library to host a websocket server and establish websocket connections +- Utilizing asynchronous programming to make all server calls nonblocking +- CRTP and template specialization to facilitate code reuse. + + + +#### Design description +transport_manager::WebSocketListener is an entity that is responsible for creating and listening for connections. +It includes creating boost library objects to establish a connection, deducing security parameters during its initialization, +opening a port and accepting new connections. +The following parameters are used to configure security connection: +- WSServerCertificatePath (path to websocket server certificate) +- WSServerKeyPath (path to websocket server private key path) +- WSServerCACertificatePath (path to CA certificate) + +SDL will run in WSS mode only if ALL these parameters are present and have valid values. +To run SDL as a WS server, one should remove ALL these parameters from smartDeviceLink.ini file (including parameter KEY and VALUE). +All other cases of parameter configuration (e.g. two of three params are set) are considered to be misconfiguration, +and SDL will launch with no websocket server transport. + +transport_manager::WebSocketConnection is a class that is used as an additional layer between WebSocketListener and WebSocketSession, +with ability to hadle input/output errors. + +transport_manager::WebSocketSession is a class that represents the lowest layer of abstraction in regards of WS server connection. It is used to read +data from socket to buffer and notifying its observers about connection events. + +transport_manager::WebSocketSecureSession is a class that inherits WebSocketSession with an additional role of supporting TLS handshake. + +\anchor wes_class_structure +### 2.2 Class Structure +The following UML class diagram shows the component structure: +![Web Engine Support class diagram](WES_classes.png) +For more information about class diagram follow: +- http://www.uml-diagrams.org/class-diagrams-overview.htqml +- https://sourcemaking.com/uml/modeling-it-systems/structural-view/class-diagram + +\anchor wes_sequence_diagram +### 2.3 Sequence diagram +The following UML sequence diagram shows the component dynamic behavior. +For more information about sequence diagram follow: +- http://www.uml-diagrams.org/sequence-diagrams.html +- https://sourcemaking.com/uml/modeling-it-systems/external-view/use-case-sequence-diagram + +Establishing WebSocket connection: +![WES Basic flow](WES_sequence.png) +*/ + +//----------------------------------------------------------- +/** +\page wes_data_structures 3 Component data and resources +\anchor wes_data_structure +### 3.1 Element Data Structure +The following data types are used by WebSocketListener: + - transport_manager::TransportAdapterController + - boost::asio::io_context + - boost::ssl::context + - boost::asio::tcp::acceptor + - boost::asio::tcp::socket + - boost::asio::thread_pool + - WebSocketConnection + - transport_manager::TransportManagerSettings + +//----------------------------------------------------------- +/** +\page wes_references_and_history 4 References and history +\anchor wes_history +### 4.1 Document history +Document change history + +| Version | Date | Author/Editor | Change description | +|-------------|------------|----------------------------------------|---------------------| +| 0.1 | 02/03/2020 | [MKed](https://github.com/mked-luxoft) | Initial version from the previous [SDL SDD](https://adc.luxoft.com/confluence/pages/viewpage.action?pageId=279677125) | + +Document approve history + +| Version | Date | Author/Editor | Change description | +|-------------|------------|-----------------------------|---------------------| +| | | | | + +For more precise document change history follow github history - +- https://github.com/smartdevicelink/sdl_core/commits/develop/src/components/transport_manager/docs/SDL.SDD.WebEngineSupport.dox +*/ \ No newline at end of file diff --git a/src/components/transport_manager/docs/assets/WES_classes.png b/src/components/transport_manager/docs/assets/WES_classes.png new file mode 100644 index 0000000000..bbb19b8f02 Binary files /dev/null and b/src/components/transport_manager/docs/assets/WES_classes.png differ diff --git a/src/components/transport_manager/docs/assets/WES_sequence.png b/src/components/transport_manager/docs/assets/WES_sequence.png new file mode 100644 index 0000000000..61aa5e35fb Binary files /dev/null and b/src/components/transport_manager/docs/assets/WES_sequence.png differ diff --git a/src/components/transport_manager/include/transport_manager/transport_adapter/transport_adapter_controller.h b/src/components/transport_manager/include/transport_manager/transport_adapter/transport_adapter_controller.h index 72a67a3087..92a3a2c2f4 100644 --- a/src/components/transport_manager/include/transport_manager/transport_adapter/transport_adapter_controller.h +++ b/src/components/transport_manager/include/transport_manager/transport_adapter/transport_adapter_controller.h @@ -225,6 +225,8 @@ class TransportAdapterController { * @param new_config The new configuration of the transport */ virtual void TransportConfigUpdated(const TransportConfig& new_config) = 0; + + virtual DeviceSptr GetWebEngineDevice() const = 0; }; } // namespace transport_adapter diff --git a/src/components/transport_manager/include/transport_manager/transport_adapter/transport_adapter_impl.h b/src/components/transport_manager/include/transport_manager/transport_adapter/transport_adapter_impl.h index db9bb03998..f8aa93b4e6 100644 --- a/src/components/transport_manager/include/transport_manager/transport_adapter/transport_adapter_impl.h +++ b/src/components/transport_manager/include/transport_manager/transport_adapter/transport_adapter_impl.h @@ -283,13 +283,6 @@ class TransportAdapterImpl : public TransportAdapter, */ void SearchDeviceFailed(const SearchDeviceError& error) OVERRIDE; - /** - * @brief Add device to the container(map), if container doesn't hold it yet. - * - * @param device Smart pointer to the device. - * - * @return Smart pointer to the device. - */ DeviceSptr AddDevice(DeviceSptr device) OVERRIDE; /** @@ -517,6 +510,12 @@ class TransportAdapterImpl : public TransportAdapter, TMTelemetryObserver* GetTelemetryObserver() OVERRIDE; #endif // TELEMETRY_MONITOR + /** + * @brief GetWebEngineDevice + * @return shared pointer to WebEngine device + */ + DeviceSptr GetWebEngineDevice() const OVERRIDE; + protected: /** * @brief Store adapter state where applicable diff --git a/src/components/transport_manager/include/transport_manager/transport_manager_default.h b/src/components/transport_manager/include/transport_manager/transport_manager_default.h index 9d428cf817..81fc92dc38 100644 --- a/src/components/transport_manager/include/transport_manager/transport_manager_default.h +++ b/src/components/transport_manager/include/transport_manager/transport_manager_default.h @@ -61,6 +61,10 @@ struct TransportAdapterFactory { CreatorTA ta_cloud_creator_; #endif +#if defined(WEBSOCKET_SERVER_TRANSPORT_SUPPORT) + CreatorTA + ta_websocket_server_creator_; +#endif }; /** diff --git a/src/components/transport_manager/include/transport_manager/transport_manager_impl.h b/src/components/transport_manager/include/transport_manager/transport_manager_impl.h index 2fbd592b72..a765bb045a 100644 --- a/src/components/transport_manager/include/transport_manager/transport_manager_impl.h +++ b/src/components/transport_manager/include/transport_manager/transport_manager_impl.h @@ -262,6 +262,10 @@ class TransportManagerImpl int PerformActionOnClients( const TransportAction required_action) const OVERRIDE; + void CreateWebEngineDevice() OVERRIDE; + + const DeviceInfo& GetWebEngineDeviceInfo() const OVERRIDE; + /** * @brief OnDeviceListUpdated updates device list and sends appropriate * notifications to listeners in case of something is changed @@ -421,6 +425,8 @@ class TransportManagerImpl sync_primitives::Lock events_processing_lock_; sync_primitives::ConditionalVariable events_processing_cond_var_; + DeviceInfo web_engine_device_info_; + /** * @brief Adds new incoming connection to connections list * @param c New connection diff --git a/src/components/transport_manager/include/transport_manager/websocket_server/websocket_connection.h b/src/components/transport_manager/include/transport_manager/websocket_server/websocket_connection.h new file mode 100644 index 0000000000..fb904d645e --- /dev/null +++ b/src/components/transport_manager/include/transport_manager/websocket_server/websocket_connection.h @@ -0,0 +1,126 @@ +/* +Copyright (c) 2020 Livio, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of SmartDeviceLink Consortium, Inc. nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef SRC_COMPONENTS_TRANSPORT_MANAGER_INCLUDE_TRANSPORT_MANAGER_WEBSOCKET_SERVER_WEBSOCKET_CONNECTION_H_ +#define SRC_COMPONENTS_TRANSPORT_MANAGER_INCLUDE_TRANSPORT_MANAGER_WEBSOCKET_SERVER_WEBSOCKET_CONNECTION_H_ + +#include +#include +#include "transport_manager/transport_adapter/connection.h" +#include "utils/message_queue.h" +#include "utils/threads/thread.h" + +#ifdef ENABLE_SECURITY +#include "transport_manager/websocket_server/websocket_secure_session.h" +#else +#include "transport_manager/websocket_server/websocket_session.h" +#endif // ENABLE_SECURITY + +namespace transport_manager { +namespace transport_adapter { + +using ::utils::MessageQueue; + +typedef ::protocol_handler::RawMessagePtr Message; +typedef std::queue AsyncQueue; + +class TransportAdapterController; + +template > +class WebSocketConnection + : public std::enable_shared_from_this >, + public Connection { + public: + WebSocketConnection(const DeviceUID& device_uid, + const ApplicationHandle& app_handle, + boost::asio::ip::tcp::socket socket, + TransportAdapterController* controller); + +#ifdef ENABLE_SECURITY + WebSocketConnection(const DeviceUID& device_uid, + const ApplicationHandle& app_handle, + boost::asio::ip::tcp::socket socket, + ssl::context& ctx, + TransportAdapterController* controller); +#endif // ENABLE_SECURITY + + ~WebSocketConnection(); + + TransportAdapter::Error Disconnect() OVERRIDE; + + TransportAdapter::Error SendData( + protocol_handler::RawMessagePtr message) OVERRIDE; + + void DataReceive(protocol_handler::RawMessagePtr frame); + void Run(); + bool IsShuttingDown(); + + protected: + void Shutdown(); + void OnError(); + + private: + const DeviceUID device_uid_; + const ApplicationHandle app_handle_; + std::shared_ptr session_; + TransportAdapterController* controller_; + + std::atomic_bool shutdown_; + + MessageQueue message_queue_; + + class LoopThreadDelegate : public threads::ThreadDelegate { + public: + LoopThreadDelegate(MessageQueue* message_queue, + DataWriteCallback data_write, + OnIOErrorCallback on_io_error); + + virtual void threadMain() OVERRIDE; + virtual void exitThreadMain() OVERRIDE; + + void OnWrite(); + + void SetShutdown(); + + private: + void DrainQueue(); + MessageQueue& message_queue_; + DataWriteCallback data_write_; + OnIOErrorCallback on_io_error_; + }; + + LoopThreadDelegate* thread_delegate_; + threads::Thread* thread_; +}; + +} // namespace transport_adapter +} // namespace transport_manager + +#endif // SRC_COMPONENTS_TRANSPORT_MANAGER_INCLUDE_TRANSPORT_MANAGER_WEBSOCKET_SERVER_WEBSOCKET_CONNECTION_H_ diff --git a/src/components/transport_manager/include/transport_manager/websocket_server/websocket_device.h b/src/components/transport_manager/include/transport_manager/websocket_server/websocket_device.h new file mode 100644 index 0000000000..10c6e54424 --- /dev/null +++ b/src/components/transport_manager/include/transport_manager/websocket_server/websocket_device.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2020, Livio + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \file websocket_device.h + * \brief WebSocketDevice class header file. + */ + +#ifndef SRC_COMPONENTS_TRANSPORT_MANAGER_INCLUDE_TRANSPORT_MANAGER_WEBSOCKET_SERVER_WEBSOCKET_DEVICE_H_ +#define SRC_COMPONENTS_TRANSPORT_MANAGER_INCLUDE_TRANSPORT_MANAGER_WEBSOCKET_SERVER_WEBSOCKET_DEVICE_H_ + +#include +#include +#include "transport_manager/transport_adapter/device.h" + +namespace transport_manager { +namespace transport_adapter { + +using tcp = boost::asio::ip::tcp; // from +using protocol_type = boost::asio::basic_stream_socket::protocol_type; + +class WebSocketDevice : public Device { + public: + WebSocketDevice(const std::string& name, const DeviceUID& unique_device_id); + + virtual const std::string& GetHost() const; + virtual const std::string& GetPort() const; + virtual const std::string GetTarget() const; + virtual void AddApplication(const ApplicationHandle& app_handle); + + protected: + bool IsSameAs(const Device* other_device) const OVERRIDE; + ApplicationList GetApplicationList() const OVERRIDE; + + private: + std::string host_; + std::string port_; + bool is_secure_connect_; + protocol_type protocol_; + ApplicationList app_list_; +}; + +} // namespace transport_adapter +} // namespace transport_manager + +#endif // SRC_COMPONENTS_TRANSPORT_MANAGER_INCLUDE_TRANSPORT_MANAGER_WEBSOCKET_SERVER_WEBSOCKET_DEVICE_H_ diff --git a/src/components/transport_manager/include/transport_manager/websocket_server/websocket_listener.h b/src/components/transport_manager/include/transport_manager/websocket_server/websocket_listener.h new file mode 100644 index 0000000000..3a0131f087 --- /dev/null +++ b/src/components/transport_manager/include/transport_manager/websocket_server/websocket_listener.h @@ -0,0 +1,120 @@ +/* + * \file websocket_listener.h + * \brief WebSocketListener class header file. + * + * Copyright (c) 2020 + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SRC_COMPONENTS_TRANSPORT_MANAGER_INCLUDE_TRANSPORT_MANAGER_WEBSOCKET_SERVER_WEBSOCKET_LISTENER_H_ +#define SRC_COMPONENTS_TRANSPORT_MANAGER_INCLUDE_TRANSPORT_MANAGER_WEBSOCKET_SERVER_WEBSOCKET_LISTENER_H_ + +#include +#include +#include +#include "transport_manager/transport_adapter/client_connection_listener.h" +#include "transport_manager/transport_manager_settings.h" +#include "transport_manager/websocket_server/websocket_connection.h" + +namespace transport_manager { +namespace transport_adapter { + +class TransportAdapterController; + +/** + * @brief Class responsible for communication over websockets. + */ +class WebSocketListener : public ClientConnectionListener { + public: + /** + * @brief Constructor. + * @param controller Pointer to the device adapter controller. + * @param number of threads for listen incoming connections + */ + WebSocketListener(TransportAdapterController* controller, + const TransportManagerSettings& settings, + const int num_threads = 1); + + /** + * @brief Destructor. + */ + ~WebSocketListener(); + + TransportAdapter::Error Init() OVERRIDE; + void Terminate() OVERRIDE; + bool IsInitialised() const OVERRIDE { + return true; + } + TransportAdapter::Error StartListening() OVERRIDE; + TransportAdapter::Error StopListening() OVERRIDE { + return TransportAdapter::OK; + } + TransportAdapter::Error SuspendListening() OVERRIDE { + return TransportAdapter::OK; + } + TransportAdapter::Error ResumeListening() OVERRIDE { + return TransportAdapter::OK; + } + + protected: +#ifdef ENABLE_SECURITY + TransportAdapter::Error AddCertificateAuthority(); +#endif + bool Run(); + bool WaitForConnection(); + void StartSession(boost::system::error_code ec); + void Shutdown(); + + template + void ProcessConnection(std::shared_ptr connection, + const DeviceSptr, + const ApplicationHandle); + + private: + TransportAdapterController* controller_; + boost::asio::io_context ioc_; +#ifdef ENABLE_SECURITY + ssl::context ctx_; + bool start_secure_; +#endif // ENABLE_SECURITY + tcp::acceptor acceptor_; + tcp::socket socket_; + std::unique_ptr io_pool_; + const int num_threads_; + std::atomic_bool shutdown_; + std::vector > connection_list_; + sync_primitives::Lock connection_list_lock; + const TransportManagerSettings& settings_; +}; + +} // namespace transport_adapter +} // namespace transport_manager + +#endif // SRC_COMPONENTS_TRANSPORT_MANAGER_INCLUDE_TRANSPORT_MANAGER_WEBSOCKET_SERVER_WEBSOCKET_LISTENER_H_ diff --git a/src/components/transport_manager/include/transport_manager/websocket_server/websocket_secure_session.h b/src/components/transport_manager/include/transport_manager/websocket_server/websocket_secure_session.h new file mode 100644 index 0000000000..a3ead8e5a5 --- /dev/null +++ b/src/components/transport_manager/include/transport_manager/websocket_server/websocket_secure_session.h @@ -0,0 +1,64 @@ +/* +Copyright (c) 2020 Livio, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of SmartDeviceLink Consortium, Inc. nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef SRC_COMPONENTS_TRANSPORT_MANAGER_INCLUDE_TRANSPORT_MANAGER_WEBSOCKET_SERVER_WEBSOCKET_SECURE_SESSION_H_ +#define SRC_COMPONENTS_TRANSPORT_MANAGER_INCLUDE_TRANSPORT_MANAGER_WEBSOCKET_SERVER_WEBSOCKET_SECURE_SESSION_H_ + +#include +#include "transport_manager/websocket_server/websocket_session.h" + +namespace transport_manager { +namespace transport_adapter { + +CREATE_LOGGERPTR_GLOBAL(wss_logger_, "WebSocketSecureSession") + +template > +class WebSocketSecureSession : public WebSocketSession { + public: + WebSocketSecureSession(tcp::socket, + ssl::context& ctx, + DataReceiveCallback data_receive, + OnIOErrorCallback on_errror); + + void AsyncAccept() OVERRIDE; + virtual void AsyncHandshake(boost::system::error_code ec); + + std::shared_ptr > shared_from_this() { + auto base_ptr = + static_cast*>(this)->shared_from_this(); + return std::static_pointer_cast >( + base_ptr); + } +}; + +} // namespace transport_adapter +} // namespace transport_manager + +#endif // SRC_COMPONENTS_TRANSPORT_MANAGER_INCLUDE_TRANSPORT_MANAGER_WEBSOCKET_SERVER_WEBSOCKET_SECURE_SESSION_H_ diff --git a/src/components/transport_manager/include/transport_manager/websocket_server/websocket_server_transport_adapter.h b/src/components/transport_manager/include/transport_manager/websocket_server/websocket_server_transport_adapter.h new file mode 100644 index 0000000000..23122b2e98 --- /dev/null +++ b/src/components/transport_manager/include/transport_manager/websocket_server/websocket_server_transport_adapter.h @@ -0,0 +1,136 @@ +/* + * \file websocket_transport_adapter.h + * \brief WebSocketTransportAdapter class header file. + * + * Copyright (c) 2020, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SRC_COMPONENTS_TRANSPORT_MANAGER_INCLUDE_TRANSPORT_MANAGER_WEBSOCKET_SERVER_WEBSOCKET_SERVER_TRANSPORT_ADAPTER_H_ +#define SRC_COMPONENTS_TRANSPORT_MANAGER_INCLUDE_TRANSPORT_MANAGER_WEBSOCKET_SERVER_WEBSOCKET_SERVER_TRANSPORT_ADAPTER_H_ + +#include +#include "transport_manager/transport_adapter/transport_adapter_impl.h" + +namespace transport_manager { +namespace transport_adapter { + +/** + * @brief Transport adapter that uses WebSocket transport. + */ +class WebSocketServerTransportAdapter : public TransportAdapterImpl { + public: + /** + * @brief Constructor. + */ + WebSocketServerTransportAdapter( + resumption::LastStateWrapperPtr last_state_wrapper, + const TransportManagerSettings& settings); + + /** + * @brief Destructor. + */ + virtual ~WebSocketServerTransportAdapter(); + + /** + * @brief Websocket server transport adapter + * specific Init() method + * @note Perform additional actions required by WS transport adapter + * then calls basic class Init() + */ + TransportAdapter::Error Init() OVERRIDE; + + /** + * @brief Adds webengine device to internal storage + * of related WebSocket transport adapter + * @param device webengine device to add + * @note webengine device storage required + * to be used in Low Voltage conditions + */ + DeviceSptr AddDevice(DeviceSptr device) OVERRIDE; + + /** + * @brief Notification that transport's configuration is updated + * + * @param new_config The new configuration of the transport + */ + void TransportConfigUpdated(const TransportConfig& new_config) OVERRIDE; + + /** + * @brief Returns the transport's configuration information + */ + virtual TransportConfig GetTransportConfiguration() const OVERRIDE; + + /** + * @brief Store adapter state in last state + */ + void Store() const OVERRIDE; + + /** + * @brief Restore adapter state from last state + * @return True on success false otherwise + */ + bool Restore() OVERRIDE; + + /** + * @brief Get stored device ID + * @return stored unique device id, or empty string if no stored device id + * present in last saved state + */ + std::string GetStoredDeviceID() const; + + protected: + /** + * @brief Return type of device. + * + * @return String with device type. + */ + DeviceType GetDeviceType() const OVERRIDE; + + private: + /** + * @brief Keeps transport specific configuration + * + * TCP transport uses following information: + * - "enabled": whether the transport is currently enabled or not. Value can + * be "true" or "false". + * - "tcp_ip_address": string representation of IP address (either IPv4 or + * IPv6) + * - "tcp_port": string representation of TCP port number (e.g. "12345") + */ + TransportConfig transport_config_; + DeviceSptr webengine_device_; + std::string webengine_device_id_; +}; + +} // namespace transport_adapter +} // namespace transport_manager + +#endif // SRC_COMPONENTS_TRANSPORT_MANAGER_INCLUDE_TRANSPORT_MANAGER_WEBSOCKET_SERVER_WEBSOCKET_SERVER_TRANSPORT_ADAPTER_H_ diff --git a/src/components/transport_manager/include/transport_manager/websocket_server/websocket_session.h b/src/components/transport_manager/include/transport_manager/websocket_server/websocket_session.h new file mode 100644 index 0000000000..a8dadc9831 --- /dev/null +++ b/src/components/transport_manager/include/transport_manager/websocket_server/websocket_session.h @@ -0,0 +1,107 @@ +/* +Copyright (c) 2020 Livio, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of SmartDeviceLink Consortium, Inc. nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef SRC_COMPONENTS_TRANSPORT_MANAGER_INCLUDE_TRANSPORT_MANAGER_WEBSOCKET_SERVER_WEBSOCKET_SESSION_H_ +#define SRC_COMPONENTS_TRANSPORT_MANAGER_INCLUDE_TRANSPORT_MANAGER_WEBSOCKET_SERVER_WEBSOCKET_SESSION_H_ + +#include +#include +#include +#include +#include "protocol/raw_message.h" +#include "transport_manager/transport_adapter/transport_adapter.h" +#include "utils/logger.h" + +#ifdef ENABLE_SECURITY +#include +#endif // ENABLE_SECURITY + +namespace transport_manager { +namespace transport_adapter { + +using DataReceiveCallback = + std::function; +using DataWriteCallback = std::function; +using OnIOErrorCallback = std::function; + +using tcp = boost::asio::ip::tcp; // from +namespace websocket = + boost::beast::websocket; // from +#ifdef ENABLE_SECURITY +namespace ssl = boost::asio::ssl; // from +#endif // ENABLE_SECURITY + +CREATE_LOGGERPTR_GLOBAL(ws_logger_, "WebSocketSession") + +class TransportAdapterController; + +template +class WebSocketSession + : public std::enable_shared_from_this > { + public: + WebSocketSession(boost::asio::ip::tcp::socket socket, + DataReceiveCallback data_receive, + OnIOErrorCallback on_error); + +#ifdef ENABLE_SECURITY + WebSocketSession(boost::asio::ip::tcp::socket socket, + ssl::context& ctx, + DataReceiveCallback data_receive, + OnIOErrorCallback on_error); +#endif // ENABLE_SECURITY + + virtual ~WebSocketSession(); + + virtual void AsyncAccept(); + + virtual void AsyncRead(boost::system::error_code ec); + + virtual TransportAdapter::Error WriteDown( + ::protocol_handler::RawMessagePtr message); + + virtual void Read(boost::system::error_code ec, + std::size_t bytes_transferred); + + virtual bool Shutdown(); + + protected: + tcp::socket socket_; + websocket::stream ws_; + boost::asio::strand strand_; + boost::beast::flat_buffer buffer_; + DataReceiveCallback data_receive_; + OnIOErrorCallback on_io_error_; +}; + +} // namespace transport_adapter +} // namespace transport_manager + +#endif // SRC_COMPONENTS_TRANSPORT_MANAGER_INCLUDE_TRANSPORT_MANAGER_WEBSOCKET_SERVER_WEBSOCKET_SESSION_H_ diff --git a/src/components/transport_manager/src/transport_adapter/transport_adapter_impl.cc b/src/components/transport_manager/src/transport_adapter/transport_adapter_impl.cc index 4e057aee63..fcae508747 100644 --- a/src/components/transport_manager/src/transport_adapter/transport_adapter_impl.cc +++ b/src/components/transport_manager/src/transport_adapter/transport_adapter_impl.cc @@ -40,6 +40,9 @@ #include "transport_manager/transport_adapter/server_connection_factory.h" #include "transport_manager/transport_adapter/transport_adapter_impl.h" #include "transport_manager/transport_adapter/transport_adapter_listener.h" +#ifdef WEBSOCKET_SERVER_TRANSPORT_SUPPORT +#include "transport_manager/websocket_server/websocket_device.h" +#endif namespace transport_manager { namespace transport_adapter { @@ -62,8 +65,9 @@ DeviceTypes devicesType = { std::string("USB_IOS_DEVICE_MODE")), std::make_pair(DeviceType::IOS_CARPLAY_WIRELESS, std::string("CARPLAY_WIRELESS_IOS")), - std::make_pair(DeviceType::CLOUD_WEBSOCKET, - std::string("CLOUD_WEBSOCKET"))}; + std::make_pair(DeviceType::CLOUD_WEBSOCKET, std::string("CLOUD_WEBSOCKET")), + std::make_pair(DeviceType::WEBENGINE_WEBSOCKET, + std::string("WEBENGINE_WEBSOCKET"))}; } TransportAdapterImpl::TransportAdapterImpl( @@ -373,6 +377,10 @@ TransportAdapter::Error TransportAdapterImpl::DisconnectDevice( Error error = OK; DeviceSptr device = FindDevice(device_id); + if (!device) { + LOG4CXX_WARN(logger_, "Device with id: " << device_id << " Not found"); + return BAD_PARAM; + } ConnectionStatusUpdated(device, ConnectionStatus::CLOSING); std::vector to_disconnect; @@ -488,6 +496,32 @@ DeviceList TransportAdapterImpl::GetDeviceList() const { return devices; } +DeviceSptr TransportAdapterImpl::GetWebEngineDevice() const { +#ifndef WEBSOCKET_SERVER_TRANSPORT_SUPPORT + LOG4CXX_TRACE(logger_, + "Web engine support is disabled. Device does not exist"); + return DeviceSptr(); +#else + LOG4CXX_AUTO_TRACE(logger_); + sync_primitives::AutoLock locker(devices_mutex_); + + auto web_engine_device = + std::find_if(devices_.begin(), + devices_.end(), + [](const std::pair device) { + return webengine_constants::kWebEngineDeviceName == + device.second->name(); + }); + + if (devices_.end() != web_engine_device) { + return web_engine_device->second; + } + + LOG4CXX_ERROR(logger_, "WebEngine device not found!"); + return std::make_shared("", ""); +#endif +} + DeviceSptr TransportAdapterImpl::AddDevice(DeviceSptr device) { LOG4CXX_TRACE(logger_, "enter. device: " << device); DeviceSptr existing_device; diff --git a/src/components/transport_manager/src/transport_manager_default.cc b/src/components/transport_manager/src/transport_manager_default.cc index 0cf9e93f40..74c5b9ceee 100644 --- a/src/components/transport_manager/src/transport_manager_default.cc +++ b/src/components/transport_manager/src/transport_manager_default.cc @@ -48,6 +48,10 @@ #include "transport_manager/cloud/cloud_websocket_transport_adapter.h" #endif // CLOUD_APP_WEBSOCKET_TRANSPORT_SUPPORT +#ifdef WEBSOCKET_SERVER_TRANSPORT_SUPPORT +#include "transport_manager/websocket_server/websocket_server_transport_adapter.h" +#endif + #if defined(ENABLE_IAP2EMULATION) #include "transport_manager/iap2_emulation/iap2_transport_adapter.h" #endif // ENABLE_IAP2EMULATION @@ -82,6 +86,15 @@ TransportAdapterFactory::TransportAdapterFactory() { last_state_wrapper, settings); }; #endif + +#if defined(WEBSOCKET_SERVER_TRANSPORT_SUPPORT) + ta_websocket_server_creator_ = + [](resumption::LastStateWrapperPtr last_state_wrapper, + const TransportManagerSettings& settings) { + return new transport_adapter::WebSocketServerTransportAdapter( + last_state_wrapper, settings); + }; +#endif } TransportManagerDefault::TransportManagerDefault( @@ -143,6 +156,19 @@ int TransportManagerDefault::Init( AddTransportAdapter(ta_cloud); #endif // CLOUD_APP_WEBSOCKET_TRANSPORT_SUPPORT +#ifdef WEBSOCKET_SERVER_TRANSPORT_SUPPORT + auto ta_websocket = + ta_factory_.ta_websocket_server_creator_(last_state_wrapper, settings); + +#ifdef TELEMETRY_MONITOR + if (metric_observer_) { + ta_websocket->SetTelemetryObserver(metric_observer_); + } +#endif // TELEMETRY_MONITOR + AddTransportAdapter(ta_websocket); + ta_websocket = NULL; +#endif // WEBSOCKET_SERVER_TRANSPORT_SUPPORT + #if defined ENABLE_IAP2EMULATION const uint16_t iap2_bt_emu_port = 23456; transport_adapter::IAP2BluetoothEmulationTransportAdapter* diff --git a/src/components/transport_manager/src/transport_manager_impl.cc b/src/components/transport_manager/src/transport_manager_impl.cc index c6fd60a185..9d4f6be316 100644 --- a/src/components/transport_manager/src/transport_manager_impl.cc +++ b/src/components/transport_manager/src/transport_manager_impl.cc @@ -54,6 +54,10 @@ #include "transport_manager/transport_adapter/transport_adapter_event.h" #include "transport_manager/transport_manager_listener.h" #include "transport_manager/transport_manager_listener_empty.h" +#ifdef WEBSOCKET_SERVER_TRANSPORT_SUPPORT +#include "transport_manager/websocket_server/websocket_device.h" +#include "transport_manager/websocket_server/websocket_server_transport_adapter.h" +#endif #include "utils/timer_task_impl.h" using ::transport_manager::transport_adapter::TransportAdapter; @@ -104,7 +108,11 @@ TransportManagerImpl::TransportManagerImpl( this, &TransportManagerImpl::ReconnectionTimeout)) , events_processing_is_active_(true) , events_processing_lock_() - , events_processing_cond_var_() { + , events_processing_cond_var_() + , web_engine_device_info_(0, + "", + webengine_constants::kWebEngineDeviceName, + webengine_constants::kWebEngineConnectionType) { LOG4CXX_TRACE(logger_, "TransportManager has created"); } @@ -655,6 +663,66 @@ int TransportManagerImpl::PerformActionOnClients( return E_SUCCESS; } +void TransportManagerImpl::CreateWebEngineDevice() { +#ifndef WEBSOCKET_SERVER_TRANSPORT_SUPPORT + LOG4CXX_TRACE(logger_, "Web engine support is disabled. Exiting function"); +#else + LOG4CXX_AUTO_TRACE(logger_); + auto web_socket_ta_iterator = std::find_if( + transport_adapters_.begin(), + transport_adapters_.end(), + [](const TransportAdapter* ta) { + return transport_adapter::DeviceType::WEBENGINE_WEBSOCKET == + ta->GetDeviceType(); + }); + + if (transport_adapters_.end() == web_socket_ta_iterator) { + LOG4CXX_WARN(logger_, + "WebSocketServerTransportAdapter not found." + "Impossible to create WebEngineDevice"); + return; + } + + auto web_socket_ta = + dynamic_cast( + *web_socket_ta_iterator); + + if (!web_socket_ta) { + LOG4CXX_ERROR(logger_, + "Unable to cast from Transport Adapter to " + "WebSocketServerTransportAdapter." + "Impossible to create WebEngineDevice"); + return; + } + + std::string unique_device_id = web_socket_ta->GetStoredDeviceID(); + + DeviceHandle device_handle = converter_.UidToHandle( + unique_device_id, webengine_constants::kWebEngineConnectionType); + + web_engine_device_info_ = + DeviceInfo(device_handle, + unique_device_id, + webengine_constants::kWebEngineDeviceName, + webengine_constants::kWebEngineConnectionType); + + auto ws_device = std::make_shared( + web_engine_device_info_.name(), web_engine_device_info_.mac_address()); + + ws_device->set_keep_on_disconnect(true); + + RaiseEvent(&TransportManagerListener::OnDeviceAdded, web_engine_device_info_); + device_list_.push_back( + std::make_pair(web_socket_ta, web_engine_device_info_)); + web_socket_ta->AddDevice(ws_device); +#endif // WEBSOCKET_SERVER_TRANSPORT_SUPPORT +} + +const DeviceInfo& TransportManagerImpl::GetWebEngineDeviceInfo() const { + LOG4CXX_AUTO_TRACE(logger_); + return web_engine_device_info_; +} + void TransportManagerImpl::UpdateDeviceList(TransportAdapter* ta) { LOG4CXX_TRACE(logger_, "enter. TransportAdapter: " << ta); std::set old_devices; @@ -856,9 +924,9 @@ void TransportManagerImpl::TryDeviceSwitch( IOSBTAdapterFinder()); if (transport_adapters_.end() == ios_bt_adapter) { - LOG4CXX_WARN( - logger_, - "There is no iAP2 Bluetooth adapter found. Switching is not possible."); + LOG4CXX_WARN(logger_, + "There is no iAP2 Bluetooth adapter found. Switching is not " + "possible."); return; } diff --git a/src/components/transport_manager/src/websocket_server/websocket_connection.cc b/src/components/transport_manager/src/websocket_server/websocket_connection.cc new file mode 100644 index 0000000000..7bcc4baef2 --- /dev/null +++ b/src/components/transport_manager/src/websocket_server/websocket_connection.cc @@ -0,0 +1,218 @@ +/* +Copyright (c) 2020 Livio, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of SmartDeviceLink Consortium, Inc. nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "transport_manager/websocket_server/websocket_connection.h" +#include +#include "transport_manager/transport_adapter/transport_adapter_controller.h" + +namespace transport_manager { +namespace transport_adapter { + +CREATE_LOGGERPTR_GLOBAL(wsc_logger_, "WebSocketConnection") + +using namespace boost::beast::websocket; + +template <> +WebSocketConnection >::WebSocketConnection( + const DeviceUID& device_uid, + const ApplicationHandle& app_handle, + boost::asio::ip::tcp::socket socket, + TransportAdapterController* controller) + : device_uid_(device_uid) + , app_handle_(app_handle) + , session_(new WebSocketSession<>( + std::move(socket), + std::bind( + &WebSocketConnection::DataReceive, this, std::placeholders::_1), + std::bind(&WebSocketConnection::OnError, this))) + , controller_(controller) + , shutdown_(false) + , thread_delegate_(new LoopThreadDelegate( + &message_queue_, + std::bind(&WebSocketSession<>::WriteDown, + session_.get(), + std::placeholders::_1), + std::bind(&WebSocketConnection::OnError, this))) + , thread_(threads::CreateThread("WS Async Send", thread_delegate_)) { + thread_->start(threads::ThreadOptions()); +} + +#ifdef ENABLE_SECURITY +template <> +WebSocketConnection >::WebSocketConnection( + const DeviceUID& device_uid, + const ApplicationHandle& app_handle, + boost::asio::ip::tcp::socket socket, + ssl::context& ctx, + TransportAdapterController* controller) + : device_uid_(device_uid) + , app_handle_(app_handle) + , session_(new WebSocketSecureSession<>( + std::move(socket), + ctx, + std::bind( + &WebSocketConnection::DataReceive, this, std::placeholders::_1), + std::bind(&WebSocketConnection::OnError, this))) + , controller_(controller) + , shutdown_(false) + , thread_delegate_(new LoopThreadDelegate( + &message_queue_, + std::bind(&WebSocketSecureSession<>::WriteDown, + session_.get(), + std::placeholders::_1), + std::bind(&WebSocketConnection::OnError, this))) + , thread_(threads::CreateThread("WS Async Send", thread_delegate_)) { + thread_->start(threads::ThreadOptions()); +} +template class WebSocketConnection >; +#endif // ENABLE_SECURITY + +template +WebSocketConnection::~WebSocketConnection() { + if (!IsShuttingDown()) { + Shutdown(); + } +} + +template +void WebSocketConnection::OnError() { + LOG4CXX_AUTO_TRACE(wsc_logger_); + + controller_->ConnectionAborted( + device_uid_, app_handle_, CommunicationError()); + + session_->Shutdown(); +} + +template +TransportAdapter::Error WebSocketConnection::Disconnect() { + LOG4CXX_AUTO_TRACE(wsc_logger_); + if (!IsShuttingDown()) { + Shutdown(); + controller_->DisconnectDone(device_uid_, app_handle_); + return TransportAdapter::OK; + } + return TransportAdapter::BAD_STATE; +} + +template +TransportAdapter::Error WebSocketConnection::SendData( + ::protocol_handler::RawMessagePtr message) { + if (IsShuttingDown()) { + return TransportAdapter::BAD_STATE; + } + + message_queue_.push(message); + + return TransportAdapter::OK; +} + +template +void WebSocketConnection::DataReceive( + protocol_handler::RawMessagePtr frame) { + controller_->DataReceiveDone(device_uid_, app_handle_, frame); +} + +template +void WebSocketConnection::Run() { + LOG4CXX_AUTO_TRACE(wsc_logger_); + session_->AsyncAccept(); +} + +template +void WebSocketConnection::Shutdown() { + LOG4CXX_AUTO_TRACE(wsc_logger_); + shutdown_ = true; + if (thread_delegate_) { + session_->Shutdown(); + thread_delegate_->SetShutdown(); + thread_->join(); + delete thread_delegate_; + thread_delegate_ = nullptr; + threads::DeleteThread(thread_); + thread_ = nullptr; + } +} + +template +bool WebSocketConnection::IsShuttingDown() { + return shutdown_; +} + +template +WebSocketConnection::LoopThreadDelegate::LoopThreadDelegate( + MessageQueue* message_queue, + DataWriteCallback data_write, + OnIOErrorCallback on_io_error) + : message_queue_(*message_queue) + , data_write_(data_write) + , on_io_error_(on_io_error) {} + +template +void WebSocketConnection::LoopThreadDelegate::threadMain() { + while (!message_queue_.IsShuttingDown()) { + DrainQueue(); + message_queue_.wait(); + } + DrainQueue(); +} + +template +void WebSocketConnection::LoopThreadDelegate::exitThreadMain() { + if (!message_queue_.IsShuttingDown()) { + message_queue_.Shutdown(); + } +} + +template +void WebSocketConnection::LoopThreadDelegate::DrainQueue() { + Message message_ptr; + while (!message_queue_.IsShuttingDown() && message_queue_.pop(message_ptr)) { + auto res = data_write_(message_ptr); + if (TransportAdapter::FAIL == res) { + LOG4CXX_WARN(wsc_logger_, + "Writing to websocket stream failed. Will now close " + "websocket connection."); + on_io_error_(); + } + } +} + +template +void WebSocketConnection::LoopThreadDelegate::SetShutdown() { + if (!message_queue_.IsShuttingDown()) { + message_queue_.Shutdown(); + } +} + +template class WebSocketConnection >; + +} // namespace transport_adapter +} // namespace transport_manager diff --git a/src/components/transport_manager/src/websocket_server/websocket_device.cc b/src/components/transport_manager/src/websocket_server/websocket_device.cc new file mode 100644 index 0000000000..502daf349b --- /dev/null +++ b/src/components/transport_manager/src/websocket_server/websocket_device.cc @@ -0,0 +1,94 @@ +/* + * + * Copyright (c) 2020, Livio + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "transport_manager/websocket_server/websocket_device.h" + +#include "utils/logger.h" + +namespace transport_manager { +namespace transport_adapter { +CREATE_LOGGERPTR_GLOBAL(logger_, "TransportManager") + +WebSocketDevice::WebSocketDevice(const std::string& name, + const DeviceUID& unique_device_id) + : Device(name, unique_device_id) + , is_secure_connect_(false) + , protocol_(boost::asio::ip::tcp::v4()) {} + +bool WebSocketDevice::IsSameAs(const Device* other) const { + LOG4CXX_TRACE(logger_, "enter. device: " << other); + + const WebSocketDevice* other_websocket_device = + dynamic_cast(other); + + if (!other_websocket_device) { + return false; + } + + if (GetHost() != other_websocket_device->GetHost()) { + return false; + } + + if (GetPort() != other_websocket_device->GetPort()) { + return false; + } + + if (GetTarget() != other_websocket_device->GetTarget()) { + return false; + } + + return true; +} + +ApplicationList WebSocketDevice::GetApplicationList() const { + return app_list_; +} + +const std::string& WebSocketDevice::GetHost() const { + return host_; +} + +const std::string& WebSocketDevice::GetPort() const { + return port_; +} + +const std::string WebSocketDevice::GetTarget() const { + return host_ + port_ + name(); +} + +void WebSocketDevice::AddApplication(const ApplicationHandle& app_handle) { + app_list_.push_back(app_handle); +} + +} // namespace transport_adapter +} // namespace transport_manager diff --git a/src/components/transport_manager/src/websocket_server/websocket_listener.cc b/src/components/transport_manager/src/websocket_server/websocket_listener.cc new file mode 100644 index 0000000000..87fff3acbc --- /dev/null +++ b/src/components/transport_manager/src/websocket_server/websocket_listener.cc @@ -0,0 +1,299 @@ +#include "transport_manager/websocket_server/websocket_listener.h" +#include "transport_manager/transport_adapter/transport_adapter_controller.h" +#include "transport_manager/websocket_server/websocket_device.h" +#include "utils/file_system.h" + +namespace transport_manager { +namespace transport_adapter { +CREATE_LOGGERPTR_GLOBAL(logger_, "WebSocketListener") + +WebSocketListener::WebSocketListener(TransportAdapterController* controller, + const TransportManagerSettings& settings, + const int num_threads) + : controller_(controller) + , ioc_(num_threads) +#ifdef ENABLE_SECURITY + , ctx_(ssl::context::sslv23) + , start_secure_(false) +#endif // ENABLE_SECURITY + , acceptor_(ioc_) + , socket_(ioc_) + , io_pool_(new boost::asio::thread_pool(num_threads)) + , num_threads_(num_threads) + , shutdown_(false) + , settings_(settings) { +} + +WebSocketListener::~WebSocketListener() { + Terminate(); +} + +TransportAdapter::Error WebSocketListener::Init() { + LOG4CXX_AUTO_TRACE(logger_); + const auto old_shutdown_value = shutdown_.exchange(false); + if (old_shutdown_value) { + ioc_.restart(); + io_pool_.reset(new boost::asio::thread_pool(num_threads_)); + } + return StartListening(); +} + +void WebSocketListener::Terminate() { + LOG4CXX_AUTO_TRACE(logger_); + Shutdown(); +} + +TransportAdapter::Error WebSocketListener::StartListening() { + LOG4CXX_AUTO_TRACE(logger_); + if (acceptor_.is_open()) { + return TransportAdapter::OK; + } + +#ifdef ENABLE_SECURITY + auto const ta_error = AddCertificateAuthority(); + if (TransportAdapter::OK != ta_error) { + return ta_error; + } +#endif + + auto const address = + boost::asio::ip::make_address(settings_.websocket_server_address()); + tcp::endpoint endpoint = {address, settings_.websocket_server_port()}; + + // Open the acceptor + boost::system::error_code ec; + acceptor_.open(endpoint.protocol(), ec); + if (ec) { + auto str_err = "ErrorOpen: " + ec.message(); + LOG4CXX_ERROR(logger_, + str_err << " host/port: " << endpoint.address().to_string() + << "/" << endpoint.port()); + return TransportAdapter::FAIL; + } + + acceptor_.set_option(boost::asio::socket_base::reuse_address(true), ec); + if (ec) { + std::string str_err = "ErrorSetOption: " + ec.message(); + LOG4CXX_ERROR(logger_, + str_err << " host/port: " << endpoint.address().to_string() + << "/" << endpoint.port()); + return TransportAdapter::FAIL; + } + + // Bind to the server address + acceptor_.bind(endpoint, ec); + if (ec) { + std::string str_err = "ErrorBind: " + ec.message(); + LOG4CXX_ERROR(logger_, + str_err << " host/port: " << endpoint.address().to_string() + << "/" << endpoint.port()); + return TransportAdapter::FAIL; + } + + // Start listening for connections + acceptor_.listen(boost::asio::socket_base::max_listen_connections, ec); + if (ec) { + std::string str_err = "ErrorListen: " + ec.message(); + LOG4CXX_ERROR(logger_, + str_err << " host/port: " << endpoint.address().to_string() + << "/" << endpoint.port()); + return TransportAdapter::FAIL; + } + + if (false == Run()) { + return TransportAdapter::FAIL; + } + + return TransportAdapter::OK; +} + +#ifdef ENABLE_SECURITY +TransportAdapter::Error WebSocketListener::AddCertificateAuthority() { + LOG4CXX_AUTO_TRACE(logger_); + + const auto cert_path = settings_.ws_server_cert_path(); + LOG4CXX_DEBUG(logger_, "Path to certificate : " << cert_path); + const auto key_path = settings_.ws_server_key_path(); + LOG4CXX_DEBUG(logger_, "Path to key : " << key_path); + const auto ca_cert_path = settings_.ws_server_ca_cert_path(); + LOG4CXX_DEBUG(logger_, "Path to ca cert : " << ca_cert_path); + start_secure_ = settings_.wss_server_supported(); + + if (start_secure_ && (!file_system::FileExists(cert_path) || + !file_system::FileExists(key_path) || + !file_system::FileExists(ca_cert_path))) { + LOG4CXX_ERROR(logger_, "Certificate or key file not found"); + return TransportAdapter::FAIL; + } + + if (!start_secure_) { + auto check_config = [](const std::string& config, + const std::string config_name) { + bool start_unsecure = config.empty(); + if (!start_unsecure) { + LOG4CXX_ERROR(logger_, + "Configuration for secure WS is incomplete. " + << config_name + << " config is " + "present, meanwhile others may be missing. Please " + "check INI file"); + } + return start_unsecure; + }; + if (!check_config(cert_path, "Server cert") || + !check_config(key_path, "Server key") || + !check_config(ca_cert_path, "CA cert")) { + return TransportAdapter::FAIL; + } + } else { + LOG4CXX_INFO(logger_, "WebSocket server will start secure connection"); + ctx_.add_verify_path(cert_path); + ctx_.set_options(boost::asio::ssl::context::default_workarounds); + using context = boost::asio::ssl::context_base; + ctx_.set_verify_mode(ssl::verify_peer | ssl::verify_fail_if_no_peer_cert); + boost::system::error_code sec_ec; + ctx_.use_certificate_chain_file(cert_path, sec_ec); + ctx_.load_verify_file(ca_cert_path); + if (sec_ec) { + LOG4CXX_ERROR( + logger_, + "Loading WS server certificate failed: " << sec_ec.message()); + return TransportAdapter::FAIL; + } + sec_ec.clear(); + ctx_.use_private_key_file(key_path, context::pem, sec_ec); + if (sec_ec) { + LOG4CXX_ERROR(logger_, + "Loading WS server key failed: " << sec_ec.message()); + return TransportAdapter::FAIL; + } + } + + return TransportAdapter::OK; +} +#endif // ENABLE_SECURITY + +bool WebSocketListener::Run() { + LOG4CXX_AUTO_TRACE(logger_); + const bool is_connection_open = WaitForConnection(); + if (is_connection_open) { + boost::asio::post(*io_pool_.get(), [&]() { ioc_.run(); }); + } else { + LOG4CXX_ERROR(logger_, "Connection is shutdown or acceptor isn't open"); + } + + return is_connection_open; +} + +bool WebSocketListener::WaitForConnection() { + LOG4CXX_AUTO_TRACE(logger_); + if (!shutdown_ && acceptor_.is_open()) { + acceptor_.async_accept( + socket_, + std::bind( + &WebSocketListener::StartSession, this, std::placeholders::_1)); + return true; + } + return false; +} + +template <> +void WebSocketListener::ProcessConnection( + std::shared_ptr > > connection, + const DeviceSptr device, + const ApplicationHandle app_handle) { + LOG4CXX_AUTO_TRACE(logger_); + controller_->ConnectionCreated( + connection, device->unique_device_id(), app_handle); + + controller_->ConnectDone(device->unique_device_id(), app_handle); + + connection->Run(); + + connection_list_lock.Acquire(); + connection_list_.push_back(connection); + connection_list_lock.Release(); + + WaitForConnection(); +} + +#ifdef ENABLE_SECURITY +template <> +void WebSocketListener::ProcessConnection( + std::shared_ptr > > connection, + const DeviceSptr device, + const ApplicationHandle app_handle) { + LOG4CXX_AUTO_TRACE(logger_); + controller_->ConnectionCreated( + connection, device->unique_device_id(), app_handle); + + controller_->ConnectDone(device->unique_device_id(), app_handle); + + connection->Run(); + + connection_list_lock.Acquire(); + connection_list_.push_back(connection); + connection_list_lock.Release(); + + WaitForConnection(); +} +#endif // ENABLE_SECURITY + +void WebSocketListener::StartSession(boost::system::error_code ec) { + LOG4CXX_AUTO_TRACE(logger_); + if (ec) { + std::string str_err = "ErrorAccept: " + ec.message(); + LOG4CXX_ERROR(logger_, str_err); + return; + } + + if (shutdown_) { + return; + } + + const ApplicationHandle app_handle = socket_.native_handle(); + + std::shared_ptr device = + std::static_pointer_cast( + controller_->GetWebEngineDevice()); + + LOG4CXX_INFO(logger_, "Connected client: " << app_handle); + +#ifdef ENABLE_SECURITY + if (start_secure_) { + auto connection = + std::make_shared > >( + device->unique_device_id(), + app_handle, + std::move(socket_), + ctx_, + controller_); + ProcessConnection(connection, device, app_handle); + return; + } +#endif // ENABLE_SECURITY + + auto connection = std::make_shared > >( + device->unique_device_id(), app_handle, std::move(socket_), controller_); + ProcessConnection(connection, device, app_handle); +} + +void WebSocketListener::Shutdown() { + LOG4CXX_AUTO_TRACE(logger_); + if (false == shutdown_.exchange(true)) { + ioc_.stop(); + socket_.close(); + boost::system::error_code ec; + acceptor_.close(ec); + + if (ec) { + LOG4CXX_ERROR(logger_, "Acceptor closed with error: " << ec); + } + + io_pool_->stop(); + io_pool_->join(); + } +} + +} // namespace transport_adapter +} // namespace transport_manager diff --git a/src/components/transport_manager/src/websocket_server/websocket_secure_session.cc b/src/components/transport_manager/src/websocket_server/websocket_secure_session.cc new file mode 100644 index 0000000000..9be94119b6 --- /dev/null +++ b/src/components/transport_manager/src/websocket_server/websocket_secure_session.cc @@ -0,0 +1,79 @@ +/* +Copyright (c) 2020 Livio, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of SmartDeviceLink Consortium, Inc. nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "transport_manager/websocket_server/websocket_secure_session.h" +#include +#include "transport_manager/transport_adapter/transport_adapter_controller.h" + +namespace transport_manager { +namespace transport_adapter { + +using namespace boost::beast::websocket; + +template +WebSocketSecureSession::WebSocketSecureSession( + tcp::socket socket, + ssl::context& ctx, + DataReceiveCallback data_receive, + OnIOErrorCallback on_error) + : WebSocketSession( + std::move(socket), ctx, data_receive, on_error) {} + +template +void WebSocketSecureSession::AsyncAccept() { + LOG4CXX_AUTO_TRACE(ws_logger_); + // Perform the SSL handshake + WebSocketSecureSession::ws_.next_layer().async_handshake( + ssl::stream_base::server, + boost::asio::bind_executor( + WebSocketSecureSession::strand_, + std::bind(&WebSocketSecureSession::AsyncHandshake, + this->shared_from_this(), + std::placeholders::_1))); +} + +template +void WebSocketSecureSession::AsyncHandshake( + boost::system::error_code ec) { + LOG4CXX_AUTO_TRACE(ws_logger_); + if (ec) { + auto str_err = "ErrorMessage: " + ec.message(); + LOG4CXX_ERROR(ws_logger_, str_err); + WebSocketSession::on_io_error_(); + return; + } + + WebSocketSession::AsyncAccept(); +} + +template class WebSocketSecureSession >; + +} // namespace transport_adapter +} // namespace transport_manager diff --git a/src/components/transport_manager/src/websocket_server/websocket_server_transport_adapter.cc b/src/components/transport_manager/src/websocket_server/websocket_server_transport_adapter.cc new file mode 100644 index 0000000000..ac8789eee8 --- /dev/null +++ b/src/components/transport_manager/src/websocket_server/websocket_server_transport_adapter.cc @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2020, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "transport_manager/websocket_server/websocket_server_transport_adapter.h" + +#include +#include +#include +#include + +#include +#include + +#include "transport_manager/websocket_server/websocket_listener.h" +#include "utils/gen_hash.h" +#include "utils/logger.h" +#include "utils/threads/thread_delegate.h" + +namespace transport_manager { +namespace transport_adapter { + +CREATE_LOGGERPTR_GLOBAL(logger_, "WebSocketTransportAdapter") + +WebSocketServerTransportAdapter::WebSocketServerTransportAdapter( + resumption::LastStateWrapperPtr last_state_wrapper, + const TransportManagerSettings& settings) + : TransportAdapterImpl(nullptr, + nullptr, + new WebSocketListener(this, settings), + last_state_wrapper, + settings) {} + +WebSocketServerTransportAdapter::~WebSocketServerTransportAdapter() {} + +void WebSocketServerTransportAdapter::TransportConfigUpdated( + const TransportConfig& new_config) { + LOG4CXX_AUTO_TRACE(logger_); + + transport_config_ = new_config; + + // call the method of parent class to trigger OnTransportConfigUpdated() for + // the listeners + TransportAdapterImpl::TransportConfigUpdated(new_config); +} + +TransportConfig WebSocketServerTransportAdapter::GetTransportConfiguration() + const { + LOG4CXX_AUTO_TRACE(logger_); + return transport_config_; +} + +DeviceType WebSocketServerTransportAdapter::GetDeviceType() const { + return WEBENGINE_WEBSOCKET; +} + +DeviceSptr WebSocketServerTransportAdapter::AddDevice(DeviceSptr device) { + LOG4CXX_AUTO_TRACE(logger_); + webengine_device_ = device; + Store(); + return TransportAdapterImpl::AddDevice(webengine_device_); +} + +TransportAdapter::Error WebSocketServerTransportAdapter::Init() { + LOG4CXX_AUTO_TRACE(logger_); + if (webengine_device_) { + AddDevice(webengine_device_); + } + return TransportAdapterImpl::Init(); +} + +void WebSocketServerTransportAdapter::Store() const { + LOG4CXX_AUTO_TRACE(logger_); + if (webengine_device_) { + Json::Value& dictionary = last_state().get_dictionary(); + if (dictionary["TransportManager"].isMember("WebsocketServerAdapter")) { + LOG4CXX_DEBUG( + logger_, "WebsocketServerAdapter already exists. Storing is skipped"); + return; + } + + Json::Value device_dictionary; + device_dictionary["unique_id"] = webengine_device_->unique_device_id(); + + Json::Value ws_adapter_dictionary; + ws_adapter_dictionary["device"] = device_dictionary; + dictionary["TransportManager"]["WebsocketServerAdapter"] = + ws_adapter_dictionary; + } +} + +bool WebSocketServerTransportAdapter::Restore() { + LOG4CXX_AUTO_TRACE(logger_); + const Json::Value& dictionary = last_state().get_dictionary(); + const Json::Value ws_adapter_dictionary = + dictionary["TransportManager"]["WebsocketServerAdapter"]; + webengine_device_id_ = + ws_adapter_dictionary["device"]["unique_id"].asString(); + if (webengine_device_id_.empty()) { + srand(time(0)); + const size_t device_id_length = 64u; + webengine_device_id_ = utils::gen_hash(device_id_length); + } + return true; +} + +std::string WebSocketServerTransportAdapter::GetStoredDeviceID() const { + LOG4CXX_AUTO_TRACE(logger_); + return webengine_device_id_; +} + +} // namespace transport_adapter +} // namespace transport_manager diff --git a/src/components/transport_manager/src/websocket_server/websocket_session.cc b/src/components/transport_manager/src/websocket_server/websocket_session.cc new file mode 100644 index 0000000000..ab62530963 --- /dev/null +++ b/src/components/transport_manager/src/websocket_server/websocket_session.cc @@ -0,0 +1,162 @@ +/* +Copyright (c) 2020 Livio, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of SmartDeviceLink Consortium, Inc. nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "transport_manager/websocket_server/websocket_session.h" +#include +#include "transport_manager/transport_adapter/transport_adapter_controller.h" + +namespace transport_manager { +namespace transport_adapter { + +using namespace boost::beast::websocket; + +template <> +WebSocketSession::WebSocketSession( + boost::asio::ip::tcp::socket socket, + DataReceiveCallback data_receive, + OnIOErrorCallback on_error) + : socket_(std::move(socket)) + , ws_(socket_) + , strand_(ws_.get_executor()) + , data_receive_(data_receive) + , on_io_error_(on_error) { + ws_.binary(true); +} + +#ifdef ENABLE_SECURITY +template <> +WebSocketSession >::WebSocketSession( + boost::asio::ip::tcp::socket socket, + ssl::context& ctx, + DataReceiveCallback data_receive, + OnIOErrorCallback on_error) + : socket_(std::move(socket)) + , ws_(socket_, ctx) + , strand_(ws_.get_executor()) + , data_receive_(data_receive) + , on_io_error_(on_error) { + ws_.binary(true); +} +template class WebSocketSession >; +#endif // ENABLE_SECURITY + +template +WebSocketSession::~WebSocketSession() {} + +template +void WebSocketSession::AsyncAccept() { + LOG4CXX_AUTO_TRACE(ws_logger_); + ws_.async_accept( + boost::asio::bind_executor(strand_, + std::bind(&WebSocketSession::AsyncRead, + this->shared_from_this(), + std::placeholders::_1))); +} + +template +void WebSocketSession::AsyncRead(boost::system::error_code ec) { + LOG4CXX_AUTO_TRACE(ws_logger_); + if (ec) { + auto str_err = "ErrorMessage: " + ec.message(); + LOG4CXX_ERROR(ws_logger_, str_err); + return; + } + + ws_.async_read(buffer_, + boost::asio::bind_executor(strand_, + std::bind(&WebSocketSession::Read, + this->shared_from_this(), + std::placeholders::_1, + std::placeholders::_2))); +} + +template +TransportAdapter::Error WebSocketSession::WriteDown( + ::protocol_handler::RawMessagePtr message) { + boost::system::error_code ec; + ws_.write(boost::asio::buffer(message->data(), message->data_size()), ec); + + if (ec) { + LOG4CXX_ERROR(ws_logger_, "A system error has occurred: " << ec.message()); + return TransportAdapter::FAIL; + } + + return TransportAdapter::OK; +} + +template +void WebSocketSession::Read(boost::system::error_code ec, + std::size_t bytes_transferred) { + LOG4CXX_AUTO_TRACE(ws_logger_); + boost::ignore_unused(bytes_transferred); + if (ec) { + LOG4CXX_ERROR(ws_logger_, ec.message()); + buffer_.consume(buffer_.size()); + on_io_error_(); + return; + } + + auto size = buffer_.size(); + const auto data = boost::asio::buffer_cast( + boost::beast::buffers_front(buffer_.data())); + + LOG4CXX_DEBUG(ws_logger_, + "Msg: " << boost::beast::buffers_to_string(buffer_.data()) + << " Size: " << size;); + + ::protocol_handler::RawMessagePtr frame( + new protocol_handler::RawMessage(0, 0, data, size, false)); + + data_receive_(frame); + + buffer_.consume(buffer_.size()); + AsyncRead(ec); +} + +template +bool WebSocketSession::Shutdown() { + LOG4CXX_AUTO_TRACE(ws_logger_); + boost::system::error_code ec; + if (socket_.is_open()) { + socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec); + socket_.close(); + } + buffer_.consume(buffer_.size()); + if (ec) { + LOG4CXX_ERROR(ws_logger_, ec.message()); + return false; + } + return true; +} + +template class WebSocketSession; + +} // namespace transport_adapter +} // namespace transport_manager diff --git a/src/components/transport_manager/test/CMakeLists.txt b/src/components/transport_manager/test/CMakeLists.txt index f6e1212b36..76680b2fad 100644 --- a/src/components/transport_manager/test/CMakeLists.txt +++ b/src/components/transport_manager/test/CMakeLists.txt @@ -48,11 +48,18 @@ set(EXCLUDE_PATHS if (NOT BUILD_CLOUD_APP_SUPPORT) list(APPEND EXCLUDE_PATHS - ${CMAKE_CURRENT_SOURCE_DIR}/websocket_connection_test.cc ${CMAKE_CURRENT_SOURCE_DIR}/sample_websocket_server.cc ) endif() +if (NOT BUILD_WEBSOCKET_SERVER_SUPPORT) + list(APPEND EXCLUDE_PATHS + ${CMAKE_CURRENT_SOURCE_DIR}/websocket_client_connection_test.cc + ${CMAKE_CURRENT_SOURCE_DIR}/websocket_connection_test.cc + ${CMAKE_CURRENT_SOURCE_DIR}/websocket_server_listener_test.cc + ) +endif() + collect_sources(SOURCES "${CMAKE_CURRENT_SOURCE_DIR}" "${EXCLUDE_PATHS}") set(PLATFORM_DEPENDENT_SOURCES) @@ -90,3 +97,4 @@ endif() create_test("transport_manager_test" "${SOURCES}" "${LIBRARIES}") file(COPY smartDeviceLink_test.ini DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) +file(COPY "test_certs/" DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/test_certs) diff --git a/src/components/transport_manager/test/include/transport_manager/transport_adapter/mock_transport_adapter_controller.h b/src/components/transport_manager/test/include/transport_manager/transport_adapter/mock_transport_adapter_controller.h index 1de5eac702..7ddb84001c 100644 --- a/src/components/transport_manager/test/include/transport_manager/transport_adapter/mock_transport_adapter_controller.h +++ b/src/components/transport_manager/test/include/transport_manager/transport_adapter/mock_transport_adapter_controller.h @@ -45,56 +45,66 @@ using namespace ::transport_manager::transport_adapter; class MockTransportAdapterController : public TransportAdapterController { public: MOCK_METHOD1(AddDevice, DeviceSptr(DeviceSptr device)); - MOCK_METHOD1(SearchDeviceDone, void(DeviceVector device)); + MOCK_METHOD1(SearchDeviceDone, void(const DeviceVector& device)); MOCK_METHOD1(ApplicationListUpdated, - ApplicationListUpdated(const DeviceUID& device_handle)); + void(const transport_manager::DeviceUID& device_handle)); MOCK_METHOD0(FindNewApplicationsRequest, void()); - MOCK_METHOD1(SearchDeviceFailed, void(const SearchDeviceError& error)); - MOCK_CONST_METHOD1(FindDevice, DeviceSptr(const DeviceUID& device_handle)); - MOCK_CONST_METHOD3(FindDevice, - void(ConnectionSPtr connection, - const DeviceUID& device_handle, - const ApplicationHandle& app_handle)); - MOCK_CONST_METHOD2(FindPendingConnection, - ConnectionSPtr(const DeviceUID& device_handle, - const ApplicationHandle& app_handle)); + MOCK_METHOD1(SearchDeviceFailed, + void(const transport_manager::SearchDeviceError& error)); + MOCK_CONST_METHOD1( + FindDevice, + DeviceSptr(const transport_manager::DeviceUID& device_handle)); + MOCK_CONST_METHOD2( + FindPendingConnection, + ConnectionSPtr(const transport_manager::DeviceUID& device_handle, + const transport_manager::ApplicationHandle& app_handle)); + MOCK_METHOD3(ConnectionCreated, + void(ConnectionSPtr connection, + const transport_manager::DeviceUID& device_handle, + const transport_manager::ApplicationHandle& app_handle)); + MOCK_METHOD2(ConnectPending, + void(const transport_manager::DeviceUID& device_handle, + const transport_manager::ApplicationHandle& app_handle)); MOCK_METHOD2(ConnectDone, - void(const DeviceUID& device_handle, - const ApplicationHandle& app_handle)); + void(const transport_manager::DeviceUID& device_handle, + const transport_manager::ApplicationHandle& app_handle)); MOCK_METHOD3(ConnectFailed, - void(const DeviceUID& device_handle, - const ApplicationHandle& app_handle, - const ConnectError& error)); + void(const transport_manager::DeviceUID& device_handle, + const transport_manager::ApplicationHandle& app_handle, + const transport_manager::ConnectError& error)); MOCK_METHOD2(ConnectionFinished, - void(const DeviceUID& device_handle, - const ApplicationHandle& app_handle)); + void(const transport_manager::DeviceUID& device_handle, + const transport_manager::ApplicationHandle& app_handle)); MOCK_METHOD3(ConnectionAborted, - void(const DeviceUID& device_handle, - const ApplicationHandle& app_handle, - const CommunicationError& error)); + void(const transport_manager::DeviceUID& device_handle, + const transport_manager::ApplicationHandle& app_handle, + const transport_manager::CommunicationError& error)); MOCK_METHOD2(DeviceDisconnected, - void(const DeviceUID& device_handle, - const DisconnectDeviceError& error)); + void(const transport_manager::DeviceUID& device_handle, + const transport_manager::DisconnectDeviceError& error)); MOCK_METHOD2(DisconnectDone, - void(const DeviceUID& device_handle, - const ApplicationHandle& app_handle)); + void(const transport_manager::DeviceUID& device_handle, + const transport_manager::ApplicationHandle& app_handle)); MOCK_METHOD3(DataReceiveDone, - void(const DeviceUID& device_handle, - const ApplicationHandle& app_handle, + void(const transport_manager::DeviceUID& device_handle, + const transport_manager::ApplicationHandle& app_handle, ::protocol_handler::RawMessagePtr message)); MOCK_METHOD3(DataReceiveFailed, - void(const DeviceUID& device_handle, - const ApplicationHandle& app_handle, - const DataReceiveError& error)); + void(const transport_manager::DeviceUID& device_handle, + const transport_manager::ApplicationHandle& app_handle, + const transport_manager::DataReceiveError& error)); MOCK_METHOD3(DataSendDone, - void(const DeviceUID& device_handle, - const ApplicationHandle& app_handle, + void(const transport_manager::DeviceUID& device_handle, + const transport_manager::ApplicationHandle& app_handle, ::protocol_handler::RawMessagePtr message)); - MOCK_METHOD3(DataReceiveFailed, - void(const DeviceUID& device_handle, - const ApplicationHandle& app_handle, + + MOCK_METHOD4(DataSendFailed, + void(const transport_manager::DeviceUID& device_handle, + const transport_manager::ApplicationHandle& app_handle, ::protocol_handler::RawMessagePtr message, - const DataSendError& error)); + const transport_manager::DataSendError&)); + MOCK_METHOD1(TransportConfigUpdated, void(const TransportConfig& new_config)); + MOCK_CONST_METHOD0(GetWebEngineDevice, DeviceSptr()); }; } // namespace transport_manager_test diff --git a/src/components/transport_manager/test/include/transport_manager/websocket_server/websocket_sample_client.h b/src/components/transport_manager/test/include/transport_manager/websocket_server/websocket_sample_client.h new file mode 100644 index 0000000000..138502e02c --- /dev/null +++ b/src/components/transport_manager/test/include/transport_manager/websocket_server/websocket_sample_client.h @@ -0,0 +1,117 @@ +/* + * \file websocket_listener.h + * \brief WebSocketListener class header file. + * + * Copyright (c) 2020 + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SRC_COMPONENTS_TRANSPORT_MANAGER_TEST_INCLUDE_TRANSPORT_MANAGER_WEBSOCKET_SERVER_WEBSOCKET_SAMPLE_CLIENT_ +#define SRC_COMPONENTS_TRANSPORT_MANAGER_TEST_INCLUDE_TRANSPORT_MANAGER_WEBSOCKET_SERVER_WEBSOCKET_SAMPLE_CLIENT_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace transport_manager { +namespace transport_adapter { + +namespace beast = boost::beast; +namespace http = beast::http; +namespace websocket = beast::websocket; +namespace asio = boost::asio; +namespace ssl = boost::asio::ssl; +using tcp = boost::asio::ip::tcp; + +using WS = websocket::stream; +using WSS = websocket::stream >; + +struct SecurityParams { + std::string ca_cert_; + std::string client_cert_; + std::string client_key_; +}; + +template +class WSSampleClient + : public std::enable_shared_from_this > { + public: + WSSampleClient(const std::string& host, const std::string& port); + WSSampleClient(const std::string& host, + const std::string& port, + const SecurityParams& params); + ~WSSampleClient() {} + + /** + * @brief Inside a Run(), functions are invoked from the boost (connection, + * handshake, message) which are blocking calls + * @return true if Run() did without errors + **/ + bool Run(); + + void OnRead(beast::error_code ec, std::size_t bytes_transferred); + + bool Connect(tcp::resolver::results_type& results); + + bool Handshake(const std::string& host, const std::string& target); + + void OnHandshakeTimeout(); + + bool IsHandshakeSuccessful() const; + + void Stop(); + + private: + asio::io_context ioc_; + tcp::resolver resolver_; + ssl::context ctx_; + std::unique_ptr ws_; + boost::asio::thread_pool io_pool_; + beast::flat_buffer buffer_; + std::string host_; + std::string port_; + std::atomic_bool handshake_successful_; +}; + +} // namespace transport_adapter +} // namespace transport_manager + +#endif // SRC_COMPONENTS_TRANSPORT_MANAGER_TEST_INCLUDE_TRANSPORT_MANAGER_WEBSOCKET_SERVER_WEBSOCKET_SAMPLE_CLIENT_ diff --git a/src/components/transport_manager/test/tcp_client_listener_test.cc b/src/components/transport_manager/test/tcp_client_listener_test.cc index d524b3eb6a..dbd7799b62 100644 --- a/src/components/transport_manager/test/tcp_client_listener_test.cc +++ b/src/components/transport_manager/test/tcp_client_listener_test.cc @@ -42,6 +42,7 @@ #include "transport_manager/tcp/tcp_client_listener.h" #include "transport_manager/transport_adapter/mock_device.h" #include "transport_manager/transport_adapter/mock_transport_adapter.h" +#include "transport_manager/transport_adapter/mock_transport_adapter_controller.h" #include "transport_manager/transport_adapter/transport_adapter_controller.h" #include "utils/test_async_waiter.h" @@ -62,67 +63,6 @@ const long kThreadStartWaitMsec = 10; const uint32_t kConnectionCreatedTimeoutMsec = 200; } // namespace -class MockTransportAdapterController : public TransportAdapterController { - public: - MOCK_METHOD1(AddDevice, DeviceSptr(DeviceSptr device)); - MOCK_METHOD0(AckDevices, void()); - MOCK_METHOD1(SearchDeviceDone, void(const DeviceVector& devices)); - MOCK_METHOD1(SearchDeviceFailed, void(const SearchDeviceError& error)); - MOCK_CONST_METHOD1(FindDevice, DeviceSptr(const DeviceUID& device_handle)); - MOCK_CONST_METHOD2(FindPendingConnection, - ConnectionSPtr(const DeviceUID& device_handle, - const ApplicationHandle& app_handle)); - MOCK_METHOD3(ConnectionCreated, - void(ConnectionSPtr connection, - const DeviceUID& device_handle, - const ApplicationHandle& app_handle)); - MOCK_METHOD2(ConnectPending, - void(const DeviceUID& device_handle, - const ApplicationHandle& app_handle)); - MOCK_METHOD2(ConnectDone, - void(const DeviceUID& device_handle, - const ApplicationHandle& app_handle)); - MOCK_METHOD3(ConnectFailed, - void(const DeviceUID& device_handle, - const ApplicationHandle& app_handle, - const ConnectError& error)); - MOCK_METHOD2(ConnectionFinished, - void(const DeviceUID& device_handle, - const ApplicationHandle& app_handle)); - MOCK_METHOD3(ConnectionAborted, - void(const DeviceUID& device_handle, - const ApplicationHandle& app_handle, - const CommunicationError& error)); - MOCK_METHOD2(DisconnectDone, - void(const DeviceUID& device_handle, - const ApplicationHandle& app_handle)); - MOCK_METHOD3(DataReceiveDone, - void(const DeviceUID& device_handle, - const ApplicationHandle& app_handle, - const ::protocol_handler::RawMessagePtr message)); - MOCK_METHOD3(DataReceiveFailed, - void(const DeviceUID& device_handle, - const ApplicationHandle& app_handle, - const DataReceiveError& error)); - MOCK_METHOD3(DataSendDone, - void(const DeviceUID& device_handle, - const ApplicationHandle& app_handle, - const ::protocol_handler::RawMessagePtr message)); - MOCK_METHOD4(DataSendFailed, - void(const DeviceUID& device_handle, - const ApplicationHandle& app_handle, - const ::protocol_handler::RawMessagePtr message, - const DataSendError& error)); - MOCK_METHOD0(FindNewApplicationsRequest, void()); - MOCK_METHOD1(ApplicationListUpdated, void(const DeviceUID& device_handle)); - MOCK_METHOD2(DeviceDisconnected, - void(const DeviceUID& device_handle, - const DisconnectDeviceError& error)); - MOCK_METHOD1(TransportConfigUpdated, - void(const transport_manager::transport_adapter::TransportConfig& - new_config)); -}; - class MockNetworkInterfaceListener : public NetworkInterfaceListener { public: MOCK_METHOD0(Init, bool()); diff --git a/src/components/transport_manager/test/test_certs/ca-cert.pem b/src/components/transport_manager/test/test_certs/ca-cert.pem new file mode 100644 index 0000000000..e28684043c --- /dev/null +++ b/src/components/transport_manager/test/test_certs/ca-cert.pem @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE----- +MIIDyzCCArOgAwIBAgIJAM6Tk4KJmUgsMA0GCSqGSIb3DQEBCwUAMHwxCzAJBgNV +BAYTAlVBMQ8wDQYDVQQIDAZPZGVzc2ExDzANBgNVBAcMBk9kZXNzYTEPMA0GA1UE +CgwGTHV4b2Z0MQ0wCwYDVQQLDARGVENOMQ8wDQYDVQQDDAZMdXgtQ0ExGjAYBgkq +hkiG9w0BCQEWC2NhQGZ0Y24uY29tMB4XDTIwMDExMDE0MzA1OFoXDTIyMTAwNjE0 +MzA1OFowfDELMAkGA1UEBhMCVUExDzANBgNVBAgMBk9kZXNzYTEPMA0GA1UEBwwG +T2Rlc3NhMQ8wDQYDVQQKDAZMdXhvZnQxDTALBgNVBAsMBEZUQ04xDzANBgNVBAMM +Bkx1eC1DQTEaMBgGCSqGSIb3DQEJARYLY2FAZnRjbi5jb20wggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQDWEz7yGIAEs6w/7CdMjkZ5J0O9IghL0f9wZVFO +ficeREJglClInPrD7BwG7MG1tydPULbrf1rXgxi1NdDY+lsJLFmkxrGVlgJUJl55 +cGpWGliTUepfPz/6CgIabRw2fEMx/eIUlcE+WjY+f4uowVyRYjmNj7IydlQ5UjcL +wWhjg1QMcjgmDzh8Jdx8I+JHYuOP9CtEEfFZy5DjVPFDSlTYhhnNclfw+4NkOYcs +hp+EcMBr6egfxpG2dZbdCJtGw6QqHGG7kqqtLr+9wM5VFhuvebus5waM1G18dIME +SgZmDdgvHO3bbylR+DRmAjJVn4DaDW6uszK9MSPsk53idOUXAgMBAAGjUDBOMB0G +A1UdDgQWBBSSRwc4sGpz6V1kb0H371ZqhDuQDzAfBgNVHSMEGDAWgBSSRwc4sGpz +6V1kb0H371ZqhDuQDzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCb +ZYtM2nrokFL1D34bhozrLu0MxWwDF+gQrUsRr45s63Y5Pv7BVvuS6gF2MubMXskw +mVeCerFw2vQHJKqe7leTy69hwIydPxPQWWno7MamwBDm3VQThr+b18rEpcjbmBMm +p50usYzU9nxEEbIaiSbxfuZNvInLNmvMhKnKO/CIazJnYin9TGdOj9vZnh0UkWF3 +780mMBisycfxG+VwPXQZz5OzWWFB1uMiYrRVdwU6Y5umc2Oce7+ykWy+fXeefMhb +lLJXHZK584qY/krmW0Ec6ZWSbiWcLW5SjGh756n05gBGLDBwijHnfEHNaqn+KlnZ +qqIAImNTA9F+DlMQ7BV3 +-----END CERTIFICATE----- diff --git a/src/components/transport_manager/test/test_certs/client-cert.pem b/src/components/transport_manager/test/test_certs/client-cert.pem new file mode 100644 index 0000000000..47e85876c8 --- /dev/null +++ b/src/components/transport_manager/test/test_certs/client-cert.pem @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDeDCCAmACAQIwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UEBhMCVUExDzANBgNV +BAgMBk9kZXNzYTEPMA0GA1UEBwwGT2Rlc3NhMQ8wDQYDVQQKDAZMdXhvZnQxDTAL +BgNVBAsMBEZUQ04xDzANBgNVBAMMBkx1eC1DQTEaMBgGCSqGSIb3DQEJARYLY2FA +ZnRjbi5jb20wHhcNMjAwMTEwMTQzODQxWhcNMjIxMDA2MTQzODQxWjCBhzELMAkG +A1UEBhMCVUExDTALBgNVBAgMBEt5aXYxDTALBgNVBAcMBEt5aXYxDzANBgNVBAoM +Bkx1eG9mdDEVMBMGA1UECwwMQXBwc0VueXdoZXJlMRIwEAYDVQQDDAlsb2NhbGhv +c3QxHjAcBgkqhkiG9w0BCQEWD2NsaWVudEBmdGNuLmNvbTCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBALV4qI/gRvVip3u5JtT+n+7j7gUsUVW5DtwHruIy +drzNvQbG1Ukd3EXvU69HTG4BtoDRubqlSe/sjvO5Ypmg/UvpzV36IbjrA46s98uR +T6fKpJU/Zl2zwAHH++iWpFo3mqIDmu7i0KVBieKaGpz+Ft0zh7wHAztS7b6Mjns4 +QynpjDO+iaLIaHqBjc1hLn8dIBXNolOtLu8F8CL7RLRpWP2I2Fk2k0+Q5YKajbil +gptA53Uu55wCBVLTOfUYzTarGwS00+7txLY06g2x20FHD8UQxfCK7kSAeZwSNkbt +SUhXc9OWUvT1uggb2/wBHJN3fwj7y6pvzUJy7p09212hw7UCAwEAATANBgkqhkiG +9w0BAQsFAAOCAQEAjfASZwfJMTPKk45XVbvuNqdlbiI20SNV7pQQ/FqTBKbFmh4g +ndNCvECmBEUH5YdZegiGaONQlsQujmtIkguu3HnA0+2pO2SncmK6D1DLzJv1IFDC +25tTStA6806hWcTK31sxEbi5/aPdy7FMmsRfyhRr/yew0TqlWCVOfJRwgDSc3NKH +/AXgDBrqHzSBegnWe9v3xL8NxehFp41dJG2fyUab03cHzmNtR9v7/NrBglSdK9VS +AU4BCmjmvYlbvmvhZai23y+uLqzlWZ9OtK3qhEWkg6QHor11iBvxBQFeYKp1ZjMl +sQuTxyBLmXOZ/u3hkqLcKvasx9W4DmmPjG2T8Q== +-----END CERTIFICATE----- diff --git a/src/components/transport_manager/test/test_certs/client-key.pem b/src/components/transport_manager/test/test_certs/client-key.pem new file mode 100644 index 0000000000..b286854bd5 --- /dev/null +++ b/src/components/transport_manager/test/test_certs/client-key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC1eKiP4Eb1Yqd7 +uSbU/p/u4+4FLFFVuQ7cB67iMna8zb0GxtVJHdxF71OvR0xuAbaA0bm6pUnv7I7z +uWKZoP1L6c1d+iG46wOOrPfLkU+nyqSVP2Zds8ABx/volqRaN5qiA5ru4tClQYni +mhqc/hbdM4e8BwM7Uu2+jI57OEMp6YwzvomiyGh6gY3NYS5/HSAVzaJTrS7vBfAi ++0S0aVj9iNhZNpNPkOWCmo24pYKbQOd1LuecAgVS0zn1GM02qxsEtNPu7cS2NOoN +sdtBRw/FEMXwiu5EgHmcEjZG7UlIV3PTllL09boIG9v8ARyTd38I+8uqb81Ccu6d +PdtdocO1AgMBAAECggEALiPCf+pfQE7YFJ4L4IXo9h1fzFLrTydhPtJ5RavdAr4w +vINbgV6lPebO2TcAmMu4smIgnfMerHDyG8fb6QHExUNp4uYRIuomGmWiD1Ef9qKQ +XB4lkdd9Dzbgts9udD3FBEJ0Zx6mPA5A16uk7puwBofukAEccj3wks08ANpaQVJh +LoYQdVY9Q2QHUucED9uO2hOv66bDM5aunk0x4Q/b0gIOAnJyqk0xXnmnU76FbkgI +bU3YQ73ZEJKTFLF8B2JaE9REASmHyLQChYqGA9SPdObVhgxJ8gz5AWp5yHgMmYjf +Dp66tCsyGnmfgTlG4Wi13HInxLpRWDWT2JWIy9cUlQKBgQDshRq/rTj4tuVW09hX +bWlAEV2IDn7JOWEZqPagnxew0atqow44VORW+OoUZ5760aOVjvmXeyGXpWCJk5ch +qsFRL9rLRzIy9oC6C/chkJQAprcaOBOSXvj3HnFHVChjbIBENf4dvtsYZHOW42h2 +br0kszv1bbBzVIyTTY0OvGsBUwKBgQDEauIuC6RiDN+qFAf4/lHkUx7wG6DPhvDm +EhpkiVEHYVjH5vm132/cc12y9CvsFS4MJPK4KQR9P+HFhEu/uH3uLa1vvKY+69iU +dZ1bfe4UrEm/bwBepDSbqlQk58WC6NyJ6fwMq0BYJVvx593znEbU2wLVUTm8H7l2 +yzyxQwXd1wKBgBkYvo/cJ5FshsVB0VDlkSd1MEGBmD5t0jnQzeqZNwBSHyg/iQC9 +MUVxQBVOMXZXzE3QT/ec3yGiMK4odP7jiYO92i97rH3v3hTftCdhmfK/veoQTTNY +1H4UQtzYtzhliO6z8/TgDYt3DTTTiIAYnAVK52/RZcm3DPuMXQ1VPN11AoGBAIN5 +eASSTmpDa8OQvPVyZqaK7P6Tv8Sp8r5OB9ScBd0G0EKe3S9cbKgHoQSUZIIWe0gt +wzp6WkLsa9emgn3GpKS1do6AnFcpz0MwpzACz0aPPJ4jUwAGsiAwlzpM2eySqmy2 +brycNOnLuAvoxKy4QsFgCDl5sUe3hJF74RhWYKrpAoGAUrJMF5IaAAsv367nD8CX +CfDsDlez54H/sZD7iKj8LhyuspAQBU3vQ3xKfaKRi4px8bgnty3stOMZxEC7I6BC +jHH1hQK8l9nqRhOjPvoViUM6aOpabCkVsOZjWKD+OCz3X9+MmlGkMuNd22GRdwlb +Emb3yEoFr5vDbez0IQNxnLs= +-----END PRIVATE KEY----- diff --git a/src/components/transport_manager/test/test_certs/invalid_cert.pem b/src/components/transport_manager/test/test_certs/invalid_cert.pem new file mode 100644 index 0000000000..70d124c2b7 --- /dev/null +++ b/src/components/transport_manager/test/test_certs/invalid_cert.pem @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDlDCCAnwCCQDIe7AwFpWRlDANBgkqhkiG9w0BAQUFADCBizELMAkGA1UEBhMC +UlUxEzARBgNVBAgMClNvbWUtU3RhdGUxGTAXBgNVBAcMEFNhaW50LVBldGVyc2J1 +cmcxDzANBgNVBAoMBkx1eG9mdDEXMBUGA1UEAwwORG1pdHJ5IENobWVyZXYxIjAg +BgkqhkiG9w0BCQEWE2RjaG1lcmV2QGx1eG9mdC5jb20wHhcNMTQwMjI1MDkxODUz +WhcNMTYxMTIyMDkxODUzWjCBizELMAkGA1UEBhMCUlUxEzARBgNVBAgMClNvbWUt +U3RhdGUxGTAXBgNVBAcMEFNhaW50LVBldGVyc2J1cmcxDzANBgNVBAoMBkx1eG9m +dDEXMBUGA1UEAwwORG1pdHJ5IENobWVyZXYxIjAgBgkqhkiG9w0BCQEWE2RjaG1l +cmV2QGx1eG9mdC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCn +Mu9wNmXKaKOnefSv5iT8G2ESLjq+eYlxys/XAnDfkmnlgGYAcPno+XMhRj/lNV/c +3A0L/R4631GFJA8vaM8m9Bn47FrPP4AXIHEQh9acA4qXiLfhhA8+9PPt4xVkjQYj +bmexBLqDvRgT3MJwwFecUn/UABBlVZRCspn+6DkjiodbgmBOqyi1p0ng8BFeUbEH ++fLQVILCX3pjnMiP2bBtvq/7njgZT2luVtAAcOdRwRTuZT0YbgaXrHYsOa6VYDl1 +I0uOcdD8qENBXtBnykEqH+jZtKu6Rej1DsGOYWqz3AAaGiR1GJauNBxh+4v+i/eB +0aCIA8T8qUqyuVVg48S/AgMBAAEwDQYJKoZIhvcNAQEFBQADggEBACliraOJYijK +yS+Sl6S6pFRqdF/evPdYF6zDJlM3P+/9qHoEy751vbBTzRkVbC/azyiZLwQMuyED +6oCpkI7MqnrRip1ZelGx9K7ChaHOpX/QRN+3eqiDhzvMTGd2nPJf9np4xi8SJpGP +UUROYI5fToIY5MaOKuOIR2a6c8xIuLWMG1XKJxXrRetLJZDgBqQPkuqaZIjYCY+q +HQRjNUFNX4Mc453tKd90gFLGI3fxs1fJDIRSGfKJsj0qc+amSz4Sgiz4QUBcUQKd +hJxUpStYhliZGZchEopLsShtIGfKKFaaPCIOTpVAwSr1oIDm9lpkdxeuQfedKT5f +ZZmkez2pAF8= +-----END CERTIFICATE----- diff --git a/src/components/transport_manager/test/test_certs/invalid_key.pem b/src/components/transport_manager/test/test_certs/invalid_key.pem new file mode 100644 index 0000000000..d2aacc1638 --- /dev/null +++ b/src/components/transport_manager/test/test_certs/invalid_key.pem @@ -0,0 +1,28 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEApzLvcDZlymijp3n0r+Yk/BthEi46vnmJccrP1wJw35Jp5YBm +AHD56PlzIUY/5TVf3NwNC/0eOt9RhSQPL2jPJvQZ+Oxazz+AFyBxEIfWnAOKl4i3 +4YQPPvTz7eMVZI0GI25nsQS6g70YE9zCcMBXnFJ/1AAQZVWUQrKZ/ug5I4qHW4Jg +TqsotadJ4PARXlGxB/ny0FSCwl96Y5zIj9mwbb6v+544GU9pblbQAHDnUcEU7mU9 +GG4Gl6x2LDmulWA5dSNLjnHQ/KhDQV7QZ8pBKh/o2bSrukXo9Q7BjmFqs9wAGhok +dRiWrjQcYfuL/ov3gdGgiAPE/KlKsrlVYOPEvwIDAQABAoIBAQCAjkNXzhuZ87bR +UI34qUYKqaqLZgw45A3v9naz5OaQoGzXz0+eSz98CECjdvYt8EoS8Qb/DtGthoOR +kVYzp6yPUOSfZmu0Kij8ny8P/MHgF0D6nl50ASwPxhu/7vhF5cCwgXUswGwAWuYm +b3j5ZIp4YV5zzNDOeWyTk+uf+UHltqFD7Ae4M9z58r17/OWhva5mtusTuuEYjzC6 +AE/fsOC0gLNSM4+SfclfCkHpH+GikzNMSQ2H0hlXllPmR73BoC6N6aoY5hQWBLV7 +LxtYbJqx7TAqRyypBQekjJe36roRetXtzy3i6V/y69045td5kk70cVjmFhl79475 +82rnRLHBAoGBANgq4axr5OotTUmPkGd0afoaWSRPJfiTTdNeMkqTzM6zIcVLSKhB +78ERwdDD9FOu+Bgivg4DlpmH7ArWn8QNDtdkhmPfKYfTqX6qH7AK4cybvYICMlct +EdW4TvKm/ZB3mrVOP9JVPjdyFMp+Je6N+qp1w+ui9mxX8pWnrC/+DfTvAoGBAMYC +GFjnw/O9hjF2Mb00qUarmM+reJZMXv/pVik+cm0eAiYvgGvKbAYkIXwdb7rLBw9k +baJmxP0PrAoXy5TpPdfROqPwrRCyReKymKkEZeTpONgD0s8MbX167ovZu1OQVKQo +IyJeUzWa0kpglnbL2lLVu49x8jWHDJdYhmkDNE0xAoGAR4ux07qGMoe5693rYoJi +TRgJZv4XSDWg7ZNgu9Q9VjBtvfoT2zSvoMw6xNkGdegUTxC4rLS9VKVrF48/o8ja +n6my3T1QZpdEoxq1kDOZ1nm5eF03wii1nXH6F0/z3qvndZingPsbs4g7n2WvMkyl +qWN+6++s9eEJ9kRftia1AdsCgYAUnU05nE97RcT9y0dcYmopMF5FaJ2yUBsn23wb +6SNylsg0f4eIMVfTv9k4mbvzH4YJpTQAz2A81G/d0SJhy3Kj0GWhgcIS1eyOsHdS +SWHuVhWT77n30lxnzu+c4bst9P3K5V7bCiTxlL/F/I5NqeV98ECJq5xC1F+MNiww +LKQ6UQKBgC2zL59Vf8QnRkRN0gOUfs3ejrLcxFRzTXvcKqcHtbaqzCs3qSNC6UvV +wjBazEwQCo1wnM81X8uT5fLhnjXebWtnYexQo5P38PiaqTQDgrbAdhP5P8NwRCXM +G3SNEz0XeL27jmWjf0VJdwD0LuHXYhcwAWq4alhJ024rjgVHwOze +-----END RSA PRIVATE KEY----- + diff --git a/src/components/transport_manager/test/test_certs/server-cert.pem b/src/components/transport_manager/test/test_certs/server-cert.pem new file mode 100644 index 0000000000..d2b1cf0ec8 --- /dev/null +++ b/src/components/transport_manager/test/test_certs/server-cert.pem @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDdDCCAlwCAQEwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UEBhMCVUExDzANBgNV +BAgMBk9kZXNzYTEPMA0GA1UEBwwGT2Rlc3NhMQ8wDQYDVQQKDAZMdXhvZnQxDTAL +BgNVBAsMBEZUQ04xDzANBgNVBAMMBkx1eC1DQTEaMBgGCSqGSIb3DQEJARYLY2FA +ZnRjbi5jb20wHhcNMjAwMTEwMTQzMzM2WhcNMjIxMDA2MTQzMzM2WjCBgzELMAkG +A1UEBhMCVUExDzANBgNVBAgMBk9kZXNzYTEPMA0GA1UEBwwGT2Rlc3NhMQ8wDQYD +VQQKDAZMdXhvZnQxDTALBgNVBAsMBEZUQ04xEjAQBgNVBAMMCWxvY2FsaG9zdDEe +MBwGCSqGSIb3DQEJARYPc2VydmVyQGZ0Y24uY29tMIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEApnW3zyWadWiD1eMPszMM0Hyzm3Zd6mr21LMtQMwqw10p +PxMpZLo0rgCkJevVRxO/y4J+TcE9LtralzzsWK+DD/i2Gf8CfAOapcDETJ8b68jM +rUMwmN3tdiEBqimHBKEKIgDOiJt2Y08Jw2AWR41LuyjtD+IWSWo1kqJF3rxpsfz0 +SfTQWkvHVXg1c0qbfsp2i82Nvt5HzvDdk0jzX+GNHSmkUECcE0GIhK8GHxAFYugk +siRU/tgY/wzP9iUkj7UbPWb5k+d8Z3sqUFpVAa4dXhIzx5L0l5peXvhunYqr7Vk+ +cfBAHIQZKJa7coBBahA7gjBylz+BbIOadGYYoYZVBQIDAQABMA0GCSqGSIb3DQEB +CwUAA4IBAQDNUMIv6X9scvVN8II/PbvvQzWAxi0qzDejnEF579PA9MCNt6JY20lj +JTscUN5lWNuLGJtkUuscBMBYe21ePtGeS855Q6csoUe6m0fnY+ybKVYIKk+SL5Hx +1vurBIsHOyX6097e8VIzWyxcWW1074oTYLpYfEWr0vECrGodoXGtPdEeyB0+QdbI +H0Pcngqu5yLoWxoWwuAj94YG7eX3sJv6PXOW71i4yMmT8ToYNXFwqTK/xq/pl6H2 +KH150zDNOaE2Z5+u21Elau+3qWPWQ6C9KpxhmJ/iDftRe+hgMISSygYK0nwk0zk4 +rmNODAeuTvsrh9bNsYQfjERsh0VYaG24 +-----END CERTIFICATE----- diff --git a/src/components/transport_manager/test/test_certs/server-key.pem b/src/components/transport_manager/test/test_certs/server-key.pem new file mode 100644 index 0000000000..6ff13eaf28 --- /dev/null +++ b/src/components/transport_manager/test/test_certs/server-key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCmdbfPJZp1aIPV +4w+zMwzQfLObdl3qavbUsy1AzCrDXSk/EylkujSuAKQl69VHE7/Lgn5NwT0u2tqX +POxYr4MP+LYZ/wJ8A5qlwMRMnxvryMytQzCY3e12IQGqKYcEoQoiAM6Im3ZjTwnD +YBZHjUu7KO0P4hZJajWSokXevGmx/PRJ9NBaS8dVeDVzSpt+ynaLzY2+3kfO8N2T +SPNf4Y0dKaRQQJwTQYiErwYfEAVi6CSyJFT+2Bj/DM/2JSSPtRs9ZvmT53xneypQ +WlUBrh1eEjPHkvSXml5e+G6diqvtWT5x8EAchBkolrtygEFqEDuCMHKXP4Fsg5p0 +ZhihhlUFAgMBAAECggEBAJ35UfuxACk0iwlNd/TlGeAyuHFtoCt8X8v0T5oTKPJH +U4GcucfyP1RzH1Utvza5M2f768n2/g2dfZ3SH6r6xjM+IfQB42W2NengS2s8BM97 +vWMhRNmOpHFbWa0XxB9MhcVHZrqWb4BH3kggxIQbQCfa60ALnIMH3NfQUObVgKl8 +khPU3fWx5zH2fbLNiLbImr5U5ViNoOKw592cmAEocIgIE33SDf2LHuuByikb38/r +98bAp6IdNhRb7qY/Jllq3fu06fLubGQusVT01vu3sp//G2gCzFwp0O/qX2M1JBPS +JYKKGXrNxeaQNzzD6cEcSkADpZvIG/CmmnR9u/FjIXECgYEA2palcAJKXPWsnwLb +QtDd7MQ6sG3qvkCaiiDsn5BAGkxn1rZ3NRGMxBx4Fb9oiIl6SBpQ/YdMkd7tMkLX +MEmbPyOcHPnsxcCqeFGsiTejpx1OyPSUAtxtpxGc/D63wCPhHGO3xNdQ2FiYb5K3 +jG8cslE39gH+/9XSN8kS2gZZ4d8CgYEAwvMUbXSBYx01I+jjqsjSI9afk3w9VwKM +vuW9MgUBYLP5ryadNqt2cuHydT5KJiZ7YUQSLNztZ++g5WR7yamWpLzoGFmrSyWb +304xA9jdLRJHMsBM0V32abdfTV5+EW+24309UmcaUtsQoUTxXOSqwDaHF4Mq1zLg +jwb2phYlzZsCgYEAtz5q2gdRh7R8TaD7ZnvqTz4BZT3/+BX4d6s6MlmfI2zB8AFu +1ZIsy4qCMNkRLMTzOda15pOx4OddOTFHbDeIadnUWYY6s1zci5kMZsu56bJsBZLj +MbLQSao+TEfXir+JS19dAyrtnzBGOeJo9NWA3QuxOg5aUuZRIGrz3spMN0kCgYB3 +ZLnpAwZO9k9aS8JLESypqEMY52kFxdj+/OKvJKOgXvkWzPZRyhcD6t878McmsEC1 +5COheDipg/etJaouan+JKuyWJSykHEdnLpMUQRfMB7q1GVKykvJb8mMaljltYlbG +4ifRNLXJcsKvkfKkKqNsjriTrNBq9YzT67bZJw1F6wKBgGlEd9O+qWY4dSPKN60N +khG1Splz+eBbbsqcISeFGZepEc4HaEIcYgIHTh8nw5ycYxh8A1UBdaBZmU9UHdfl +j9M2u0htKZ27ntVVNZJCLeSgufaPUDIfvnK4o5q630NGhKJmVcYD3WeggIrPfca3 +fP8WaHq9fx5k4YZokD2VHOJb +-----END PRIVATE KEY----- diff --git a/src/components/transport_manager/test/transport_manager_default_test.cc b/src/components/transport_manager/test/transport_manager_default_test.cc index bedc1634cc..67b4a0a8ba 100644 --- a/src/components/transport_manager/test/transport_manager_default_test.cc +++ b/src/components/transport_manager/test/transport_manager_default_test.cc @@ -65,6 +65,12 @@ const std::string kTransportManager = "TransportManager"; const std::string kTcpAdapter = "TcpAdapter"; const std::string kBluetoothAdapter = "BluetoothAdapter"; const std::string kDevices = "devices"; +const uint16_t kPort = 12345u; +const std::string kAddress = "127.0.0.1"; +const std::string kServerCertPath = "server_certificate.crt"; +const std::string kServerCACertPath = "ca-certificate.crt"; +const std::string kWSServerKeyPathKey = "WSServerKeyPath"; +const std::string kWSServerCACertPath = "WSServerCACertificatePath"; std::vector kBTUUID = {0x93, 0x6D, 0xA0, @@ -180,7 +186,7 @@ void TestTransportManagerDefault::ExpectationsSettings_TM( // Arrange TM Settings expectations Json::Value tcp_device; tcp_device[kDeviceName] = unique_tcp_dev_name_; - tcp_device[kDeviceAddress] = "127.0.0.1"; + tcp_device[kDeviceAddress] = kAddress; tcp_device[kDeviceApplications][0][kApplicationPort] = "1"; Json::Value bluetooth_device; @@ -192,16 +198,29 @@ void TestTransportManagerDefault::ExpectationsSettings_TM( custom_dictionary_[kTransportManager][kTcpAdapter][kDevices][0] = tcp_device; custom_dictionary_[kTransportManager][kBluetoothAdapter][kDevices][0] = bluetooth_device; + ON_CALL(transport_manager_settings_, websocket_server_port()) + .WillByDefault(Return(kPort)); + ON_CALL(transport_manager_settings_, websocket_server_address()) + .WillByDefault(ReturnRef(kAddress)); + ON_CALL(transport_manager_settings_, ws_server_cert_path()) + .WillByDefault(ReturnRef(kServerCertPath)); + ON_CALL(transport_manager_settings_, ws_server_key_path()) + .WillByDefault(ReturnRef(kWSServerKeyPathKey)); + ON_CALL(transport_manager_settings_, ws_server_ca_cert_path()) + .WillByDefault(ReturnRef(kWSServerCACertPath)); ON_CALL(*mock_last_state_, dictionary()) .WillByDefault(Return(custom_dictionary_)); ON_CALL(*mock_last_state_, get_dictionary()) .WillByDefault(ReturnRef(custom_dictionary_)); + EXPECT_CALL(transport_manager_settings_, use_last_state()) .WillRepeatedly(Return(use_last_state)); EXPECT_CALL(transport_manager_settings_, transport_manager_tcp_adapter_port()) .WillRepeatedly(Return(tcp_adapter_port_)); + EXPECT_CALL(transport_manager_settings_, bluetooth_uuid()) .WillRepeatedly(Return(kBTUUID.data())); + EXPECT_CALL(transport_manager_settings_, aoa_filter_manufacturer()) .WillRepeatedly(ReturnRef(dummy_parameter_)); EXPECT_CALL(transport_manager_settings_, aoa_filter_model_name()) diff --git a/src/components/transport_manager/test/websocket_client_connection_test.cc b/src/components/transport_manager/test/websocket_client_connection_test.cc new file mode 100644 index 0000000000..b9aa6f7c7e --- /dev/null +++ b/src/components/transport_manager/test/websocket_client_connection_test.cc @@ -0,0 +1,482 @@ +/* + * Copyright (c) 2020, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "transport_manager/cloud/websocket_client_connection.h" +#include "gtest/gtest.h" +#include "resumption/last_state_impl.h" +#include "resumption/last_state_wrapper_impl.h" +#include "transport_manager/cloud/cloud_websocket_transport_adapter.h" +#include "transport_manager/cloud/sample_websocket_server.h" +#include "transport_manager/transport_adapter/connection.h" +#include "transport_manager/transport_adapter/transport_adapter_impl.h" + +#include "transport_manager/mock_transport_manager_settings.h" + +namespace test { +namespace components { +namespace transport_manager_test { + +using ::testing::_; +using ::testing::NiceMock; +using ::testing::Return; +using namespace ::transport_manager; +using namespace ::transport_manager::transport_adapter; +namespace websocket = sample::websocket; + +class WebsocketConnectionTest : public ::testing::Test { + public: + struct WebsocketClient { + std::shared_ptr adapter; + std::shared_ptr connection; + }; + + void InitWebsocketClient( + const transport_manager::transport_adapter::CloudAppProperties& + properties, + WebsocketClient& client_out) { + uniq_id = dev_id = properties.endpoint; + + client_out = + WebsocketClient{std::make_shared( + last_state_wrapper_, transport_manager_settings), + nullptr}; + client_out.adapter->SetAppCloudTransportConfig(uniq_id, properties); + + TransportAdapterImpl* ta_cloud = + dynamic_cast(client_out.adapter.get()); + ta_cloud->CreateDevice(uniq_id); + + auto connection = client_out.adapter->FindPendingConnection(dev_id, 0); + + ASSERT_NE(connection, nullptr); + + client_out.connection = + std::dynamic_pointer_cast(connection); + + ASSERT_NE(client_out.connection.use_count(), 0); + } + + void StartWSServer(std::string path) { + ws_session = std::make_shared(kHost, kPort); + ws_session->AddRoute(path); + ws_session->Run(); + } + + void StartWSSServer(std::string path) { + wss_session = std::make_shared( + kHost, kPort, kCertificate, kPrivateKey); + wss_session->AddRoute(path); + wss_session->Run(); + } + + protected: + WebsocketConnectionTest() + : last_state_(std::make_shared( + "app_storage_folder", "app_info_storage")) + , last_state_wrapper_( + std::make_shared(last_state_)) {} + + ~WebsocketConnectionTest() {} + + void SetUp() OVERRIDE { + ON_CALL(transport_manager_settings, use_last_state()) + .WillByDefault(Return(true)); + } + + NiceMock transport_manager_settings; + std::shared_ptr last_state_; + std::shared_ptr last_state_wrapper_; + std::string dev_id; + std::string uniq_id; + std::shared_ptr ws_session; + std::shared_ptr wss_session; + WebsocketClient ws_client; + std::string kHost = "127.0.0.1"; + uint16_t kPort = 8080; + std::string kPath = "/folder/file.html/"; + std::string kQuery = "?eventId=2345&eventName='Test'&expectedResult=true"; + std::string kFragment = "#section_1"; + + // Sample certificate for localhost + std::string kCertificate = + "-----BEGIN " + "CERTIFICATE-----\nMIIDqTCCApECCQC/" + "5LlQ+" + "GLgqTANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAwx\nMjcuMC4wLjEgQ0EwIBcNMTkwNTA" + "2MTkzMjM2WhgPMjExOTA0MTIxOTMyMzZaMBQx\nEjAQBgNVBAMMCTEyNy4wLjAuMTCCAiIwD" + "QYJKoZIhvcNAQEBBQADggIPADCCAgoC\nggIBALbeIoAHFaFeNqbMnhtAO5QTgRd0X9qxpB0" + "d4M0dEeog2l/+inNA/eu+CCvm\nJj2I8+6MWH2TUrl/" + "2xfhHjzsMrtISCdpNcjaNzCnvi8ZcspFi3evknvs3+uo2/" + "wn\nyNZ04jp0oQ0k1cZ6WBpLTYV7WgmueemiWEiAfw+YE+wtRg+" + "0H7rksrbpeNPnxQHX\nBDDkWqwvfkD15Sd0XFQkW27K72/" + "et2uKuAcJHCIUbsA4iZyJw4Uu4eusy7W5kddX\nThE7Y1WqTXyA4j/" + "ZCYigXmsHbWrikPLVXbORhiMF4/60u8RDs0jI8xtgRQhLR9Vp\n3xys7/" + "5tHZX00s6x6OVy8aMSZIIVS0eWoVN8bGd9B4+fDMOcNT0YODeQA10w/" + "85P\nEiZDQ8AxneQkh8H3qjD2+" + "G9oHZaTk0zHTyaKRg3xGP3N9C96onaJX4Rm6nNvApO8\nU7lQ+xHkLwjKCQke39W+" + "r3FHwwQvUDeoJBXf6iVkIMFoUPAHNZqKf9Db6KKIEp8i\nDgIhbBxiB4MSn36Zly4SOMojyM" + "ZFri+" + "HzMbuHFlm8e8QRWGmM4UM2rHIpl4OJolg\nejesDqO8YZR5mZXV0FJRiPgLo2Q4OTtb3tEHJ" + "ZLmlT+" + "f42bge4ZCZmGPrkNfr68Y\nDEnJ6z4ksOVkMefOp2SNYLYYGPYyiKwa9qVkH9Obkect1omNA" + "gMBAAEwDQYJKoZI\nhvcNAQELBQADggEBABFJQtOTftrzbLBA5Vm6aPkbUyxhcaOpz+d+" + "Ljd6pIs4H+" + "Eb\nXkoHhmay4stZkDc2HVSKESZloI3Ylup8z3aRJjfOexJqHlYzk2vraYryWm8odgID\n5V" + "B0Zle8ofpHTJw1LCOXHkzKt1G6vdQpuq/" + "4OKpmggaIqqEC1bfOYZt5t6vIx3OF\nxjPz91NTR9gZ4lKrho1+sfS+" + "jbSjKkqVAhE4yTpKLPHRshQnBFEhvATXNvdZGftF\n+tXxqKsBZ9aX0/" + "YmPFIXFcjdjSSiuq1F1DjiqIZo88qfa9jlTg6VJdayyQ/" + "cu41C\nBucY8YTF0Ui8ccIS55h2UTzPy5/4PbrwI4P+Zgo=\n-----END " + "CERTIFICATE-----\n"; + // Sample private key + std::string kPrivateKey = + "-----BEGIN RSA PRIVATE " + "KEY-----\nMIIJKAIBAAKCAgEAtt4igAcVoV42psyeG0A7lBOBF3Rf2rGkHR3gzR0R6iDaX/" + "6K\nc0D9674IK+YmPYjz7oxYfZNSuX/" + "bF+EePOwyu0hIJ2k1yNo3MKe+LxlyykWLd6+S\ne+zf66jb/" + "CfI1nTiOnShDSTVxnpYGktNhXtaCa556aJYSIB/" + "D5gT7C1GD7QfuuSy\ntul40+fFAdcEMORarC9+" + "QPXlJ3RcVCRbbsrvb963a4q4BwkcIhRuwDiJnInDhS7h\n66zLtbmR11dOETtjVapNfIDiP9" + "kJiKBeawdtauKQ8tVds5GGIwXj/rS7xEOzSMjz\nG2BFCEtH1WnfHKzv/" + "m0dlfTSzrHo5XLxoxJkghVLR5ahU3xsZ30Hj58Mw5w1PRg4\nN5ADXTD/" + "zk8SJkNDwDGd5CSHwfeqMPb4b2gdlpOTTMdPJopGDfEY/" + "c30L3qidolf\nhGbqc28Ck7xTuVD7EeQvCMoJCR7f1b6vcUfDBC9QN6gkFd/" + "qJWQgwWhQ8Ac1mop/" + "\n0NvooogSnyIOAiFsHGIHgxKffpmXLhI4yiPIxkWuL4fMxu4cWWbx7xBFYaYzhQza\nscim" + "Xg4miWB6N6wOo7xhlHmZldXQUlGI+AujZDg5O1ve0QclkuaVP5/" + "jZuB7hkJm\nYY+uQ1+" + "vrxgMScnrPiSw5WQx586nZI1gthgY9jKIrBr2pWQf05uR5y3WiY0CAwEA\nAQKCAgBGSDGyS" + "wbBMliG2vWZO6KqUqS2wv9kKgoNNsKDkryj42SKqGXFziDJTgwN\n8zKXS9+Uu1P3T3vn13/" + "5OYhJme4VlL5Gh2UogNXdWVr69yjrHLdxlIUUJAIbrJZ/" + "\n3zqNUfbwyIptZs7SrYrW8EInHzWHqwsoBEEx/" + "FDZSXW+u9fFiVD4n5UgP7M0nktV\nXbI6qElBDC/V/" + "6vG8i3aGO8bMdu8fzi3mGUKLzIk1v2J2zDofPosYcxqq8rPWTb4\nMJHMhaqz7fRB+" + "bb7GwtS+2/Oathe0B0td1u//Bo1s7ng1s2jrPFm8/" + "SbfPCLM4O0\nPjCF8OF8Q6uvSp0K283LAdZk+liuDztc/" + "Ed8mcnCZQhBp86mJQi0Jj3Mje7prOAY\nXojMroYj7r2igCJvcwGb1y6zZWSj3jXuHze3bLy" + "fv7pCD+hkiZR7mZhQpOhQRZaU\ntdFGc+" + "DuykxKPqVjAPy7iVQXYnMjpo36SGIWoZLuepQto3GvU6czyOwhK0/" + "Mwbwd\nZpYpLH3L9IetY8GcPefmUR5wQUlUTrpxgGElIzkkWW8zmUWBXwrGbAtN1HJWpJdN" + "\neVshKod2fo03IQMPywSdENCJVeSrgRMuwPyFaOM+" + "CVrBJwD66K9YWn4cVRUIZsTq\nAXhQ8DzF+WCOZshhMUbCJX+KpcOFI8nxOrPp+" + "J1s1YpLLvdmcQKCAQEA7bwvOiCD\nHvaqpYg1jJak6l/" + "iY3QIOOpFyjfYrQXS0BNRmmxK8Lzevi/" + "NPTqu146QKDaIGvzu\n+" + "bXnuV1LmZqnOm5J6Kdx0Mk4Fb88akRtS9gOdzU7WWMYIGkeF1oih0ZrhHuIey6e\nCeLSmJh" + "UDaTIWcCirALRHcLWUS6BTGGuE+up5QG7djIW/" + "LD17lhGE6fXPlbYXb7l\nPbYwL1Yr0urIp9Un+zrExw+77TTGK7T37T1ZJv46qnro0/" + "HK8XxZ+" + "JNc18F763O4\nPmwu8KWrx4qnyPYAuB1rbVntK6UxYks9jvk93XecCUP6HHp0I0tV/" + "kBNd2+" + "18zux\n033xFEVKrUksmwKCAQEAxOrPGyBVFp29V4gQsMQdmafkDAgCLREgjQTOamFsYL5+" + "\nZWq+6VhT/" + "B650sIoRdX0N8timnSLBfjeqaBG5VVhhyKZhP5hulfRjALhdbGBOYvf\n0gLSffImwWdYQfx" + "jtCSO+" + "XCLVdAJGOOWeBVVKzH18ZvCFQwUr3Yrp7KmKWKAqgf7\n6rYovWh8T5LLYS0NzXCEwf9nJ0N" + "JMOy7I9B7EtF8Cs6tK3aaHVqDz7zufwosS7gI\n3aI51Qh4a5D1p95+" + "YU09beWjWGYnPiCKk4D47zaeOe7OQINaWugExlelHtJh9unO\nnhOFXhziav2Kxq1CICAuXl" + "Vx3A+gn/cU3niNHz2A9wKCAQEAws+aw78ws4bef5cG\nipZHveek1GqY8krHtdXdsKs8/" + "VVXYXusTWn3/VGelbYo4GrqpolJLxRloCr4IGXb\nNZwNvUvzNLtCAR1i4C89irdX+Paro/" + "PzFmSluKlrByfNc5y5Lm8sgATLbL56ZKEu\n/58wrpu0sc/" + "9HK40gYHiYn0I8ToElqy8uTaCr78zSIT9p826DFOOKgPsRo2tHp02\nfDf5Bc8eXDjkV1sFX" + "HQKkHZTVA0ZqWJbIKhncoaJDyofcBsR0ZuzuFWzfTOZo4mf\nInz00TEFldpF1e4C8+" + "kCdtHBOA/2Ki2Bp/YUVpHh6aoqZZa75Euehhs8tVpW242M\njEOSUQKCAQAM64sjMH/kt/" + "zQXXEa6AM5LbbcwznBUzpbhlE00aeWwWjxpotYLB92\nj12J4otZ6avYbVPO5o6omaeiYY3F" + "RlDb2P1RqI8o9tIc6aN5YWglKnRJBz5gXR8F\n2Y4E5lZ0X2GyJBxASSIPq/" + "8Xae7ooqKMc7fMQbqpuIssuaAFXx0qCtQQllsd8lkV\nr4AApEAflp5fTC6seNG4kA/" + "HTcqFdZE59E2QaHu8KVA0tSTA2R4G6dBLGnXI8IFW\nLXCwzvxjzfmV2FdbWXiBrwjonLG4o" + "FDJZE3MFdI73LVTfjSrTQp4dObFoGpDvols\nk64jUwLfsLzaG6kY0z2qwT9xSV+" + "ZCSQJAoIBADsSBeyELc5KnmOhT0Xue2o0bkAS\n8KcGWdAoQlaLCIs3vtdlC7DXDXO1l8FkT" + "Qrd+GwP3eWDq6ymtO4vkJ3m4cZ1PEsv\n6Qet7qtkVhUfa+" + "FYKtDzSMRuSaFPW3Ro1PesFa1H3y+sw5HL36vhRaSK+T4Wy5k2\nf7EwNZIf/" + "ZZeA+" + "sEtqj33obOBIiuU9htAjN81Kz4a0Xlh6jc4q6iwYKL8nZ76JYV\n8hXWIz6OXxLXE158+" + "QtJSZaRCvdr6L5UtWfMPKSMqgfhXfTYViPDleQCkJ132mIS\nH28UoET0Y5wI8M6pMkWpSqW" + "WcKPFGwyLInvHdxgnTAsutowkldA7qFwoRz4=\n-----END RSA PRIVATE KEY-----\n"; + // Sample CA certificate(used to sign the server certificate) + std::string kCACertificate = + "-----BEGIN " + "CERTIFICATE-----" + "\nMIIDBjCCAe6gAwIBAgIJAPyCrKRDl3SWMA0GCSqGSIb3DQEBCwUAMBcxFTATBgNV\nBAMM" + "DDEyNy4wLjAuMSBDQTAgFw0xOTA1MDYxOTMyMzZaGA8yMTE5MDQxMjE5MzIz\nNlowFzEVMB" + "MGA1UEAwwMMTI3LjAuMC4xIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC\nAQ8AMIIBCgKCAQEA" + "xrNHoY5+" + "JCgnyvEdG2dvvOaZ3sg6uhuF5Ssb5snyo9ixrxO5\nZkDGWwUqFO9PiYuO5ovNeq9LZtPG6s" + "K8zsCS062ChZX/7tZHndf4MKCUDzv/" + "LPHe\nnROoPi9n2FAiOPctY5hpgpIJDPI5Ofx0el2KPeFGeUO/" + "W3yqnfol1ZqzZ2h3uErR\noHkgT2Ja4K+5gnPkr/" + "RluJIu3AmWYw4eKi8i3+" + "PoThGmCFvoGfcWvRoctgnOHYHE\n4bDRirXL9nGkZ5FMzOVDeoIAEAShOqJwL08VcY+Pg/" + "qFQjzRrTmiKgm6QsHNnm0q\nzg70XaD88VJimiGYZOuJHNZpX8o0W+1Ls/" + "NbawIDAQABo1MwUTAdBgNVHQ4EFgQU\nkW3hgFWYMpVUkq9AlzGlI3awTGEwHwYDVR0jBBgw" + "FoAUkW3hgFWYMpVUkq9AlzGl\nI3awTGEwDwYDVR0TAQH/BAUwAwEB/" + "zANBgkqhkiG9w0BAQsFAAOCAQEAZeMkILiG\neEcELWb8cktP3LzvS47O8hys9+" + "6TFmftuO7kjDBd9YH2v8iQ7qCcUvMJ7bqL5RP1\nQssKfNOHZtw/" + "MMcKE6E3nl4yQSKc8ymivvYSVu5SYtQCedcgfRLb5zvVxXw8JmCp\nGNS3/" + "OlIYZAamh76GxkKSaV3tv0XZB6n3rUVQZShncFbMpyJRW0XWxReGWrhXv4s\nNxMeC1r07EE" + "WIDecv8KKf1F8uT4UF48HnC0VBpXiOyDGvn35NiKp+" + "Q5k7QV6jdCS\ngPRcnZhs6jiU0jnV8C9A1A+" + "3pXSSPrAed7tvECOgHCfS10CLsLWsLuSjc93BE5Vt\nav7kmxSwrdvQ2A==\n-----END " + "CERTIFICATE-----\n"; + std::string kIncorrectCertificate = + "-----BEGIN " + "CERTIFICATE-----\nMIIC/" + "jCCAeagAwIBAgIJAIZjLucUID1mMA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNV\nBAMMCTEyNy4" + "wLjAuMTAeFw0xOTA1MDYxNDA1MzdaFw0yOjA1MDZxNDA1MzdaMBQx\nEjAQBgNVBAMMCTEyN" + "y4wLjAuMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC\nggEBALfE5Qhc2mHTIux30l7" + "eHFjFLdzYeXE8vcaXKodalCG8EkRxojDOfUv+y2DV\nJzHAMiGxMFAEcSz71k+" + "jFZwhNG8PLY0b36ChnUsrGkOSJWq3OKUFrg8KxO9At9dL\nJsa+" + "R0N0D1bMoPYdpCi3m0b0q2ITHe56qKuTLTrIPia+" + "qXGEVD7EoEhU9tnwlcwE\npsUURMXCn2+FhHyqN9wjFkldmu4k8U3OJOK4385L+" + "4RJoIV8dsYawAMAf+" + "WuxyWq\niPQTPxr8q33ZZm6z0XrgsgxHYCCsryx8L9Ub9Zwu0mie7eL63rYdr86gULvnF1bY" + "\ncOunKFc71rBYFalbD6YYsre733kCAwEAAaNTMFEwHQYDVR0OBBYEFKW9ByUNG84Z\nYiSc" + "hUrB7KV9FinZMB8GA1UdIwQYMBaAFKW9ByUNG84ZYiSchUrB7KV9FinZMA8G\nA1UdEwEB/" + "wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAHYROS1EL2qnrwmAsR6c\nqo8yrk8qzLKt4os" + "41nv7QMUQFIO+QLPE8SbH4fK1YOMMUJ4ppARQBDaIIR3UEhp1\nZHT/" + "wGjK9qxcuQ1EXLyHOY0rxS5q57dYGxOyQo4v6IoLVMZ1ij+RJGPYI/" + "2fDXs0\nbDldeJyC1voHmG6lqTN5nLG7Y3j9j6rtSqJyRz5muaecQNiFPQOM2OTp0rC4VeAF" + "\ndejmTmLhUFVuHMzLF+" + "bpzsN76GnnQquJy2jexzFoWgbEfFVLKuyhTHQAalRb4ccq\nXCIx1hecNDYRY3Sc2Gzv5qxk" + "kWF8zqltT/0d5tx0JwN3k5nP4SlaEldFvD6BELxy\nVkU=\n-----END " + "CERTIFICATE-----\n"; +}; + +TEST_F(WebsocketConnectionTest, WSConnection_SUCCESS) { + transport_manager::transport_adapter::CloudAppProperties properties{ + .endpoint = "ws://" + kHost + ":" + std::to_string(kPort), + .certificate = "no cert", + .enabled = true, + .auth_token = "auth_token", + .cloud_transport_type = "WS", + .hybrid_app_preference = "CLOUD"}; + + // Start server + StartWSServer("/"); + + // Start client + InitWebsocketClient(properties, ws_client); + std::shared_ptr ws_connection = + ws_client.connection; + + // Check websocket connection + TransportAdapter::Error ret_code = ws_connection->Start(); + EXPECT_EQ(TransportAdapter::OK, ret_code); + + // Stop client + ret_code = ws_connection->Disconnect(); + EXPECT_EQ(TransportAdapter::OK, ret_code); + + // Stop server thread + ws_session->Stop(); +} + +TEST_F(WebsocketConnectionTest, WSConnection_SUCCESS_ValidTarget) { + transport_manager::transport_adapter::CloudAppProperties properties{ + .endpoint = "ws://" + kHost + ":" + std::to_string(kPort) + kPath + + kQuery + kFragment, + .certificate = "no cert", + .enabled = true, + .auth_token = "auth_token", + .cloud_transport_type = "WS", + .hybrid_app_preference = "CLOUD"}; + + // Start server + StartWSServer(kPath); + + // Start client + InitWebsocketClient(properties, ws_client); + std::shared_ptr ws_connection = + ws_client.connection; + + // Check websocket connection + TransportAdapter::Error ret_code = ws_connection->Start(); + EXPECT_EQ(TransportAdapter::OK, ret_code); + + // Stop client + ret_code = ws_connection->Disconnect(); + EXPECT_EQ(TransportAdapter::OK, ret_code); + + // Stop server thread + ws_session->Stop(); +} + +TEST_F(WebsocketConnectionTest, WSConnection_FAILURE_InvalidTarget) { + transport_manager::transport_adapter::CloudAppProperties properties{ + .endpoint = "ws://" + kHost + ":" + std::to_string(kPort) + kPath + + kQuery + kFragment, + .certificate = "no cert", + .enabled = true, + .auth_token = "auth_token", + .cloud_transport_type = "WS", + .hybrid_app_preference = "CLOUD"}; + + // Start server + StartWSServer("/"); + + // Start client + InitWebsocketClient(properties, ws_client); + std::shared_ptr ws_connection = + ws_client.connection; + + // Check websocket connection + TransportAdapter::Error ret_code = ws_connection->Start(); + EXPECT_EQ(TransportAdapter::FAIL, ret_code); + + // Stop client + ret_code = ws_connection->Disconnect(); + EXPECT_EQ(TransportAdapter::OK, ret_code); + + // Stop server thread + ws_session->Stop(); +} + +TEST_F(WebsocketConnectionTest, WSSConnection_SUCCESS) { + transport_manager::transport_adapter::CloudAppProperties properties{ + .endpoint = "wss://" + kHost + ":" + std::to_string(kPort), + .certificate = kCACertificate, + .enabled = true, + .auth_token = "auth_token", + .cloud_transport_type = "WSS", + .hybrid_app_preference = "CLOUD"}; + + // Start server + StartWSSServer("/"); + + // Start client + InitWebsocketClient(properties, ws_client); + std::shared_ptr wss_connection = + ws_client.connection; + + // Check websocket connection + TransportAdapter::Error ret_code = wss_connection->Start(); + EXPECT_EQ(TransportAdapter::OK, ret_code); + + // Stop client + ret_code = wss_connection->Disconnect(); + EXPECT_EQ(TransportAdapter::OK, ret_code); + + // Stop server thread + wss_session->Stop(); +} + +TEST_F(WebsocketConnectionTest, WSSConnection_SUCCESS_ValidTarget) { + transport_manager::transport_adapter::CloudAppProperties properties{ + .endpoint = "wss://" + kHost + ":" + std::to_string(kPort) + kPath, + .certificate = kCACertificate, + .enabled = true, + .auth_token = "auth_token", + .cloud_transport_type = "WSS", + .hybrid_app_preference = "CLOUD"}; + + // Start server + StartWSSServer((kPath + kQuery + kFragment)); + + // Start client + InitWebsocketClient(properties, ws_client); + std::shared_ptr wss_connection = + ws_client.connection; + + // Check websocket connection + TransportAdapter::Error ret_code = wss_connection->Start(); + EXPECT_EQ(TransportAdapter::OK, ret_code); + + // Stop client + ret_code = wss_connection->Disconnect(); + EXPECT_EQ(TransportAdapter::OK, ret_code); + + // Stop server thread + wss_session->Stop(); +} + +#ifdef ENABLE_SECURITY +TEST_F(WebsocketConnectionTest, WSSConnection_FAILURE_InvalidTarget) { + transport_manager::transport_adapter::CloudAppProperties properties{ + .endpoint = "wss://" + kHost + ":" + std::to_string(kPort), + .certificate = kCACertificate, + .enabled = true, + .auth_token = "auth_token", + .cloud_transport_type = "WSS", + .hybrid_app_preference = "CLOUD"}; + + // Start server + StartWSSServer(kPath); + + // Start client + InitWebsocketClient(properties, ws_client); + std::shared_ptr wss_connection = + ws_client.connection; + + // Check websocket connection + TransportAdapter::Error ret_code = wss_connection->Start(); + EXPECT_EQ(TransportAdapter::FAIL, ret_code); + + // Stop client + ret_code = wss_connection->Disconnect(); + EXPECT_EQ(TransportAdapter::OK, ret_code); + + // Stop server thread + wss_session->Stop(); +} + +TEST_F(WebsocketConnectionTest, WSSConnection_FAILURE_IncorrectCert) { + transport_manager::transport_adapter::CloudAppProperties properties{ + .endpoint = "wss://" + kHost + ":" + std::to_string(kPort), + .certificate = kIncorrectCertificate, + .enabled = true, + .auth_token = "auth_token", + .cloud_transport_type = "WSS", + .hybrid_app_preference = "CLOUD"}; + + // Start server + StartWSSServer("/"); + + // Start client + InitWebsocketClient(properties, ws_client); + std::shared_ptr wss_connection = + ws_client.connection; + + // Check websocket connection + TransportAdapter::Error ret_code = wss_connection->Start(); + EXPECT_EQ(TransportAdapter::FAIL, ret_code); + + // Stop client + ret_code = wss_connection->Disconnect(); + EXPECT_EQ(TransportAdapter::OK, ret_code); + + // Stop server thread + wss_session->Stop(); +} +#endif // ENABLE_SECURITY +} // namespace transport_manager_test +} // namespace components +} // namespace test diff --git a/src/components/transport_manager/test/websocket_connection_test.cc b/src/components/transport_manager/test/websocket_connection_test.cc index a7ddb820a0..306bdc4784 100644 --- a/src/components/transport_manager/test/websocket_connection_test.cc +++ b/src/components/transport_manager/test/websocket_connection_test.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Ford Motor Company + * Copyright (c) 2020, Ford Motor Company * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -31,15 +31,26 @@ */ #include "gtest/gtest.h" + +#include +#include + #include "resumption/last_state_impl.h" -#include "resumption/last_state_wrapper_impl.h" -#include "transport_manager/cloud/cloud_websocket_transport_adapter.h" -#include "transport_manager/cloud/sample_websocket_server.h" -#include "transport_manager/cloud/websocket_client_connection.h" -#include "transport_manager/transport_adapter/connection.h" -#include "transport_manager/transport_adapter/transport_adapter_impl.h" +#include "transport_manager/websocket_server/websocket_connection.h" +#include "transport_manager/websocket_server/websocket_session.h" #include "transport_manager/mock_transport_manager_settings.h" +#include "transport_manager/transport_adapter/mock_transport_adapter_controller.h" + +namespace { +const std::string kHost = "127.0.0.1"; +const uint16_t kPort = 8080; +const std::string kPath = "/folder/file.html/"; +const std::uint32_t kConnectionKey = 1u; +const std::uint32_t kProtocolVersion = 5u; +const std::string kDeviceUid_ = "deviceUID"; +const transport_manager::ApplicationHandle kAppHandle = 12345u; +} // namespace namespace test { namespace components { @@ -48,433 +59,112 @@ namespace transport_manager_test { using ::testing::_; using ::testing::NiceMock; using ::testing::Return; + +using protocol_handler::RawMessagePtr; +using protocol_handler::ServiceType; + using namespace ::transport_manager; using namespace ::transport_manager::transport_adapter; -namespace websocket = sample::websocket; -class WebsocketConnectionTest : public ::testing::Test { +class WebsocketNotSecureSessionConnectionTest : public testing::Test { public: - struct WebsocketClient { - std::shared_ptr adapter; - std::shared_ptr connection; - }; + WebsocketNotSecureSessionConnectionTest() + : websocket_connection_( + std::make_shared > >( + kDeviceUid_, + kAppHandle, + boost::asio::ip::tcp::socket(i_co_), + &mock_transport_adapter_ctrl_)) - void InitWebsocketClient( - const transport_manager::transport_adapter::CloudAppProperties& - properties, - WebsocketClient& client_out) { - uniq_id = dev_id = properties.endpoint; + , last_state_("test_app_folder", "test_app_info_storage") {} - client_out = - WebsocketClient{std::make_shared( - last_state_, transport_manager_settings), - nullptr}; - client_out.adapter->SetAppCloudTransportConfig(uniq_id, properties); - - TransportAdapterImpl* ta_cloud = - dynamic_cast(client_out.adapter.get()); - ta_cloud->CreateDevice(uniq_id); + void SetUp() OVERRIDE { + ON_CALL(mock_transport_manager_settings_, use_last_state()) + .WillByDefault(Return(true)); + } - auto connection = client_out.adapter->FindPendingConnection(dev_id, 0); + RawMessagePtr CreateDefaultRawMessage() { + const uint32_t data_sending_size = 3u; + unsigned char data_sending[data_sending_size] = {0x20, 0x07, 0x01}; + RawMessagePtr raw_message_ptr( + new ::protocol_handler::RawMessage(kConnectionKey, + kProtocolVersion, + data_sending, + data_sending_size, + false, + ServiceType::kAudio)); + return raw_message_ptr; + } - ASSERT_NE(connection, nullptr); + protected: + boost::asio::io_context i_co_; + std::shared_ptr > > + websocket_connection_; + NiceMock mock_transport_adapter_ctrl_; + NiceMock mock_transport_manager_settings_; + resumption::LastStateImpl last_state_; +}; - client_out.connection = - std::dynamic_pointer_cast(connection); +TEST_F(WebsocketNotSecureSessionConnectionTest, Disconnect_SUCCESS) { + websocket_connection_->Run(); + EXPECT_CALL(mock_transport_adapter_ctrl_, + DisconnectDone(kDeviceUid_, kAppHandle)) + .Times(1); - ASSERT_NE(client_out.connection.use_count(), 0); - } + auto error = websocket_connection_->Disconnect(); - void StartWSServer(std::string path) { - ws_session = std::make_shared(kHost, kPort); - ws_session->AddRoute(path); - ws_session->Run(); - } + ASSERT_EQ(TransportAdapter::Error::OK, error); +} - void StartWSSServer(std::string path) { - wss_session = std::make_shared( - kHost, kPort, kCertificate, kPrivateKey); - wss_session->AddRoute(path); - wss_session->Run(); - } +TEST_F(WebsocketNotSecureSessionConnectionTest, SecondDisconnect_UNSUCCESS) { + websocket_connection_->Run(); + EXPECT_CALL(mock_transport_adapter_ctrl_, + DisconnectDone(kDeviceUid_, kAppHandle)) + .Times(1); - protected: - WebsocketConnectionTest() - : last_state_(std::make_shared( - std::make_shared("app_storage_folder", - "app_info_storage"))) {} + auto result_error = websocket_connection_->Disconnect(); - ~WebsocketConnectionTest() {} + ASSERT_EQ(TransportAdapter::Error::OK, result_error); - void SetUp() OVERRIDE { - ON_CALL(transport_manager_settings, use_last_state()) - .WillByDefault(Return(true)); - } + EXPECT_CALL(mock_transport_adapter_ctrl_, + DisconnectDone(kDeviceUid_, kAppHandle)) + .Times(0); - NiceMock transport_manager_settings; - resumption::LastStateWrapperPtr last_state_; - std::string dev_id; - std::string uniq_id; - std::shared_ptr ws_session; - std::shared_ptr wss_session; - WebsocketClient ws_client; - std::string kHost = "127.0.0.1"; - uint16_t kPort = 8080; - std::string kPath = "/folder/file.html/"; - std::string kQuery = "?eventId=2345&eventName='Test'&expectedResult=true"; - std::string kFragment = "#section_1"; - - // Sample certificate for localhost - std::string kCertificate = - "-----BEGIN " - "CERTIFICATE-----\nMIIDqTCCApECCQC/" - "5LlQ+" - "GLgqTANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAwx\nMjcuMC4wLjEgQ0EwIBcNMTkwNTA" - "2MTkzMjM2WhgPMjExOTA0MTIxOTMyMzZaMBQx\nEjAQBgNVBAMMCTEyNy4wLjAuMTCCAiIwD" - "QYJKoZIhvcNAQEBBQADggIPADCCAgoC\nggIBALbeIoAHFaFeNqbMnhtAO5QTgRd0X9qxpB0" - "d4M0dEeog2l/+inNA/eu+CCvm\nJj2I8+6MWH2TUrl/" - "2xfhHjzsMrtISCdpNcjaNzCnvi8ZcspFi3evknvs3+uo2/" - "wn\nyNZ04jp0oQ0k1cZ6WBpLTYV7WgmueemiWEiAfw+YE+wtRg+" - "0H7rksrbpeNPnxQHX\nBDDkWqwvfkD15Sd0XFQkW27K72/" - "et2uKuAcJHCIUbsA4iZyJw4Uu4eusy7W5kddX\nThE7Y1WqTXyA4j/" - "ZCYigXmsHbWrikPLVXbORhiMF4/60u8RDs0jI8xtgRQhLR9Vp\n3xys7/" - "5tHZX00s6x6OVy8aMSZIIVS0eWoVN8bGd9B4+fDMOcNT0YODeQA10w/" - "85P\nEiZDQ8AxneQkh8H3qjD2+" - "G9oHZaTk0zHTyaKRg3xGP3N9C96onaJX4Rm6nNvApO8\nU7lQ+xHkLwjKCQke39W+" - "r3FHwwQvUDeoJBXf6iVkIMFoUPAHNZqKf9Db6KKIEp8i\nDgIhbBxiB4MSn36Zly4SOMojyM" - "ZFri+" - "HzMbuHFlm8e8QRWGmM4UM2rHIpl4OJolg\nejesDqO8YZR5mZXV0FJRiPgLo2Q4OTtb3tEHJ" - "ZLmlT+" - "f42bge4ZCZmGPrkNfr68Y\nDEnJ6z4ksOVkMefOp2SNYLYYGPYyiKwa9qVkH9Obkect1omNA" - "gMBAAEwDQYJKoZI\nhvcNAQELBQADggEBABFJQtOTftrzbLBA5Vm6aPkbUyxhcaOpz+d+" - "Ljd6pIs4H+" - "Eb\nXkoHhmay4stZkDc2HVSKESZloI3Ylup8z3aRJjfOexJqHlYzk2vraYryWm8odgID\n5V" - "B0Zle8ofpHTJw1LCOXHkzKt1G6vdQpuq/" - "4OKpmggaIqqEC1bfOYZt5t6vIx3OF\nxjPz91NTR9gZ4lKrho1+sfS+" - "jbSjKkqVAhE4yTpKLPHRshQnBFEhvATXNvdZGftF\n+tXxqKsBZ9aX0/" - "YmPFIXFcjdjSSiuq1F1DjiqIZo88qfa9jlTg6VJdayyQ/" - "cu41C\nBucY8YTF0Ui8ccIS55h2UTzPy5/4PbrwI4P+Zgo=\n-----END " - "CERTIFICATE-----\n"; - // Sample private key - std::string kPrivateKey = - "-----BEGIN RSA PRIVATE " - "KEY-----\nMIIJKAIBAAKCAgEAtt4igAcVoV42psyeG0A7lBOBF3Rf2rGkHR3gzR0R6iDaX/" - "6K\nc0D9674IK+YmPYjz7oxYfZNSuX/" - "bF+EePOwyu0hIJ2k1yNo3MKe+LxlyykWLd6+S\ne+zf66jb/" - "CfI1nTiOnShDSTVxnpYGktNhXtaCa556aJYSIB/" - "D5gT7C1GD7QfuuSy\ntul40+fFAdcEMORarC9+" - "QPXlJ3RcVCRbbsrvb963a4q4BwkcIhRuwDiJnInDhS7h\n66zLtbmR11dOETtjVapNfIDiP9" - "kJiKBeawdtauKQ8tVds5GGIwXj/rS7xEOzSMjz\nG2BFCEtH1WnfHKzv/" - "m0dlfTSzrHo5XLxoxJkghVLR5ahU3xsZ30Hj58Mw5w1PRg4\nN5ADXTD/" - "zk8SJkNDwDGd5CSHwfeqMPb4b2gdlpOTTMdPJopGDfEY/" - "c30L3qidolf\nhGbqc28Ck7xTuVD7EeQvCMoJCR7f1b6vcUfDBC9QN6gkFd/" - "qJWQgwWhQ8Ac1mop/" - "\n0NvooogSnyIOAiFsHGIHgxKffpmXLhI4yiPIxkWuL4fMxu4cWWbx7xBFYaYzhQza\nscim" - "Xg4miWB6N6wOo7xhlHmZldXQUlGI+AujZDg5O1ve0QclkuaVP5/" - "jZuB7hkJm\nYY+uQ1+" - "vrxgMScnrPiSw5WQx586nZI1gthgY9jKIrBr2pWQf05uR5y3WiY0CAwEA\nAQKCAgBGSDGyS" - "wbBMliG2vWZO6KqUqS2wv9kKgoNNsKDkryj42SKqGXFziDJTgwN\n8zKXS9+Uu1P3T3vn13/" - "5OYhJme4VlL5Gh2UogNXdWVr69yjrHLdxlIUUJAIbrJZ/" - "\n3zqNUfbwyIptZs7SrYrW8EInHzWHqwsoBEEx/" - "FDZSXW+u9fFiVD4n5UgP7M0nktV\nXbI6qElBDC/V/" - "6vG8i3aGO8bMdu8fzi3mGUKLzIk1v2J2zDofPosYcxqq8rPWTb4\nMJHMhaqz7fRB+" - "bb7GwtS+2/Oathe0B0td1u//Bo1s7ng1s2jrPFm8/" - "SbfPCLM4O0\nPjCF8OF8Q6uvSp0K283LAdZk+liuDztc/" - "Ed8mcnCZQhBp86mJQi0Jj3Mje7prOAY\nXojMroYj7r2igCJvcwGb1y6zZWSj3jXuHze3bLy" - "fv7pCD+hkiZR7mZhQpOhQRZaU\ntdFGc+" - "DuykxKPqVjAPy7iVQXYnMjpo36SGIWoZLuepQto3GvU6czyOwhK0/" - "Mwbwd\nZpYpLH3L9IetY8GcPefmUR5wQUlUTrpxgGElIzkkWW8zmUWBXwrGbAtN1HJWpJdN" - "\neVshKod2fo03IQMPywSdENCJVeSrgRMuwPyFaOM+" - "CVrBJwD66K9YWn4cVRUIZsTq\nAXhQ8DzF+WCOZshhMUbCJX+KpcOFI8nxOrPp+" - "J1s1YpLLvdmcQKCAQEA7bwvOiCD\nHvaqpYg1jJak6l/" - "iY3QIOOpFyjfYrQXS0BNRmmxK8Lzevi/" - "NPTqu146QKDaIGvzu\n+" - "bXnuV1LmZqnOm5J6Kdx0Mk4Fb88akRtS9gOdzU7WWMYIGkeF1oih0ZrhHuIey6e\nCeLSmJh" - "UDaTIWcCirALRHcLWUS6BTGGuE+up5QG7djIW/" - "LD17lhGE6fXPlbYXb7l\nPbYwL1Yr0urIp9Un+zrExw+77TTGK7T37T1ZJv46qnro0/" - "HK8XxZ+" - "JNc18F763O4\nPmwu8KWrx4qnyPYAuB1rbVntK6UxYks9jvk93XecCUP6HHp0I0tV/" - "kBNd2+" - "18zux\n033xFEVKrUksmwKCAQEAxOrPGyBVFp29V4gQsMQdmafkDAgCLREgjQTOamFsYL5+" - "\nZWq+6VhT/" - "B650sIoRdX0N8timnSLBfjeqaBG5VVhhyKZhP5hulfRjALhdbGBOYvf\n0gLSffImwWdYQfx" - "jtCSO+" - "XCLVdAJGOOWeBVVKzH18ZvCFQwUr3Yrp7KmKWKAqgf7\n6rYovWh8T5LLYS0NzXCEwf9nJ0N" - "JMOy7I9B7EtF8Cs6tK3aaHVqDz7zufwosS7gI\n3aI51Qh4a5D1p95+" - "YU09beWjWGYnPiCKk4D47zaeOe7OQINaWugExlelHtJh9unO\nnhOFXhziav2Kxq1CICAuXl" - "Vx3A+gn/cU3niNHz2A9wKCAQEAws+aw78ws4bef5cG\nipZHveek1GqY8krHtdXdsKs8/" - "VVXYXusTWn3/VGelbYo4GrqpolJLxRloCr4IGXb\nNZwNvUvzNLtCAR1i4C89irdX+Paro/" - "PzFmSluKlrByfNc5y5Lm8sgATLbL56ZKEu\n/58wrpu0sc/" - "9HK40gYHiYn0I8ToElqy8uTaCr78zSIT9p826DFOOKgPsRo2tHp02\nfDf5Bc8eXDjkV1sFX" - "HQKkHZTVA0ZqWJbIKhncoaJDyofcBsR0ZuzuFWzfTOZo4mf\nInz00TEFldpF1e4C8+" - "kCdtHBOA/2Ki2Bp/YUVpHh6aoqZZa75Euehhs8tVpW242M\njEOSUQKCAQAM64sjMH/kt/" - "zQXXEa6AM5LbbcwznBUzpbhlE00aeWwWjxpotYLB92\nj12J4otZ6avYbVPO5o6omaeiYY3F" - "RlDb2P1RqI8o9tIc6aN5YWglKnRJBz5gXR8F\n2Y4E5lZ0X2GyJBxASSIPq/" - "8Xae7ooqKMc7fMQbqpuIssuaAFXx0qCtQQllsd8lkV\nr4AApEAflp5fTC6seNG4kA/" - "HTcqFdZE59E2QaHu8KVA0tSTA2R4G6dBLGnXI8IFW\nLXCwzvxjzfmV2FdbWXiBrwjonLG4o" - "FDJZE3MFdI73LVTfjSrTQp4dObFoGpDvols\nk64jUwLfsLzaG6kY0z2qwT9xSV+" - "ZCSQJAoIBADsSBeyELc5KnmOhT0Xue2o0bkAS\n8KcGWdAoQlaLCIs3vtdlC7DXDXO1l8FkT" - "Qrd+GwP3eWDq6ymtO4vkJ3m4cZ1PEsv\n6Qet7qtkVhUfa+" - "FYKtDzSMRuSaFPW3Ro1PesFa1H3y+sw5HL36vhRaSK+T4Wy5k2\nf7EwNZIf/" - "ZZeA+" - "sEtqj33obOBIiuU9htAjN81Kz4a0Xlh6jc4q6iwYKL8nZ76JYV\n8hXWIz6OXxLXE158+" - "QtJSZaRCvdr6L5UtWfMPKSMqgfhXfTYViPDleQCkJ132mIS\nH28UoET0Y5wI8M6pMkWpSqW" - "WcKPFGwyLInvHdxgnTAsutowkldA7qFwoRz4=\n-----END RSA PRIVATE KEY-----\n"; - // Sample CA certificate(used to sign the server certificate) - std::string kCACertificate = - "-----BEGIN " - "CERTIFICATE-----" - "\nMIIDBjCCAe6gAwIBAgIJAPyCrKRDl3SWMA0GCSqGSIb3DQEBCwUAMBcxFTATBgNV\nBAMM" - "DDEyNy4wLjAuMSBDQTAgFw0xOTA1MDYxOTMyMzZaGA8yMTE5MDQxMjE5MzIz\nNlowFzEVMB" - "MGA1UEAwwMMTI3LjAuMC4xIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC\nAQ8AMIIBCgKCAQEA" - "xrNHoY5+" - "JCgnyvEdG2dvvOaZ3sg6uhuF5Ssb5snyo9ixrxO5\nZkDGWwUqFO9PiYuO5ovNeq9LZtPG6s" - "K8zsCS062ChZX/7tZHndf4MKCUDzv/" - "LPHe\nnROoPi9n2FAiOPctY5hpgpIJDPI5Ofx0el2KPeFGeUO/" - "W3yqnfol1ZqzZ2h3uErR\noHkgT2Ja4K+5gnPkr/" - "RluJIu3AmWYw4eKi8i3+" - "PoThGmCFvoGfcWvRoctgnOHYHE\n4bDRirXL9nGkZ5FMzOVDeoIAEAShOqJwL08VcY+Pg/" - "qFQjzRrTmiKgm6QsHNnm0q\nzg70XaD88VJimiGYZOuJHNZpX8o0W+1Ls/" - "NbawIDAQABo1MwUTAdBgNVHQ4EFgQU\nkW3hgFWYMpVUkq9AlzGlI3awTGEwHwYDVR0jBBgw" - "FoAUkW3hgFWYMpVUkq9AlzGl\nI3awTGEwDwYDVR0TAQH/BAUwAwEB/" - "zANBgkqhkiG9w0BAQsFAAOCAQEAZeMkILiG\neEcELWb8cktP3LzvS47O8hys9+" - "6TFmftuO7kjDBd9YH2v8iQ7qCcUvMJ7bqL5RP1\nQssKfNOHZtw/" - "MMcKE6E3nl4yQSKc8ymivvYSVu5SYtQCedcgfRLb5zvVxXw8JmCp\nGNS3/" - "OlIYZAamh76GxkKSaV3tv0XZB6n3rUVQZShncFbMpyJRW0XWxReGWrhXv4s\nNxMeC1r07EE" - "WIDecv8KKf1F8uT4UF48HnC0VBpXiOyDGvn35NiKp+" - "Q5k7QV6jdCS\ngPRcnZhs6jiU0jnV8C9A1A+" - "3pXSSPrAed7tvECOgHCfS10CLsLWsLuSjc93BE5Vt\nav7kmxSwrdvQ2A==\n-----END " - "CERTIFICATE-----\n"; - std::string kIncorrectCertificate = - "-----BEGIN " - "CERTIFICATE-----\nMIIC/" - "jCCAeagAwIBAgIJAIZjLucUID1mMA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNV\nBAMMCTEyNy4" - "wLjAuMTAeFw0xOTA1MDYxNDA1MzdaFw0yOjA1MDZxNDA1MzdaMBQx\nEjAQBgNVBAMMCTEyN" - "y4wLjAuMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC\nggEBALfE5Qhc2mHTIux30l7" - "eHFjFLdzYeXE8vcaXKodalCG8EkRxojDOfUv+y2DV\nJzHAMiGxMFAEcSz71k+" - "jFZwhNG8PLY0b36ChnUsrGkOSJWq3OKUFrg8KxO9At9dL\nJsa+" - "R0N0D1bMoPYdpCi3m0b0q2ITHe56qKuTLTrIPia+" - "qXGEVD7EoEhU9tnwlcwE\npsUURMXCn2+FhHyqN9wjFkldmu4k8U3OJOK4385L+" - "4RJoIV8dsYawAMAf+" - "WuxyWq\niPQTPxr8q33ZZm6z0XrgsgxHYCCsryx8L9Ub9Zwu0mie7eL63rYdr86gULvnF1bY" - "\ncOunKFc71rBYFalbD6YYsre733kCAwEAAaNTMFEwHQYDVR0OBBYEFKW9ByUNG84Z\nYiSc" - "hUrB7KV9FinZMB8GA1UdIwQYMBaAFKW9ByUNG84ZYiSchUrB7KV9FinZMA8G\nA1UdEwEB/" - "wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAHYROS1EL2qnrwmAsR6c\nqo8yrk8qzLKt4os" - "41nv7QMUQFIO+QLPE8SbH4fK1YOMMUJ4ppARQBDaIIR3UEhp1\nZHT/" - "wGjK9qxcuQ1EXLyHOY0rxS5q57dYGxOyQo4v6IoLVMZ1ij+RJGPYI/" - "2fDXs0\nbDldeJyC1voHmG6lqTN5nLG7Y3j9j6rtSqJyRz5muaecQNiFPQOM2OTp0rC4VeAF" - "\ndejmTmLhUFVuHMzLF+" - "bpzsN76GnnQquJy2jexzFoWgbEfFVLKuyhTHQAalRb4ccq\nXCIx1hecNDYRY3Sc2Gzv5qxk" - "kWF8zqltT/0d5tx0JwN3k5nP4SlaEldFvD6BELxy\nVkU=\n-----END " - "CERTIFICATE-----\n"; -}; + result_error = websocket_connection_->Disconnect(); -TEST_F(WebsocketConnectionTest, WSConnection_SUCCESS) { - transport_manager::transport_adapter::CloudAppProperties properties{ - .endpoint = "ws://" + kHost + ":" + std::to_string(kPort), - .certificate = "no cert", - .enabled = true, - .auth_token = "auth_token", - .cloud_transport_type = "WS", - .hybrid_app_preference = "CLOUD"}; - - // Start server - StartWSServer("/"); - - // Start client - InitWebsocketClient(properties, ws_client); - std::shared_ptr ws_connection = - ws_client.connection; - - // Check websocket connection - TransportAdapter::Error ret_code = ws_connection->Start(); - EXPECT_EQ(TransportAdapter::OK, ret_code); - - // Stop client - ret_code = ws_connection->Disconnect(); - EXPECT_EQ(TransportAdapter::OK, ret_code); - - // Stop server thread - ws_session->Stop(); + ASSERT_EQ(TransportAdapter::Error::BAD_STATE, result_error); } -TEST_F(WebsocketConnectionTest, WSConnection_SUCCESS_ValidTarget) { - transport_manager::transport_adapter::CloudAppProperties properties{ - .endpoint = "ws://" + kHost + ":" + std::to_string(kPort) + kPath + - kQuery + kFragment, - .certificate = "no cert", - .enabled = true, - .auth_token = "auth_token", - .cloud_transport_type = "WS", - .hybrid_app_preference = "CLOUD"}; - - // Start server - StartWSServer(kPath); - - // Start client - InitWebsocketClient(properties, ws_client); - std::shared_ptr ws_connection = - ws_client.connection; - - // Check websocket connection - TransportAdapter::Error ret_code = ws_connection->Start(); - EXPECT_EQ(TransportAdapter::OK, ret_code); - - // Stop client - ret_code = ws_connection->Disconnect(); - EXPECT_EQ(TransportAdapter::OK, ret_code); - - // Stop server thread - ws_session->Stop(); -} +TEST_F(WebsocketNotSecureSessionConnectionTest, SUCCESS_SendData) { + auto message = CreateDefaultRawMessage(); -TEST_F(WebsocketConnectionTest, WSConnection_FAILURE_InvalidTarget) { - transport_manager::transport_adapter::CloudAppProperties properties{ - .endpoint = "ws://" + kHost + ":" + std::to_string(kPort) + kPath + - kQuery + kFragment, - .certificate = "no cert", - .enabled = true, - .auth_token = "auth_token", - .cloud_transport_type = "WS", - .hybrid_app_preference = "CLOUD"}; - - // Start server - StartWSServer("/"); - - // Start client - InitWebsocketClient(properties, ws_client); - std::shared_ptr ws_connection = - ws_client.connection; - - // Check websocket connection - TransportAdapter::Error ret_code = ws_connection->Start(); - EXPECT_EQ(TransportAdapter::FAIL, ret_code); - - // Stop client - ret_code = ws_connection->Disconnect(); - EXPECT_EQ(TransportAdapter::OK, ret_code); - - // Stop server thread - ws_session->Stop(); -} + auto error = websocket_connection_->SendData(message); -TEST_F(WebsocketConnectionTest, WSSConnection_SUCCESS) { - transport_manager::transport_adapter::CloudAppProperties properties{ - .endpoint = "wss://" + kHost + ":" + std::to_string(kPort), - .certificate = kCACertificate, - .enabled = true, - .auth_token = "auth_token", - .cloud_transport_type = "WSS", - .hybrid_app_preference = "CLOUD"}; - - // Start server - StartWSSServer("/"); - - // Start client - InitWebsocketClient(properties, ws_client); - std::shared_ptr wss_connection = - ws_client.connection; - - // Check websocket connection - TransportAdapter::Error ret_code = wss_connection->Start(); - EXPECT_EQ(TransportAdapter::OK, ret_code); - - // Stop client - ret_code = wss_connection->Disconnect(); - EXPECT_EQ(TransportAdapter::OK, ret_code); - - // Stop server thread - wss_session->Stop(); + ASSERT_EQ(TransportAdapter::Error::OK, error); } -TEST_F(WebsocketConnectionTest, WSSConnection_SUCCESS_ValidTarget) { - transport_manager::transport_adapter::CloudAppProperties properties{ - .endpoint = "wss://" + kHost + ":" + std::to_string(kPort) + kPath, - .certificate = kCACertificate, - .enabled = true, - .auth_token = "auth_token", - .cloud_transport_type = "WSS", - .hybrid_app_preference = "CLOUD"}; - - // Start server - StartWSSServer((kPath + kQuery + kFragment)); - - // Start client - InitWebsocketClient(properties, ws_client); - std::shared_ptr wss_connection = - ws_client.connection; - - // Check websocket connection - TransportAdapter::Error ret_code = wss_connection->Start(); - EXPECT_EQ(TransportAdapter::OK, ret_code); - - // Stop client - ret_code = wss_connection->Disconnect(); - EXPECT_EQ(TransportAdapter::OK, ret_code); - - // Stop server thread - wss_session->Stop(); -} +TEST_F(WebsocketNotSecureSessionConnectionTest, UNSUCCESS_SendData_BAD_STATE) { + websocket_connection_->Run(); + auto message = CreateDefaultRawMessage(); + + auto disconnect_error = websocket_connection_->Disconnect(); + + auto send_data_error = websocket_connection_->SendData(message); -#ifdef ENABLE_SECURITY -TEST_F(WebsocketConnectionTest, WSSConnection_FAILURE_InvalidTarget) { - transport_manager::transport_adapter::CloudAppProperties properties{ - .endpoint = "wss://" + kHost + ":" + std::to_string(kPort), - .certificate = kCACertificate, - .enabled = true, - .auth_token = "auth_token", - .cloud_transport_type = "WSS", - .hybrid_app_preference = "CLOUD"}; - - // Start server - StartWSSServer(kPath); - - // Start client - InitWebsocketClient(properties, ws_client); - std::shared_ptr wss_connection = - ws_client.connection; - - // Check websocket connection - TransportAdapter::Error ret_code = wss_connection->Start(); - EXPECT_EQ(TransportAdapter::FAIL, ret_code); - - // Stop client - ret_code = wss_connection->Disconnect(); - EXPECT_EQ(TransportAdapter::OK, ret_code); - - // Stop server thread - wss_session->Stop(); + ASSERT_EQ(TransportAdapter::Error::OK, disconnect_error); + ASSERT_EQ(TransportAdapter::Error::BAD_STATE, send_data_error); } -TEST_F(WebsocketConnectionTest, WSSConnection_FAILURE_IncorrectCert) { - transport_manager::transport_adapter::CloudAppProperties properties{ - .endpoint = "wss://" + kHost + ":" + std::to_string(kPort), - .certificate = kIncorrectCertificate, - .enabled = true, - .auth_token = "auth_token", - .cloud_transport_type = "WSS", - .hybrid_app_preference = "CLOUD"}; - - // Start server - StartWSSServer("/"); - - // Start client - InitWebsocketClient(properties, ws_client); - std::shared_ptr wss_connection = - ws_client.connection; - - // Check websocket connection - TransportAdapter::Error ret_code = wss_connection->Start(); - EXPECT_EQ(TransportAdapter::FAIL, ret_code); - - // Stop client - ret_code = wss_connection->Disconnect(); - EXPECT_EQ(TransportAdapter::OK, ret_code); - - // Stop server thread - wss_session->Stop(); +TEST_F(WebsocketNotSecureSessionConnectionTest, DataReceive_SUCCESS) { + auto message = CreateDefaultRawMessage(); + + EXPECT_CALL(mock_transport_adapter_ctrl_, + DataReceiveDone(kDeviceUid_, kAppHandle, _)) + .Times(1); + + websocket_connection_->DataReceive(message); } -#endif // ENABLE_SECURITY + } // namespace transport_manager_test } // namespace components } // namespace test diff --git a/src/components/transport_manager/test/websocket_sample_client/websocket_sample_client.cc b/src/components/transport_manager/test/websocket_sample_client/websocket_sample_client.cc new file mode 100644 index 0000000000..88525ad29d --- /dev/null +++ b/src/components/transport_manager/test/websocket_sample_client/websocket_sample_client.cc @@ -0,0 +1,193 @@ +/* + * \file websocket_listener.h + * \brief WebSocketListener class header file. + * + * Copyright (c) 2020 + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "transport_manager/websocket_server/websocket_sample_client.h" + +namespace transport_manager { +namespace transport_adapter { + +template <> +WSSampleClient > >::WSSampleClient( + const std::string& host, + const std::string& port, + const SecurityParams& params) + : resolver_(ioc_) + , ctx_(ssl::context::sslv23_client) + , ws_(nullptr) + , io_pool_(1) + , host_(host) + , port_(port) + , handshake_successful_(false) { + ctx_.set_verify_mode(ssl::context::verify_peer); + ctx_.load_verify_file(params.ca_cert_); + ctx_.use_certificate_chain_file(params.client_cert_); + ctx_.use_private_key_file(params.client_key_, boost::asio::ssl::context::pem); + ws_.reset(new WSS(ioc_, ctx_)); +} + +template <> +WSSampleClient::WSSampleClient(const std::string& host, + const std::string& port) + : resolver_(ioc_) + , ctx_(ssl::context::sslv23_client) + , ws_(new WS(ioc_)) + , host_(host) + , port_(port) {} + +template +bool WSSampleClient::Run() { + boost::system::error_code ec; + ctx_.set_verify_mode(ssl::verify_none); + + auto results = resolver_.resolve(host_, port_, ec); + if (ec) { + std::cout << "ErrorMessage: " + ec.message() << std::endl; + return false; + } + + if (!Connect(results)) { + return false; + } + + if (!Handshake(host_, "/")) { + return false; + } + + ws_->async_read(buffer_, + std::bind(&WSSampleClient::OnRead, + this->shared_from_this(), + std::placeholders::_1, + std::placeholders::_2)); + boost::asio::post(io_pool_, [&]() { ioc_.run(); }); + return true; +} + +template +void WSSampleClient::OnRead(beast::error_code ec, + std::size_t bytes_transferred) { + boost::ignore_unused(bytes_transferred); +} + +template <> +bool WSSampleClient::Connect(tcp::resolver::results_type& results) { + boost::system::error_code ec; + boost::asio::connect(ws_->next_layer(), results.begin(), results.end(), ec); + if (ec) { + std::string str_err = "ErrorMessage: " + ec.message(); + return false; + } + return true; +} + +template <> +bool WSSampleClient::Connect(tcp::resolver::results_type& results) { + boost::system::error_code ec; + boost::asio::connect(ws_->lowest_layer(), results.begin(), results.end(), ec); + if (ec) { + std::string str_err = "ErrorMessage: " + ec.message(); + return false; + } + return true; +} + +template <> +bool WSSampleClient::Handshake(const std::string& host, + const std::string& target) { + boost::system::error_code ec; + ws_->handshake(host, target, ec); + if (ec) { + std::string str_err = "ErrorMessage: " + ec.message(); + return false; + } + return true; +} + +template <> +void WSSampleClient::Stop() { + ioc_.stop(); + ws_->lowest_layer().close(); + + io_pool_.stop(); + io_pool_.join(); +} + +template <> +bool WSSampleClient::Handshake(const std::string& host, + const std::string& target) { + boost::system::error_code ec; + + ws_->next_layer().handshake(ssl::stream_base::client, ec); + if (ec) { + std::cout << "ErrorMessage: " + ec.message() << std::endl; + return false; + } + + ws_->handshake(host, target, ec); + if (ec) { + std::string str_err = "ErrorMessage: " + ec.message(); + return false; + } + + handshake_successful_ = true; + return true; +} + +template <> +void WSSampleClient::Stop() { + ioc_.stop(); + ws_->next_layer().next_layer().shutdown( + boost::asio::ip::tcp::socket::shutdown_both); + ws_->lowest_layer().close(); + + io_pool_.stop(); + io_pool_.join(); +} + +template <> +void WSSampleClient::OnHandshakeTimeout() { + if (!handshake_successful_) { + Stop(); + } +} + +template <> +bool WSSampleClient::IsHandshakeSuccessful() const { + return handshake_successful_; +} + +template class WSSampleClient; +template class WSSampleClient; +} // namespace transport_adapter +} // namespace transport_manager diff --git a/src/components/transport_manager/test/websocket_server_listener_test.cc b/src/components/transport_manager/test/websocket_server_listener_test.cc new file mode 100644 index 0000000000..7991c6f1cb --- /dev/null +++ b/src/components/transport_manager/test/websocket_server_listener_test.cc @@ -0,0 +1,260 @@ +/* + * Copyright (c) 2020, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "transport_manager/mock_transport_manager_settings.h" +#include "transport_manager/transport_adapter/mock_transport_adapter_controller.h" +#include "transport_manager/websocket_server/websocket_device.h" +#include "transport_manager/websocket_server/websocket_listener.h" +#include "utils/timer.h" +#include "utils/timer_task_impl.h" + +#include +#include "transport_manager/websocket_server/websocket_sample_client.h" + +namespace test { +namespace components { +namespace transport_manager_test { + +using ::testing::_; +using ::testing::NiceMock; +using ::testing::Return; +using ::testing::ReturnArg; +using ::testing::ReturnPointee; +using ::testing::ReturnRef; +using namespace ::transport_manager; +using namespace ::transport_manager::transport_adapter; + +namespace { +const std::string kDefaultAddress = "127.0.0.1"; +const std::string kDefaultCertPath = ""; +const std::string kDefaultKeyPath = ""; +const std::string kDefaultCACertPath = ""; +const uint32_t kDefaultPort = 2021; +const std::string kDefaultPortStr = "2021"; +const uint32_t kWrongPort = 1000; +const std::string kCACertPath = "./test_certs/ca-cert.pem"; +const std::string kClientCertPath = "./test_certs/client-cert.pem"; +const std::string kClientKeyPath = "./test_certs/client-key.pem"; +const std::string kServerCert = "./test_certs/server-cert.pem"; +const std::string kServerKey = "./test_certs/server-key.pem"; +const std::string kCACert = "./test_certs/ca-cert.pem"; +const std::string kDefaultDeviceName = "Web Engine"; +const int kNumThreads = 2; +} // namespace + +class WebSocketListenerTest : public ::testing::Test { + protected: + MockTransportAdapterController mock_ta_controller_; + MockTransportManagerSettings mock_tm_settings_; + + public: + WebSocketListenerTest() {} + ~WebSocketListenerTest() {} + + void SetUp() OVERRIDE { + ON_CALL(mock_tm_settings_, websocket_server_address()) + .WillByDefault(ReturnRef(kDefaultAddress)); + ON_CALL(mock_tm_settings_, websocket_server_port()) + .WillByDefault(Return(kDefaultPort)); + ON_CALL(mock_tm_settings_, ws_server_cert_path()) + .WillByDefault(ReturnRef(kServerCert)); + ON_CALL(mock_tm_settings_, ws_server_key_path()) + .WillByDefault(ReturnRef(kServerKey)); + ON_CALL(mock_tm_settings_, ws_server_ca_cert_path()) + .WillByDefault(ReturnRef(kCACert)); + ON_CALL(mock_tm_settings_, wss_server_supported()) + .WillByDefault(Return(true)); + } + + std::shared_ptr CreateDevice(const bool secure_connection) { + return std::make_shared(kDefaultDeviceName, + kDefaultDeviceName); + } +}; + +TEST_F(WebSocketListenerTest, StartListening_ClientConnect_SUCCESS) { + ON_CALL(mock_tm_settings_, ws_server_cert_path()) + .WillByDefault(ReturnRef(kDefaultCertPath)); + ON_CALL(mock_tm_settings_, ws_server_key_path()) + .WillByDefault(ReturnRef(kDefaultKeyPath)); + ON_CALL(mock_tm_settings_, ws_server_ca_cert_path()) + .WillByDefault(ReturnRef(kDefaultCACertPath)); + ON_CALL(mock_tm_settings_, wss_server_supported()) + .WillByDefault(Return(false)); + + const auto ws_listener = std::make_shared( + &mock_ta_controller_, mock_tm_settings_, kNumThreads); + const auto ws_client = + std::make_shared >(kDefaultAddress, kDefaultPortStr); + + EXPECT_CALL(mock_ta_controller_, ConnectDone(_, _)); + EXPECT_CALL(mock_ta_controller_, ConnectionCreated(_, _, _)); + EXPECT_CALL(mock_ta_controller_, GetWebEngineDevice()) + .WillOnce(Return(CreateDevice(false))); + + ws_listener->StartListening(); + EXPECT_TRUE(ws_client->Run()); + ws_client->Stop(); +} + +TEST_F(WebSocketListenerTest, StartListening_ClientConnectSecure_SUCCESS) { + const auto ws_listener = std::make_shared( + &mock_ta_controller_, mock_tm_settings_, kNumThreads); + const SecurityParams params{kCACertPath, kClientCertPath, kClientKeyPath}; + const auto wss_client = std::make_shared >( + kDefaultAddress, kDefaultPortStr, params); + + EXPECT_CALL(mock_ta_controller_, ConnectDone(_, _)); + EXPECT_CALL(mock_ta_controller_, ConnectionCreated(_, _, _)); + EXPECT_CALL(mock_ta_controller_, GetWebEngineDevice()) + .WillOnce(Return(CreateDevice(true))); + + ws_listener->StartListening(); + EXPECT_TRUE(wss_client->Run()); + wss_client->Stop(); +} + +TEST_F(WebSocketListenerTest, + StartListening_ClientConnectSecureInvalidCert_FAIL) { + const auto ws_listener = std::make_shared( + &mock_ta_controller_, mock_tm_settings_, kNumThreads); + const SecurityParams params{kCACertPath, + "./test_certs/invalid_cert.pem", + "./test_certs/invalid_key.pem"}; + const auto wss_client = std::make_shared >( + kDefaultAddress, kDefaultPortStr, params); + + EXPECT_CALL(mock_ta_controller_, ConnectDone(_, _)); + EXPECT_CALL(mock_ta_controller_, ConnectionCreated(_, _, _)); + EXPECT_CALL(mock_ta_controller_, GetWebEngineDevice()) + .WillOnce(Return(CreateDevice(true))); + EXPECT_CALL(mock_ta_controller_, ConnectionAborted(_, _, _)); + + ws_listener->StartListening(); + timer::Timer handshake_timer( + "HandshakeTimer", + new ::timer::TimerTaskImpl >( + wss_client.get(), &WSSampleClient::OnHandshakeTimeout)); + handshake_timer.Start(3000, timer::kSingleShot); + wss_client->Run(); + EXPECT_EQ(wss_client->IsHandshakeSuccessful(), false); +} + +TEST_F(WebSocketListenerTest, StartListening_CertificateNotFound_Fail) { + const std::string server_cert = "./test_certs/server-cert.pem"; + const std::string server_key = "./test_certs/server-key.pem"; + const std::string ca_cert = "./not_valid_path/ca-cert.pem"; + ON_CALL(mock_tm_settings_, ws_server_cert_path()) + .WillByDefault(ReturnRef(server_cert)); + ON_CALL(mock_tm_settings_, ws_server_key_path()) + .WillByDefault(ReturnRef(server_key)); + ON_CALL(mock_tm_settings_, ws_server_ca_cert_path()) + .WillByDefault(ReturnRef(ca_cert)); + + const auto ws_listener_ = std::make_shared( + &mock_ta_controller_, mock_tm_settings_, kNumThreads); + const auto ws_client_ = + std::make_shared >(kDefaultAddress, kDefaultPortStr); + + EXPECT_EQ(TransportAdapter::Error::FAIL, ws_listener_->StartListening()); +} + +TEST_F(WebSocketListenerTest, StartListening_WrongConfig_FAIL) { + const std::string server_cert = "./test_certs/server-cert.pem"; + + ON_CALL(mock_tm_settings_, ws_server_cert_path()) + .WillByDefault(ReturnRef(server_cert)); + ON_CALL(mock_tm_settings_, ws_server_key_path()) + .WillByDefault(ReturnRef(kDefaultKeyPath)); + EXPECT_CALL(mock_tm_settings_, ws_server_ca_cert_path()) + .WillOnce(ReturnRef(kDefaultCACertPath)); + + const auto ws_listener_ = std::make_shared( + &mock_ta_controller_, mock_tm_settings_, kNumThreads); + const auto ws_client_ = + std::make_shared >(kDefaultAddress, kDefaultPortStr); + + EXPECT_EQ(TransportAdapter::Error::FAIL, ws_listener_->StartListening()); +} + +TEST_F(WebSocketListenerTest, StartListening_BindToTheServerAddress_FAIL) { + ON_CALL(mock_tm_settings_, ws_server_cert_path()) + .WillByDefault(ReturnRef(kDefaultCertPath)); + ON_CALL(mock_tm_settings_, ws_server_key_path()) + .WillByDefault(ReturnRef(kDefaultKeyPath)); + ON_CALL(mock_tm_settings_, wss_server_supported()) + .WillByDefault(Return(false)); + EXPECT_CALL(mock_tm_settings_, ws_server_ca_cert_path()) + .WillOnce(ReturnRef(kDefaultCACertPath)); + EXPECT_CALL(mock_tm_settings_, websocket_server_port()) + .WillOnce(Return(kWrongPort)); + + const auto ws_listener_ = std::make_shared( + &mock_ta_controller_, mock_tm_settings_, kNumThreads); + const auto ws_client_ = + std::make_shared >(kDefaultAddress, kDefaultPortStr); + + EXPECT_EQ(TransportAdapter::Error::FAIL, ws_listener_->StartListening()); +} + +TEST_F(WebSocketListenerTest, StartListening_AcceptorIsOpen_SUCCESS) { + ON_CALL(mock_tm_settings_, ws_server_cert_path()) + .WillByDefault(ReturnRef(kDefaultCertPath)); + ON_CALL(mock_tm_settings_, ws_server_key_path()) + .WillByDefault(ReturnRef(kDefaultKeyPath)); + ON_CALL(mock_tm_settings_, wss_server_supported()) + .WillByDefault(Return(false)); + + EXPECT_CALL(mock_ta_controller_, ConnectDone(_, _)); + EXPECT_CALL(mock_ta_controller_, ConnectionCreated(_, _, _)); + EXPECT_CALL(mock_ta_controller_, GetWebEngineDevice()) + .WillOnce(Return(CreateDevice(false))); + + EXPECT_CALL(mock_tm_settings_, ws_server_ca_cert_path()) + .WillOnce(ReturnRef(kDefaultCACertPath)); + + const auto ws_listener = std::make_shared( + &mock_ta_controller_, mock_tm_settings_, kNumThreads); + const auto ws_client = + std::make_shared >(kDefaultAddress, kDefaultPortStr); + + ws_listener->StartListening(); + ws_client->Run(); + EXPECT_EQ(TransportAdapter::Error::OK, ws_listener->StartListening()); + ws_client->Stop(); +} + +} // namespace transport_manager_test +} // namespace components +} // namespace test -- cgit v1.2.1