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 { 25 public: application_test_client(struct application_test::service_info _service_info)26 application_test_client(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 wait_until_service_available_(true), 31 wait_for_stop_(true), 32 received_responses_(0), 33 sent_requests_(0), 34 stop_called_(false), 35 stop_thread_(std::bind(&application_test_client::wait_for_stop, this)), 36 send_thread_(std::bind(&application_test_client::send, this)) { 37 if (!app_->init()) { 38 ADD_FAILURE() << "Couldn't initialize application"; 39 return; 40 } 41 app_->register_state_handler( 42 std::bind(&application_test_client::on_state, this, 43 std::placeholders::_1)); 44 45 app_->register_message_handler(vsomeip::ANY_SERVICE, 46 vsomeip::ANY_INSTANCE, vsomeip::ANY_METHOD, 47 std::bind(&application_test_client::on_message, this, 48 std::placeholders::_1)); 49 50 // register availability for all other services and request their event. 51 app_->register_availability_handler(service_info_.service_id, 52 service_info_.instance_id, 53 std::bind(&application_test_client::on_availability, this, 54 std::placeholders::_1, std::placeholders::_2, 55 std::placeholders::_3)); 56 app_->request_service(service_info_.service_id, 57 service_info_.instance_id); 58 std::promise<bool> its_promise; 59 application_thread_ = std::thread([&](){ 60 its_promise.set_value(true); 61 app_->start(); 62 }); 63 EXPECT_TRUE(its_promise.get_future().get()); 64 std::this_thread::sleep_for(std::chrono::milliseconds(100)); 65 } 66 ~application_test_client()67 ~application_test_client() { 68 send_thread_.join(); 69 stop_thread_.join(); 70 application_thread_.join(); 71 } 72 on_state(vsomeip::state_type_e _state)73 void on_state(vsomeip::state_type_e _state) { 74 VSOMEIP_INFO << "Application " << app_->get_name() << " is " 75 << (_state == vsomeip::state_type_e::ST_REGISTERED ? 76 "registered." : "deregistered."); 77 78 if (_state == vsomeip::state_type_e::ST_REGISTERED) { 79 std::lock_guard<std::mutex> its_lock(mutex_); 80 wait_until_registered_ = false; 81 condition_.notify_one(); 82 } 83 } 84 on_availability(vsomeip::service_t _service,vsomeip::instance_t _instance,bool _is_available)85 void on_availability(vsomeip::service_t _service, 86 vsomeip::instance_t _instance, bool _is_available) { 87 VSOMEIP_INFO << "Service [" << std::setw(4) 88 << std::setfill('0') << std::hex << _service << "." << _instance 89 << "] is " << (_is_available ? "available":"not available") << "."; 90 std::lock_guard<std::mutex> its_lock(mutex_); 91 if(_is_available) { 92 wait_until_service_available_ = false; 93 condition_.notify_one(); 94 } else { 95 wait_until_service_available_ = true; 96 condition_.notify_one(); 97 } 98 } 99 on_message(const std::shared_ptr<vsomeip::message> & _message)100 void on_message(const std::shared_ptr<vsomeip::message> &_message) { 101 ++received_responses_; 102 EXPECT_EQ(service_info_.service_id, _message->get_service()); 103 EXPECT_EQ(service_info_.method_id, _message->get_method()); 104 EXPECT_EQ(service_info_.instance_id, _message->get_instance()); 105 VSOMEIP_INFO << "Received a response with Client/Session [" << std::setw(4) 106 << std::setfill('0') << std::hex << _message->get_client() << "/" 107 << std::setw(4) << std::setfill('0') << std::hex 108 << _message->get_session() << "]"; 109 } 110 send()111 void send() { 112 std::unique_lock<std::mutex> its_lock(mutex_); 113 while (wait_until_registered_ && !stop_called_) { 114 condition_.wait_for(its_lock, std::chrono::milliseconds(100)); 115 } 116 117 while (wait_until_service_available_ && !stop_called_) { 118 condition_.wait_for(its_lock, std::chrono::milliseconds(100)); 119 } 120 its_lock.unlock(); 121 its_lock.release(); 122 123 for (;;) { 124 bool send(false); 125 { 126 std::lock_guard<std::mutex> its_lock(mutex_); 127 send = !wait_until_service_available_; 128 } 129 if (send && !stop_called_) { 130 std::shared_ptr<vsomeip::message> its_req = vsomeip::runtime::get()->create_request(); 131 its_req->set_service(service_info_.service_id); 132 its_req->set_instance(service_info_.instance_id); 133 its_req->set_method(service_info_.method_id); 134 app_->send(its_req); 135 ++sent_requests_; 136 VSOMEIP_INFO << "Sent a request to the service!"; 137 std::this_thread::sleep_for(std::chrono::milliseconds(100)); 138 } else { 139 std::this_thread::sleep_for(std::chrono::milliseconds(50)); 140 } 141 if(stop_called_) { 142 break; 143 } 144 } 145 } 146 wait_for_stop()147 void wait_for_stop() { 148 std::unique_lock<std::mutex> its_lock(stop_mutex_); 149 while (wait_for_stop_) { 150 stop_condition_.wait(its_lock); 151 } 152 VSOMEIP_INFO << "going down"; 153 app_->clear_all_handler(); 154 app_->stop(); 155 } 156 stop(bool check)157 void stop(bool check) { 158 stop_called_ = true; 159 std::lock_guard<std::mutex> its_lock(stop_mutex_); 160 wait_for_stop_ = false; 161 VSOMEIP_INFO << "going down. Sent " << sent_requests_ 162 << " requests and received " << received_responses_ 163 << " responses. Delta: " << sent_requests_ - received_responses_; 164 std::uint32_t counter(0); 165 if (check) { 166 while(sent_requests_ == 0 || sent_requests_ < received_responses_) { 167 std::this_thread::sleep_for(std::chrono::milliseconds(100)); 168 if(++counter > 50) { 169 break; 170 } 171 } 172 EXPECT_GT(sent_requests_, 0u); 173 EXPECT_GT(received_responses_, 0u); 174 EXPECT_EQ(sent_requests_, received_responses_); 175 } 176 stop_condition_.notify_one(); 177 } 178 179 private: 180 struct application_test::service_info service_info_; 181 std::shared_ptr<vsomeip::application> app_; 182 183 bool wait_until_registered_; 184 bool wait_until_service_available_; 185 std::mutex mutex_; 186 std::condition_variable condition_; 187 188 bool wait_for_stop_; 189 std::mutex stop_mutex_; 190 std::condition_variable stop_condition_; 191 192 std::atomic<std::uint32_t> received_responses_; 193 std::atomic<std::uint32_t> sent_requests_; 194 std::atomic<bool> stop_called_; 195 196 std::thread stop_thread_; 197 std::thread send_thread_; 198 std::thread application_thread_; 199 }; 200