a4ed8a31e94e1656e0b9de05195cfed7bfa42bbd
[platform/upstream/iotivity.git] / service / resource-encapsulation / src / serverBuilder / unittests / RCSResourceObjectTest.cpp
1 //******************************************************************
2 //
3 // Copyright 2015 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 "UnitTestHelper.h"
22
23 #include "RCSResourceObject.h"
24
25 #include "OCPlatform.h"
26
27 using namespace std;
28 using namespace std::placeholders;
29
30 using namespace OIC::Service;
31 using namespace OC;
32
33 typedef OCStackResult (*registerResource)(OCResourceHandle&, string&, const string&, const string&,
34                            EntityHandler, uint8_t );
35
36 typedef OCStackResult (*NotifyAllObservers)(OCResourceHandle);
37
38 constexpr char RESOURCE_URI[]{ "a/test" };
39 constexpr char RESOURCE_TYPE[]{ "resourcetype" };
40 constexpr char KEY[]{ "key" };
41 constexpr int VALUE{ 100 };
42
43 TEST(ResourceObjectBuilderCreateTest, ThrowIfUriIsInvalid)
44 {
45     ASSERT_THROW(RCSResourceObject::Builder("", "", "").build(), RCSPlatformException);
46 }
47
48 class ResourceObjectBuilderTest: public TestWithMock
49 {
50 protected:
51     void SetUp()
52     {
53         TestWithMock::SetUp();
54
55         mocks.OnCallFuncOverload(static_cast< registerResource >(OCPlatform::registerResource))
56                 .Return(OC_STACK_OK);
57     }
58 };
59
60 TEST_F(ResourceObjectBuilderTest, RegisterResourceWhenCallCreate)
61 {
62     mocks.ExpectCallFuncOverload(static_cast< registerResource >(OCPlatform::registerResource))
63             .Return(OC_STACK_OK);
64
65     RCSResourceObject::Builder(RESOURCE_URI, RESOURCE_TYPE, "").build();
66 }
67
68 TEST_F(ResourceObjectBuilderTest, ResourceServerHasPropertiesSetByBuilder)
69 {
70     auto serverResource = RCSResourceObject::Builder(RESOURCE_URI, RESOURCE_TYPE, "").
71             setDiscoverable(false).setObservable(true).build();
72
73     EXPECT_FALSE(serverResource->isDiscoverable());
74     EXPECT_TRUE(serverResource->isObservable());
75 }
76
77 TEST_F(ResourceObjectBuilderTest, ResourceServerHasAttrsSetByBuilder)
78 {
79     RCSResourceAttributes attrs;
80     attrs[KEY] = 100;
81
82     auto serverResource = RCSResourceObject::Builder(RESOURCE_URI, RESOURCE_TYPE, "").
83             setAttributes(attrs).build();
84
85     RCSResourceObject::LockGuard lock{ serverResource, RCSResourceObject::AutoNotifyPolicy::NEVER };
86     EXPECT_EQ(attrs, serverResource->getAttributes());
87 }
88
89 TEST_F(ResourceObjectBuilderTest, TypesAddedInBuilderWillBeBound)
90 {
91     int count = 0;
92     mocks.OnCallFunc(OCPlatform::bindTypeToResource).Do(
93             [&count](const OCResourceHandle&, const std::string&)
94             {
95                 ++count;
96                 return OC_STACK_OK;
97             }
98     );
99
100     auto serverResource = RCSResourceObject::Builder(RESOURCE_URI, RESOURCE_TYPE, "").
101             addType("1").addType("2").build();
102
103     EXPECT_EQ(2, count);
104 }
105
106 TEST_F(ResourceObjectBuilderTest, InterfaceAddedInBuilderWillBeBound)
107 {
108     int count = 0;
109     mocks.OnCallFunc(OCPlatform::bindInterfaceToResource).Do(
110             [&count](const OCResourceHandle&, const std::string&)
111             {
112                 ++count;
113                 return OC_STACK_OK;
114             }
115     );
116
117     auto serverResource = RCSResourceObject::Builder(RESOURCE_URI, RESOURCE_TYPE, "").
118             addInterface("1").addInterface("2").build();
119
120     EXPECT_EQ(2, count);
121 }
122
123 class ResourceObjectTest: public TestWithMock
124 {
125 public:
126     RCSResourceObject::Ptr server;
127
128 protected:
129     void SetUp()
130     {
131         TestWithMock::SetUp();
132
133         initMocks();
134
135         server = RCSResourceObject::Builder(RESOURCE_URI, RESOURCE_TYPE, "").build();
136
137         initResourceObject();
138     }
139
140     virtual void initMocks()
141     {
142         mocks.OnCallFuncOverload(static_cast< registerResource >(OCPlatform::registerResource)).
143                 Return(OC_STACK_OK);
144
145         mocks.OnCallFunc(OCPlatform::unregisterResource).Return(OC_STACK_OK);
146     }
147
148     virtual void initResourceObject() {
149         server->setAutoNotifyPolicy(RCSResourceObject::AutoNotifyPolicy::NEVER);
150     }
151 };
152
153 TEST_F(ResourceObjectTest, AccessAttributesWithLock)
154 {
155     {
156         RCSResourceObject::LockGuard lock{ server };
157         auto& attr = server->getAttributes();
158         attr[KEY] = VALUE;
159     }
160
161     ASSERT_EQ(VALUE, server->getAttribute<int>(KEY));
162 }
163
164 TEST_F(ResourceObjectTest, ThrowIfTryToAccessAttributesWithoutGuard)
165 {
166     ASSERT_THROW(server->getAttributes(), NoLockException);
167 }
168
169 TEST_F(ResourceObjectTest, SettingAttributesWithinGuardDoesntCauseDeadLock)
170 {
171     {
172         RCSResourceObject::LockGuard guard{ server };
173         server->setAttribute(KEY, VALUE);
174     }
175
176     ASSERT_EQ(VALUE, server->getAttribute<int>(KEY));
177 }
178
179 TEST_F(ResourceObjectTest, SettingNestedAttributesIsSameToGettingNestedAttributes)
180 {
181     RCSResourceAttributes lightAttributes;
182
183     lightAttributes["red"]=50;
184     lightAttributes["blue"]=100;
185     lightAttributes["green"]=150;
186
187     server->setAttribute(KEY, lightAttributes);
188
189     ASSERT_EQ(lightAttributes, server->getAttribute<RCSResourceAttributes>(KEY));
190 }
191
192 TEST_F(ResourceObjectTest, SettingNestedVectorAttributesIsSameToGettingNestedVectorAttributes)
193 {
194     vector<int> arr11 = {0,1}, arr12 = {4,5}, arr13 ={7,8};
195     vector<vector<int>> arr21 = { arr11, arr12 }, arr22 = { arr12, arr13 };
196     vector<vector<vector<int>>> arr31={ arr21, arr22 };
197
198     server->setAttribute(KEY, arr31);
199
200     ASSERT_EQ(arr31, server->getAttributeValue(KEY));
201 }
202
203 TEST_F(ResourceObjectTest, ThrowIfResourceToBindIsInvalid)
204 {
205     ASSERT_THROW(server->bindResource(server), RCSInvalidParameterException);
206 }
207
208 TEST_F(ResourceObjectTest, ThrowIfBindResourceFailed)
209 {
210     mocks.OnCallFunc(OCBindResource).Return(OC_STACK_ERROR);
211
212     ASSERT_THROW(server->bindResource(
213             RCSResourceObject::Builder("a/temp", RESOURCE_TYPE, "").build()), RCSPlatformException);
214 }
215
216 TEST_F(ResourceObjectTest, ThrowIfResourceToUnbindIsInvalid)
217 {
218     ASSERT_THROW(server->unbindResource(server), RCSInvalidParameterException);
219 }
220
221 TEST_F(ResourceObjectTest, BoundResourceCanBeRetrieved)
222 {
223     mocks.OnCallFunc(OCBindResource).Return(OC_STACK_OK);
224
225     auto boundResource = RCSResourceObject::Builder("a/temp", RESOURCE_TYPE, "").build();
226     server->bindResource(boundResource);
227
228     ASSERT_EQ(boundResource, server->getBoundResources()[0]);
229 }
230
231
232 class AutoNotifyTest: public ResourceObjectTest
233 {
234 protected:
235     void initMocks()
236     {
237         mocks.OnCallFuncOverload(static_cast< NotifyAllObservers >(
238                 OCPlatform::notifyAllObservers)).Return(OC_STACK_OK);
239     }
240
241     virtual void initResourceObject() {
242         // intended blank
243     }
244 };
245
246 TEST_F(AutoNotifyTest, DefalutAutoNotifyPolicyIsUpdated)
247 {
248     ASSERT_EQ(RCSResourceObject::AutoNotifyPolicy::UPDATED, server->getAutoNotifyPolicy());
249 }
250
251 TEST_F(AutoNotifyTest, AutoNotifyPolicyCanBeSet)
252 {
253     server->setAutoNotifyPolicy(RCSResourceObject::AutoNotifyPolicy::NEVER);
254
255     ASSERT_EQ(RCSResourceObject::AutoNotifyPolicy::NEVER, server->getAutoNotifyPolicy());
256 }
257
258 TEST_F(AutoNotifyTest, WithUpdatedPolicy_NeverBeNotifiedIfAttributeIsNotChanged)
259 {
260     server->setAutoNotifyPolicy(RCSResourceObject::AutoNotifyPolicy::UPDATED);
261     server->setAttribute(KEY, VALUE);
262
263     mocks.NeverCallFuncOverload(static_cast< NotifyAllObservers >(
264             OC::OCPlatform::notifyAllObservers));
265
266     server->setAttribute(KEY, VALUE);
267 }
268
269 TEST_F(AutoNotifyTest, WithUpdatedPolicy_WillBeNotifiedIfAttributeIsChanged)
270 {
271     server->setAutoNotifyPolicy(RCSResourceObject::AutoNotifyPolicy::UPDATED);
272     server->setAttribute(KEY, VALUE);
273
274     mocks.ExpectCallFuncOverload(static_cast< NotifyAllObservers >(
275             OC::OCPlatform::notifyAllObservers)).Return(OC_STACK_OK);
276
277     server->setAttribute(KEY, VALUE + 1);
278 }
279
280 TEST_F(AutoNotifyTest, WithUpdatedPolicy_WillBeNotifiedIfValueIsAdded)
281 {
282     constexpr char newKey[]{ "newKey" };
283     server->setAutoNotifyPolicy(RCSResourceObject::AutoNotifyPolicy::UPDATED);
284
285     mocks.ExpectCallFuncOverload(static_cast< NotifyAllObservers >(
286             OC::OCPlatform::notifyAllObservers)).Return(OC_STACK_OK);
287
288     server->setAttribute(newKey, VALUE);
289 }
290
291 TEST_F(AutoNotifyTest, WithNeverPolicy_NeverBeNotifiedEvenIfAttributeIsChanged)
292 {
293     server->setAutoNotifyPolicy(RCSResourceObject::AutoNotifyPolicy::NEVER);
294
295     mocks.NeverCallFuncOverload(static_cast< NotifyAllObservers >(
296             OC::OCPlatform::notifyAllObservers));
297
298     RCSResourceObject::LockGuard lock{ server };
299     server->setAttribute(KEY, VALUE);
300 }
301
302 TEST_F(AutoNotifyTest, WithUpdatePolicy_WillBeNotifiedIfAttributeIsDeleted)
303 {
304     server->setAutoNotifyPolicy(RCSResourceObject::AutoNotifyPolicy::UPDATED);
305     server->setAttribute(KEY, VALUE);
306
307     mocks.ExpectCallFuncOverload(static_cast< NotifyAllObservers >(
308             OC::OCPlatform::notifyAllObservers)).Return(OC_STACK_OK);
309
310     server->removeAttribute(KEY);
311 }
312
313 class AutoNotifyWithGuardTest: public AutoNotifyTest
314 {
315 };
316
317 TEST_F(AutoNotifyWithGuardTest, GuardFollowsServerPolicyByDefault)
318 {
319     server->setAutoNotifyPolicy(RCSResourceObject::AutoNotifyPolicy::UPDATED);
320
321     mocks.ExpectCallFuncOverload(static_cast< NotifyAllObservers >(
322             OC::OCPlatform::notifyAllObservers)).Return(OC_STACK_OK);
323
324     RCSResourceObject::LockGuard guard{ server };
325     server->setAttribute(KEY, VALUE);
326 }
327
328 TEST_F(AutoNotifyWithGuardTest, GuardCanOverridePolicy)
329 {
330     server->setAutoNotifyPolicy(RCSResourceObject::AutoNotifyPolicy::ALWAYS);
331
332     mocks.NeverCallFuncOverload(static_cast< NotifyAllObservers >(
333             OC::OCPlatform::notifyAllObservers));
334
335     RCSResourceObject::LockGuard guard{ server, RCSResourceObject::AutoNotifyPolicy::NEVER };
336     server->getAttributes()[KEY] = VALUE;
337 }
338
339 TEST_F(AutoNotifyWithGuardTest, GuardInvokesNotifyWhenDestroyed)
340 {
341     server->setAutoNotifyPolicy(RCSResourceObject::AutoNotifyPolicy::NEVER);
342
343     mocks.ExpectCallFuncOverload(static_cast< NotifyAllObservers >(
344             OC::OCPlatform::notifyAllObservers)).Return(OC_STACK_OK);
345
346     {
347         RCSResourceObject::LockGuard guard{ server, RCSResourceObject::AutoNotifyPolicy::ALWAYS };
348         server->setAttribute(KEY, VALUE);
349     }
350
351     mocks.NeverCallFuncOverload(static_cast< NotifyAllObservers >(
352                OC::OCPlatform::notifyAllObservers)).Return(OC_STACK_OK);
353
354     server->setAttribute(KEY, VALUE);
355 }
356
357
358
359 class ResourceObjectHandlingRequestTest: public ResourceObjectTest
360 {
361 public:
362     EntityHandler handler;
363
364     static constexpr OCRequestHandle fakeRequestHandle =
365             reinterpret_cast<OCRequestHandle>(0x1234);
366     static constexpr OCResourceHandle fakeResourceHandle =
367             reinterpret_cast<OCResourceHandle>(0x4321);
368
369 public:
370     OCResourceRequest::Ptr createRequest(OCMethod method = OC_REST_GET, OCRepresentation ocRep =
371             OCRepresentation{})
372     {
373         auto request = make_shared<OCResourceRequest>();
374
375         OCEntityHandlerRequest ocEntityHandlerRequest;
376         memset(&ocEntityHandlerRequest, 0, sizeof(OCEntityHandlerRequest));
377         OC::MessageContainer mc;
378
379         mc.addRepresentation(ocRep);
380
381         ocEntityHandlerRequest.requestHandle = fakeRequestHandle;
382         ocEntityHandlerRequest.resource = fakeResourceHandle;
383         ocEntityHandlerRequest.method = method;
384         ocEntityHandlerRequest.payload = reinterpret_cast<OCPayload*>(mc.getPayload());
385
386         formResourceRequest(OC_REQUEST_FLAG, &ocEntityHandlerRequest, request);
387
388         return request;
389     }
390
391 protected:
392     OCStackResult registerResourceFake(OCResourceHandle&, string&, const string&,
393             const string&, EntityHandler handler, uint8_t)
394     {
395         this->handler = handler;
396         return OC_STACK_OK;
397     }
398
399     void initMocks()
400     {
401         mocks.OnCallFuncOverload(
402             static_cast<registerResource>(OCPlatform::registerResource)).Do(
403                     bind(&ResourceObjectHandlingRequestTest::registerResourceFake,
404                             this, _1, _2, _3, _4, _5, _6));
405         mocks.OnCallFunc(OCPlatform::unregisterResource).Return(OC_STACK_OK);
406     }
407 };
408
409 TEST_F(ResourceObjectHandlingRequestTest, CallSendResponseWhenReceiveRequest)
410 {
411     mocks.ExpectCallFunc(OCPlatform::sendResponse).Return(OC_STACK_OK);
412
413     ASSERT_EQ(OC_EH_OK, handler(createRequest()));
414 }
415
416 TEST_F(ResourceObjectHandlingRequestTest, ReturnErrorCodeWhenSendResponseFailed)
417 {
418     mocks.ExpectCallFunc(OCPlatform::sendResponse).Return(OC_STACK_ERROR);
419
420     ASSERT_EQ(OC_EH_ERROR, handler(createRequest()));
421 }
422
423 TEST_F(ResourceObjectHandlingRequestTest, SendResponseWithSameHandlesPassedByRequest)
424 {
425     mocks.ExpectCallFunc(OCPlatform::sendResponse).Match(
426             [](const shared_ptr<OCResourceResponse> response)
427             {
428                 return response->getRequestHandle() == fakeRequestHandle &&
429                         response->getResourceHandle() == fakeResourceHandle;
430             }
431     ).Return(OC_STACK_OK);
432
433     ASSERT_EQ(OC_EH_OK, handler(createRequest()));
434 }
435
436 TEST_F(ResourceObjectHandlingRequestTest, SendResponseWithRCSResponseResults)
437 {
438     constexpr int errorCode{ 1999 };
439
440     server->setGetRequestHandler(
441             [](const RCSRequest&, RCSResourceAttributes&) -> RCSGetResponse
442             {
443                 return RCSGetResponse::create(errorCode);
444             }
445     );
446
447     mocks.ExpectCallFunc(OCPlatform::sendResponse).Match(
448             [](const shared_ptr<OCResourceResponse> response)
449             {
450                 return response->getErrorCode() == errorCode;
451             }
452     ).Return(OC_STACK_OK);
453
454     ASSERT_EQ(OC_EH_OK, handler(createRequest()));
455 }
456
457 TEST_F(ResourceObjectHandlingRequestTest, SendSetResponseWithCustomAttrs)
458 {
459     constexpr int errorCode{ 1999 };
460     constexpr char value[]{ "VALUE" };
461
462     server->setSetRequestHandler(
463             [](const RCSRequest&, RCSResourceAttributes&) -> RCSSetResponse
464             {
465                 RCSResourceAttributes attrs;
466                 attrs[KEY] = value;
467                 return RCSSetResponse::create(attrs, errorCode);
468             }
469     );
470
471     mocks.ExpectCallFunc(OCPlatform::sendResponse).Match(
472             [](const shared_ptr<OCResourceResponse> response)
473             {
474                 return value == response->getResourceRepresentation()[KEY].getValue<std::string>()
475                         && response->getErrorCode() == errorCode;
476             }
477     ).Return(OC_STACK_OK);
478
479     ASSERT_EQ(OC_EH_OK, handler(createRequest(OC_REST_POST)));
480 }
481
482
483
484 class SetRequestHandlerPolicyTest: public ResourceObjectHandlingRequestTest
485 {
486 public:
487     typedef OCStackResult (*SendResponse)(std::shared_ptr<OCResourceResponse>);
488
489 public:
490     OCRepresentation createOCRepresentation()
491     {
492         OCRepresentation ocRep;
493         ocRep[KEY] = VALUE;
494         return ocRep;
495     }
496
497     void initMocks()
498     {
499         ResourceObjectHandlingRequestTest::initMocks();
500         mocks.OnCallFunc(OCPlatform::sendResponse).Return(OC_STACK_OK);
501     }
502 };
503
504 TEST_F(SetRequestHandlerPolicyTest, DefalutSetRequestHandlerPolicyIsNever)
505 {
506     ASSERT_EQ(RCSResourceObject::SetRequestHandlerPolicy::NEVER,
507                 server->getSetRequestHandlerPolicy());
508 }
509
510 TEST_F(SetRequestHandlerPolicyTest, SetRequestHandlerPolicyCanBeSet)
511 {
512     server->setSetRequestHandlerPolicy(RCSResourceObject::SetRequestHandlerPolicy::ACCEPTANCE);
513
514     ASSERT_EQ(RCSResourceObject::SetRequestHandlerPolicy::ACCEPTANCE,
515                 server->getSetRequestHandlerPolicy());
516 }
517
518 TEST_F(SetRequestHandlerPolicyTest, WithNeverPolicy_DeniedIfKeyIsNew)
519 {
520     server->setSetRequestHandlerPolicy(RCSResourceObject::SetRequestHandlerPolicy::NEVER);
521
522     handler(createRequest(OC_REST_POST, createOCRepresentation()));
523
524     RCSResourceObject::LockGuard guard{ server };
525     ASSERT_FALSE(server->getAttributes().contains(KEY));
526 }
527
528 TEST_F(SetRequestHandlerPolicyTest, WithAcceptancePolicy_AcceptedEvenIfKeyIsNew)
529 {
530     server->setSetRequestHandlerPolicy(RCSResourceObject::SetRequestHandlerPolicy::ACCEPTANCE);
531
532     handler(createRequest(OC_REST_POST, createOCRepresentation()));
533
534     RCSResourceObject::LockGuard guard{ server };
535     ASSERT_TRUE(server->getAttributes().contains(KEY));
536 }
537
538
539
540 class ResourceObjectSynchronizationTest: public ResourceObjectHandlingRequestTest
541 {
542 public:
543
544     static void withLock(RCSResourceObject::Ptr serverResource, int count)
545     {
546         for (int i=0; i<count; ++i)
547         {
548             RCSResourceObject::LockGuard lock{ serverResource };
549
550             auto& attrs = serverResource->getAttributes();
551
552             attrs[KEY] = attrs[KEY].get<int>() + 1;
553         }
554     }
555
556     static void withSetter(RCSResourceObject::Ptr serverResource, int count)
557     {
558         for (int i=0; i<count; ++i)
559         {
560             RCSResourceObject::LockGuard lock{ serverResource };
561
562             serverResource->setAttribute(KEY, serverResource->getAttribute<int>(KEY) + 1);
563         }
564     }
565 };
566
567 TEST_F(ResourceObjectSynchronizationTest, MultipleAccessToServerResource)
568 {
569     int expected { 0 };
570     vector<thread> threads;
571
572     server->setAttribute(KEY, 0);
573
574     for (int i = 20; i >= 0; --i) {
575         int count = 5000 + i * 100;
576         threads.push_back(thread { withLock, server, count });
577         expected += count;
578     }
579
580     for (int i = 20; i >= 0; --i) {
581         int count = 5000 + i * 100;
582         threads.push_back(thread { withSetter, server, count });
583         expected +=count;
584     }
585
586     for (auto& t : threads)
587     {
588         t.join();
589     }
590
591     ASSERT_EQ(expected, server->getAttribute<int>(KEY));
592 }
593
594 TEST_F(ResourceObjectSynchronizationTest, MultipleAccessToServerResourceWithRequests)
595 {
596     int expected { 0 };
597     vector<thread> threads;
598
599     mocks.OnCallFunc(OCPlatform::sendResponse).Return(OC_STACK_OK);
600
601     server->setAttribute(KEY, 0);
602
603     for (int i = 20; i >= 0; --i) {
604         int count = 5000 + i * 100;
605         threads.push_back(thread{ withLock, server, count });
606         expected += count;
607     }
608
609     for (int i = 20; i >= 0; --i) {
610         int count = 5000 + i * 100;
611         threads.push_back(thread{ withSetter, server, count });
612         expected +=count;
613     }
614
615     threads.push_back(thread{
616         [this]()
617         {
618             for (int i=0; i<10000; ++i)
619             {
620                 if (i % 5 == 0) handler(createRequest(OC_REST_OBSERVE));
621                 handler(createRequest((i & 1) ? OC_REST_GET : OC_REST_POST));
622             }
623         }
624     });
625
626     for (auto& t : threads)
627     {
628         t.join();
629     }
630
631     ASSERT_EQ(expected, server->getAttribute<int>(KEY));
632 }
633
634
635
636 class AttributeUpdatedListenerTest: public ResourceObjectHandlingRequestTest
637 {
638 public:
639     typedef OCStackResult (*SendResponse)(std::shared_ptr<OCResourceResponse>);
640
641 public:
642     OCRepresentation createOCRepresentation(void)
643     {
644         OCRepresentation ocRep;
645         ocRep[KEY] = VALUE;
646         return ocRep;
647     }
648
649 protected:
650     void SetUp()
651     {
652         ResourceObjectHandlingRequestTest::SetUp();
653         mocks.OnCallFunc(OCPlatform::sendResponse).Return(OC_STACK_OK);
654
655         server->setAttribute(KEY, 0);
656     }
657 };
658
659 class AttributeUpdatedListener
660 {
661 public:
662     virtual void onUpdated(const OIC::Service::RCSResourceAttributes::Value&,
663         const OIC::Service::RCSResourceAttributes::Value&)=0;
664
665     virtual ~AttributeUpdatedListener() {}
666 };
667
668
669 TEST_F(AttributeUpdatedListenerTest, RemoveListenerReturnsFalseIfListenerIsNotAdded)
670 {
671     ASSERT_FALSE(server->removeAttributeUpdatedListener(KEY));
672 }
673
674 TEST_F(AttributeUpdatedListenerTest, RemoveListenerReturnsTrueIfListenerIsAdded)
675 {
676     auto listener = mocks.Mock< AttributeUpdatedListener >();
677
678     server->addAttributeUpdatedListener(KEY,
679             std::bind(&AttributeUpdatedListener::onUpdated, listener, _1, _2));
680
681     ASSERT_TRUE(server->removeAttributeUpdatedListener(KEY));
682 }
683
684 TEST_F(AttributeUpdatedListenerTest, AddListenerRunsAddedFunction)
685 {
686     auto listener = mocks.Mock< AttributeUpdatedListener >();
687
688     server->addAttributeUpdatedListener(KEY,
689             std::bind(&AttributeUpdatedListener::onUpdated, listener, _1, _2));
690
691     mocks.ExpectCall(listener, AttributeUpdatedListener::onUpdated);
692
693     handler(createRequest(OC_REST_POST, createOCRepresentation()));
694 }
695
696 TEST_F(AttributeUpdatedListenerTest, ListenerWithSameKeyOverridesPreviousOne)
697 {
698     auto first = mocks.Mock< AttributeUpdatedListener >();
699     auto second = mocks.Mock< AttributeUpdatedListener >();
700
701     mocks.NeverCall(first, AttributeUpdatedListener::onUpdated);
702     mocks.ExpectCall(second, AttributeUpdatedListener::onUpdated);
703
704     server->addAttributeUpdatedListener(KEY,
705             std::bind(&AttributeUpdatedListener::onUpdated, first, _1, _2));
706     server->addAttributeUpdatedListener(KEY,
707             std::bind(&AttributeUpdatedListener::onUpdated, second, _1, _2));
708
709     handler(createRequest(OC_REST_POST, createOCRepresentation()));
710 }
711
712 TEST_F(AttributeUpdatedListenerTest, RemovedListenerNotBeInvoked)
713 {
714     auto listener = mocks.Mock< AttributeUpdatedListener >();
715     server->addAttributeUpdatedListener(KEY,
716             std::bind(&AttributeUpdatedListener::onUpdated, listener, _1, _2));
717
718     mocks.NeverCall(listener, AttributeUpdatedListener::onUpdated);
719
720     server->removeAttributeUpdatedListener(KEY);
721
722     handler(createRequest(OC_REST_POST, createOCRepresentation()));
723 }