• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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