[IoT-1562] Handle unit test segfaults at notification service
[platform/upstream/iotivity.git] / service / notification / unittest / NSConsumerTest.cpp
1 //******************************************************************
2 //
3 // Copyright 2016 Samsung Electronics All Rights Reserved.
4 //
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
6 //
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
10 //
11 //      http://www.apache.org/licenses/LICENSE-2.0
12 //
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
18 //
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
20
21 #include <gtest/gtest.h>
22 #include <HippoMocks/hippomocks.h>
23 #include <atomic>
24 #include <functional>
25 #include <condition_variable>
26 #include <mutex>
27 #include <chrono>
28
29 #include "ocstack.h"
30
31 #include "NSCommon.h"
32 #include "NSConsumerInterface.h"
33
34 #include "NSProviderSimulator.h"
35
36 namespace
37 {
38     NSProviderSimulator g_providerSimul;
39     NSProvider * g_provider;
40
41     std::atomic_bool g_isStartedStack(false);
42
43     std::chrono::milliseconds g_waitForResponse(500);
44
45     std::condition_variable responseCon;
46     std::mutex mutexForCondition;
47
48     enum class NSSelector
49     {
50         NS_SELECTION_CONSUMER = 0,
51         NS_SELECTION_PROVIDER = 1
52     };
53
54     NSConsumerConfig cfg;
55
56     NSProviderSimulator::NS_TopicStateList g_topicStateList;
57 }
58
59 class TestWithMock: public testing::Test
60 {
61 public:
62     MockRepository mocks;
63
64 protected:
65     virtual ~TestWithMock() noexcept(noexcept(std::declval<Test>().~Test()))
66     {
67
68     }
69
70     virtual void TearDown()
71     {
72         try
73         {
74             mocks.VerifyAll();
75         }
76         catch (...)
77         {
78             mocks.reset();
79             throw;
80         }
81     }
82 };
83
84 class NotificationConsumerTest : public TestWithMock
85 {
86 public:
87     NotificationConsumerTest() = default;
88     ~NotificationConsumerTest() = default;
89
90     static void NSNotificationReceivedCallbackEmpty(NSMessage *)
91     {
92         std::cout << __func__ << std::endl;
93     }
94
95     static void NSSyncCallbackEmpty(NSSyncInfo *)
96     {
97         std::cout << __func__ << std::endl;
98     }
99
100     static void NSFoundResourceEmpty(std::shared_ptr< OC::OCResource >)
101     {
102         std::cout << __func__ << std::endl;
103     }
104
105     static void NSProviderChangedCallback(NSProvider *,  NSProviderState)
106     {
107         std::cout << __func__ << std::endl;
108     }
109
110 protected:
111
112     void SetUp()
113     {
114         TestWithMock::SetUp();
115
116         if (g_isStartedStack == false)
117         {
118             OC::PlatformConfig occfg
119             {
120                 OC::ServiceType::InProc,
121                 OC::ModeType::Both,
122                 "0.0.0.0",
123                 0,
124                 OC::QualityOfService::LowQos
125             };
126             OC::OCPlatform::Configure(occfg);
127
128             try
129             {
130                 OC::OCPlatform::stopPresence();
131             }
132             catch (...)
133             {
134
135             }
136
137             g_isStartedStack = true;
138
139             cfg.changedCb = NSProviderChangedCallback;
140             cfg.messageCb = NSNotificationReceivedCallbackEmpty;
141             cfg.syncInfoCb = NSSyncCallbackEmpty;
142         }
143
144     }
145
146     void TearDown()
147     {
148         TestWithMock::TearDown();
149     }
150
151 };
152
153 TEST_F(NotificationConsumerTest, StartConsumerNegativeNonSetChangedCB)
154 {
155     cfg.changedCb = NULL;
156     cfg.messageCb = NSNotificationReceivedCallbackEmpty;
157     cfg.syncInfoCb = NSSyncCallbackEmpty;
158
159     EXPECT_EQ(NS_ERROR, NSStartConsumer(cfg));
160     std::unique_lock< std::mutex > lock{ mutexForCondition };
161     responseCon.wait_for(lock, g_waitForResponse);
162 }
163
164 TEST_F(NotificationConsumerTest, StartConsumerNegativeNonSetNotiReceiveCB)
165 {
166     cfg.changedCb = NSProviderChangedCallback;
167     cfg.messageCb = NULL;
168     cfg.syncInfoCb = NSSyncCallbackEmpty;
169
170     EXPECT_EQ(NS_ERROR, NSStartConsumer(cfg));
171     std::unique_lock< std::mutex > lock{ mutexForCondition };
172     responseCon.wait_for(lock, g_waitForResponse);
173 }
174
175 TEST_F(NotificationConsumerTest, StartConsumerNegativeNonSetSyncCB)
176 {
177     cfg.changedCb = NSProviderChangedCallback;
178     cfg.messageCb = NSNotificationReceivedCallbackEmpty;
179     cfg.syncInfoCb = NULL;
180
181     EXPECT_EQ(NS_ERROR, NSStartConsumer(cfg));
182     std::unique_lock< std::mutex > lock{ mutexForCondition };
183     responseCon.wait_for(lock, g_waitForResponse);
184 }
185
186 TEST_F(NotificationConsumerTest, StartConsumerPositive)
187 {
188     cfg.changedCb = NSProviderChangedCallback;
189     cfg.messageCb = NSNotificationReceivedCallbackEmpty;
190     cfg.syncInfoCb = NSSyncCallbackEmpty;
191
192     EXPECT_EQ(NS_OK, NSStartConsumer(cfg));
193     std::unique_lock< std::mutex > lock{ mutexForCondition };
194     responseCon.wait_for(lock, g_waitForResponse);
195 }
196
197 TEST_F(NotificationConsumerTest, StopConsumerPositive)
198 {
199     EXPECT_EQ(NSStopConsumer(), NS_OK);
200 }
201
202 TEST_F(NotificationConsumerTest, StopConsumerNegative)
203 {
204     EXPECT_EQ(NSStopConsumer(), NS_ERROR);
205 }
206
207 TEST_F(NotificationConsumerTest, DiscoverProviderWithNonAccepterWhenStartedConsumerFirst)
208 {
209     NSProviderState revState = NS_STOPPED;
210     mocks.OnCallFunc(NSProviderChangedCallback).Do(
211             [this, & revState](NSProvider *, NSProviderState state)
212             {
213                 std::cout << "Call Discovered" << std::endl;
214                 revState = state;
215                 responseCon.notify_all();
216             });
217
218     NSStartConsumer(cfg);
219
220     g_providerSimul.setAccepter((int)NSSelector::NS_SELECTION_CONSUMER);
221     g_providerSimul.createNotificationResource();
222
223     std::unique_lock< std::mutex > lock{ mutexForCondition };
224     responseCon.wait_for(lock, g_waitForResponse);
225
226     NSStopConsumer();
227     g_providerSimul.deleteNotificationResource();
228
229     EXPECT_EQ(NS_DISCOVERED, revState);
230 }
231
232 TEST_F(NotificationConsumerTest, DiscoverProviderWithNonAccepterWhenStartedConsumerAfter)
233 {
234     g_providerSimul.setAccepter((int)NSSelector::NS_SELECTION_CONSUMER);
235     g_providerSimul.createNotificationResource();
236     {
237         std::unique_lock< std::mutex > lock{ mutexForCondition };
238         responseCon.wait_for(lock, g_waitForResponse);
239     }
240
241     NSProviderState revState = NS_STOPPED;
242     mocks.OnCallFunc(NSProviderChangedCallback).Do(
243             [this, & revState](NSProvider * provider, NSProviderState state)
244             {
245                 std::cout << "Call Discovered" << std::endl;
246
247                 g_provider = provider;
248                 revState = state;
249                 responseCon.notify_all();
250             });
251
252     NSStartConsumer(cfg);
253
254     std::unique_lock< std::mutex > lock{ mutexForCondition };
255     responseCon.wait_for(lock, g_waitForResponse);
256
257     EXPECT_EQ(NS_DISCOVERED, revState);
258
259     ASSERT_NE(nullptr, g_provider) << "error: discovery failure";
260 }
261
262 TEST_F(NotificationConsumerTest, DiscoverProviderWithNonAccepterWhenRescan)
263 {
264     g_providerSimul.setAccepter((int)NSSelector::NS_SELECTION_CONSUMER);
265     NSProviderState revState = NS_STOPPED;
266     mocks.OnCallFunc(NSProviderChangedCallback).Do(
267             [this, &revState](NSProvider * provider, NSProviderState state)
268             {
269                 std::cout << "Call Discovered" << std::endl;
270                 revState = state;
271                 g_provider = provider;
272                 std::cout << g_provider->providerId << std::endl;
273                 responseCon.notify_all();
274             });
275
276     NSRescanProvider();
277
278     std::unique_lock< std::mutex > lock{ mutexForCondition };
279     responseCon.wait_for(lock, g_waitForResponse);
280
281     EXPECT_EQ(NS_DISCOVERED, revState);
282 }
283
284 TEST_F(NotificationConsumerTest, ExpectSubscribeSuccess)
285 {
286     NSProviderState revState = NS_DENY;
287
288     ASSERT_NE(nullptr, g_provider) << "error: discovery failure";
289
290     mocks.OnCallFunc(NSProviderChangedCallback).Do(
291             [this, & revState](NSProvider * , NSProviderState state)
292             {
293                 std::cout << "Income Changed Callback : " << state << std::endl;
294                 revState = state;
295                 responseCon.notify_all();
296             });
297
298     NSResult ret = NSSubscribe(g_provider->providerId);
299     std::unique_lock< std::mutex > lock{ mutexForCondition };
300     responseCon.wait_for(lock, g_waitForResponse);
301
302     EXPECT_EQ(NS_ALLOW, revState);
303     EXPECT_EQ(NS_OK, ret);
304 }
305
306 TEST_F(NotificationConsumerTest, ExpectReceiveNotification)
307 {
308     uint64_t id = 10;
309     std::string title = "title";
310     std::string msg = "msg";
311     uint64_t revId = 0;
312
313     mocks.OnCallFunc(NSNotificationReceivedCallbackEmpty).Do(
314             [this, & revId](NSMessage * message)
315             {
316                 std::cout << "Income Notification : " << message->messageId << std::endl;
317                 revId = message->messageId;
318                 responseCon.notify_all();
319             });
320
321     g_providerSimul.notifyMessage(id, title, msg);
322
323     std::unique_lock< std::mutex > lock{ mutexForCondition };
324     responseCon.wait_for(lock, g_waitForResponse);
325
326     EXPECT_EQ(id, revId);
327     NSStopConsumer();
328     g_providerSimul.deleteNotificationResource();
329 }
330
331 TEST_F(NotificationConsumerTest, ExpectReceiveSubAllowWithAccepterisProvider)
332 {
333     g_providerSimul.setAccepter((int)NSSelector::NS_SELECTION_PROVIDER);
334     NSProviderState revState = NS_DENY;
335     g_providerSimul.createNotificationResource();
336     {
337         std::unique_lock< std::mutex > lock{ mutexForCondition };
338         responseCon.wait_for(lock, g_waitForResponse);
339     }
340
341     mocks.OnCallFunc(NSProviderChangedCallback).Do(
342             [this, & revState](NSProvider * provider, NSProviderState state)
343             {
344                 std::cout << "Income Changed Callback : " << state << std::endl;
345                 revState = state;
346                 g_provider = provider;
347                 responseCon.notify_all();
348             });
349     mocks.OnCallFunc(NSProviderChangedCallback).Do(
350             [this, & revState](NSProvider *, NSProviderState state)
351             {
352                 std::cout << "Income Changed Callback : " << state << std::endl;
353                 revState = state;
354                 responseCon.notify_all();
355             });
356
357     NSStartConsumer(cfg);
358     std::unique_lock< std::mutex > lock{ mutexForCondition };
359     responseCon.wait_for(lock, g_waitForResponse);
360
361     EXPECT_EQ(NS_ALLOW, revState);
362 }
363
364 TEST_F(NotificationConsumerTest, ExpectReceiveNotificationWithAccepterisProvider)
365 {
366     uint64_t id = 11;
367     std::string title = "title";
368     std::string msg = "msg";
369     uint64_t revId = 1;
370
371     mocks.OnCallFunc(NSNotificationReceivedCallbackEmpty).Do(
372             [this, & id, & revId](NSMessage * message)
373             {
374                 std::cout << "Income Notification : " << message->messageId << std::endl;
375                 revId = message->messageId;
376                 responseCon.notify_all();
377             });
378
379     g_providerSimul.notifyMessage(id, title, msg);
380
381     std::unique_lock< std::mutex > lock{ mutexForCondition };
382     responseCon.wait_for(lock, g_waitForResponse);
383
384     EXPECT_EQ(id, revId);
385 }
386
387 TEST_F(NotificationConsumerTest, ExpectCallbackReadCheckWhenProviderNotifySync)
388 {
389     uint64_t id = 12;
390     std::string title = "title";
391     std::string msg = "msg";
392     NSSyncType type = NS_SYNC_DELETED;
393
394     mocks.OnCallFunc(NSNotificationReceivedCallbackEmpty).Do(
395             [this](NSMessage * message)
396             {
397                 std::cout << "Income Notification : " << message->messageId << std::endl;
398                 responseCon.notify_all();
399             });
400
401     mocks.OnCallFunc(NSSyncCallbackEmpty).Do(
402             [& type, this](NSSyncInfo * sync)
403             {
404                 std::cout << "Income SyncInfo : " << sync->messageId
405                         << ", State : " << sync->state << std::endl;
406                 type = sync->state;
407                 responseCon.notify_all();
408             });
409
410     g_providerSimul.notifyMessage(id, title, msg);
411     {
412         std::unique_lock< std::mutex > lock{ mutexForCondition };
413         responseCon.wait_for(lock, g_waitForResponse);
414     }
415
416     g_providerSimul.sendRead(id);
417     {
418         std::unique_lock< std::mutex > lock{ mutexForCondition };
419         responseCon.wait_for(lock, g_waitForResponse);
420     }
421
422     EXPECT_EQ(NS_SYNC_READ, type);
423 }
424
425 TEST_F(NotificationConsumerTest, ExpectCallbackDismissCheckWhenProviderNotifySync)
426 {
427     uint64_t id = 13;
428     std::string title = "title";
429     std::string msg = "msg";
430     NSSyncType type = NS_SYNC_READ;
431
432     mocks.OnCallFunc(NSNotificationReceivedCallbackEmpty).Do(
433             [this](NSMessage * message)
434             {
435                 std::cout << "Income Notification : " << message->messageId << std::endl;
436                 responseCon.notify_all();
437             });
438
439     mocks.OnCallFunc(NSSyncCallbackEmpty).Do(
440             [& type, this](NSSyncInfo * sync)
441             {
442                 std::cout << "Income Notification : " << sync->messageId
443                         << ", State : " << sync->state << std::endl;
444                 type = sync->state;
445                 responseCon.notify_all();
446             });
447
448     g_providerSimul.notifyMessage(id, title, msg);
449     {
450         std::unique_lock< std::mutex > lock{ mutexForCondition };
451         responseCon.wait_for(lock, g_waitForResponse);
452     }
453
454     g_providerSimul.sendDismiss(id);
455     {
456         std::unique_lock< std::mutex > lock{ mutexForCondition };
457         responseCon.wait_for(lock, g_waitForResponse);
458     }
459
460     EXPECT_EQ(NS_SYNC_DELETED, type);
461 }
462
463 TEST_F(NotificationConsumerTest, ExpectCallbackReadCheckWhenConsumerPostSync)
464 {
465     uint64_t id = 14;
466     std::string title = "title";
467     std::string msg = "msg";
468     NSSyncType type = NS_SYNC_DELETED;
469
470     mocks.OnCallFunc(NSNotificationReceivedCallbackEmpty).Do(
471             [this](NSMessage * message)
472             {
473                 std::cout << "Income Notification : " << message->messageId << std::endl;
474                 NSConsumerSendSyncInfo(message->providerId, message->messageId, NS_SYNC_READ);
475                 std::unique_lock< std::mutex > lock{ mutexForCondition };
476                 responseCon.wait_for(lock, g_waitForResponse);
477             });
478
479     mocks.OnCallFunc(NSSyncCallbackEmpty).Do(
480             [& type, this](NSSyncInfo * sync)
481             {
482                 std::cout << "Income Notification : " << sync->messageId
483                         << ", State : " << sync->state << std::endl;
484                 type = sync->state;
485                 responseCon.notify_all();
486             });
487
488     g_providerSimul.notifyMessage(id, title, msg);
489     {
490         std::unique_lock< std::mutex > lock{ mutexForCondition };
491         responseCon.wait_for(lock, g_waitForResponse);
492     }
493
494     EXPECT_EQ(NS_SYNC_READ, type);
495 }
496
497 TEST_F(NotificationConsumerTest, ExpectCallbackDismissCheckWhenConsumerPostSync)
498 {
499     uint64_t id = 15;
500     std::string title = "title";
501     std::string msg = "msg";
502     NSSyncType state = NS_SYNC_READ;
503
504     mocks.OnCallFunc(NSNotificationReceivedCallbackEmpty).Do(
505             [this](NSMessage * message)
506             {
507                 std::cout << "Income Notification : " << message->messageId << std::endl;
508                 NSConsumerSendSyncInfo(message->providerId, message->messageId, NS_SYNC_DELETED);
509                 std::unique_lock< std::mutex > lock{ mutexForCondition };
510                 responseCon.wait_for(lock, g_waitForResponse);
511             });
512
513     mocks.OnCallFunc(NSSyncCallbackEmpty).Do(
514             [& state, this](NSSyncInfo * sync)
515             {
516                 std::cout << "Income Notification : " << sync->messageId
517                         << ", State : " << sync->state << std::endl;
518                 state = sync->state;
519                 responseCon.notify_all();
520             });
521
522     g_providerSimul.notifyMessage(id, title, msg);
523     {
524         std::unique_lock< std::mutex > lock{ mutexForCondition };
525         responseCon.wait_for(lock, g_waitForResponse);
526     }
527
528     EXPECT_EQ(NS_SYNC_DELETED, state);
529 }
530
531 TEST_F(NotificationConsumerTest, ExpectGetProviderSuccessWithValidProviderId)
532 {
533     ASSERT_NE(nullptr, g_provider) << "error: discovery failure";
534
535     NSProvider * provider = NSConsumerGetProvider(g_provider->providerId);
536     int ret = strcmp(provider->providerId, g_provider->providerId);
537     EXPECT_EQ(0, ret);
538     free(provider);
539 }
540
541 TEST_F(NotificationConsumerTest, ExpectGetProviderSuccessWithInvalidProviderId)
542 {
543     NSProvider * provider = NSConsumerGetProvider("123456789012345678901234567890123457");
544     EXPECT_EQ(provider, (void*)NULL);
545 }
546
547 TEST_F(NotificationConsumerTest, ExpectGetProviderSuccessWithNULL)
548 {
549     NSProvider * provider = NSConsumerGetProvider(NULL);
550     EXPECT_EQ(provider, (void*)NULL);
551 }
552
553 TEST_F(NotificationConsumerTest, ExpectGetTopicListIsNULL)
554 {
555     ASSERT_NE(nullptr, g_provider) << "error: discovery failure";
556
557     NSTopicLL * currentTopics = NSConsumerGetTopicList(g_provider->providerId);
558     EXPECT_EQ(NULL, currentTopics);
559 }
560
561 TEST_F(NotificationConsumerTest, ExpectCallbackTopicUpdated)
562 {
563     NSProviderState revState = NS_STOPPED;
564     mocks.OnCallFunc(NSProviderChangedCallback).Do(
565         [this, & revState](NSProvider * , NSProviderState state)
566         {
567             std::cout << "Income Changed Callback : " << state << std::endl;
568             revState = state;
569             responseCon.notify_all();
570         });
571
572     NSProviderSimulator::NS_TopicList topics;
573     topics.push_back("1");
574     topics.push_back("2");
575     topics.push_back("3");
576
577     g_providerSimul.setTopics(topics);
578
579     std::unique_lock< std::mutex > lock{ mutexForCondition };
580     responseCon.wait_for(lock, g_waitForResponse);
581
582     EXPECT_EQ(NS_TOPIC, revState);
583 }
584
585 TEST_F(NotificationConsumerTest, ExpectEQTopicList)
586 {
587     bool isSame = false;
588
589     NSProviderSimulator::NS_TopicList topics;
590     topics.push_back("1");
591     topics.push_back("2");
592     topics.push_back("3");
593
594     ASSERT_NE(nullptr, g_provider) << "error: discovery failure";
595
596     NSTopicLL * retTopic = NSConsumerGetTopicList(g_provider->providerId);
597     std::for_each (topics.begin(), topics.end(),
598             [this, & retTopic, & isSame](const std::string & str)
599             {
600                 isSame = (str == std::string(retTopic->topicName));
601                 retTopic = retTopic->next;
602             });
603
604     EXPECT_EQ(true, isSame);
605 }
606
607 TEST_F(NotificationConsumerTest, ExpectFailUpdateTopicOnConsumer)
608 {
609     ASSERT_NE(nullptr, g_provider) << "error: discovery failure";
610
611     NSTopicLL * retTopic = NSConsumerGetTopicList(g_provider->providerId);
612     for (; retTopic; retTopic = retTopic->next)
613     {
614         retTopic->state = NS_TOPIC_SUBSCRIBED;
615     }
616     NSResult ret = NSConsumerUpdateTopicList(g_provider->providerId, retTopic);
617
618     EXPECT_EQ(NS_ERROR, ret);
619 }
620
621 TEST_F(NotificationConsumerTest, ExpectCallbackDeletedProvider)
622 {
623     NSProviderState type = NS_ALLOW;
624     mocks.OnCallFunc(NSProviderChangedCallback).Do(
625             [& type, this](NSProvider * , NSProviderState state)
626             {
627                 std::cout << "Income Changed Callback : " << state << std::endl;
628                 type = state;
629                 responseCon.notify_all();
630             });
631
632     g_providerSimul.deleteNotificationResource();
633
634     std::unique_lock< std::mutex > lock{ mutexForCondition };
635     responseCon.wait_for(lock, std::chrono::milliseconds(2000));
636
637     EXPECT_EQ(type, NS_STOPPED);
638     NSStopConsumer();
639 }