1 // Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) 2 // This Source Code Form is subject to the terms of the Mozilla Public 3 // License, v. 2.0. If a copy of the MPL was not distributed with this 4 // file, You can obtain one at http://mozilla.org/MPL/2.0/. 5 6 #include <chrono> 7 #include <condition_variable> 8 #include <iomanip> 9 #include <iostream> 10 #include <sstream> 11 #include <thread> 12 #include <map> 13 #include <algorithm> 14 #include <future> 15 #include <atomic> 16 17 #include <gtest/gtest.h> 18 19 #include <vsomeip/vsomeip.hpp> 20 #include <vsomeip/internal/logger.hpp> 21 22 #include "application_test_globals.hpp" 23 24 class application_test_client_availability { 25 public: application_test_client_availability(struct application_test::service_info _service_info)26 application_test_client_availability(struct application_test::service_info _service_info) : 27 service_info_(_service_info), 28 app_(vsomeip::runtime::get()->create_application("client")), 29 wait_until_registered_(true), 30 all_availability_handlers_called_(false), 31 run_thread_(std::bind(&application_test_client_availability::run, this)) { 32 if (!app_->init()) { 33 ADD_FAILURE() << "Couldn't initialize application"; 34 return; 35 } 36 app_->register_state_handler( 37 std::bind(&application_test_client_availability::on_state, this, 38 std::placeholders::_1)); 39 40 // register availability handler for every possiblity of 41 // ANY_SERVICE, ANY_INSTANCE, ANY_MAJOR, ANY_MINOR 42 for (std::uint32_t i = 0; i < 16; i++) { 43 vsomeip::service_t its_service = (i & 0x8) ? service_info_.service_id : vsomeip::ANY_SERVICE; 44 vsomeip::instance_t its_instance = (i & 0x4) ? service_info_.instance_id : vsomeip::ANY_INSTANCE; 45 vsomeip::major_version_t its_major = (i & 0x2) ? service_info_.major_version : vsomeip::ANY_MAJOR; 46 vsomeip::minor_version_t its_minor = (i & 0x1) ? service_info_.minor_version : vsomeip::ANY_MINOR; 47 app_->register_availability_handler(its_service, 48 its_instance, 49 std::bind(&application_test_client_availability::on_availability, this, 50 std::placeholders::_1, std::placeholders::_2, 51 std::placeholders::_3, i), 52 its_major, its_minor); 53 VSOMEIP_DEBUG << "Registering: " 54 << std::setw(4) << std::setfill('0') << std::hex << its_service << "." 55 << std::setw(4) << std::setfill('0') << std::hex << its_instance << "." 56 << std::setw(2) << std::setfill('0') << std::hex << (std::uint32_t)its_major << "." 57 << std::setw(4) << std::setfill('0') << std::hex << its_minor << "." 58 << i; 59 60 } 61 app_->register_availability_handler(service_info_.service_id, 62 service_info_.instance_id, 63 std::bind(&application_test_client_availability::on_availability, this, 64 std::placeholders::_1, std::placeholders::_2, 65 std::placeholders::_3, 16), 66 service_info_.major_version, vsomeip::DEFAULT_MINOR); 67 VSOMEIP_DEBUG << "Registering: " 68 << std::setw(4) << std::setfill('0') << std::hex << service_info_.service_id << "." 69 << std::setw(4) << std::setfill('0') << std::hex << service_info_.instance_id << "." 70 << std::setw(2) << std::setfill('0') << std::hex << (std::uint32_t)service_info_.service_id << "." 71 << std::setw(4) << std::setfill('0') << std::hex << vsomeip::DEFAULT_MINOR << "." 72 << 16; 73 app_->request_service(service_info_.service_id, 74 service_info_.instance_id); 75 std::promise<bool> its_promise; 76 application_thread_ = std::thread([&](){ 77 its_promise.set_value(true); 78 app_->start(); 79 }); 80 EXPECT_TRUE(its_promise.get_future().get()); 81 } 82 ~application_test_client_availability()83 ~application_test_client_availability() { 84 run_thread_.join(); 85 application_thread_.join(); 86 } 87 on_state(vsomeip::state_type_e _state)88 void on_state(vsomeip::state_type_e _state) { 89 VSOMEIP_INFO << "Application " << app_->get_name() << " is " 90 << (_state == vsomeip::state_type_e::ST_REGISTERED ? 91 "registered." : "deregistered."); 92 93 if (_state == vsomeip::state_type_e::ST_REGISTERED) { 94 std::lock_guard<std::mutex> its_lock(mutex_); 95 wait_until_registered_ = false; 96 condition_.notify_one(); 97 } 98 } 99 on_availability(vsomeip::service_t _service,vsomeip::instance_t _instance,bool _is_available,std::uint32_t _handler_index)100 void on_availability(vsomeip::service_t _service, 101 vsomeip::instance_t _instance, bool _is_available, 102 std::uint32_t _handler_index) 103 { 104 VSOMEIP_DEBUG<< "Service [" << std::setw(4) << std::setfill('0') << std::hex 105 << _service << "." << std::setw(4) << std::setfill('0') << _instance << "] is " 106 << (_is_available ? "available." : "NOT available.") << ". " 107 << _handler_index; 108 if(service_info_.service_id == _service 109 && service_info_.instance_id == _instance) { 110 std::lock_guard<std::mutex> its_lock(availability_handler_called_mutex_); 111 availability_handler_called_[_handler_index] = _is_available; 112 availability_condition_.notify_one(); 113 } 114 } 115 run()116 void run() { 117 { 118 std::unique_lock<std::mutex> its_lock(mutex_); 119 while (wait_until_registered_) { 120 condition_.wait(its_lock); 121 } 122 } 123 while(!app_->is_available(service_info_.service_id, 124 service_info_.instance_id, service_info_.major_version, 125 service_info_.minor_version)) { 126 std::this_thread::sleep_for(std::chrono::milliseconds(100)); 127 } 128 for (std::uint32_t i = 0; i < 16; i++) { 129 vsomeip::service_t its_service = (i & 0x8) ? service_info_.service_id : vsomeip::ANY_SERVICE; 130 vsomeip::instance_t its_instance = (i & 0x4) ? service_info_.instance_id : vsomeip::ANY_INSTANCE; 131 vsomeip::major_version_t its_major = (i & 0x2) ? service_info_.major_version : vsomeip::ANY_MAJOR; 132 vsomeip::minor_version_t its_minor = (i & 0x1) ? service_info_.minor_version : vsomeip::ANY_MINOR; 133 134 VSOMEIP_DEBUG << "Calling is_available: " 135 << std::setw(4) << std::setfill('0') << std::hex << its_service << "." 136 << std::setw(4) << std::setfill('0') << std::hex << its_instance << "." 137 << std::setw(2) << std::setfill('0') << std::hex << (std::uint32_t)its_major << "." 138 << std::setw(4) << std::setfill('0') << std::hex << its_minor; 139 EXPECT_TRUE(app_->is_available(its_service, its_instance, its_major, its_minor)); 140 141 VSOMEIP_DEBUG << "Calling are_available: " 142 << std::setw(4) << std::setfill('0') << std::hex << its_service << "." 143 << std::setw(4) << std::setfill('0') << std::hex << its_instance << "." 144 << std::setw(2) << std::setfill('0') << std::hex << (std::uint32_t)its_major << "." 145 << std::setw(4) << std::setfill('0') << std::hex << its_minor; 146 vsomeip::application::available_t are_available; 147 EXPECT_TRUE(app_->are_available(are_available, its_service, its_instance, its_major, its_minor)); 148 bool found(false); 149 auto found_service = are_available.find(service_info_.service_id); 150 if(found_service != are_available.end()) { 151 auto found_instance = found_service->second.find(service_info_.instance_id); 152 if(found_instance != found_service->second.end()) { 153 auto found_major = found_instance->second.find(service_info_.major_version); 154 if (found_major != found_instance->second.end()) { 155 if (found_major->second == service_info_.minor_version) { 156 found = true; 157 } 158 } 159 } 160 } 161 EXPECT_TRUE(found); 162 163 } 164 { 165 std::unique_lock<std::mutex> its_lock(availability_handler_called_mutex_); 166 while(!std::all_of(availability_handler_called_.cbegin(), 167 availability_handler_called_.cend(), 168 [&](const availability_handler_called_t::value_type &v) { 169 return v; 170 })) { 171 availability_condition_.wait(its_lock); 172 } 173 } 174 VSOMEIP_INFO <<" Everything is available"; 175 all_availability_handlers_called_ = true; 176 } 177 stop()178 void stop() { 179 VSOMEIP_INFO << "going down"; 180 app_->clear_all_handler(); 181 app_->stop(); 182 } 183 all_availability_handlers_called() const184 bool all_availability_handlers_called() const { 185 return all_availability_handlers_called_; 186 } 187 188 private: 189 struct application_test::service_info service_info_; 190 std::shared_ptr<vsomeip::application> app_; 191 std::mutex availability_handler_called_mutex_; 192 std::condition_variable availability_condition_; 193 typedef std::array<bool, 17> availability_handler_called_t; 194 availability_handler_called_t availability_handler_called_; 195 196 197 bool wait_until_registered_; 198 std::mutex mutex_; 199 std::condition_variable condition_; 200 std::atomic<bool> all_availability_handlers_called_; 201 std::thread run_thread_; 202 std::thread application_thread_; 203 }; 204