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