1 // Copyright (C) 2015-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 <thread>
7 #include <mutex>
8 #include <condition_variable>
9 #include <future>
10
11 #include <gtest/gtest.h>
12
13 #include <vsomeip/vsomeip.hpp>
14
15 #include "someip_test_globals.hpp"
16
17 using namespace vsomeip;
18
19 class someip_application_test: public ::testing::Test {
20 public:
someip_application_test()21 someip_application_test() :
22 registered_(false) {
23
24 }
25 protected:
SetUp()26 void SetUp() {
27 app_ = runtime::get()->create_application("application_test");
28 if (!app_->init()) {
29 ADD_FAILURE() << "Couldn't initialize application";
30 return;
31 }
32
33 app_->register_state_handler(
34 std::bind(&someip_application_test::on_state, this,
35 std::placeholders::_1));
36 }
37
on_state(vsomeip::state_type_e _state)38 void on_state(vsomeip::state_type_e _state) {
39 registered_ = (_state == vsomeip::state_type_e::ST_REGISTERED);
40 }
41
42 bool registered_;
43 std::shared_ptr<application> app_;
44 };
45
46 /**
47 * @test Start and stop application
48 */
TEST_F(someip_application_test,start_stop_application)49 TEST_F(someip_application_test, start_stop_application)
50 {
51 std::promise<bool> its_promise;
52 std::thread t([&](){
53 its_promise.set_value(true);
54 app_->start();
55 });
56 EXPECT_TRUE(its_promise.get_future().get());
57 std::this_thread::sleep_for(std::chrono::milliseconds(100));
58 app_->stop();
59 t.join();
60 }
61
62 /**
63 * @test Start and stop application multiple times
64 */
TEST_F(someip_application_test,start_stop_application_multiple)65 TEST_F(someip_application_test, start_stop_application_multiple)
66 {
67 for (int i = 0; i < 10; ++i) {
68 std::promise<bool> its_promise;
69 std::thread t([&]() {
70 its_promise.set_value(true);
71 app_->start();
72 });
73 EXPECT_TRUE(its_promise.get_future().get());
74 std::this_thread::sleep_for(std::chrono::milliseconds(100));
75 app_->stop();
76 t.join();
77 }
78 }
79
80 /**
81 * @test Start and stop application multiple times and offer a service
82 */
TEST_F(someip_application_test,start_stop_application_multiple_offer_service)83 TEST_F(someip_application_test, start_stop_application_multiple_offer_service)
84 {
85 for (int i = 0; i < 10; ++i) {
86 std::promise<bool> its_promise;
87 std::thread t([&]() {
88 its_promise.set_value(true);
89 app_->start();
90 });
91 EXPECT_TRUE(its_promise.get_future().get());
92 std::this_thread::sleep_for(std::chrono::milliseconds(100));
93 app_->offer_service(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID);
94 std::this_thread::sleep_for(std::chrono::milliseconds(100));
95 app_->stop_offer_service(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID);
96 std::this_thread::sleep_for(std::chrono::milliseconds(100));
97 app_->stop();
98 t.join();
99 }
100 }
101
102 /**
103 * @test Try to start an already running application again
104 */
TEST_F(someip_application_test,restart_without_stopping)105 TEST_F(someip_application_test, restart_without_stopping)
106 {
107 std::promise<bool> its_promise;
108 std::thread t([&]() {
109 its_promise.set_value(true);
110 app_->start();
111
112 });
113 EXPECT_TRUE(its_promise.get_future().get());
114 std::this_thread::sleep_for(std::chrono::milliseconds(100));
115 VSOMEIP_WARNING << "An error message should appear now";
116 // should print error
117 app_->start();
118 app_->stop();
119 t.join();
120 }
121
122 /**
123 * @test Try to stop a running application twice
124 */
TEST_F(someip_application_test,stop_application_twice)125 TEST_F(someip_application_test, stop_application_twice)
126 {
127 std::promise<bool> its_promise;
128 std::thread t([&]() {
129 its_promise.set_value(true);
130 app_->start();
131
132 });
133 EXPECT_TRUE(its_promise.get_future().get());
134 std::this_thread::sleep_for(std::chrono::milliseconds(100));
135
136 app_->stop();
137 t.join();
138 app_->stop();
139 }
140
141 /**
142 * @test Checks whether watchdog handler is invoked (regularly) also after restarting.
143 */
TEST_F(someip_application_test,watchdog_handler)144 TEST_F(someip_application_test, watchdog_handler)
145 {
146 std::atomic<int> cb_count(0);
147 auto wd_handler = [&] () {
148 ++cb_count;
149 };
150
151 app_->set_watchdog_handler(std::cref(wd_handler), std::chrono::seconds(1));
152
153 std::promise<bool> its_promise;
154 std::thread t([&]() {
155 its_promise.set_value(true);
156 app_->start();
157 });
158 EXPECT_TRUE(its_promise.get_future().get());
159
160 // wait till watchdog handler has been invoked once
161 while (0 == cb_count.load()) {
162 std::this_thread::sleep_for(std::chrono::milliseconds(100));
163 }
164 ASSERT_EQ(1, cb_count.load());
165
166 // clear handler (must not be called again)
167 app_->set_watchdog_handler(nullptr, std::chrono::seconds::zero());
168
169 // wait doubled interval (used previously)..
170 std::this_thread::sleep_for(std::chrono::seconds(2));
171 // .. to ensure it was not called again
172 ASSERT_EQ(1, cb_count.load());
173
174 // enable handler again
175 app_->set_watchdog_handler(std::cref(wd_handler), std::chrono::seconds(1));
176
177 // wait till watchdog handler has been invoked again (2nd time)
178 while (1 == cb_count.load()) {
179 std::this_thread::sleep_for(std::chrono::milliseconds(100));
180 }
181
182 app_->stop();
183 t.join();
184
185 // wait doubled interval (used previously)..
186 std::this_thread::sleep_for(std::chrono::seconds(2));
187 // .. to ensure it was not called after stop()
188 ASSERT_EQ(2, cb_count.load());
189
190 // restart application (w/ watchdog handler still set)
191 std::promise<bool> its_promise2;
192 std::thread t2([&]() {
193 its_promise2.set_value(true);
194 app_->start();
195 });
196 EXPECT_TRUE(its_promise2.get_future().get());
197
198 // wait till watchdog handler has been invoked again (3rd time)
199 while (2 == cb_count.load()) {
200 std::this_thread::sleep_for(std::chrono::milliseconds(100));
201 }
202 ASSERT_EQ(3, cb_count.load());
203
204 // clear handler again (must not be called again), this time via zero interval
205 app_->set_watchdog_handler(std::cref(wd_handler), std::chrono::seconds::zero());
206
207 // wait doubled interval (used previously)..
208 std::this_thread::sleep_for(std::chrono::seconds(2));
209 // .. to ensure it was not called again
210 ASSERT_EQ(3, cb_count.load());
211
212 app_->stop();
213 t2.join();
214 }
215
216 class someip_application_shutdown_test: public ::testing::Test {
217
218 protected:
SetUp()219 void SetUp() {
220 is_registered_ = false;
221 is_available_ = false;
222
223 app_ = runtime::get()->create_application("application_test");
224 if (!app_->init()) {
225 ADD_FAILURE() << "Couldn't initialize application";
226 return;
227 }
228
229 app_->register_message_handler(vsomeip_test::TEST_SERVICE_SERVICE_ID,
230 vsomeip_test::TEST_SERVICE_INSTANCE_ID,
231 vsomeip_test::TEST_SERVICE_METHOD_ID_SHUTDOWN,
232 std::bind(&someip_application_shutdown_test::on_message_shutdown, this,
233 std::placeholders::_1));
234
235 app_->register_state_handler(
236 std::bind(&someip_application_shutdown_test::on_state, this,
237 std::placeholders::_1));
238 app_->register_availability_handler(
239 vsomeip_test::TEST_SERVICE_SERVICE_ID,
240 vsomeip_test::TEST_SERVICE_INSTANCE_ID,
241 std::bind(&someip_application_shutdown_test::on_availability,
242 this, std::placeholders::_1, std::placeholders::_2,
243 std::placeholders::_3));
244
245 shutdown_thread_ = std::thread(&someip_application_shutdown_test::send_shutdown_message, this);
246
247 app_->start();
248 }
249
TearDown()250 void TearDown() {
251 shutdown_thread_.join();
252 app_->stop();
253 app_.reset();
254 std::this_thread::sleep_for(std::chrono::milliseconds(5));
255 }
256
on_state(vsomeip::state_type_e _state)257 void on_state(vsomeip::state_type_e _state) {
258 if(_state == vsomeip::state_type_e::ST_REGISTERED)
259 {
260 std::lock_guard<std::mutex> its_lock(mutex_);
261 is_registered_ = true;
262 cv_.notify_one();
263 }
264 }
265
on_availability(vsomeip::service_t _service,vsomeip::instance_t _instance,bool _is_available)266 void on_availability(vsomeip::service_t _service,
267 vsomeip::instance_t _instance, bool _is_available) {
268 (void)_service;
269 (void)_instance;
270 if(_is_available) {
271 std::lock_guard<std::mutex> its_lock(mutex_);
272 is_available_ = _is_available;
273 cv_.notify_one();
274 }
275 }
276
on_message_shutdown(const std::shared_ptr<message> & _request)277 void on_message_shutdown(const std::shared_ptr<message>& _request)
278 {
279 (void)_request;
280 VSOMEIP_INFO << "Shutdown method was called, going down now.";
281 app_->clear_all_handler();
282 app_->stop();
283 }
284
send_shutdown_message()285 void send_shutdown_message() {
286 {
287 std::unique_lock<std::mutex> its_lock(mutex_);
288 while (!is_registered_) {
289 if (std::cv_status::timeout
290 == cv_.wait_for(its_lock, std::chrono::seconds(10))) {
291 ADD_FAILURE()<< "Application wasn't registered in time!";
292 is_registered_ = true;
293 }
294 }
295 app_->request_service(vsomeip_test::TEST_SERVICE_SERVICE_ID,
296 vsomeip_test::TEST_SERVICE_INSTANCE_ID);
297 app_->offer_service(vsomeip_test::TEST_SERVICE_SERVICE_ID,
298 vsomeip_test::TEST_SERVICE_INSTANCE_ID);
299 while (!is_available_) {
300 if (std::cv_status::timeout
301 == cv_.wait_for(its_lock, std::chrono::seconds(10))) {
302 ADD_FAILURE()<< "Service didn't become available in time!";
303 is_available_ = true;
304 }
305 }
306 }
307
308 std::shared_ptr<message> r = runtime::get()->create_request();
309 r->set_service(vsomeip_test::TEST_SERVICE_SERVICE_ID);
310 r->set_instance(vsomeip_test::TEST_SERVICE_INSTANCE_ID);
311 r->set_method(vsomeip_test::TEST_SERVICE_METHOD_ID_SHUTDOWN);
312 app_->send(r);
313 }
314
315 bool is_registered_;
316 bool is_available_;
317 std::shared_ptr<application> app_;
318 std::condition_variable cv_;
319 std::mutex mutex_;
320 std::thread shutdown_thread_;
321 };
322
323 class someip_application_exception_test: public ::testing::Test {
324
325 protected:
SetUp()326 void SetUp() {
327 is_registered_ = false;
328 is_available_ = false;
329 exception_method_called_ = false;
330
331 app_ = runtime::get()->create_application("application_test");
332 if (!app_->init()) {
333 ADD_FAILURE() << "Couldn't initialize application";
334 return;
335 }
336
337 app_->register_message_handler(vsomeip_test::TEST_SERVICE_SERVICE_ID,
338 vsomeip_test::TEST_SERVICE_INSTANCE_ID,
339 vsomeip_test::TEST_SERVICE_METHOD_ID_SHUTDOWN,
340 std::bind(&someip_application_exception_test::on_message_shutdown, this,
341 std::placeholders::_1));
342 app_->register_message_handler(vsomeip_test::TEST_SERVICE_SERVICE_ID,
343 vsomeip_test::TEST_SERVICE_INSTANCE_ID,
344 vsomeip_test::TEST_SERVICE_METHOD_ID_SHUTDOWN+1,
345 std::bind(&someip_application_exception_test::on_message_exception, this,
346 std::placeholders::_1));
347
348 app_->register_state_handler(
349 std::bind(&someip_application_exception_test::on_state, this,
350 std::placeholders::_1));
351 app_->register_availability_handler(
352 vsomeip_test::TEST_SERVICE_SERVICE_ID,
353 vsomeip_test::TEST_SERVICE_INSTANCE_ID,
354 std::bind(&someip_application_exception_test::on_availability,
355 this, std::placeholders::_1, std::placeholders::_2,
356 std::placeholders::_3));
357
358 shutdown_thread_ = std::thread(&someip_application_exception_test::send_shutdown_message, this);
359
360 app_->start();
361 }
362
TearDown()363 void TearDown() {
364 shutdown_thread_.join();
365 app_->stop();
366 app_.reset();
367 std::this_thread::sleep_for(std::chrono::milliseconds(5));
368 }
369
on_state(vsomeip::state_type_e _state)370 void on_state(vsomeip::state_type_e _state) {
371 if(_state == vsomeip::state_type_e::ST_REGISTERED)
372 {
373 std::lock_guard<std::mutex> its_lock(mutex_);
374 is_registered_ = true;
375 cv_.notify_one();
376 }
377 }
378
on_availability(vsomeip::service_t _service,vsomeip::instance_t _instance,bool _is_available)379 void on_availability(vsomeip::service_t _service,
380 vsomeip::instance_t _instance, bool _is_available) {
381 (void)_service;
382 (void)_instance;
383 if(_is_available) {
384 std::lock_guard<std::mutex> its_lock(mutex_);
385 is_available_ = _is_available;
386 cv_.notify_one();
387 }
388 }
389
on_message_shutdown(const std::shared_ptr<message> & _request)390 void on_message_shutdown(const std::shared_ptr<message>& _request)
391 {
392 (void)_request;
393 VSOMEIP_INFO << "Shutdown method was called, going down now.";
394 app_->clear_all_handler();
395 app_->stop();
396 }
397
on_message_exception(const std::shared_ptr<message> & _request)398 void on_message_exception(const std::shared_ptr<message>& _request)
399 {
400 (void)_request;
401 {
402 std::lock_guard<std::mutex> its_lock(mutex_);
403 exception_method_called_ = true;
404 cv_.notify_one();
405 }
406 throw std::invalid_argument("something went terribly wrong");
407 }
408
send_shutdown_message()409 void send_shutdown_message() {
410 {
411 std::unique_lock<std::mutex> its_lock(mutex_);
412 while(!is_registered_) {
413 cv_.wait(its_lock);
414 }
415 app_->request_service(vsomeip_test::TEST_SERVICE_SERVICE_ID,
416 vsomeip_test::TEST_SERVICE_INSTANCE_ID);
417 app_->offer_service(vsomeip_test::TEST_SERVICE_SERVICE_ID,
418 vsomeip_test::TEST_SERVICE_INSTANCE_ID);
419 while(!is_available_) {
420 cv_.wait(its_lock);
421 }
422 }
423
424 std::shared_ptr<message> r = runtime::get()->create_request();
425 // call method which throws exception
426 r->set_service(vsomeip_test::TEST_SERVICE_SERVICE_ID);
427 r->set_instance(vsomeip_test::TEST_SERVICE_INSTANCE_ID);
428 r->set_method(vsomeip_test::TEST_SERVICE_METHOD_ID_SHUTDOWN+1);
429 app_->send(r);
430
431 {
432 std::unique_lock<std::mutex> its_lock(mutex_);
433 while (!exception_method_called_) {
434 cv_.wait(its_lock);
435 }
436 }
437
438
439 //shutdown test
440 r->set_service(vsomeip_test::TEST_SERVICE_SERVICE_ID);
441 r->set_instance(vsomeip_test::TEST_SERVICE_INSTANCE_ID);
442 r->set_method(vsomeip_test::TEST_SERVICE_METHOD_ID_SHUTDOWN);
443 app_->send(r);
444 }
445
446 bool is_registered_;
447 bool is_available_;
448 bool exception_method_called_;
449 std::shared_ptr<application> app_;
450 std::condition_variable cv_;
451 std::mutex mutex_;
452 std::thread shutdown_thread_;
453 };
454
455 /**
456 * @test Stop the application through a method invoked from a dispatcher thread
457 */
TEST_F(someip_application_shutdown_test,stop_application_from_dispatcher_thread)458 TEST_F(someip_application_shutdown_test, stop_application_from_dispatcher_thread) {
459
460 }
461
462 /**
463 * @test Catch unhandled exceptions from invoked handlers
464 */
TEST_F(someip_application_exception_test,catch_exception_in_invoked_handler)465 TEST_F(someip_application_exception_test, catch_exception_in_invoked_handler) {
466
467 }
468
469 #ifndef _WIN32
main(int argc,char ** argv)470 int main(int argc, char** argv)
471 {
472 ::testing::InitGoogleTest(&argc, argv);
473 return RUN_ALL_TESTS();
474 }
475 #endif
476
477
478
479
480