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 <atomic>
15 #include <future>
16
17 #include <gtest/gtest.h>
18
19 #include <vsomeip/vsomeip.hpp>
20 #include <vsomeip/internal/logger.hpp>
21
22 #include "pending_subscription_test_globals.hpp"
23
24 class pending_subscription_test_service {
25 public:
pending_subscription_test_service(struct pending_subscription_test::service_info _service_info,pending_subscription_test::test_mode_e _testmode)26 pending_subscription_test_service(struct pending_subscription_test::service_info _service_info, pending_subscription_test::test_mode_e _testmode) :
27 service_info_(_service_info),
28 testmode_(_testmode),
29 app_(vsomeip::runtime::get()->create_application("pending_subscription_test_service")),
30 wait_until_registered_(true),
31 wait_until_shutdown_method_called_(true),
32 subscription_accepted_asynchronous_(false),
33 subscription_accepted_synchronous_(false),
34 offer_thread_(std::bind(&pending_subscription_test_service::run, this)) {
35 if (!app_->init()) {
36 ADD_FAILURE() << "Couldn't initialize application";
37 return;
38 }
39 app_->register_state_handler(
40 std::bind(&pending_subscription_test_service::on_state, this,
41 std::placeholders::_1));
42
43 // offer field
44 std::set<vsomeip::eventgroup_t> its_eventgroups;
45 its_eventgroups.insert(_service_info.eventgroup_id);
46 app_->offer_event(service_info_.service_id, 0x1,
47 service_info_.event_id,
48 its_eventgroups, vsomeip::event_type_e::ET_FIELD,
49 std::chrono::milliseconds::zero(),
50 false, true, nullptr, vsomeip::reliability_type_e::RT_UNRELIABLE);
51
52 its_eventgroups.clear();
53 its_eventgroups.insert(static_cast<vsomeip::eventgroup_t>(_service_info.eventgroup_id+1u));
54
55 app_->offer_event(service_info_.service_id, 0x1,
56 static_cast<vsomeip::event_t>(service_info_.event_id+1u),
57 its_eventgroups, vsomeip::event_type_e::ET_FIELD,
58 std::chrono::milliseconds::zero(),
59 false, true, nullptr, vsomeip::reliability_type_e::RT_UNRELIABLE);
60
61 app_->register_message_handler(vsomeip::ANY_SERVICE,
62 vsomeip::ANY_INSTANCE, service_info_.shutdown_method_id,
63 std::bind(&pending_subscription_test_service::on_shutdown_method_called, this,
64 std::placeholders::_1));
65
66 app_->register_message_handler(vsomeip::ANY_SERVICE,
67 vsomeip::ANY_INSTANCE, service_info_.notify_method_id,
68 std::bind(&pending_subscription_test_service::on_notify_method_called, this,
69 std::placeholders::_1));
70
71 app_->register_async_subscription_handler(service_info_.service_id,
72 0x1, service_info_.eventgroup_id,
73 std::bind(&pending_subscription_test_service::subscription_handler_async,
74 this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3,
75 std::placeholders::_4, std::placeholders::_5));
76 app_->register_subscription_handler(service_info_.service_id,
77 0x1, static_cast<vsomeip::eventgroup_t>(service_info_.eventgroup_id+1u),
78 std::bind(&pending_subscription_test_service::subscription_handler,
79 this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3,
80 std::placeholders::_4));
81 app_->start();
82 }
83
~pending_subscription_test_service()84 ~pending_subscription_test_service() {
85 offer_thread_.join();
86 }
87
offer()88 void offer() {
89 app_->offer_service(service_info_.service_id, 0x1);
90 }
91
stop()92 void stop() {
93 app_->stop_offer_service(service_info_.service_id, 0x1);
94 app_->clear_all_handler();
95 app_->stop();
96 }
97
on_state(vsomeip::state_type_e _state)98 void on_state(vsomeip::state_type_e _state) {
99 VSOMEIP_INFO << "Application " << app_->get_name() << " is "
100 << (_state == vsomeip::state_type_e::ST_REGISTERED ?
101 "registered." : "deregistered.");
102
103 if (_state == vsomeip::state_type_e::ST_REGISTERED) {
104 std::lock_guard<std::mutex> its_lock(mutex_);
105 wait_until_registered_ = false;
106 condition_.notify_one();
107 }
108 }
109
on_shutdown_method_called(const std::shared_ptr<vsomeip::message> & _message)110 void on_shutdown_method_called(const std::shared_ptr<vsomeip::message> &_message) {
111 app_->send(vsomeip::runtime::get()->create_response(_message));
112 VSOMEIP_WARNING << "************************************************************";
113 VSOMEIP_WARNING << "Shutdown method called -> going down!";
114 VSOMEIP_WARNING << "************************************************************";
115 std::lock_guard<std::mutex> its_lock(mutex_);
116 wait_until_shutdown_method_called_ = false;
117 condition_.notify_one();
118 }
119
on_notify_method_called(const std::shared_ptr<vsomeip::message> & _message)120 void on_notify_method_called(const std::shared_ptr<vsomeip::message> &_message) {
121 (void)_message;
122 std::shared_ptr<vsomeip::payload> its_payload = vsomeip::runtime::get()->create_payload();
123 its_payload->set_data( {0xDD});
124 app_->notify(service_info_.service_id, service_info_.instance_id,
125 service_info_.event_id, its_payload);
126 app_->notify(service_info_.service_id, service_info_.instance_id,
127 static_cast<vsomeip::event_t>(service_info_.event_id + 1u) , its_payload);
128 notify_method_called_.set_value(true);
129 }
130
run()131 void run() {
132 VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex
133 << service_info_.service_id << "] Running";
134 std::unique_lock<std::mutex> its_lock(mutex_);
135 while (wait_until_registered_) {
136 condition_.wait(its_lock);
137 }
138
139 VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex
140 << service_info_.service_id << "] Offering";
141 offer();
142
143 if (testmode_ == pending_subscription_test::test_mode_e::REQUEST_TO_SD) {
144 // this testcase won't send valid subscriptions -> ensure to exit
145 subscription_accepted_asynchronous_ = true;
146 subscription_accepted_synchronous_ = true;
147 }
148
149 while (!subscription_accepted_asynchronous_ || !subscription_accepted_synchronous_) {
150 std::this_thread::sleep_for(std::chrono::milliseconds(100));
151 }
152 switch (testmode_) {
153 case pending_subscription_test::test_mode_e::SUBSCRIBE:
154 async_subscription_handler_(true);
155 break;
156 case pending_subscription_test::test_mode_e::SUBSCRIBE_UNSUBSCRIBE:
157 case pending_subscription_test::test_mode_e::UNSUBSCRIBE:
158 case pending_subscription_test::test_mode_e::SUBSCRIBE_UNSUBSCRIBE_NACK:
159 case pending_subscription_test::test_mode_e::SUBSCRIBE_UNSUBSCRIBE_SAME_PORT:
160 case pending_subscription_test::test_mode_e::SUBSCRIBE_RESUBSCRIBE_MIXED:
161 case pending_subscription_test::test_mode_e::SUBSCRIBE_STOPSUBSCRIBE_SUBSCRIBE:
162 case pending_subscription_test::test_mode_e::REQUEST_TO_SD:
163 default:
164 break;
165 }
166
167 std::future<bool> itsFuture = notify_method_called_.get_future();
168 if (std::future_status::timeout == itsFuture.wait_for(std::chrono::seconds(30))) {
169 ADD_FAILURE() << "notify method wasn't called within time!";
170 } else {
171 EXPECT_TRUE(itsFuture.get());
172 }
173 while (wait_until_shutdown_method_called_) {
174 condition_.wait(its_lock);
175 }
176 std::this_thread::sleep_for(std::chrono::milliseconds(2000));
177 stop();
178 }
179
subscription_handler_async(vsomeip::client_t _client,std::uint32_t _uid,std::uint32_t _gid,bool _subscribed,const std::function<void (const bool)> & _cbk)180 void subscription_handler_async(vsomeip::client_t _client, std::uint32_t _uid, std::uint32_t _gid,
181 bool _subscribed, const std::function<void(const bool)>& _cbk) {
182 (void)_uid;
183 (void)_gid;
184 VSOMEIP_WARNING << __func__ << " " << std::hex << _client << " subscribed." << _subscribed;
185 if (testmode_ == pending_subscription_test::test_mode_e::SUBSCRIBE) {
186 async_subscription_handler_ = _cbk;
187 static int was_called = 0;
188 was_called++;
189 EXPECT_EQ(1, was_called);
190 EXPECT_TRUE(_subscribed);
191 subscription_accepted_asynchronous_ = true;
192 } else if (testmode_ == pending_subscription_test::test_mode_e::SUBSCRIBE_UNSUBSCRIBE) {
193 static int count_subscribe = 0;
194 static int count_unsubscribe = 0;
195 _subscribed ? count_subscribe++ : count_unsubscribe++;
196 if (count_subscribe == 1) {
197 std::this_thread::sleep_for(std::chrono::milliseconds(500));
198 }
199 _cbk(true);
200 if (count_subscribe == 8 || count_unsubscribe == 7) {
201 subscription_accepted_asynchronous_ = true;
202 }
203 } else if (testmode_ == pending_subscription_test::test_mode_e::UNSUBSCRIBE) {
204 static int count_subscribe = 0;
205 static int count_unsubscribe = 0;
206 _subscribed ? count_subscribe++ : count_unsubscribe++;
207 if (count_subscribe == 1) {
208 std::this_thread::sleep_for(std::chrono::milliseconds(500));
209 }
210 _cbk(true);
211 if (count_subscribe == 2 || count_unsubscribe == 1) {
212 subscription_accepted_asynchronous_ = true;
213 }
214 } else if (testmode_ == pending_subscription_test::test_mode_e::SUBSCRIBE_UNSUBSCRIBE_NACK) {
215 static int count_subscribe = 0;
216 static int count_unsubscribe = 0;
217 _subscribed ? count_subscribe++ : count_unsubscribe++;
218 if (count_subscribe == 1) {
219 std::this_thread::sleep_for(std::chrono::milliseconds(500));
220 }
221 if (_subscribed) {
222 _cbk(((count_subscribe + 1) % 2)); // nack every second subscription
223 } else {
224 _cbk(true);
225 }
226 if (count_subscribe == 8 || count_unsubscribe == 7) {
227 subscription_accepted_asynchronous_ = true;
228 }
229 } else if (testmode_ == pending_subscription_test::test_mode_e::SUBSCRIBE_UNSUBSCRIBE_SAME_PORT) {
230 static int count_subscribe = 0;
231 static int count_unsubscribe = 0;
232 _subscribed ? count_subscribe++ : count_unsubscribe++;
233 if (count_subscribe == 1) {
234 std::this_thread::sleep_for(std::chrono::milliseconds(500));
235 }
236 _cbk(true);
237 if (count_subscribe == 8 || count_unsubscribe == 7) {
238 subscription_accepted_asynchronous_ = true;
239 }
240 } else if (testmode_ == pending_subscription_test::test_mode_e::SUBSCRIBE_RESUBSCRIBE_MIXED) {
241 static int was_called = 0;
242 was_called++;
243 EXPECT_EQ(1, was_called);
244 EXPECT_TRUE(_subscribed);
245 _cbk(true);
246 subscription_accepted_asynchronous_ = true;
247 } else if (testmode_ == pending_subscription_test::test_mode_e::SUBSCRIBE_STOPSUBSCRIBE_SUBSCRIBE) {
248 static int was_called = 0;
249 was_called++;
250 EXPECT_EQ(1, was_called);
251 EXPECT_TRUE(_subscribed);
252 subscription_accepted_asynchronous_ = true;
253 // this test doesn't subscribe to the second eventgroup which is handled by the asynchronous
254 // subscription handler, set it to true here:
255 subscription_accepted_synchronous_ = true;
256 _cbk(true);
257 }
258 }
259
subscription_handler(vsomeip::client_t _client,std::uint32_t _uid,std::uint32_t _gid,bool _subscribed)260 bool subscription_handler(vsomeip::client_t _client, std::uint32_t _uid, std::uint32_t _gid, bool _subscribed) {
261 (void)_subscribed;
262 (void)_uid;
263 (void)_gid;
264 bool ret(false);
265 VSOMEIP_WARNING << __func__ << " " << std::hex << _client << " subscribed. " << _subscribed;
266 if (testmode_ == pending_subscription_test::test_mode_e::SUBSCRIBE) {
267 static int was_called = 0;
268 was_called++;
269 EXPECT_EQ(1, was_called);
270 EXPECT_TRUE(_subscribed);
271 subscription_accepted_synchronous_ = true;
272 ret = true;
273 } else if (testmode_ == pending_subscription_test::test_mode_e::SUBSCRIBE_UNSUBSCRIBE) {
274 static int count_subscribed = 0;
275 static int count_unsubscribe = 0;
276 _subscribed ? count_subscribed++ : count_unsubscribe++;
277 if (count_subscribed == 1) {
278 std::this_thread::sleep_for(std::chrono::milliseconds(500));
279 }
280 if (count_subscribed == 8 && count_unsubscribe == 7) {
281 subscription_accepted_synchronous_ = true;
282 }
283 ret = true;
284 } else if (testmode_ == pending_subscription_test::test_mode_e::UNSUBSCRIBE) {
285 static int count_subscribed = 0;
286 static int count_unsubscribe = 0;
287 _subscribed ? count_subscribed++ : count_unsubscribe++;
288 if (count_subscribed == 1) {
289 std::this_thread::sleep_for(std::chrono::milliseconds(500));
290 }
291 if (count_subscribed == 2 && count_unsubscribe == 1) {
292 subscription_accepted_synchronous_ = true;
293 }
294 ret = true;
295 } else if (testmode_ == pending_subscription_test::test_mode_e::SUBSCRIBE_UNSUBSCRIBE_NACK) {
296 static int count_subscribed = 0;
297 static int count_unsubscribe = 0;
298 _subscribed ? count_subscribed++ : count_unsubscribe++;
299 if (count_subscribed == 1) {
300 std::this_thread::sleep_for(std::chrono::milliseconds(500));
301 }
302 if (count_subscribed == 8 && count_unsubscribe == 7) {
303 subscription_accepted_synchronous_ = true;
304 }
305 if (_subscribed) {
306 ret = ((count_subscribed + 1) % 2); // nack every second subscription
307 } else {
308 ret = true;
309 }
310 } else if (testmode_ == pending_subscription_test::test_mode_e::SUBSCRIBE_UNSUBSCRIBE_SAME_PORT) {
311 static int count_subscribed = 0;
312 static int count_unsubscribe = 0;
313 _subscribed ? count_subscribed++ : count_unsubscribe++;
314
315 if (count_subscribed == 1) {
316 std::this_thread::sleep_for(std::chrono::milliseconds(500));
317 }
318 if (count_subscribed == 8 && count_unsubscribe == 7) {
319 subscription_accepted_synchronous_ = true;
320 }
321 ret = true;
322 } else if (testmode_ == pending_subscription_test::test_mode_e::SUBSCRIBE_RESUBSCRIBE_MIXED) {
323 static int was_called = 0;
324 was_called++;
325 EXPECT_EQ(1, was_called);
326 EXPECT_TRUE(_subscribed);
327 subscription_accepted_synchronous_ = true;
328 ret = true;
329 }
330 return ret;
331 }
332
333 private:
334 struct pending_subscription_test::service_info service_info_;
335 pending_subscription_test::test_mode_e testmode_;
336 std::shared_ptr<vsomeip::application> app_;
337
338 bool wait_until_registered_;
339 bool wait_until_shutdown_method_called_;
340 std::mutex mutex_;
341 std::condition_variable condition_;
342 std::atomic<bool> subscription_accepted_asynchronous_;
343 std::atomic<bool> subscription_accepted_synchronous_;
344 std::thread offer_thread_;
345 std::function<void(const bool)> async_subscription_handler_;
346 std::promise<bool> notify_method_called_;
347 };
348
349 pending_subscription_test::test_mode_e its_testmode(pending_subscription_test::test_mode_e::SUBSCRIBE);
350
TEST(someip_pending_subscription_test,block_subscription_handler)351 TEST(someip_pending_subscription_test, block_subscription_handler)
352 {
353 pending_subscription_test_service its_sample(pending_subscription_test::service, its_testmode);
354 }
355
356
357 #ifndef _WIN32
main(int argc,char ** argv)358 int main(int argc, char** argv)
359 {
360 ::testing::InitGoogleTest(&argc, argv);
361 if (argc < 2) {
362 std::cerr << "Please pass a test mode to this binary like: "
363 << argv[0] << " SUBSCRIBE" << std::endl;
364 std::cerr << "Testmodes are [SUBSCRIBE, SUBSCRIBE_UNSUBSCRIBE, UNSUBSCRIBE, SUBSCRIBE_UNSUBSCRIBE_NACK, SUBSCRIBE_UNSUBSCRIBE_SAME_PORT]" << std::endl;
365 exit(1);
366 }
367
368 std::string its_pased_testmode = argv[1];
369 if (its_pased_testmode == std::string("SUBSCRIBE")) {
370 its_testmode = pending_subscription_test::test_mode_e::SUBSCRIBE;
371 } else if (its_pased_testmode == std::string("SUBSCRIBE_UNSUBSCRIBE")) {
372 its_testmode = pending_subscription_test::test_mode_e::SUBSCRIBE_UNSUBSCRIBE;
373 } else if (its_pased_testmode == std::string("UNSUBSCRIBE")) {
374 its_testmode = pending_subscription_test::test_mode_e::UNSUBSCRIBE;
375 } else if (its_pased_testmode == std::string("SUBSCRIBE_UNSUBSCRIBE_NACK")) {
376 its_testmode = pending_subscription_test::test_mode_e::SUBSCRIBE_UNSUBSCRIBE_NACK;
377 } else if (its_pased_testmode == std::string("SUBSCRIBE_UNSUBSCRIBE_SAME_PORT")) {
378 its_testmode = pending_subscription_test::test_mode_e::SUBSCRIBE_UNSUBSCRIBE_SAME_PORT;
379 } else if (its_pased_testmode == std::string("SUBSCRIBE_RESUBSCRIBE_MIXED")) {
380 its_testmode = pending_subscription_test::test_mode_e::SUBSCRIBE_RESUBSCRIBE_MIXED;
381 } else if (its_pased_testmode == std::string("SUBSCRIBE_STOPSUBSCRIBE_SUBSCRIBE")) {
382 its_testmode = pending_subscription_test::test_mode_e::SUBSCRIBE_STOPSUBSCRIBE_SUBSCRIBE;
383 } else if (its_pased_testmode == std::string("REQUEST_TO_SD")) {
384 its_testmode = pending_subscription_test::test_mode_e::REQUEST_TO_SD;
385 }
386
387 return RUN_ALL_TESTS();
388 }
389 #endif
390