diff options
author | Andrey Oleynik (GitHub) <dev-gh@users.noreply.github.com> | 2017-01-05 15:39:37 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-01-05 15:39:37 +0200 |
commit | 980a945110ed1f58000de4ad178dc877a9372b80 (patch) | |
tree | a93877c94bebce1ff198c3222cfd6cca56b4bf8a /src/components/application_manager | |
parent | 086097c4d8aac14cb425207f3392fe8ab3f28bf6 (diff) | |
parent | 059dae5f04ff38bd9f61827a9ed53b07e2adcbd7 (diff) | |
download | sdl_core-980a945110ed1f58000de4ad178dc877a9372b80.tar.gz |
Merge pull request #1149 from dev-gh/fix/Fix_max_requiests_constraint_check
Fixes logic of max requests per time scale constraint verification
Diffstat (limited to 'src/components/application_manager')
9 files changed, 537 insertions, 272 deletions
diff --git a/src/components/application_manager/include/application_manager/request_controller.h b/src/components/application_manager/include/application_manager/request_controller.h index 479ebb217e..d3a5a0b821 100644 --- a/src/components/application_manager/include/application_manager/request_controller.h +++ b/src/components/application_manager/include/application_manager/request_controller.h @@ -49,6 +49,7 @@ #include "application_manager/request_info.h" #include "application_manager/request_controller_settings.h" +#include "application_manager/request_tracker.h" namespace application_manager { @@ -229,11 +230,15 @@ class RequestController { void terminateWaitingForResponseAppRequests(const uint32_t& app_id); /** - * @brief Check Posibility to add new requests, or limits was exceeded - * @param request - request to check possipility to Add - * @return True if new request could be added, false otherwise + * @brief Checks whether all constraints are met before adding of request into + * processing queue. Verifies amount of pending requests, amount of requests + * per time scale for different HMI levels + * @param request - request to check constraints for + * @param level - HMI level in which request has been issued + * @return Appropriate result code of verification */ - TResult CheckPosibilitytoAdd(const RequestPtr request); + TResult CheckPosibilitytoAdd(const RequestPtr request, + const mobile_api::HMILevel::eType level); /** * @brief Check Posibility to add new requests, or limits was exceeded @@ -274,6 +279,12 @@ class RequestController { RequestInfoSet waiting_for_response_; /** + * @brief Tracker verifying time scale and maximum requests amount in + * different HMI levels + */ + RequestTracker request_tracker_; + + /** * @brief Set of HMI notifications with timeout. */ std::list<RequestPtr> notification_list_; diff --git a/src/components/application_manager/include/application_manager/request_info.h b/src/components/application_manager/include/application_manager/request_info.h index 193699be78..216eb86cc5 100644 --- a/src/components/application_manager/include/application_manager/request_info.h +++ b/src/components/application_manager/include/application_manager/request_info.h @@ -63,9 +63,7 @@ struct RequestInfo { RequestInfo(RequestPtr request, const RequestType requst_type, const uint64_t timeout_msec) - : request_(request) - , timeout_msec_(timeout_msec) - , hmi_level_(mobile_apis::HMILevel::INVALID_ENUM) { + : request_(request), timeout_msec_(timeout_msec) { start_time_ = date_time::DateTime::getCurrentTime(); updateEndTime(); requst_type_ = requst_type; @@ -106,14 +104,6 @@ struct RequestInfo { return app_id_; } - mobile_apis::HMILevel::eType hmi_level() { - return hmi_level_; - } - - void set_hmi_level(const mobile_apis::HMILevel::eType& level) { - hmi_level_ = level; - } - RequestType requst_type() const { return requst_type_; } @@ -135,7 +125,6 @@ struct RequestInfo { uint64_t timeout_msec_; TimevalStruct end_time_; uint32_t app_id_; - mobile_apis::HMILevel::eType hmi_level_; RequestType requst_type_; uint32_t correlation_id_; }; @@ -234,34 +223,6 @@ class RequestInfoSet { */ const size_t Size(); - /** - * @brief Check if this app is able to add new requests, - * or limits was exceeded - * @param app_id - application id - * @param app_time_scale - time scale (seconds) - * @param max_request_per_time_scale - maximum count of request - * that should be allowed for app_time_scale seconds - * @return True if new request could be added, false otherwise - */ - bool CheckTimeScaleMaxRequest(uint32_t app_id, - uint32_t app_time_scale, - uint32_t max_request_per_time_scale); - - /** - * @brief Check if this app is able to add new requests - * in current hmi_level, or limits was exceeded - * @param hmi_level - hmi level - * @param app_id - application id - * @param app_time_scale - time scale (seconds) - * @param max_request_per_time_scale - maximum count of request - * that should be allowed for app_time_scale seconds - * @return True if new request could be added, false otherwise - */ - bool CheckHMILevelTimeScaleMaxRequest(mobile_apis::HMILevel::eType hmi_level, - uint32_t app_id, - uint32_t app_time_scale, - uint32_t max_request_per_time_scale); - private: /* * @brief Comparator of connection key for std::find_if function @@ -329,47 +290,6 @@ struct TimeScale { uint32_t app_id_; }; -/** -* @brief Structure used in std algorithms to determine amount of request -* during time scale for application in defined hmi level -*/ -struct HMILevelTimeScale { - HMILevelTimeScale(const TimevalStruct& start, - const TimevalStruct& end, - const uint32_t& app_id, - const mobile_apis::HMILevel::eType& hmi_level) - : start_(start), end_(end), app_id_(app_id), hmi_level_(hmi_level) {} - - bool operator()(RequestInfoPtr setEntry) { - if (!setEntry.valid()) { - return false; - } - - if (setEntry->app_id() != app_id_) { - return false; - } - - if (setEntry->hmi_level() != hmi_level_) { - return false; - } - - if (date_time::DateTime::getSecs(setEntry->start_time()) < - date_time::DateTime::getSecs(start_) || - date_time::DateTime::getSecs(setEntry->start_time()) > - date_time::DateTime::getSecs(end_)) { - return false; - } - - return true; - } - - private: - TimevalStruct start_; - TimevalStruct end_; - uint32_t app_id_; - mobile_apis::HMILevel::eType hmi_level_; -}; - } // namespace request_controller } // namespace application_manager diff --git a/src/components/application_manager/include/application_manager/request_tracker.h b/src/components/application_manager/include/application_manager/request_tracker.h new file mode 100644 index 0000000000..36ab3eaefb --- /dev/null +++ b/src/components/application_manager/include/application_manager/request_tracker.h @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2017, 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_INCLUDE_APPLICATION_MANAGER_REQUEST_TRACKER_H_ +#define SRC_COMPONENTS_APPLICATION_MANAGER_INCLUDE_APPLICATION_MANAGER_REQUEST_TRACKER_H_ + +#include <string> +#include <map> +#include <vector> +#include "application_manager/request_controller_settings.h" +#include "interfaces/MOBILE_API.h" +#include "utils/date_time.h" + +namespace application_manager { + +namespace request_controller { + +/** + * @brief The TrackResult enum defines results of application request tracking + */ +enum class TrackResult { + kSuccess, + kNoneLevelMaxRequestsExceeded, + kMaxRequestsExceeded +}; + +/** + * @brief The RequestTracker class tracks requests per time constraints. + * There are several parameters in configuration file defining maximum + * requests + * number and time scale for that number, so application must consider that, + * otherwise it will be disconnected and won't be registered till next + * ignition + * cycle. + */ +class RequestTracker { + public: + typedef uint32_t ApplicationID; + + /** + * @brief RequestTracker class constructor + * @param settings Settings instance having time scale and maximum requests + * values + */ + explicit RequestTracker(const RequestControlerSettings& settings); + + /** + * @brief Tracks amount of requests per defined time considering HMI level + * Currently there is a separate restrictions can be set for NONE level. + * Other levels tracked by single constraint. + * @param app_id Unique application id + * @param level HMI level of request + * @return Success if constraints are not exceeded, otherwise - exceeded + * error code (depends on HMI level) + */ + TrackResult Track(const ApplicationID& app_id, + const mobile_apis::HMILevel::eType level); + + private: + typedef std::vector<TimevalStruct> RequestAddedAt; + typedef std::map<ApplicationID, RequestAddedAt> ApplicationsRequestsTracker; + + /** + * @brief Checks whether maximum requests number is exceeded per defined + * time + * scale. + * @param app_id Unique application id + * @param time_scale Time scale defined in configuration file + * @param max_requests Maximum requests number defined in configuration file + * @param tracker Container tracking applications requests amount and their + * time of addition into processing + * @return + */ + bool Track(const ApplicationID& app_id, + const uint32_t time_scale, + const uint32_t max_requests, + ApplicationsRequestsTracker& tracker); + + /** + * @brief settings_ having time scale and maximum requests values + */ + const RequestControlerSettings& settings_; + + /** + * @brief Tracker for applications requests done in NONE level + */ + ApplicationsRequestsTracker none_level_tracker_; + + /** + * @brief Tracker for applications requests done in other than NONE level + */ + ApplicationsRequestsTracker tracker_; +}; + +} // namespace request_controller +} // namespace application_manager +#endif // SRC_COMPONENTS_APPLICATION_MANAGER_INCLUDE_APPLICATION_MANAGER_REQUEST_TRACKER_H_ diff --git a/src/components/application_manager/src/request_controller.cc b/src/components/application_manager/src/request_controller.cc index 3b3ea839d7..77a1853a39 100644 --- a/src/components/application_manager/src/request_controller.cc +++ b/src/components/application_manager/src/request_controller.cc @@ -49,6 +49,7 @@ CREATE_LOGGERPTR_GLOBAL(logger_, "RequestController") RequestController::RequestController(const RequestControlerSettings& settings) : pool_state_(UNDEFINED) , pool_size_(settings.thread_pool_size()) + , request_tracker_(settings) , timer_("AM RequestCtrlTimer", new timer::TimerTaskImpl<RequestController>( this, &RequestController::TimeoutThread)) @@ -101,42 +102,26 @@ void RequestController::DestroyThreadpool() { } RequestController::TResult RequestController::CheckPosibilitytoAdd( - const RequestPtr request) { + const RequestPtr request, const mobile_apis::HMILevel::eType level) { LOG4CXX_AUTO_TRACE(logger_); - const uint32_t& app_hmi_level_none_time_scale = - settings_.app_hmi_level_none_time_scale(); - - // app_hmi_level_none_max_request_per_time_scale - const uint32_t& hmi_level_none_count = - settings_.app_hmi_level_none_time_scale_max_requests(); - - const uint32_t& app_time_scale = settings_.app_time_scale(); - - const uint32_t& max_request_per_time_scale = - settings_.app_time_scale_max_requests(); - - const uint32_t& pending_requests_amount = settings_.pending_requests_amount(); - - if (!CheckPendingRequestsAmount(pending_requests_amount)) { + if (!CheckPendingRequestsAmount(settings_.pending_requests_amount())) { LOG4CXX_ERROR(logger_, "Too many pending request"); return RequestController::TOO_MANY_PENDING_REQUESTS; } - if (!waiting_for_response_.CheckHMILevelTimeScaleMaxRequest( - mobile_apis::HMILevel::HMI_NONE, - request->connection_key(), - app_hmi_level_none_time_scale, - hmi_level_none_count)) { + const TrackResult track_result = + request_tracker_.Track(request->connection_key(), level); + + if (TrackResult::kNoneLevelMaxRequestsExceeded == track_result) { LOG4CXX_ERROR(logger_, "Too many application requests in hmi level NONE"); return RequestController::NONE_HMI_LEVEL_MANY_REQUESTS; } - if (!waiting_for_response_.CheckTimeScaleMaxRequest( - request->connection_key(), - app_time_scale, - max_request_per_time_scale)) { + + if (TrackResult::kMaxRequestsExceeded == track_result) { LOG4CXX_ERROR(logger_, "Too many application requests"); return RequestController::TOO_MANY_REQUESTS; } + return SUCCESS; } @@ -171,7 +156,7 @@ RequestController::TResult RequestController::addMobileRequest( logger_, "correlation_id : " << request->correlation_id() << "connection_key : " << request->connection_key()); - RequestController::TResult result = CheckPosibilitytoAdd(request); + RequestController::TResult result = CheckPosibilitytoAdd(request, hmi_level); if (SUCCESS == result) { AutoLock auto_lock_list(mobile_request_list_lock_); mobile_request_list_.push_back(request); diff --git a/src/components/application_manager/src/request_info.cc b/src/components/application_manager/src/request_info.cc index 80b18a53c6..9a5828d939 100644 --- a/src/components/application_manager/src/request_info.cc +++ b/src/components/application_manager/src/request_info.cc @@ -268,66 +268,6 @@ void RequestInfoSet::CheckSetSizes() { DCHECK(set_sizes_equal); } -bool RequestInfoSet::CheckTimeScaleMaxRequest( - uint32_t app_id, - uint32_t app_time_scale, - uint32_t max_request_per_time_scale) { - LOG4CXX_AUTO_TRACE(logger_); - if (max_request_per_time_scale > 0 && app_time_scale > 0) { - TimevalStruct end = date_time::DateTime::getCurrentTime(); - TimevalStruct start = {0, 0}; - start.tv_sec = end.tv_sec - app_time_scale; - - sync_primitives::AutoLock lock(this_lock_); - TimeScale scale(start, end, app_id); - const uint32_t count = std::count_if(time_sorted_pending_requests_.begin(), - time_sorted_pending_requests_.end(), - scale); - if (count >= max_request_per_time_scale) { - LOG4CXX_WARN(logger_, - "Processing requests count " << count - << " exceed application limit " - << max_request_per_time_scale); - return false; - } - LOG4CXX_DEBUG(logger_, "Requests count " << count); - } else { - LOG4CXX_DEBUG(logger_, "CheckTimeScaleMaxRequest disabled"); - } - return true; -} - -bool RequestInfoSet::CheckHMILevelTimeScaleMaxRequest( - mobile_apis::HMILevel::eType hmi_level, - uint32_t app_id, - uint32_t app_time_scale, - uint32_t max_request_per_time_scale) { - LOG4CXX_AUTO_TRACE(logger_); - if (max_request_per_time_scale > 0 && app_time_scale > 0) { - TimevalStruct end = date_time::DateTime::getCurrentTime(); - TimevalStruct start = {0, 0}; - start.tv_sec = end.tv_sec - app_time_scale; - - sync_primitives::AutoLock lock(this_lock_); - HMILevelTimeScale scale(start, end, app_id, hmi_level); - const uint32_t count = std::count_if(time_sorted_pending_requests_.begin(), - time_sorted_pending_requests_.end(), - scale); - if (count >= max_request_per_time_scale) { - LOG4CXX_WARN(logger_, - "Processing requests count " - << count << " exceed application limit " - << max_request_per_time_scale << " in hmi level " - << hmi_level); - return false; - } - LOG4CXX_DEBUG(logger_, "Requests count " << count); - } else { - LOG4CXX_DEBUG(logger_, "CheckHMILevelTimeScaleMaxRequest disabled"); - } - return true; -} - bool RequestInfoSet::AppIdCompararator::operator()( const RequestInfoPtr value_compare) const { switch (compare_type_) { diff --git a/src/components/application_manager/src/request_tracker.cc b/src/components/application_manager/src/request_tracker.cc new file mode 100644 index 0000000000..13b3d4d873 --- /dev/null +++ b/src/components/application_manager/src/request_tracker.cc @@ -0,0 +1,133 @@ +/* +* Copyright (c) 2017, 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 "utils/logger.h" +#include "utils/macro.h" +#include "application_manager/request_tracker.h" +#include "application_manager/message_helper.h" + +namespace application_manager { + +namespace request_controller { + +CREATE_LOGGERPTR_GLOBAL(logger_, "RequestController") + +RequestTracker::RequestTracker(const RequestControlerSettings& settings) + : settings_(settings) {} + +TrackResult RequestTracker::Track(const ApplicationID& app_id, + const mobile_apis::HMILevel::eType level) { + LOG4CXX_AUTO_TRACE(logger_); + bool track_result = false; + + LOG4CXX_DEBUG(logger_, + "Tracking request for level: " + << MessageHelper::StringifiedHMILevel(level)); + + if (mobile_apis::HMILevel::HMI_NONE == level) { + track_result = Track(app_id, + settings_.app_hmi_level_none_time_scale(), + settings_.app_hmi_level_none_time_scale_max_requests(), + none_level_tracker_); + + return track_result ? TrackResult::kSuccess + : TrackResult::kNoneLevelMaxRequestsExceeded; + } + + track_result = Track(app_id, + settings_.app_time_scale(), + settings_.app_time_scale_max_requests(), + tracker_); + + return track_result ? TrackResult::kSuccess + : TrackResult::kMaxRequestsExceeded; +} + +bool RequestTracker::Track(const ApplicationID& app_id, + const uint32_t time_scale, + const uint32_t max_requests, + ApplicationsRequestsTracker& tracker) { + LOG4CXX_AUTO_TRACE(logger_); + using date_time::DateTime; + + if (!time_scale || !max_requests) { + LOG4CXX_INFO(logger_, "Time scale request tracking is disabled."); + return true; + } + + LOG4CXX_DEBUG(logger_, + "Time scale is: " << time_scale << ". Max requests number is: " + << max_requests); + + LOG4CXX_DEBUG(logger_, "Tracking app id: " << app_id); + ApplicationsRequestsTracker::iterator it_app = tracker.find(app_id); + + if (tracker.end() == it_app) { + LOG4CXX_DEBUG(logger_, "Adding new application into tracking."); + tracker[app_id].push_back(DateTime::getCurrentTime()); + return true; + } + + LOG4CXX_DEBUG(logger_, + "Amount of known requests is: " << it_app->second.size()); + + if (it_app->second.size() < max_requests) { + LOG4CXX_DEBUG(logger_, "Adding new request into tracking."); + tracker[app_id].push_back(DateTime::getCurrentTime()); + return true; + } + + LOG4CXX_DEBUG(logger_, + "Oldest request is added at: " + << DateTime::getmSecs(it_app->second.front()) + << ". Current time is: " + << DateTime::getmSecs(DateTime::getCurrentTime()) + << ". Time scale is: " << time_scale); + + if (DateTime::calculateTimeSpan(it_app->second.front()) > time_scale) { + LOG4CXX_DEBUG(logger_, "Dropping oldest request, adding new one."); + ApplicationsRequestsTracker::mapped_type& times = tracker[app_id]; + + DCHECK_OR_RETURN(!times.empty(), false); + + times.erase(times.begin()); + times.push_back(DateTime::getCurrentTime()); + return true; + } + + LOG4CXX_DEBUG(logger_, "Requests amount per time scale is exceeded."); + + return false; +} + +} // namespace request_controller +} // namespace application_manager diff --git a/src/components/application_manager/test/CMakeLists.txt b/src/components/application_manager/test/CMakeLists.txt index 4ce8760006..a7f5d8b243 100644 --- a/src/components/application_manager/test/CMakeLists.txt +++ b/src/components/application_manager/test/CMakeLists.txt @@ -52,6 +52,7 @@ if (BUILD_TESTS) ${AM_TEST_DIR}/mobile_message_handler_test.cc ${AM_TEST_DIR}/mobile_message_handler_v1_test.cc ${AM_TEST_DIR}/request_info_test.cc + ${AM_TEST_DIR}/request_tracker_test.cc ${AM_TEST_DIR}/resumption_sql_queries_test.cc ${AM_TEST_DIR}/event_engine_test.cc ${AM_TEST_DIR}/policy_event_observer_test.cc diff --git a/src/components/application_manager/test/request_info_test.cc b/src/components/application_manager/test/request_info_test.cc index 74c4041736..62d9897a18 100644 --- a/src/components/application_manager/test/request_info_test.cc +++ b/src/components/application_manager/test/request_info_test.cc @@ -177,107 +177,6 @@ TEST_F(RequestInfoTest, AddHMIRequests_RemoveAllRequests) { EXPECT_EQ(0u, request_info_set_.Size()); } -TEST_F(RequestInfoTest, CheckRequestsMaxCount) { - const uint32_t app_hmi_level_time_scale = 100; - const uint32_t hmi_level_count = 1000; - - // Count of added requests is less than max possible - std::vector<utils::SharedPtr<TestRequestInfo> > requests; - for (uint32_t i = 0; i < hmi_level_count - 1; ++i) { - utils::SharedPtr<TestRequestInfo> request = - CreateTestInfo(mobile_connection_key1_, - i, - request_info::RequestInfo::MobileRequest, - date_time::DateTime::getCurrentTime(), - default_timeout_); - - request->set_hmi_level(mobile_apis::HMILevel::HMI_FULL); - requests.push_back(request); - EXPECT_TRUE(request_info_set_.Add(request)); - } - EXPECT_EQ(hmi_level_count - 1, request_info_set_.Size()); - - EXPECT_TRUE(request_info_set_.CheckHMILevelTimeScaleMaxRequest( - mobile_apis::HMILevel::HMI_FULL, - mobile_connection_key1_, - app_hmi_level_time_scale, - hmi_level_count)); - - // Adding new request is correct - utils::SharedPtr<TestRequestInfo> new_request = - CreateTestInfo(mobile_connection_key1_, - hmi_level_count, - request_info::RequestInfo::MobileRequest, - date_time::DateTime::getCurrentTime(), - default_timeout_); - new_request->set_hmi_level(mobile_apis::HMILevel::HMI_FULL); - EXPECT_TRUE(request_info_set_.Add(new_request)); - EXPECT_EQ(hmi_level_count, request_info_set_.Size()); - - // Count of added requests is max - EXPECT_FALSE(request_info_set_.CheckHMILevelTimeScaleMaxRequest( - mobile_apis::HMILevel::HMI_FULL, - mobile_connection_key1_, - app_hmi_level_time_scale, - hmi_level_count)); - - utils::SharedPtr<TestRequestInfo> new_request2 = - CreateTestInfo(mobile_connection_key1_, - hmi_level_count + 1, - request_info::RequestInfo::MobileRequest, - date_time::DateTime::getCurrentTime(), - default_timeout_); - - EXPECT_TRUE(request_info_set_.Add(new_request2)); -} - -TEST_F(RequestInfoTest, CheckMaxCountOfRequest) { - const uint32_t app_hmi_level_time_scale = 100; - const uint32_t hmi_level_count = 1000; - - // Count of added requests is less than max possible - std::vector<utils::SharedPtr<TestRequestInfo> > requests; - for (uint32_t i = 0; i < hmi_level_count - 1; ++i) { - utils::SharedPtr<TestRequestInfo> request = - CreateTestInfo(mobile_connection_key1_, - i, - request_info::RequestInfo::MobileRequest, - date_time::DateTime::getCurrentTime(), - default_timeout_); - request->set_hmi_level(mobile_apis::HMILevel::HMI_FULL); - requests.push_back(request); - EXPECT_TRUE(request_info_set_.Add(request)); - } - EXPECT_EQ(hmi_level_count - 1, request_info_set_.Size()); - - EXPECT_TRUE(request_info_set_.CheckTimeScaleMaxRequest( - mobile_connection_key1_, app_hmi_level_time_scale, hmi_level_count)); - - // Adding new request is correct - utils::SharedPtr<TestRequestInfo> new_request = - CreateTestInfo(mobile_connection_key1_, - hmi_level_count, - request_info::RequestInfo::MobileRequest, - date_time::DateTime::getCurrentTime(), - default_timeout_); - new_request->set_hmi_level(mobile_apis::HMILevel::HMI_FULL); - EXPECT_TRUE(request_info_set_.Add(new_request)); - EXPECT_EQ(hmi_level_count, request_info_set_.Size()); - - // Count of added requests is max - EXPECT_FALSE(request_info_set_.CheckTimeScaleMaxRequest( - mobile_connection_key1_, app_hmi_level_time_scale, hmi_level_count)); - - utils::SharedPtr<TestRequestInfo> new_request2 = - CreateTestInfo(mobile_connection_key1_, - hmi_level_count + 1, - request_info::RequestInfo::MobileRequest, - date_time::DateTime::getCurrentTime(), - default_timeout_); - - EXPECT_TRUE(request_info_set_.Add(new_request2)); -} - TEST_F(RequestInfoTest, AddMobileRequests_RemoveMobileRequests) { utils::SharedPtr<TestRequestInfo> mobile_request1 = CreateTestInfo(mobile_connection_key1_, diff --git a/src/components/application_manager/test/request_tracker_test.cc b/src/components/application_manager/test/request_tracker_test.cc new file mode 100644 index 0000000000..ee09e0a3e0 --- /dev/null +++ b/src/components/application_manager/test/request_tracker_test.cc @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2017, 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 "utils/macro.h" +#include "application_manager/request_tracker.h" +#include "application_manager/mock_request_controller_settings.h" +#include "interfaces/MOBILE_API.h" +#include "utils/lock.h" +#include "utils/conditional_variable.h" + +namespace test { +namespace components { +namespace request_controller_test { + +using ::testing::Return; +using ::testing::ReturnRef; + +class RequestTrackerTestClass : public ::testing::Test { + public: + RequestTrackerTestClass() : tracker_(mock_request_controller_settings_) {} + + void SetDefaultConstraints() { + EXPECT_CALL(mock_request_controller_settings_, + app_hmi_level_none_time_scale()) + .WillRepeatedly(ReturnRef(kDefaultAppHmiLevelNoneRequestsTimeScale)); + + EXPECT_CALL(mock_request_controller_settings_, + app_hmi_level_none_time_scale_max_requests()) + .WillRepeatedly(ReturnRef(kDefaultAppHmiLevelNoneTimeScaleMaxRequests)); + + EXPECT_CALL(mock_request_controller_settings_, app_time_scale()) + .WillRepeatedly(ReturnRef(kDefaultAppRequestsTimeScale)); + + EXPECT_CALL(mock_request_controller_settings_, + app_time_scale_max_requests()) + .WillRepeatedly(ReturnRef(kDefaultAppTimeScaleMaxRequests)); + } + + protected: + application_manager_test::MockRequestControlerSettings + mock_request_controller_settings_; + + application_manager::request_controller::RequestTracker tracker_; + + const uint32_t kDefaultAppHmiLevelNoneRequestsTimeScale = 10u; + const uint32_t kDefaultAppHmiLevelNoneTimeScaleMaxRequests = 100u; + const uint32_t kDefaultAppTimeScaleMaxRequests = 5u; + const uint32_t kDefaultAppRequestsTimeScale = 200u; +}; + +TEST_F(RequestTrackerTestClass, TrackAppRequestInNone_ExpectSuccessTillLimit) { + const uint32_t app_id = 1u; + const mobile_apis::HMILevel::eType none_level = + mobile_apis::HMILevel::HMI_NONE; + + SetDefaultConstraints(); + + for (uint32_t i = 0; i < kDefaultAppHmiLevelNoneTimeScaleMaxRequests; ++i) { + EXPECT_EQ(application_manager::request_controller::TrackResult::kSuccess, + tracker_.Track(app_id, none_level)); + } + + EXPECT_EQ(application_manager::request_controller::TrackResult:: + kNoneLevelMaxRequestsExceeded, + tracker_.Track(app_id, none_level)); +} + +TEST_F(RequestTrackerTestClass, + TrackAppRequestInNone_NoLimits_ExpectAlwaysSuccess) { + const uint32_t no_limit = 0; + + EXPECT_CALL(mock_request_controller_settings_, + app_hmi_level_none_time_scale()) + .WillRepeatedly(ReturnRef(no_limit)); + + EXPECT_CALL(mock_request_controller_settings_, + app_hmi_level_none_time_scale_max_requests()) + .WillRepeatedly(ReturnRef(no_limit)); + + const uint32_t app_id = 1u; + const mobile_apis::HMILevel::eType none_level = + mobile_apis::HMILevel::HMI_NONE; + + for (uint32_t i = 0; i < kDefaultAppHmiLevelNoneTimeScaleMaxRequests; ++i) { + EXPECT_EQ(application_manager::request_controller::TrackResult::kSuccess, + tracker_.Track(app_id, none_level)); + } + + EXPECT_EQ(application_manager::request_controller::TrackResult::kSuccess, + tracker_.Track(app_id, none_level)); +} + +TEST_F(RequestTrackerTestClass, + TrackAppRequestInOtherThanNone_ExpectSuccessTillLimit) { + const uint32_t app_id = 1u; + mobile_apis::HMILevel::eType hmi_level = + mobile_apis::HMILevel::HMI_BACKGROUND; + + SetDefaultConstraints(); + + for (uint32_t i = 0; i < kDefaultAppTimeScaleMaxRequests; ++i) { + EXPECT_EQ(application_manager::request_controller::TrackResult::kSuccess, + tracker_.Track(app_id, hmi_level)); + if (i % 2) { + hmi_level = mobile_apis::HMILevel::HMI_FULL; + } else { + hmi_level = mobile_apis::HMILevel::HMI_LIMITED; + } + } + + EXPECT_EQ(application_manager::request_controller::TrackResult:: + kMaxRequestsExceeded, + tracker_.Track(app_id, hmi_level)); +} + +TEST_F(RequestTrackerTestClass, + TrackAppRequestInOtherThanNone_NoLimits_ExpectAlwaysSuccess) { + const uint32_t no_limit = 0; + + EXPECT_CALL(mock_request_controller_settings_, app_time_scale()) + .WillRepeatedly(ReturnRef(no_limit)); + + EXPECT_CALL(mock_request_controller_settings_, app_time_scale_max_requests()) + .WillRepeatedly(ReturnRef(no_limit)); + + const uint32_t app_id = 1u; + mobile_apis::HMILevel::eType hmi_level = + mobile_apis::HMILevel::HMI_BACKGROUND; + + for (uint32_t i = 0; i < kDefaultAppTimeScaleMaxRequests; ++i) { + EXPECT_EQ(application_manager::request_controller::TrackResult::kSuccess, + tracker_.Track(app_id, hmi_level)); + if (i % 2) { + hmi_level = mobile_apis::HMILevel::HMI_FULL; + } else { + hmi_level = mobile_apis::HMILevel::HMI_LIMITED; + } + } + + EXPECT_EQ(application_manager::request_controller::TrackResult::kSuccess, + tracker_.Track(app_id, hmi_level)); +} + +TEST_F(RequestTrackerTestClass, + TrackTwoAppsRequestInNone_ExpectSuccessTillLimit) { + const uint32_t app_id_1 = 1u; + const uint32_t app_id_2 = 2u; + + const mobile_apis::HMILevel::eType none_level = + mobile_apis::HMILevel::HMI_NONE; + + SetDefaultConstraints(); + + for (uint32_t i = 0; i < kDefaultAppHmiLevelNoneTimeScaleMaxRequests; ++i) { + if (i % 2) { + EXPECT_EQ(application_manager::request_controller::TrackResult::kSuccess, + tracker_.Track(app_id_1, none_level)); + } else { + EXPECT_EQ(application_manager::request_controller::TrackResult::kSuccess, + tracker_.Track(app_id_2, none_level)); + } + } + + for (uint32_t i = 0; i < kDefaultAppHmiLevelNoneTimeScaleMaxRequests / 2; + ++i) { + EXPECT_EQ(application_manager::request_controller::TrackResult::kSuccess, + tracker_.Track(app_id_1, none_level)); + EXPECT_EQ(application_manager::request_controller::TrackResult::kSuccess, + tracker_.Track(app_id_2, none_level)); + } + + EXPECT_EQ(application_manager::request_controller::TrackResult:: + kNoneLevelMaxRequestsExceeded, + tracker_.Track(app_id_1, none_level)); + + EXPECT_EQ(application_manager::request_controller::TrackResult:: + kNoneLevelMaxRequestsExceeded, + tracker_.Track(app_id_2, none_level)); +} + +TEST_F(RequestTrackerTestClass, + TrackAppRequestInNone_DoPause_TrackAgain_ExpectSuccessTillLimit) { + const uint32_t max_requests = 5; + const uint32_t time_scale_ms = 1; + + sync_primitives::ConditionalVariable awaiter; + sync_primitives::Lock lock; + sync_primitives::AutoLock auto_lock(lock); + + EXPECT_CALL(mock_request_controller_settings_, + app_hmi_level_none_time_scale()) + .WillRepeatedly(ReturnRef(time_scale_ms)); + + EXPECT_CALL(mock_request_controller_settings_, + app_hmi_level_none_time_scale_max_requests()) + .WillRepeatedly(ReturnRef(max_requests)); + + const uint32_t app_id = 1u; + const mobile_apis::HMILevel::eType none_level = + mobile_apis::HMILevel::HMI_NONE; + + for (uint32_t i = 0; i < max_requests; ++i) { + EXPECT_EQ(application_manager::request_controller::TrackResult::kSuccess, + tracker_.Track(app_id, none_level)); + } + + awaiter.WaitFor(auto_lock, time_scale_ms * 2); + + for (uint32_t i = 0; i < max_requests; ++i) { + EXPECT_EQ(application_manager::request_controller::TrackResult::kSuccess, + tracker_.Track(app_id, none_level)); + } + + EXPECT_EQ(application_manager::request_controller::TrackResult:: + kNoneLevelMaxRequestsExceeded, + tracker_.Track(app_id, none_level)); +} + +} // namespace request_controller +} // namespace components +} // namespace test |