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
15 #include <gtest/gtest.h>
16
17 #include <vsomeip/vsomeip.hpp>
18 #include <vsomeip/internal/logger.hpp>
19
20 #include "client_id_test_globals.hpp"
21
22
23 class client_id_test_service {
24 public:
client_id_test_service(struct client_id_test::service_info _service_info)25 client_id_test_service(struct client_id_test::service_info _service_info) :
26 service_info_(_service_info),
27 app_(vsomeip::runtime::get()->create_application()),
28 blocked_(false),
29 offer_thread_(std::bind(&client_id_test_service::run, this)),
30 stopped_(false),
31 stop_thread_(std::bind(&client_id_test_service::wait_for_stop, this)) {
32 if (!app_->init()) {
33 offer_thread_.detach();
34 stop_thread_.detach();
35 ADD_FAILURE() << "Couldn't initialize application";
36 return;
37 }
38 app_->register_state_handler(
39 std::bind(&client_id_test_service::on_state, this,
40 std::placeholders::_1));
41 app_->register_message_handler(service_info_.service_id,
42 service_info_.instance_id, service_info_.method_id,
43 std::bind(&client_id_test_service::on_request, this,
44 std::placeholders::_1));
45 app_->register_message_handler(vsomeip::ANY_SERVICE,
46 service_info_.instance_id, vsomeip::ANY_METHOD,
47 std::bind(&client_id_test_service::on_response, this,
48 std::placeholders::_1));
49
50 for(const auto& i : client_id_test::service_infos) {
51 if ((i.service_id == service_info_.service_id
52 && i.instance_id == service_info_.instance_id)
53 || (i.service_id == 0xFFFF && i.instance_id == 0xFFFF)) {
54 continue;
55 }
56 app_->request_service(i.service_id, i.instance_id);
57 app_->register_availability_handler(i.service_id, i.instance_id,
58 std::bind(&client_id_test_service::on_availability, this,
59 std::placeholders::_1, std::placeholders::_2,
60 std::placeholders::_3));
61
62 other_services_available_[std::make_pair(i.service_id, i.instance_id)] = false;
63 other_services_received_response_[std::make_pair(i.service_id, i.method_id)] = 0;
64 other_services_received_request_[i.offering_client] = 0;
65 }
66
67 app_->start();
68 }
69
~client_id_test_service()70 ~client_id_test_service() {
71 if (offer_thread_.joinable()) {
72 offer_thread_.join();
73 }
74 if (stop_thread_.joinable()) {
75 stop_thread_.join();
76 }
77 }
78
offer()79 void offer() {
80 app_->offer_service(service_info_.service_id, service_info_.instance_id);
81 }
82
stop_offer()83 void stop_offer() {
84 app_->stop_offer_service(service_info_.service_id, service_info_.instance_id);
85 }
86
on_state(vsomeip::state_type_e _state)87 void on_state(vsomeip::state_type_e _state) {
88 VSOMEIP_INFO << "Application " << app_->get_name() << " is "
89 << (_state == vsomeip::state_type_e::ST_REGISTERED ?
90 "registered." : "deregistered.");
91
92 if (_state == vsomeip::state_type_e::ST_REGISTERED) {
93 std::lock_guard<std::mutex> its_lock(mutex_);
94 blocked_ = true;
95 condition_.notify_one();
96 }
97 }
98
on_availability(vsomeip::service_t _service,vsomeip::instance_t _instance,bool _is_available)99 void on_availability(vsomeip::service_t _service,
100 vsomeip::instance_t _instance, bool _is_available) {
101 if(_is_available) {
102 VSOMEIP_INFO
103 << "[" << std::setw(4) << std::setfill('0') << std::hex
104 << service_info_.service_id << "] Service ["
105 << std::setw(4) << std::setfill('0') << std::hex << _service << "." << _instance
106 << "] is "
107 << (_is_available ? "available." : "NOT available.");
108
109 auto its_service = other_services_available_.find(std::make_pair(_service, _instance));
110 if(its_service != other_services_available_.end()) {
111 its_service->second = true;
112 }
113
114 if(std::all_of(other_services_available_.cbegin(),
115 other_services_available_.cend(),
116 [](const std::map<std::pair<vsomeip::service_t,
117 vsomeip::instance_t>, bool>::value_type& v) {
118 return v.second;})) {
119 std::lock_guard<std::mutex> its_lock(mutex_);
120 blocked_ = true;
121 condition_.notify_one();
122 }
123 }
124 }
125
on_request(const std::shared_ptr<vsomeip::message> & _message)126 void on_request(const std::shared_ptr<vsomeip::message> &_message) {
127 if(_message->get_message_type() == vsomeip::message_type_e::MT_REQUEST) {
128 VSOMEIP_DEBUG
129 << "[" << std::setw(4) << std::setfill('0') << std::hex
130 << service_info_.service_id
131 << "] Received a request with Client/Session [" << std::setw(4)
132 << std::setfill('0') << std::hex << _message->get_client() << "/"
133 << std::setw(4) << std::setfill('0') << std::hex
134 << _message->get_session() << "]";
135 std::shared_ptr<vsomeip::message> its_response = vsomeip::runtime::get()
136 ->create_response(_message);
137 app_->send(its_response);
138
139 other_services_received_request_[_message->get_client()]++;
140 if(all_responses_and_requests_received()) {
141 std::lock_guard<std::mutex> its_lock(stop_mutex_);
142 stopped_ = true;
143 stop_condition_.notify_one();
144 }
145 }
146 }
147
on_response(const std::shared_ptr<vsomeip::message> & _message)148 void on_response(const std::shared_ptr<vsomeip::message> &_message) {
149 if(_message->get_message_type() == vsomeip::message_type_e::MT_RESPONSE) {
150 VSOMEIP_DEBUG
151 << "[" << std::setw(4) << std::setfill('0') << std::hex
152 << service_info_.service_id
153 << "] Received a response with Client/Session [" << std::setw(4)
154 << std::setfill('0') << std::hex << _message->get_client() << "/"
155 << std::setw(4) << std::setfill('0') << std::hex
156 << _message->get_session() << "] from Service/Method ["
157 << std::setw(4) << std::setfill('0') << std::hex
158 << _message->get_service() << "/" << std::setw(4) << std::setfill('0')
159 << std::hex << _message->get_method() <<"]";
160 other_services_received_response_[std::make_pair(_message->get_service(),
161 _message->get_method())]++;
162
163 if(all_responses_and_requests_received()) {
164 std::lock_guard<std::mutex> its_lock(stop_mutex_);
165 stopped_ = true;
166 stop_condition_.notify_one();
167 }
168 }
169 }
170
all_responses_and_requests_received()171 bool all_responses_and_requests_received() {
172 const bool responses = std::all_of(
173 other_services_received_response_.cbegin(),
174 other_services_received_response_.cend(),
175 [](const std::map<std::pair<vsomeip::service_t,
176 vsomeip::method_t>, std::uint32_t>::value_type& v)
177 { return v.second == client_id_test::messages_to_send;});
178 const bool requests = std::all_of(
179 other_services_received_request_.cbegin(),
180 other_services_received_request_.cend(),
181 [](const std::map<vsomeip::client_t, std::uint32_t>::value_type& v)
182 { return v.second == client_id_test::messages_to_send;});
183 return (responses && requests);
184 }
185
run()186 void run() {
187 std::unique_lock<std::mutex> its_lock(mutex_);
188 while (!blocked_) {
189 condition_.wait(its_lock);
190 }
191 blocked_ = false;
192
193 VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex
194 << service_info_.service_id << "] Offering";
195 offer();
196
197
198 while (!blocked_) {
199 condition_.wait(its_lock);
200 }
201 blocked_ = false;
202
203 VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex
204 << service_info_.service_id << "] Sending";
205 // send a message to all other services
206 for (int var = 0; var < client_id_test::messages_to_send; ++var) {
207 for(const client_id_test::service_info& i: client_id_test::service_infos) {
208 if ((i.service_id == service_info_.service_id
209 && i.instance_id == service_info_.instance_id)
210 || (i.service_id == 0xFFFF && i.instance_id == 0xFFFF)) {
211 continue;
212 }
213 std::shared_ptr<vsomeip::message> msg = vsomeip::runtime::get()->create_request();
214 msg->set_service(i.service_id);
215 msg->set_instance(i.instance_id);
216 msg->set_method(i.method_id);
217 app_->send(msg);
218 VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0')
219 << std::hex << service_info_.service_id
220 << "] Sending a request to Service/Method ["
221 << std::setw(4) << std::setfill('0') << std::hex
222 << i.service_id << "/" << std::setw(4) << std::setfill('0')
223 << std::hex << i.instance_id <<"]";
224 }
225 }
226
227 while (!blocked_) {
228 condition_.wait(its_lock);
229 }
230 blocked_ = false;
231 }
232
wait_for_stop()233 void wait_for_stop() {
234 std::unique_lock<std::mutex> its_lock(stop_mutex_);
235 while (!stopped_) {
236 stop_condition_.wait(its_lock);
237 }
238 VSOMEIP_INFO << "[" << std::setw(4) << std::setfill('0') << std::hex
239 << service_info_.service_id
240 << "] Received responses and requests from all other services, going down";
241
242 // let offer thread exit
243 {
244 std::lock_guard<std::mutex> its_lock(mutex_);
245 blocked_ = true;
246 condition_.notify_one();
247 }
248
249 std::this_thread::sleep_for(std::chrono::seconds(3));
250 app_->clear_all_handler();
251 app_->stop();
252 }
253
254 private:
255 client_id_test::service_info service_info_;
256 std::shared_ptr<vsomeip::application> app_;
257 std::map<std::pair<vsomeip::service_t, vsomeip::instance_t>, bool> other_services_available_;
258 std::map<std::pair<vsomeip::service_t, vsomeip::method_t>, std::uint32_t> other_services_received_response_;
259 std::map<vsomeip::client_t, std::uint32_t> other_services_received_request_;
260
261 bool blocked_;
262 std::mutex mutex_;
263 std::condition_variable condition_;
264 std::thread offer_thread_;
265
266 bool stopped_;
267 std::mutex stop_mutex_;
268 std::condition_variable stop_condition_;
269 std::thread stop_thread_;
270 };
271
272 static int service_number;
273
TEST(someip_client_id_test,send_ten_messages_to_service)274 TEST(someip_client_id_test, send_ten_messages_to_service)
275 {
276 client_id_test_service its_sample(
277 client_id_test::service_infos[static_cast<size_t>(service_number)]);
278 }
279
280 #ifndef _WIN32
main(int argc,char ** argv)281 int main(int argc, char** argv)
282 {
283 ::testing::InitGoogleTest(&argc, argv);
284 if(argc < 2) {
285 std::cerr << "Please specify a service number, like: " << argv[0] << " 2" << std::endl;
286 std::cerr << "Valid service numbers are in the range of [1,6]" << std::endl;
287 return 1;
288 }
289 service_number = std::stoi(std::string(argv[1]), nullptr);
290 return RUN_ALL_TESTS();
291 }
292 #endif
293