1 // Copyright (C) 2014-2019 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 <atomic>
15 #include <future>
16 #include <cstring>
17
18 #include <gtest/gtest.h>
19
20 #include <vsomeip/vsomeip.hpp>
21 #include <vsomeip/internal/logger.hpp>
22 #include "../../implementation/endpoints/include/tp.hpp"
23
24 #include "someip_tp_test_globals.hpp"
25
26 class someip_tp_test_service {
27 public:
someip_tp_test_service(struct someip_tp_test::service_info _service_info,someip_tp_test::test_mode_e _testmode)28 someip_tp_test_service(struct someip_tp_test::service_info _service_info, someip_tp_test::test_mode_e _testmode) :
29 service_info_(_service_info),
30 testmode_(_testmode),
31 app_(vsomeip::runtime::get()->create_application("someip_tp_test_service")),
32 wait_until_registered_(true),
33 wait_until_shutdown_method_called_(true),
34 wait_for_slave_subscription_(true),
35 number_notifications_of_slave_(0x0),
36 wait_for_slave_service_available_(true),
37 wait_for_two_responses_of_slave_(true),
38 number_responses_of_slave_(0),
39 wait_for_two_requests_of_slave_(true),
40 number_requests_from_slave_(0),
41 wait_for_two_notifications_of_slave_(true),
42 offer_thread_(std::bind(&someip_tp_test_service::run, this)) {
43 if (!app_->init()) {
44 ADD_FAILURE() << "Couldn't initialize application";
45 return;
46 }
47 app_->register_state_handler(
48 std::bind(&someip_tp_test_service::on_state, this,
49 std::placeholders::_1));
50
51 // offer field
52 std::set<vsomeip::eventgroup_t> its_eventgroups;
53 its_eventgroups.insert(_service_info.eventgroup_id);
54 app_->offer_event(service_info_.service_id, service_info_.instance_id,
55 service_info_.event_id, its_eventgroups,
56 vsomeip::event_type_e::ET_EVENT, std::chrono::milliseconds::zero(),
57 false, true, nullptr, vsomeip::reliability_type_e::RT_UNRELIABLE);
58
59 app_->register_message_handler(vsomeip::ANY_SERVICE,
60 vsomeip::ANY_INSTANCE, service_info_.shutdown_method_id,
61 std::bind(&someip_tp_test_service::on_shutdown_method_called, this,
62 std::placeholders::_1));
63
64 app_->register_message_handler(vsomeip::ANY_SERVICE,
65 vsomeip::ANY_INSTANCE, service_info_.notify_method_id,
66 std::bind(&someip_tp_test_service::on_notify_method_called, this,
67 std::placeholders::_1));
68 app_->register_message_handler(vsomeip::ANY_SERVICE,
69 vsomeip::ANY_INSTANCE, service_info_.method_id,
70 std::bind(&someip_tp_test_service::on_message, this,
71 std::placeholders::_1));
72
73 app_->register_async_subscription_handler(service_info_.service_id,
74 0x1, service_info_.eventgroup_id,
75 std::bind(&someip_tp_test_service::subscription_handler_async,
76 this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3,
77 std::placeholders::_4, std::placeholders::_5));
78
79 // request remote service
80 app_->request_service(someip_tp_test::service_slave.service_id,
81 someip_tp_test::service_slave.instance_id);
82 its_eventgroups.clear();
83 its_eventgroups.insert(someip_tp_test::service_slave.eventgroup_id);
84 app_->request_event(someip_tp_test::service_slave.service_id,
85 someip_tp_test::service_slave.instance_id,
86 someip_tp_test::service_slave.event_id, its_eventgroups,
87 vsomeip::event_type_e::ET_EVENT,
88 vsomeip::reliability_type_e::RT_UNRELIABLE);
89 app_->register_message_handler(someip_tp_test::service_slave.service_id,
90 someip_tp_test::service_slave.instance_id,
91 someip_tp_test::service_slave.event_id,
92 std::bind(&someip_tp_test_service::on_notification, this,
93 std::placeholders::_1));
94 app_->subscribe(someip_tp_test::service_slave.service_id,
95 someip_tp_test::service_slave.instance_id,
96 someip_tp_test::service_slave.eventgroup_id, 0x0,
97 someip_tp_test::service_slave.event_id);
98 app_->register_availability_handler(someip_tp_test::service_slave.service_id,
99 someip_tp_test::service_slave.instance_id,
100 std::bind(&someip_tp_test_service::on_availability, this,
101 std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
102 app_->register_message_handler(
103 someip_tp_test::service_slave.service_id,
104 someip_tp_test::service_slave.instance_id,
105 someip_tp_test::service_slave.method_id,
106 std::bind(&someip_tp_test_service::on_response_from_slave, this,
107 std::placeholders::_1));
108 app_->start();
109 }
110
~someip_tp_test_service()111 ~someip_tp_test_service() {
112 offer_thread_.join();
113 }
114
offer()115 void offer() {
116 app_->offer_service(service_info_.service_id, 0x1);
117 }
118
stop()119 void stop() {
120 app_->stop_offer_service(service_info_.service_id, service_info_.instance_id);
121 app_->clear_all_handler();
122 app_->stop();
123 }
124
on_state(vsomeip::state_type_e _state)125 void on_state(vsomeip::state_type_e _state) {
126 VSOMEIP_INFO << "Application " << app_->get_name() << " is "
127 << (_state == vsomeip::state_type_e::ST_REGISTERED ?
128 "registered." : "deregistered.");
129
130 if (_state == vsomeip::state_type_e::ST_REGISTERED) {
131 std::lock_guard<std::mutex> its_lock(mutex_);
132 wait_until_registered_ = false;
133 condition_.notify_one();
134 }
135 }
136
on_availability(vsomeip::service_t _service,vsomeip::instance_t _instance,bool _available)137 void on_availability(vsomeip::service_t _service, vsomeip::instance_t _instance, bool _available) {
138 if (_service == someip_tp_test::service_slave.service_id &&
139 _instance == someip_tp_test::service_slave.instance_id &&
140 _available) {
141 std::lock_guard<std::mutex> its_lock(mutex_);
142 wait_for_slave_service_available_ = false;
143 condition_.notify_one();
144 VSOMEIP_INFO << "Service available Service/Instance ["
145 << std::setw(4) << std::setfill('0') << std::hex << _service << "/"
146 << std::setw(4) << std::setfill('0') << std::hex << _instance << "]";
147 }
148 }
149
on_message(const std::shared_ptr<vsomeip::message> & _message)150 void on_message(const std::shared_ptr<vsomeip::message>& _message) {
151 VSOMEIP_INFO << "Received a message with Client/Session ["
152 << std::setw(4) << std::setfill('0') << std::hex << _message->get_client() << "/"
153 << std::setw(4) << std::setfill('0') << std::hex << _message->get_session()
154 << "] size: " << std::dec << _message->get_payload()->get_length();
155 auto response = vsomeip::runtime::get()->create_response(_message);
156 auto payload = vsomeip::runtime::get()->create_payload(_message->get_payload()->get_data(), _message->get_payload()->get_length());
157 response->set_payload(payload);
158 app_->send(response);
159 if (++number_requests_from_slave_ == 2) {
160 std::lock_guard<std::mutex> its_lock(mutex_);
161 wait_for_two_requests_of_slave_ = false;
162 condition_.notify_one();
163 }
164 }
165
on_notification(const std::shared_ptr<vsomeip::message> & _message)166 void on_notification(const std::shared_ptr<vsomeip::message>& _message) {
167 VSOMEIP_INFO << "Received a notification with Client/Session ["
168 << std::setw(4) << std::setfill('0') << std::hex << _message->get_client() << "/"
169 << std::setw(4) << std::setfill('0') << std::hex << _message->get_session()
170 << "] size: " << std::dec << _message->get_payload()->get_length();
171 EXPECT_EQ(someip_tp_test::service_slave.service_id, _message->get_service());
172 EXPECT_EQ(someip_tp_test::service_slave.event_id, _message->get_method());
173 std::vector<vsomeip::byte_t> its_cmp_data =
174 generate_payload(someip_tp_test::number_of_fragments,
175 (testmode_ == someip_tp_test::test_mode_e::OVERLAP
176 || testmode_ == someip_tp_test::test_mode_e::OVERLAP_FRONT_BACK) ?
177 someip_tp_test::max_segment_size - 160 :
178 someip_tp_test::max_segment_size);
179
180 std::vector<vsomeip::byte_t> its_rcv_data(_message->get_payload()->get_data(),
181 _message->get_payload()->get_data() + _message->get_payload()->get_length());
182 EXPECT_EQ(its_cmp_data.size(), its_rcv_data.size());
183 if (testmode_ == someip_tp_test::test_mode_e::OVERLAP) {
184 if (number_notifications_of_slave_ == 0) { //ASCENDING with 2nd segment too big
185 for (std::uint32_t i = 0; i < 16; i++) {
186 its_cmp_data[2 * (someip_tp_test::max_segment_size - 160) + i] = 0xff;
187 }
188 } else if (number_notifications_of_slave_ == 1) {
189 // DESCENDING with 2nd last segment too big
190 // no action as successive 4 byte at end of message would
191 // overwrite the beginning of the last segment which was received first
192 }
193 }
194 EXPECT_EQ(its_cmp_data, its_rcv_data);
195 EXPECT_EQ(0, std::memcmp(static_cast<void*>(&its_cmp_data[0]),
196 static_cast<void*>(&its_rcv_data[0]),
197 its_cmp_data.size()));
198 if (++number_notifications_of_slave_ == 2) {
199 std::lock_guard<std::mutex> its_lock(mutex_);
200 wait_for_two_notifications_of_slave_ = false;
201 condition_.notify_one();
202 }
203 }
204
on_shutdown_method_called(const std::shared_ptr<vsomeip::message> & _message)205 void on_shutdown_method_called(const std::shared_ptr<vsomeip::message> &_message) {
206 app_->send(vsomeip::runtime::get()->create_response(_message));
207 VSOMEIP_WARNING << "************************************************************";
208 VSOMEIP_WARNING << "Shutdown method called -> going down!";
209 VSOMEIP_WARNING << "************************************************************";
210 std::lock_guard<std::mutex> its_lock(mutex_);
211 wait_until_shutdown_method_called_ = false;
212 condition_.notify_one();
213 }
214
on_notify_method_called(const std::shared_ptr<vsomeip::message> & _message)215 void on_notify_method_called(const std::shared_ptr<vsomeip::message> &_message) {
216 (void)_message;
217 std::vector<vsomeip::byte_t> its_data = generate_payload(someip_tp_test::number_of_fragments,
218 (testmode_ == someip_tp_test::test_mode_e::OVERLAP) ?
219 someip_tp_test::max_segment_size - 160 :
220 someip_tp_test::max_segment_size);
221 std::shared_ptr<vsomeip::payload> its_payload = vsomeip::runtime::get()->create_payload();
222 its_payload->set_data(its_data);
223 app_->notify(service_info_.service_id, service_info_.instance_id,
224 service_info_.event_id, its_payload);
225 VSOMEIP_INFO << __func__ << " send event";
226 notify_method_called_.set_value(true);
227 }
228
send_fragmented_request_to_slave()229 void send_fragmented_request_to_slave() {
230 auto its_req = vsomeip::runtime::get()->create_request();
231 its_req->set_service(someip_tp_test::service_slave.service_id);
232 its_req->set_instance(someip_tp_test::service_slave.instance_id);
233 its_req->set_method(someip_tp_test::service_slave.method_id);
234 std::vector<vsomeip::byte_t> its_data = generate_payload(someip_tp_test::number_of_fragments,
235 (testmode_ == someip_tp_test::test_mode_e::OVERLAP
236 || testmode_ == someip_tp_test::test_mode_e::OVERLAP_FRONT_BACK) ?
237 someip_tp_test::max_segment_size - 160 :
238 someip_tp_test::max_segment_size);
239 auto its_payload = vsomeip::runtime::get()->create_payload();
240 its_payload->set_data(its_data);
241 its_req->set_payload(its_payload);
242 request_send_to_slave_ = its_req;
243 app_->send(its_req);
244 }
245
on_response_from_slave(const std::shared_ptr<vsomeip::message> & _message)246 void on_response_from_slave(const std::shared_ptr<vsomeip::message> &_message) {
247 VSOMEIP_INFO << "Received a response from the slave with Client/Session ["
248 << std::setw(4) << std::setfill('0') << std::hex << _message->get_client() << "/"
249 << std::setw(4) << std::setfill('0') << std::hex << _message->get_session()
250 << "] size: " << std::dec << _message->get_payload()->get_length();
251 EXPECT_EQ(someip_tp_test::service_slave.service_id, _message->get_service());
252 EXPECT_EQ(someip_tp_test::service_slave.instance_id, _message->get_instance());
253 EXPECT_EQ(someip_tp_test::service_slave.method_id, _message->get_method());
254 std::vector<vsomeip::byte_t> its_resp_payload(_message->get_payload()->get_data(),
255 _message->get_payload()->get_data() + _message->get_payload()->get_length());
256 std::vector<vsomeip::byte_t> its_req_payload(request_send_to_slave_->get_payload()->get_data(),
257 request_send_to_slave_->get_payload()->get_data() + request_send_to_slave_->get_payload()->get_length());
258 if (testmode_ == someip_tp_test::test_mode_e::OVERLAP) {
259 if (number_responses_of_slave_ == 0) { //ASCENDING with 2nd segment too big
260 for (std::uint32_t i = 0; i < 16; i++) {
261 its_req_payload[2 * (someip_tp_test::max_segment_size - 160) + i] = 0xff;
262 }
263 } else if (number_responses_of_slave_ == 1) {
264 // DESCENDING with 2nd last segment too big
265 // no action as successive 4 byte at end of message would
266 // overwrite the beginning of the last segment which was received first
267 }
268 }
269
270 EXPECT_EQ(its_req_payload.size(), its_resp_payload.size());
271 EXPECT_EQ(its_req_payload, its_resp_payload);
272 EXPECT_EQ(0, std::memcmp(static_cast<void*>(&its_req_payload[0]),
273 static_cast<void*>(&its_resp_payload[0]),
274 its_req_payload.size()));
275
276 if (++number_responses_of_slave_ < 2) {
277 send_fragmented_request_to_slave();
278 } else {
279 std::lock_guard<std::mutex> its_lock(mutex_);
280 wait_for_two_responses_of_slave_ = false;
281 condition_.notify_one();
282 }
283 }
284
generate_payload(std::uint32_t _number_of_fragments,std::uint32_t _segment_size)285 std::vector<vsomeip::byte_t> generate_payload(std::uint32_t _number_of_fragments,
286 std::uint32_t _segment_size) {
287 std::vector<vsomeip::byte_t> its_data;
288 for (std::uint32_t i = 0; i < _number_of_fragments; i++) {
289 its_data.resize((i * _segment_size) + _segment_size,
290 static_cast<std::uint8_t>(i));
291 }
292 return its_data;
293 }
294
run()295 void run() {
296 VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex
297 << service_info_.service_id << "] Running";
298 std::unique_lock<std::mutex> its_lock(mutex_);
299 while (wait_until_registered_) {
300 condition_.wait(its_lock);
301 }
302
303 VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex
304 << service_info_.service_id << "] Offering";
305 offer();
306
307 while (wait_for_slave_service_available_) {
308 condition_.wait(its_lock);
309 }
310 send_fragmented_request_to_slave();
311
312 while (wait_for_two_responses_of_slave_) {
313 condition_.wait(its_lock);
314 }
315 EXPECT_EQ(2u, number_responses_of_slave_);
316
317 while (wait_for_two_requests_of_slave_) {
318 condition_.wait(its_lock);
319 }
320 EXPECT_EQ(2u, number_requests_from_slave_);
321
322 while (wait_for_two_notifications_of_slave_) {
323 condition_.wait(its_lock);
324 }
325 EXPECT_EQ(2u, number_notifications_of_slave_);
326
327 while (wait_for_slave_subscription_) {
328 condition_.wait(its_lock);
329 }
330 // slave subscribed --> sent a notification
331 on_notify_method_called(vsomeip::runtime::get()->create_message());
332
333 while (wait_until_shutdown_method_called_) {
334 condition_.wait(its_lock);
335 }
336 stop();
337 }
338
subscription_handler_async(vsomeip::client_t _client,std::uint32_t _uid,std::uint32_t _gid,bool _subscribed,const std::function<void (const bool)> & _cbk)339 void subscription_handler_async(vsomeip::client_t _client, std::uint32_t _uid, std::uint32_t _gid,
340 bool _subscribed, const std::function<void(const bool)>& _cbk) {
341 (void)_uid;
342 (void)_gid;
343 VSOMEIP_WARNING << __func__ << " " << std::hex << _client << " subscribed." << _subscribed;
344 static int was_called = 0;
345 was_called++;
346 EXPECT_EQ(1, was_called);
347 EXPECT_TRUE(_subscribed);
348 _cbk(true);
349 std::lock_guard<std::mutex> its_lock(mutex_);
350 wait_for_slave_subscription_ = false;
351 condition_.notify_one();
352 }
353
354
355 private:
356 struct someip_tp_test::service_info service_info_;
357 someip_tp_test::test_mode_e testmode_;
358 std::shared_ptr<vsomeip::application> app_;
359
360 bool wait_until_registered_;
361 bool wait_until_shutdown_method_called_;
362 std::mutex mutex_;
363 std::condition_variable condition_;
364 std::atomic<bool> wait_for_slave_subscription_;
365 std::atomic<std::uint32_t> number_notifications_of_slave_;
366 std::promise<bool> notify_method_called_;
367 bool wait_for_slave_service_available_;
368 bool wait_for_two_responses_of_slave_;
369 std::uint32_t number_responses_of_slave_;
370 bool wait_for_two_requests_of_slave_;
371 std::uint32_t number_requests_from_slave_;
372 bool wait_for_two_notifications_of_slave_;
373 std::shared_ptr<vsomeip::message> request_send_to_slave_;
374 std::thread offer_thread_;
375 };
376
377 someip_tp_test::test_mode_e its_testmode(someip_tp_test::test_mode_e::IN_SEQUENCE);
378
TEST(someip_someip_tp_test,echo_requests)379 TEST(someip_someip_tp_test, echo_requests)
380 {
381 someip_tp_test_service its_sample(someip_tp_test::service, its_testmode);
382 }
383
384
385 #ifndef _WIN32
main(int argc,char ** argv)386 int main(int argc, char** argv)
387 {
388 ::testing::InitGoogleTest(&argc, argv);
389 if (argc < 2) {
390 std::cerr << "Please pass a test mode to this binary like: "
391 << argv[0] << " IN_SEQUENCE" << std::endl;
392 std::cerr << "Testmodes are [ IN_SEQUENCE, MIXED, INCOMPLETE, DUPLICATE, OVERLAP, OVERLAP_FRONT_BACK ]" << std::endl;
393 exit(1);
394 }
395
396 std::string its_pased_testmode = argv[1];
397 if (its_pased_testmode == std::string("IN_SEQUENCE")) {
398 its_testmode = someip_tp_test::test_mode_e::IN_SEQUENCE;
399 } else if (its_pased_testmode == std::string("MIXED")) {
400 its_testmode = someip_tp_test::test_mode_e::MIXED;
401 } else if (its_pased_testmode == std::string("INCOMPLETE")) {
402 its_testmode = someip_tp_test::test_mode_e::INCOMPLETE;
403 } else if (its_pased_testmode == std::string("DUPLICATE")) {
404 its_testmode = someip_tp_test::test_mode_e::DUPLICATE;
405 } else if (its_pased_testmode == std::string("OVERLAP")) {
406 its_testmode = someip_tp_test::test_mode_e::OVERLAP;
407 } else if (its_pased_testmode == std::string("OVERLAP_FRONT_BACK")) {
408 its_testmode = someip_tp_test::test_mode_e::OVERLAP_FRONT_BACK;
409 }
410
411 return RUN_ALL_TESTS();
412 }
413 #endif
414