diff options
Diffstat (limited to 'test/network_tests/npdu_tests/npdu_test_service.cpp')
-rw-r--r-- | test/network_tests/npdu_tests/npdu_test_service.cpp | 306 |
1 files changed, 306 insertions, 0 deletions
diff --git a/test/network_tests/npdu_tests/npdu_test_service.cpp b/test/network_tests/npdu_tests/npdu_test_service.cpp new file mode 100644 index 0000000..b4ee984 --- /dev/null +++ b/test/network_tests/npdu_tests/npdu_test_service.cpp @@ -0,0 +1,306 @@ +// Copyright (C) 2015-2019 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "../npdu_tests/npdu_test_service.hpp" +#include "../npdu_tests/npdu_test_globals.hpp" + +#include <vsomeip/internal/logger.hpp> +#include "../../implementation/configuration/include/configuration.hpp" +#include "../../implementation/configuration/include/configuration_impl.hpp" +#include "../../implementation/configuration/include/configuration_plugin.hpp" +#include "../../implementation/plugin/include/plugin_manager_impl.hpp" + + + +// this variable is set during compile time to create 4 service binaries of +// which each of them offers a service. +// Based on this number the service id, instance id and method ids are +// selected from the arrays defined in npdu_test_globals.hpp +#ifndef SERVICE_NUMBER +#define SERVICE_NUMBER 0 +#endif + +npdu_test_service::npdu_test_service(vsomeip::service_t _service_id, + vsomeip::instance_t _instance_id, + std::array<vsomeip::method_t, 4> _method_ids, + std::array<std::chrono::nanoseconds, 4> _debounce_times, + std::array<std::chrono::nanoseconds, 4> _max_retention_times) : + app_(vsomeip::runtime::get()->create_application()), + is_registered_(false), + method_ids_(_method_ids), + debounce_times_(_debounce_times), + max_retention_times_(_max_retention_times), + service_id_(_service_id), + instance_id_(_instance_id), + blocked_(false), + allowed_to_shutdown_(false), + number_of_received_messages_(0), + offer_thread_(std::bind(&npdu_test_service::run, this)), + shutdown_thread_(std::bind(&npdu_test_service::stop, this)) +{ + // init timepoints of last received message to one hour before now. + // needed that the first message which arrives isn't registered as undershot + // debounce time + for(auto &tp : timepoint_last_received_message_) { + tp = std::chrono::steady_clock::now() - std::chrono::hours(1); + } +} + +void npdu_test_service::init() +{ + std::lock_guard<std::mutex> its_lock(mutex_); + + app_->init(); + + register_message_handler<0>(); + register_message_handler<1>(); + register_message_handler<2>(); + register_message_handler<3>(); + + app_->register_message_handler(service_id_, instance_id_, + npdu_test::NPDU_SERVICE_SHUTDOWNMETHOD_ID, + std::bind(&npdu_test_service::on_message_shutdown, this, + std::placeholders::_1)); + + app_->register_state_handler( + std::bind(&npdu_test_service::on_state, this, + std::placeholders::_1)); +} + +template <int method_idx> +void npdu_test_service::register_message_handler() { + app_->register_message_handler(service_id_, instance_id_, method_ids_[method_idx], + std::bind(&npdu_test_service::on_message<method_idx>, this, + std::placeholders::_1)); +} + +void npdu_test_service::start() +{ + VSOMEIP_INFO << "Starting..."; + app_->start(); +} + +void npdu_test_service::stop() +{ + std::unique_lock<std::mutex> its_lock(shutdown_mutex_); + while (!allowed_to_shutdown_) { + shutdown_condition_.wait(its_lock); + } + + VSOMEIP_INFO << "Stopping..."; + if (!undershot_debounce_times_.empty()) { + std::chrono::microseconds sum(0); + for (const auto t : undershot_debounce_times_) { + sum += t; + } + double average = static_cast<double>(sum.count())/static_cast<double>(undershot_debounce_times_.size()); + VSOMEIP_INFO << "[" + << std::setw(4) << std::setfill('0') << std::hex << service_id_ << "." + << std::setw(4) << std::setfill('0') << std::hex << instance_id_ << "]: " + << " Debounce time was undershot " << std::dec << undershot_debounce_times_.size() << "/" << number_of_received_messages_ + << "(" << std::setprecision(2) << (static_cast<double>(undershot_debounce_times_.size()) / static_cast<double>(number_of_received_messages_)) * 100.00 + << "%) on average: " << std::setprecision(4) << average << "µs"; + } + app_->unregister_message_handler(service_id_, instance_id_, method_ids_[0]); + app_->unregister_message_handler(service_id_, instance_id_, method_ids_[1]); + app_->unregister_message_handler(service_id_, instance_id_, method_ids_[2]); + app_->unregister_message_handler(service_id_, instance_id_, method_ids_[3]); + app_->unregister_message_handler(service_id_, + instance_id_, npdu_test::NPDU_SERVICE_SHUTDOWNMETHOD_ID); + app_->unregister_state_handler(); + offer_thread_.join(); + stop_offer(); + app_->stop(); +} + +void npdu_test_service::offer() +{ + app_->offer_service(service_id_, instance_id_); +} + +void npdu_test_service::stop_offer() +{ + app_->stop_offer_service(service_id_, instance_id_); +} + +void npdu_test_service::join_shutdown_thread() { + shutdown_thread_.join(); +} + +void npdu_test_service::on_state(vsomeip::state_type_e _state) +{ + VSOMEIP_INFO << "Application " << app_->get_name() << " is " + << (_state == vsomeip::state_type_e::ST_REGISTERED ? "registered." : + "deregistered."); + + if(_state == vsomeip::state_type_e::ST_REGISTERED) + { + if(!is_registered_) + { + std::lock_guard<std::mutex> its_lock(mutex_); + is_registered_ = true; + blocked_ = true; + // "start" the run method thread + condition_.notify_one(); + } + } + else + { + is_registered_ = false; + } +} + +template<int method_idx> +void npdu_test_service::check_times() { + std::lock_guard<std::mutex> its_lock(timepoint_mutexes_[method_idx]); + // what time is it? + std::chrono::steady_clock::time_point now = + std::chrono::steady_clock::now(); + // how long is it since we received the last message? + std::chrono::nanoseconds time_since_last_message = + std::chrono::duration_cast<std::chrono::nanoseconds>( + now - timepoint_last_received_message_[method_idx]); + // store the current time + timepoint_last_received_message_[method_idx] = now; + + // check if the debounce time was undershot + if (time_since_last_message < debounce_times_[method_idx]) { + const auto time_undershot = std::chrono::duration_cast< + std::chrono::microseconds>(debounce_times_[method_idx] - time_since_last_message); + undershot_debounce_times_.push_back(time_undershot); + } + // check if maximum retention time was exceeded + // Disabled as it can't be guaranteed that exact every max retention time a + // message leaves the client endpoint. +#if 0 + if(time_since_last_message > max_retention_times_[method_idx]) { + VSOMEIP_ERROR << std::setw(4) << std::setfill('0') << std::hex + << service_id_ << ":" << std::setw(4) << std::setfill('0') + << std::hex << instance_id_ << ":" << std::setw(4) << std::setfill('0') + << std::hex << npdu_test::method_ids[SERVICE_NUMBER][method_idx] + << ": max_retention_time exceeded by: " << std::dec + << std::chrono::duration_cast<std::chrono::milliseconds>( + time_since_last_message - max_retention_times_[method_idx]).count() + << "ms"; + GTEST_FATAL_FAILURE_("Max retention time was exceeded"); + } +#endif +} + +template<int method_idx> +void npdu_test_service::on_message(const std::shared_ptr<vsomeip::message>& _request) +{ + number_of_received_messages_++; + check_times<method_idx>(); + VSOMEIP_DEBUG << __func__ << " 0x" << std::setw(4) << std::setfill('0') << std::hex + << method_ids_[method_idx] << " payload size: " + << std::dec << _request->get_payload()->get_length(); + if(_request->get_message_type() != vsomeip::message_type_e::MT_REQUEST_NO_RETURN) { + std::shared_ptr<vsomeip::message> its_response = + vsomeip::runtime::get()->create_response(_request); + app_->send(its_response); + } +} + +void npdu_test_service::on_message_shutdown( + const std::shared_ptr<vsomeip::message>& _request) +{ + (void)_request; + VSOMEIP_DEBUG << "Number of received messages: " << number_of_received_messages_; + VSOMEIP_INFO << "Shutdown method was called, going down now."; + + std::lock_guard<std::mutex> its_lock(shutdown_mutex_); + allowed_to_shutdown_ = true; + shutdown_condition_.notify_one(); +} + +void npdu_test_service::run() +{ + std::unique_lock<std::mutex> its_lock(mutex_); + while (!blocked_) + condition_.wait(its_lock); + + offer(); +} + +TEST(someip_npdu_test, offer_service_and_check_debounce_times) +{ + // get the configuration + std::shared_ptr<vsomeip::configuration> its_configuration; + auto its_plugin = vsomeip::plugin_manager::get()->get_plugin( + vsomeip::plugin_type_e::CONFIGURATION_PLUGIN, VSOMEIP_CFG_LIBRARY); + if (its_plugin) { + auto its_config_plugin = std::dynamic_pointer_cast<vsomeip::configuration_plugin>(its_plugin); + if (its_config_plugin) { + its_configuration = its_config_plugin->get_configuration("",""); + } + } + if (!its_configuration) { + ADD_FAILURE() << "No configuration object. " + "Either memory overflow or loading error detected!"; + return; + } + + // used to store the debounce times + std::array<std::chrono::nanoseconds, 4> debounce_times; + std::array<std::chrono::nanoseconds, 4> max_retention_times; + + + // query the debouncetimes from the configuration. We want to know the + // debounce times which the _clients_ of this service have to comply with + // when they send requests to this service. This is necessary as we want to + // check on the service side if they adhere to them. + // client one will only query method one, client two will only query method + // two and so on. + for(int i = 0; i < 4; i++) { + std::chrono::nanoseconds debounce(0), retention(0); + its_configuration->get_configured_timing_requests( + npdu_test::service_ids[SERVICE_NUMBER], + its_configuration->get_unicast_address().to_string(), + its_configuration->get_unreliable_port( + npdu_test::service_ids[SERVICE_NUMBER], + npdu_test::instance_ids[SERVICE_NUMBER]), + npdu_test::method_ids[SERVICE_NUMBER][i], + &debounce_times[i], + &max_retention_times[i]); + if (debounce == std::chrono::nanoseconds(VSOMEIP_DEFAULT_NPDU_DEBOUNCING_NANO) && + retention == std::chrono::nanoseconds(VSOMEIP_DEFAULT_NPDU_MAXIMUM_RETENTION_NANO)) { + // no timings specified - checks in check_times() should never + // report an error in this case. + // set debounce time to 0 this can't be undershot + debounce_times[i] = std::chrono::nanoseconds(0); + // set max retention time its max, this won't be exceeded + max_retention_times[i] = std::chrono::nanoseconds::max(); + } + } + + npdu_test_service test_service( + npdu_test::service_ids[SERVICE_NUMBER], + npdu_test::instance_ids[SERVICE_NUMBER], + npdu_test::method_ids[SERVICE_NUMBER], + debounce_times, max_retention_times); + test_service.init(); + test_service.start(); + test_service.join_shutdown_thread(); +} + +#if defined(__linux__) || defined(ANDROID) +int main(int argc, char** argv) +{ + int i = 1; + while (i < argc) + { + if(std::string("--help") == argv[i]) + { + VSOMEIP_INFO << "Parameters:\n" + << "--help: print this help"; + } + i++; + } + + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} +#endif |