diff options
Diffstat (limited to 'test/network_tests/application_tests')
16 files changed, 1423 insertions, 0 deletions
diff --git a/test/network_tests/application_tests/application_test.cpp b/test/network_tests/application_tests/application_test.cpp new file mode 100644 index 0000000..c7ad4f8 --- /dev/null +++ b/test/network_tests/application_tests/application_test.cpp @@ -0,0 +1,479 @@ +// Copyright (C) 2015-2017 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 <thread> +#include <mutex> +#include <condition_variable> +#include <future> + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> + +#include "someip_test_globals.hpp" + +using namespace vsomeip; + +class someip_application_test: public ::testing::Test { +public: + someip_application_test() : + registered_(false) { + + } +protected: + void SetUp() { + app_ = runtime::get()->create_application("application_test"); + if (!app_->init()) { + ADD_FAILURE() << "Couldn't initialize application"; + return; + } + + app_->register_state_handler( + std::bind(&someip_application_test::on_state, this, + std::placeholders::_1)); + } + + void on_state(vsomeip::state_type_e _state) { + registered_ = (_state == vsomeip::state_type_e::ST_REGISTERED); + } + + bool registered_; + std::shared_ptr<application> app_; +}; + +/** + * @test Start and stop application + */ +TEST_F(someip_application_test, start_stop_application) +{ + std::promise<bool> its_promise; + std::thread t([&](){ + its_promise.set_value(true); + app_->start(); + }); + EXPECT_TRUE(its_promise.get_future().get()); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + app_->stop(); + t.join(); +} + +/** + * @test Start and stop application multiple times + */ +TEST_F(someip_application_test, start_stop_application_multiple) +{ + for (int i = 0; i < 10; ++i) { + std::promise<bool> its_promise; + std::thread t([&]() { + its_promise.set_value(true); + app_->start(); + }); + EXPECT_TRUE(its_promise.get_future().get()); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + app_->stop(); + t.join(); + } +} + +/** + * @test Start and stop application multiple times and offer a service + */ +TEST_F(someip_application_test, start_stop_application_multiple_offer_service) +{ + for (int i = 0; i < 10; ++i) { + std::promise<bool> its_promise; + std::thread t([&]() { + its_promise.set_value(true); + app_->start(); + }); + EXPECT_TRUE(its_promise.get_future().get()); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + app_->offer_service(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + app_->stop_offer_service(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + app_->stop(); + t.join(); + } +} + +/** + * @test Try to start an already running application again + */ +TEST_F(someip_application_test, restart_without_stopping) +{ + std::promise<bool> its_promise; + std::thread t([&]() { + its_promise.set_value(true); + app_->start(); + + }); + EXPECT_TRUE(its_promise.get_future().get()); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + VSOMEIP_WARNING << "An error message should appear now"; + // should print error + app_->start(); + app_->stop(); + t.join(); +} + +/** + * @test Try to stop a running application twice + */ +TEST_F(someip_application_test, stop_application_twice) +{ + std::promise<bool> its_promise; + std::thread t([&]() { + its_promise.set_value(true); + app_->start(); + + }); + EXPECT_TRUE(its_promise.get_future().get()); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + app_->stop(); + t.join(); + app_->stop(); +} + +/** + * @test Checks whether watchdog handler is invoked (regularly) also after restarting. + */ +TEST_F(someip_application_test, watchdog_handler) +{ + std::atomic<int> cb_count(0); + auto wd_handler = [&] () { + ++cb_count; + }; + + app_->set_watchdog_handler(std::cref(wd_handler), std::chrono::seconds(1)); + + std::promise<bool> its_promise; + std::thread t([&]() { + its_promise.set_value(true); + app_->start(); + }); + EXPECT_TRUE(its_promise.get_future().get()); + + // wait till watchdog handler has been invoked once + while (0 == cb_count.load()) { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + ASSERT_EQ(1, cb_count.load()); + + // clear handler (must not be called again) + app_->set_watchdog_handler(nullptr, std::chrono::seconds::zero()); + + // wait doubled interval (used previously).. + std::this_thread::sleep_for(std::chrono::seconds(2)); + // .. to ensure it was not called again + ASSERT_EQ(1, cb_count.load()); + + // enable handler again + app_->set_watchdog_handler(std::cref(wd_handler), std::chrono::seconds(1)); + + // wait till watchdog handler has been invoked again (2nd time) + while (1 == cb_count.load()) { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + + app_->stop(); + t.join(); + + // wait doubled interval (used previously).. + std::this_thread::sleep_for(std::chrono::seconds(2)); + // .. to ensure it was not called after stop() + ASSERT_EQ(2, cb_count.load()); + + // restart application (w/ watchdog handler still set) + std::promise<bool> its_promise2; + std::thread t2([&]() { + its_promise2.set_value(true); + app_->start(); + }); + EXPECT_TRUE(its_promise2.get_future().get()); + + // wait till watchdog handler has been invoked again (3rd time) + while (2 == cb_count.load()) { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + ASSERT_EQ(3, cb_count.load()); + + // clear handler again (must not be called again), this time via zero interval + app_->set_watchdog_handler(std::cref(wd_handler), std::chrono::seconds::zero()); + + // wait doubled interval (used previously).. + std::this_thread::sleep_for(std::chrono::seconds(2)); + // .. to ensure it was not called again + ASSERT_EQ(3, cb_count.load()); + + app_->stop(); + t2.join(); +} + +class someip_application_shutdown_test: public ::testing::Test { + +protected: + void SetUp() { + is_registered_ = false; + is_available_ = false; + + app_ = runtime::get()->create_application("application_test"); + if (!app_->init()) { + ADD_FAILURE() << "Couldn't initialize application"; + return; + } + + app_->register_message_handler(vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, + vsomeip_test::TEST_SERVICE_METHOD_ID_SHUTDOWN, + std::bind(&someip_application_shutdown_test::on_message_shutdown, this, + std::placeholders::_1)); + + app_->register_state_handler( + std::bind(&someip_application_shutdown_test::on_state, this, + std::placeholders::_1)); + app_->register_availability_handler( + vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, + std::bind(&someip_application_shutdown_test::on_availability, + this, std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3)); + + shutdown_thread_ = std::thread(&someip_application_shutdown_test::send_shutdown_message, this); + + app_->start(); + } + + void TearDown() { + shutdown_thread_.join(); + app_->stop(); + app_.reset(); + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + } + + void on_state(vsomeip::state_type_e _state) { + if(_state == vsomeip::state_type_e::ST_REGISTERED) + { + std::lock_guard<std::mutex> its_lock(mutex_); + is_registered_ = true; + cv_.notify_one(); + } + } + + void on_availability(vsomeip::service_t _service, + vsomeip::instance_t _instance, bool _is_available) { + (void)_service; + (void)_instance; + if(_is_available) { + std::lock_guard<std::mutex> its_lock(mutex_); + is_available_ = _is_available; + cv_.notify_one(); + } + } + + void on_message_shutdown(const std::shared_ptr<message>& _request) + { + (void)_request; + VSOMEIP_INFO << "Shutdown method was called, going down now."; + app_->clear_all_handler(); + app_->stop(); + } + + void send_shutdown_message() { + { + std::unique_lock<std::mutex> its_lock(mutex_); + while (!is_registered_) { + if (std::cv_status::timeout + == cv_.wait_for(its_lock, std::chrono::seconds(10))) { + ADD_FAILURE()<< "Application wasn't registered in time!"; + is_registered_ = true; + } + } + app_->request_service(vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID); + app_->offer_service(vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID); + while (!is_available_) { + if (std::cv_status::timeout + == cv_.wait_for(its_lock, std::chrono::seconds(10))) { + ADD_FAILURE()<< "Service didn't become available in time!"; + is_available_ = true; + } + } + } + + std::shared_ptr<message> r = runtime::get()->create_request(); + r->set_service(vsomeip_test::TEST_SERVICE_SERVICE_ID); + r->set_instance(vsomeip_test::TEST_SERVICE_INSTANCE_ID); + r->set_method(vsomeip_test::TEST_SERVICE_METHOD_ID_SHUTDOWN); + app_->send(r); + } + + bool is_registered_; + bool is_available_; + std::shared_ptr<application> app_; + std::condition_variable cv_; + std::mutex mutex_; + std::thread shutdown_thread_; +}; + +class someip_application_exception_test: public ::testing::Test { + +protected: + void SetUp() { + is_registered_ = false; + is_available_ = false; + exception_method_called_ = false; + + app_ = runtime::get()->create_application("application_test"); + if (!app_->init()) { + ADD_FAILURE() << "Couldn't initialize application"; + return; + } + + app_->register_message_handler(vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, + vsomeip_test::TEST_SERVICE_METHOD_ID_SHUTDOWN, + std::bind(&someip_application_exception_test::on_message_shutdown, this, + std::placeholders::_1)); + app_->register_message_handler(vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, + vsomeip_test::TEST_SERVICE_METHOD_ID_SHUTDOWN+1, + std::bind(&someip_application_exception_test::on_message_exception, this, + std::placeholders::_1)); + + app_->register_state_handler( + std::bind(&someip_application_exception_test::on_state, this, + std::placeholders::_1)); + app_->register_availability_handler( + vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, + std::bind(&someip_application_exception_test::on_availability, + this, std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3)); + + shutdown_thread_ = std::thread(&someip_application_exception_test::send_shutdown_message, this); + + app_->start(); + } + + void TearDown() { + shutdown_thread_.join(); + app_->stop(); + app_.reset(); + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + } + + void on_state(vsomeip::state_type_e _state) { + if(_state == vsomeip::state_type_e::ST_REGISTERED) + { + std::lock_guard<std::mutex> its_lock(mutex_); + is_registered_ = true; + cv_.notify_one(); + } + } + + void on_availability(vsomeip::service_t _service, + vsomeip::instance_t _instance, bool _is_available) { + (void)_service; + (void)_instance; + if(_is_available) { + std::lock_guard<std::mutex> its_lock(mutex_); + is_available_ = _is_available; + cv_.notify_one(); + } + } + + void on_message_shutdown(const std::shared_ptr<message>& _request) + { + (void)_request; + VSOMEIP_INFO << "Shutdown method was called, going down now."; + app_->clear_all_handler(); + app_->stop(); + } + + void on_message_exception(const std::shared_ptr<message>& _request) + { + (void)_request; + { + std::lock_guard<std::mutex> its_lock(mutex_); + exception_method_called_ = true; + cv_.notify_one(); + } + throw std::invalid_argument("something went terribly wrong"); + } + + void send_shutdown_message() { + { + std::unique_lock<std::mutex> its_lock(mutex_); + while(!is_registered_) { + cv_.wait(its_lock); + } + app_->request_service(vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID); + app_->offer_service(vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID); + while(!is_available_) { + cv_.wait(its_lock); + } + } + + std::shared_ptr<message> r = runtime::get()->create_request(); + // call method which throws exception + r->set_service(vsomeip_test::TEST_SERVICE_SERVICE_ID); + r->set_instance(vsomeip_test::TEST_SERVICE_INSTANCE_ID); + r->set_method(vsomeip_test::TEST_SERVICE_METHOD_ID_SHUTDOWN+1); + app_->send(r); + + { + std::unique_lock<std::mutex> its_lock(mutex_); + while (!exception_method_called_) { + cv_.wait(its_lock); + } + } + + + //shutdown test + r->set_service(vsomeip_test::TEST_SERVICE_SERVICE_ID); + r->set_instance(vsomeip_test::TEST_SERVICE_INSTANCE_ID); + r->set_method(vsomeip_test::TEST_SERVICE_METHOD_ID_SHUTDOWN); + app_->send(r); + } + + bool is_registered_; + bool is_available_; + bool exception_method_called_; + std::shared_ptr<application> app_; + std::condition_variable cv_; + std::mutex mutex_; + std::thread shutdown_thread_; +}; + +/** + * @test Stop the application through a method invoked from a dispatcher thread + */ +TEST_F(someip_application_shutdown_test, stop_application_from_dispatcher_thread) { + +} + +/** + * @test Catch unhandled exceptions from invoked handlers + */ +TEST_F(someip_application_exception_test, catch_exception_in_invoked_handler) { + +} + +#if defined(__linux__) || defined(ANDROID) +int main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} +#endif + + + + diff --git a/test/network_tests/application_tests/application_test_availability.cpp b/test/network_tests/application_tests/application_test_availability.cpp new file mode 100644 index 0000000..89d94c1 --- /dev/null +++ b/test/network_tests/application_tests/application_test_availability.cpp @@ -0,0 +1,39 @@ +// Copyright (C) 2014-2017 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 <gtest/gtest.h> + +#include "application_test_client_availability.cpp" +#include "application_test_service.cpp" +#include "application_test_daemon.cpp" + +TEST(someip_application_test_availability, register_availability_handlers) +{ + // start application acting as daemon + application_test_daemon its_daemon; + + // start receiver service + application_test_service its_receiver(application_test::service); + + // start client + application_test_client_availability its_client(application_test::service); + int counter(0); + while (!its_client.all_availability_handlers_called() && counter < 500) { + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + counter++; + } + + //shutdown + its_receiver.stop(); + its_client.stop(); + its_daemon.stop(); +} + +#if defined(__linux__) || defined(ANDROID) +int main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} +#endif diff --git a/test/network_tests/application_tests/application_test_availability_starter.sh b/test/network_tests/application_tests/application_test_availability_starter.sh new file mode 100755 index 0000000..645e347 --- /dev/null +++ b/test/network_tests/application_tests/application_test_availability_starter.sh @@ -0,0 +1,10 @@ +#!/bin/bash +# Copyright (C) 2015-2017 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/. + +export VSOMEIP_CONFIGURATION=application_test_single_process.json +./application_test_availability + + exit $?
\ No newline at end of file diff --git a/test/network_tests/application_tests/application_test_client.cpp b/test/network_tests/application_tests/application_test_client.cpp new file mode 100644 index 0000000..30d0084 --- /dev/null +++ b/test/network_tests/application_tests/application_test_client.cpp @@ -0,0 +1,199 @@ +// Copyright (C) 2014-2017 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 <chrono> +#include <condition_variable> +#include <iomanip> +#include <iostream> +#include <sstream> +#include <thread> +#include <map> +#include <algorithm> +#include <future> +#include <atomic> + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> +#include <vsomeip/internal/logger.hpp> + +#include "application_test_globals.hpp" + +class application_test_client { +public: + application_test_client(struct application_test::service_info _service_info) : + service_info_(_service_info), + app_(vsomeip::runtime::get()->create_application("client")), + wait_until_registered_(true), + wait_until_service_available_(true), + wait_for_stop_(true), + received_responses_(0), + sent_requests_(0), + stop_called_(false), + stop_thread_(std::bind(&application_test_client::wait_for_stop, this)), + send_thread_(std::bind(&application_test_client::send, this)) { + if (!app_->init()) { + ADD_FAILURE() << "Couldn't initialize application"; + return; + } + app_->register_state_handler( + std::bind(&application_test_client::on_state, this, + std::placeholders::_1)); + + app_->register_message_handler(vsomeip::ANY_SERVICE, + vsomeip::ANY_INSTANCE, vsomeip::ANY_METHOD, + std::bind(&application_test_client::on_message, this, + std::placeholders::_1)); + + // register availability for all other services and request their event. + app_->register_availability_handler(service_info_.service_id, + service_info_.instance_id, + std::bind(&application_test_client::on_availability, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3)); + app_->request_service(service_info_.service_id, + service_info_.instance_id); + std::promise<bool> its_promise; + application_thread_ = std::thread([&](){ + its_promise.set_value(true); + app_->start(); + }); + EXPECT_TRUE(its_promise.get_future().get()); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + + ~application_test_client() { + send_thread_.join(); + stop_thread_.join(); + application_thread_.join(); + } + + void 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) { + std::lock_guard<std::mutex> its_lock(mutex_); + wait_until_registered_ = false; + condition_.notify_one(); + } + } + + void on_availability(vsomeip::service_t _service, + vsomeip::instance_t _instance, bool _is_available) { + VSOMEIP_INFO << "Service [" << std::setw(4) + << std::setfill('0') << std::hex << _service << "." << _instance + << "] is " << (_is_available ? "available":"not available") << "."; + std::lock_guard<std::mutex> its_lock(mutex_); + if(_is_available) { + wait_until_service_available_ = false; + condition_.notify_one(); + } else { + wait_until_service_available_ = true; + condition_.notify_one(); + } + } + + void on_message(const std::shared_ptr<vsomeip::message> &_message) { + ++received_responses_; + EXPECT_EQ(service_info_.service_id, _message->get_service()); + EXPECT_EQ(service_info_.method_id, _message->get_method()); + EXPECT_EQ(service_info_.instance_id, _message->get_instance()); + VSOMEIP_INFO << "Received a response with Client/Session [" << std::setw(4) + << std::setfill('0') << std::hex << _message->get_client() << "/" + << std::setw(4) << std::setfill('0') << std::hex + << _message->get_session() << "]"; + } + + void send() { + std::unique_lock<std::mutex> its_lock(mutex_); + while (wait_until_registered_ && !stop_called_) { + condition_.wait_for(its_lock, std::chrono::milliseconds(100)); + } + + while (wait_until_service_available_ && !stop_called_) { + condition_.wait_for(its_lock, std::chrono::milliseconds(100)); + } + its_lock.unlock(); + its_lock.release(); + + for (;;) { + bool send(false); + { + std::lock_guard<std::mutex> its_lock(mutex_); + send = !wait_until_service_available_; + } + if (send && !stop_called_) { + std::shared_ptr<vsomeip::message> its_req = vsomeip::runtime::get()->create_request(); + its_req->set_service(service_info_.service_id); + its_req->set_instance(service_info_.instance_id); + its_req->set_method(service_info_.method_id); + app_->send(its_req); + ++sent_requests_; + VSOMEIP_INFO << "Sent a request to the service!"; + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } else { + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + } + if(stop_called_) { + break; + } + } + } + + void wait_for_stop() { + std::unique_lock<std::mutex> its_lock(stop_mutex_); + while (wait_for_stop_) { + stop_condition_.wait(its_lock); + } + VSOMEIP_INFO << "going down"; + app_->clear_all_handler(); + app_->stop(); + } + + void stop(bool check) { + stop_called_ = true; + std::lock_guard<std::mutex> its_lock(stop_mutex_); + wait_for_stop_ = false; + VSOMEIP_INFO << "going down. Sent " << sent_requests_ + << " requests and received " << received_responses_ + << " responses. Delta: " << sent_requests_ - received_responses_; + std::uint32_t counter(0); + if (check) { + while(sent_requests_ == 0 || sent_requests_ < received_responses_) { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + if(++counter > 50) { + break; + } + } + EXPECT_GT(sent_requests_, 0u); + EXPECT_GT(received_responses_, 0u); + EXPECT_EQ(sent_requests_, received_responses_); + } + stop_condition_.notify_one(); + } + +private: + struct application_test::service_info service_info_; + std::shared_ptr<vsomeip::application> app_; + + bool wait_until_registered_; + bool wait_until_service_available_; + std::mutex mutex_; + std::condition_variable condition_; + + bool wait_for_stop_; + std::mutex stop_mutex_; + std::condition_variable stop_condition_; + + std::atomic<std::uint32_t> received_responses_; + std::atomic<std::uint32_t> sent_requests_; + std::atomic<bool> stop_called_; + + std::thread stop_thread_; + std::thread send_thread_; + std::thread application_thread_; +}; diff --git a/test/network_tests/application_tests/application_test_client_availability.cpp b/test/network_tests/application_tests/application_test_client_availability.cpp new file mode 100644 index 0000000..16fe87b --- /dev/null +++ b/test/network_tests/application_tests/application_test_client_availability.cpp @@ -0,0 +1,203 @@ +// Copyright (C) 2014-2017 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 <chrono> +#include <condition_variable> +#include <iomanip> +#include <iostream> +#include <sstream> +#include <thread> +#include <map> +#include <algorithm> +#include <future> +#include <atomic> + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> +#include <vsomeip/internal/logger.hpp> + +#include "application_test_globals.hpp" + +class application_test_client_availability { +public: + application_test_client_availability(struct application_test::service_info _service_info) : + service_info_(_service_info), + app_(vsomeip::runtime::get()->create_application("client")), + wait_until_registered_(true), + all_availability_handlers_called_(false), + run_thread_(std::bind(&application_test_client_availability::run, this)) { + if (!app_->init()) { + ADD_FAILURE() << "Couldn't initialize application"; + return; + } + app_->register_state_handler( + std::bind(&application_test_client_availability::on_state, this, + std::placeholders::_1)); + + // register availability handler for every possiblity of + // ANY_SERVICE, ANY_INSTANCE, ANY_MAJOR, ANY_MINOR + for (std::uint32_t i = 0; i < 16; i++) { + vsomeip::service_t its_service = (i & 0x8) ? service_info_.service_id : vsomeip::ANY_SERVICE; + vsomeip::instance_t its_instance = (i & 0x4) ? service_info_.instance_id : vsomeip::ANY_INSTANCE; + vsomeip::major_version_t its_major = (i & 0x2) ? service_info_.major_version : vsomeip::ANY_MAJOR; + vsomeip::minor_version_t its_minor = (i & 0x1) ? service_info_.minor_version : vsomeip::ANY_MINOR; + app_->register_availability_handler(its_service, + its_instance, + std::bind(&application_test_client_availability::on_availability, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3, i), + its_major, its_minor); + VSOMEIP_DEBUG << "Registering: " + << std::setw(4) << std::setfill('0') << std::hex << its_service << "." + << std::setw(4) << std::setfill('0') << std::hex << its_instance << "." + << std::setw(2) << std::setfill('0') << std::hex << (std::uint32_t)its_major << "." + << std::setw(4) << std::setfill('0') << std::hex << its_minor << "." + << i; + + } + app_->register_availability_handler(service_info_.service_id, + service_info_.instance_id, + std::bind(&application_test_client_availability::on_availability, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3, 16), + service_info_.major_version, vsomeip::DEFAULT_MINOR); + VSOMEIP_DEBUG << "Registering: " + << std::setw(4) << std::setfill('0') << std::hex << service_info_.service_id << "." + << std::setw(4) << std::setfill('0') << std::hex << service_info_.instance_id << "." + << std::setw(2) << std::setfill('0') << std::hex << (std::uint32_t)service_info_.service_id << "." + << std::setw(4) << std::setfill('0') << std::hex << vsomeip::DEFAULT_MINOR << "." + << 16; + app_->request_service(service_info_.service_id, + service_info_.instance_id); + std::promise<bool> its_promise; + application_thread_ = std::thread([&](){ + its_promise.set_value(true); + app_->start(); + }); + EXPECT_TRUE(its_promise.get_future().get()); + } + + ~application_test_client_availability() { + run_thread_.join(); + application_thread_.join(); + } + + void 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) { + std::lock_guard<std::mutex> its_lock(mutex_); + wait_until_registered_ = false; + condition_.notify_one(); + } + } + + void on_availability(vsomeip::service_t _service, + vsomeip::instance_t _instance, bool _is_available, + std::uint32_t _handler_index) + { + VSOMEIP_DEBUG<< "Service [" << std::setw(4) << std::setfill('0') << std::hex + << _service << "." << std::setw(4) << std::setfill('0') << _instance << "] is " + << (_is_available ? "available." : "NOT available.") << ". " + << _handler_index; + if(service_info_.service_id == _service + && service_info_.instance_id == _instance) { + std::lock_guard<std::mutex> its_lock(availability_handler_called_mutex_); + availability_handler_called_[_handler_index] = _is_available; + availability_condition_.notify_one(); + } + } + + void run() { + { + std::unique_lock<std::mutex> its_lock(mutex_); + while (wait_until_registered_) { + condition_.wait(its_lock); + } + } + while(!app_->is_available(service_info_.service_id, + service_info_.instance_id, service_info_.major_version, + service_info_.minor_version)) { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + for (std::uint32_t i = 0; i < 16; i++) { + vsomeip::service_t its_service = (i & 0x8) ? service_info_.service_id : vsomeip::ANY_SERVICE; + vsomeip::instance_t its_instance = (i & 0x4) ? service_info_.instance_id : vsomeip::ANY_INSTANCE; + vsomeip::major_version_t its_major = (i & 0x2) ? service_info_.major_version : vsomeip::ANY_MAJOR; + vsomeip::minor_version_t its_minor = (i & 0x1) ? service_info_.minor_version : vsomeip::ANY_MINOR; + + VSOMEIP_DEBUG << "Calling is_available: " + << std::setw(4) << std::setfill('0') << std::hex << its_service << "." + << std::setw(4) << std::setfill('0') << std::hex << its_instance << "." + << std::setw(2) << std::setfill('0') << std::hex << (std::uint32_t)its_major << "." + << std::setw(4) << std::setfill('0') << std::hex << its_minor; + EXPECT_TRUE(app_->is_available(its_service, its_instance, its_major, its_minor)); + + VSOMEIP_DEBUG << "Calling are_available: " + << std::setw(4) << std::setfill('0') << std::hex << its_service << "." + << std::setw(4) << std::setfill('0') << std::hex << its_instance << "." + << std::setw(2) << std::setfill('0') << std::hex << (std::uint32_t)its_major << "." + << std::setw(4) << std::setfill('0') << std::hex << its_minor; + vsomeip::application::available_t are_available; + EXPECT_TRUE(app_->are_available(are_available, its_service, its_instance, its_major, its_minor)); + bool found(false); + auto found_service = are_available.find(service_info_.service_id); + if(found_service != are_available.end()) { + auto found_instance = found_service->second.find(service_info_.instance_id); + if(found_instance != found_service->second.end()) { + auto found_major = found_instance->second.find(service_info_.major_version); + if (found_major != found_instance->second.end()) { + if (found_major->second == service_info_.minor_version) { + found = true; + } + } + } + } + EXPECT_TRUE(found); + + } + { + std::unique_lock<std::mutex> its_lock(availability_handler_called_mutex_); + while(!std::all_of(availability_handler_called_.cbegin(), + availability_handler_called_.cend(), + [&](const availability_handler_called_t::value_type &v) { + return v; + })) { + availability_condition_.wait(its_lock); + } + } + VSOMEIP_INFO <<" Everything is available"; + all_availability_handlers_called_ = true; + } + + void stop() { + VSOMEIP_INFO << "going down"; + app_->clear_all_handler(); + app_->stop(); + } + + bool all_availability_handlers_called() const { + return all_availability_handlers_called_; + } + +private: + struct application_test::service_info service_info_; + std::shared_ptr<vsomeip::application> app_; + std::mutex availability_handler_called_mutex_; + std::condition_variable availability_condition_; + typedef std::array<bool, 17> availability_handler_called_t; + availability_handler_called_t availability_handler_called_; + + + bool wait_until_registered_; + std::mutex mutex_; + std::condition_variable condition_; + std::atomic<bool> all_availability_handlers_called_; + std::thread run_thread_; + std::thread application_thread_; +}; diff --git a/test/network_tests/application_tests/application_test_daemon.cpp b/test/network_tests/application_tests/application_test_daemon.cpp new file mode 100644 index 0000000..2f0b244 --- /dev/null +++ b/test/network_tests/application_tests/application_test_daemon.cpp @@ -0,0 +1,42 @@ +// Copyright (C) 2014-2017 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 <gtest/gtest.h> +#include <future> + +#include <vsomeip/vsomeip.hpp> +#include <vsomeip/internal/logger.hpp> + +class application_test_daemon { +public: + application_test_daemon() : + app_(vsomeip::runtime::get()->create_application("daemon")) { + if (!app_->init()) { + ADD_FAILURE() << "Couldn't initialize application"; + return; + } + std::promise<bool> its_promise; + application_thread_ = std::thread([&](){ + its_promise.set_value(true); + app_->start(); + }); + EXPECT_TRUE(its_promise.get_future().get()); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + VSOMEIP_INFO << "Daemon starting"; + } + + ~application_test_daemon() { + application_thread_.join(); + } + + void stop() { + VSOMEIP_INFO << "Daemon stopping"; + app_->stop(); + } + +private: + std::shared_ptr<vsomeip::application> app_; + std::thread application_thread_; +}; diff --git a/test/network_tests/application_tests/application_test_globals.hpp b/test/network_tests/application_tests/application_test_globals.hpp new file mode 100644 index 0000000..7caa9db --- /dev/null +++ b/test/network_tests/application_tests/application_test_globals.hpp @@ -0,0 +1,28 @@ +// Copyright (C) 2014-2017 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/. + +#ifndef APPLICATION_TEST_GLOBALS_HPP_ +#define APPLICATION_TEST_GLOBALS_HPP_ + +namespace application_test { + +struct service_info { + vsomeip::service_t service_id; + vsomeip::instance_t instance_id; + vsomeip::method_t method_id; + vsomeip::event_t event_id; + vsomeip::eventgroup_t eventgroup_id; + vsomeip::method_t shutdown_method_id; + vsomeip::major_version_t major_version; + vsomeip::minor_version_t minor_version; +}; + + +struct service_info service = { 0x1111, 0x1, 0x1111, 0x1111, 0x1000, 0x1404, 0x2, 0x4711 }; + +static constexpr int number_of_messages_to_send = 150; +} + +#endif /* APPLICATION_TEST_GLOBALS_HPP_ */ diff --git a/test/network_tests/application_tests/application_test_service.cpp b/test/network_tests/application_tests/application_test_service.cpp new file mode 100644 index 0000000..77d40cd --- /dev/null +++ b/test/network_tests/application_tests/application_test_service.cpp @@ -0,0 +1,128 @@ +// Copyright (C) 2014-2017 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 <chrono> +#include <condition_variable> +#include <iomanip> +#include <iostream> +#include <sstream> +#include <thread> +#include <map> +#include <algorithm> +#include <future> +#include <atomic> + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> +#include <vsomeip/internal/logger.hpp> + +#include "application_test_globals.hpp" + +class application_test_service { +public: + application_test_service(struct application_test::service_info _service_info) : + service_info_(_service_info), + // service with number 1 uses "routingmanagerd" as application name + // this way the same json file can be reused for all local tests + // including the ones with routingmanagerd + app_(vsomeip::runtime::get()->create_application("service")), + wait_until_registered_(true), + stop_called_(false), + offer_thread_(std::bind(&application_test_service::run, this)) { + if (!app_->init()) { + ADD_FAILURE() << "Couldn't initialize application"; + return; + } + app_->register_state_handler( + std::bind(&application_test_service::on_state, this, + std::placeholders::_1)); + + app_->register_message_handler(service_info_.service_id, + service_info_.instance_id, service_info_.method_id, + std::bind(&application_test_service::on_request, this, + std::placeholders::_1)); + + app_->register_message_handler(service_info_.service_id, + service_info_.instance_id, service_info_.shutdown_method_id, + std::bind(&application_test_service::on_shutdown_method_called, this, + std::placeholders::_1)); + std::promise<bool> its_promise; + application_thread_ = std::thread([&](){ + its_promise.set_value(true); + app_->start(); + }); + EXPECT_TRUE(its_promise.get_future().get()); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + + ~application_test_service() { + offer_thread_.join(); + application_thread_.join(); + } + + + void offer() { + app_->offer_service(service_info_.service_id, service_info_.instance_id, + service_info_.major_version, service_info_.minor_version); + } + + void 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) { + std::lock_guard<std::mutex> its_lock(mutex_); + wait_until_registered_ = false; + condition_.notify_one(); + } + } + + void on_request(const std::shared_ptr<vsomeip::message> &_message) { + app_->send(vsomeip::runtime::get()->create_response(_message)); + VSOMEIP_INFO << "Received a request with Client/Session [" << std::setw(4) + << std::setfill('0') << std::hex << _message->get_client() << "/" + << std::setw(4) << std::setfill('0') << std::hex + << _message->get_session() << "]"; + } + + void on_shutdown_method_called(const std::shared_ptr<vsomeip::message> &_message) { + (void)_message; + stop(); + } + + void stop() { + stop_called_ = true; + app_->stop_offer_service(service_info_.service_id, service_info_.instance_id, + service_info_.major_version, service_info_.minor_version); + app_->clear_all_handler(); + app_->stop(); + } + + void run() { + VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex + << service_info_.service_id << "] Running"; + std::unique_lock<std::mutex> its_lock(mutex_); + while (wait_until_registered_ && !stop_called_) { + condition_.wait_for(its_lock, std::chrono::milliseconds(100)); + } + + VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex + << service_info_.service_id << "] Offering"; + offer(); + } + +private: + struct application_test::service_info service_info_; + std::shared_ptr<vsomeip::application> app_; + + bool wait_until_registered_; + std::mutex mutex_; + std::condition_variable condition_; + std::atomic<bool> stop_called_; + std::thread offer_thread_; + std::thread application_thread_; +}; diff --git a/test/network_tests/application_tests/application_test_single_process.cpp b/test/network_tests/application_tests/application_test_single_process.cpp new file mode 100644 index 0000000..c738899 --- /dev/null +++ b/test/network_tests/application_tests/application_test_single_process.cpp @@ -0,0 +1,47 @@ +// Copyright (C) 2014-2017 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 <gtest/gtest.h> +#include "application_test_service.cpp" +#include "application_test_client.cpp" +#include "application_test_daemon.cpp" + +TEST(someip_application_test_single_process, notify_increasing_counter) +{ + // start application acting as daemon (rm_stub) + auto its_daemon = std::make_shared<application_test_daemon>(); + + // start receiver service (rm_proxy) + application_test_service its_receiver(application_test::service); + + // stop the daemon (rm_stub goes away) + its_daemon->stop(); + its_daemon.reset(); + // restart client which tries to communicate with service multiple times + // thus it will always be the new routing manager + for (int var = 0; var < 10; ++var) { + // every time the client is restarted it becomes the rm_stub again + application_test_client its_client(application_test::service); + if(var != 9) { + its_client.stop(false); + } else { + // for the last iteration we sleep to make sure the communication + // between the client and the service can be established + std::this_thread::sleep_for(std::chrono::milliseconds(2000)); + its_client.stop(true); + } + } + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + its_receiver.on_shutdown_method_called(vsomeip::runtime::get()->create_message()); +} + + +#if defined(__linux__) || defined(ANDROID) +int main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} +#endif diff --git a/test/network_tests/application_tests/application_test_single_process.json b/test/network_tests/application_tests/application_test_single_process.json new file mode 100644 index 0000000..b604d9a --- /dev/null +++ b/test/network_tests/application_tests/application_test_single_process.json @@ -0,0 +1,14 @@ +{ + "unicast":"127.0.0.1", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/someip.log" + }, + "dlt":"false" + } +} diff --git a/test/network_tests/application_tests/application_test_single_process_starter.sh b/test/network_tests/application_tests/application_test_single_process_starter.sh new file mode 100755 index 0000000..3919358 --- /dev/null +++ b/test/network_tests/application_tests/application_test_single_process_starter.sh @@ -0,0 +1,23 @@ +#!/bin/bash +# Copyright (C) 2015-2017 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/. + +FAIL=0 + +export VSOMEIP_CONFIGURATION=application_test_single_process.json +./application_test_single_process + +if [ $? -ne 0 ] +then + ((FAIL+=1)) +fi + +# Check if both exited successfully +if [ $FAIL -eq 0 ] +then + exit 0 +else + exit 1 +fi diff --git a/test/network_tests/application_tests/application_test_starter.sh b/test/network_tests/application_tests/application_test_starter.sh new file mode 100755 index 0000000..7e8c022 --- /dev/null +++ b/test/network_tests/application_tests/application_test_starter.sh @@ -0,0 +1,61 @@ +#!/bin/bash +# Copyright (C) 2015-2017 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/. + +FAIL=0 + +export VSOMEIP_CONFIGURATION=application_test_no_dispatch_threads.json +./application_test + +if [ $? -ne 0 ] +then + ((FAIL+=1)) +fi + +export VSOMEIP_CONFIGURATION=application_test.json +./application_test + +if [ $? -ne 0 ] +then + ((FAIL+=1)) +fi + +cat <<End-of-message +******************************************************************************* +******************************************************************************* +** Now running same tests with routingmanagerd +******************************************************************************* +******************************************************************************* +End-of-message +export VSOMEIP_CONFIGURATION=application_test_no_dispatch_threads_daemon.json +../../examples/routingmanagerd/./routingmanagerd & +DAEMON_PID=$! +./application_test +if [ $? -ne 0 ] +then + ((FAIL+=1)) +fi + +kill $DAEMON_PID +wait $DAEMON_PID + +export VSOMEIP_CONFIGURATION=application_test_daemon.json +../../examples/routingmanagerd/./routingmanagerd & +DAEMON_PID=$! +./application_test +if [ $? -ne 0 ] +then + ((FAIL+=1)) +fi + +kill $DAEMON_PID + +# Check if both exited successfully +if [ $FAIL -eq 0 ] +then + exit 0 +else + exit 1 +fi diff --git a/test/network_tests/application_tests/conf/application_test.json.in b/test/network_tests/application_tests/conf/application_test.json.in new file mode 100644 index 0000000..ed5a7fc --- /dev/null +++ b/test/network_tests/application_tests/conf/application_test.json.in @@ -0,0 +1,38 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/someip.log" + }, + "dlt":"false" + }, + "applications": + [ + { + "name":"application_test", + "id":"0x7788", + "num_dispatchers":"5" + } + ], + "services": + [ + { + "service":"0x1234", + "instance":"0x5678", + "reliable":"30503" + } + ], + "routing":"application_test", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp" + } +} diff --git a/test/network_tests/application_tests/conf/application_test_daemon.json.in b/test/network_tests/application_tests/conf/application_test_daemon.json.in new file mode 100644 index 0000000..f7fd3dc --- /dev/null +++ b/test/network_tests/application_tests/conf/application_test_daemon.json.in @@ -0,0 +1,38 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/someip.log" + }, + "dlt":"false" + }, + "applications": + [ + { + "name":"application_test", + "id":"0x7788", + "num_dispatchers":"5" + } + ], + "services": + [ + { + "service":"0x1234", + "instance":"0x5678", + "reliable":"30503" + } + ], + "routing":"routingmanagerd", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp" + } +} diff --git a/test/network_tests/application_tests/conf/application_test_no_dispatch_threads.json.in b/test/network_tests/application_tests/conf/application_test_no_dispatch_threads.json.in new file mode 100644 index 0000000..20d0ebd --- /dev/null +++ b/test/network_tests/application_tests/conf/application_test_no_dispatch_threads.json.in @@ -0,0 +1,37 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/someip.log" + }, + "dlt":"false" + }, + "applications": + [ + { + "name":"application_test", + "id":"0x7788" + } + ], + "services": + [ + { + "service":"0x1234", + "instance":"0x5678", + "reliable":"30503" + } + ], + "routing":"application_test", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp" + } +} diff --git a/test/network_tests/application_tests/conf/application_test_no_dispatch_threads_daemon.json.in b/test/network_tests/application_tests/conf/application_test_no_dispatch_threads_daemon.json.in new file mode 100644 index 0000000..8c7622a --- /dev/null +++ b/test/network_tests/application_tests/conf/application_test_no_dispatch_threads_daemon.json.in @@ -0,0 +1,37 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/someip.log" + }, + "dlt":"false" + }, + "applications": + [ + { + "name":"application_test", + "id":"0x7788" + } + ], + "services": + [ + { + "service":"0x1234", + "instance":"0x5678", + "reliable":"30503" + } + ], + "routing":"routingmanagerd", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp" + } +} |