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