Imported Upstream version 1.1.0
[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 #include "RCSRequest.h"
25 #include "RCSSeparateResponse.h"
26 #include "InterfaceHandler.h"
27 #include "ResourceAttributesConverter.h"
28
29 #include "OCPlatform.h"
30
31 using namespace std;
32 using namespace std::placeholders;
33
34 using namespace OIC::Service;
35 using namespace OC;
36
37 typedef OCStackResult (*registerResource)(OCResourceHandle&, string&, const string&, const string&,
38                            EntityHandler, uint8_t );
39
40 typedef OCStackResult (*NotifyAllObservers)(OCResourceHandle);
41
42 constexpr char RESOURCE_URI[]{ "a/test" };
43 constexpr char RESOURCE_TYPE[]{ "resourcetype" };
44 constexpr char KEY[]{ "key" };
45 constexpr char CUSTOM_INTERFACE[]{ "oic.if.custom" };
46 constexpr int VALUE{ 100 };
47
48 TEST(ResourceObjectBuilderCreateTest, ThrowIfUriIsInvalid)
49 {
50     ASSERT_THROW(RCSResourceObject::Builder("", "", "").build(), RCSPlatformException);
51 }
52
53 class ResourceObjectBuilderTest: public TestWithMock
54 {
55 protected:
56     void SetUp()
57     {
58         TestWithMock::SetUp();
59
60         mocks.OnCallFuncOverload(static_cast< registerResource >(OCPlatform::registerResource))
61                 .Return(OC_STACK_OK);
62     }
63 };
64
65 TEST_F(ResourceObjectBuilderTest, RegisterResourceWhenCallCreate)
66 {
67     mocks.ExpectCallFuncOverload(static_cast< registerResource >(OCPlatform::registerResource))
68             .Return(OC_STACK_OK);
69
70     RCSResourceObject::Builder(RESOURCE_URI, RESOURCE_TYPE, "").build();
71 }
72
73 TEST_F(ResourceObjectBuilderTest, ResourceServerHasPropertiesSetByBuilder)
74 {
75     auto serverResource = RCSResourceObject::Builder(RESOURCE_URI, RESOURCE_TYPE, "").
76             setDiscoverable(false).setObservable(true).build();
77
78     EXPECT_FALSE(serverResource->isDiscoverable());
79     EXPECT_TRUE(serverResource->isObservable());
80 }
81
82 TEST_F(ResourceObjectBuilderTest, ResourceServerHasAttrsSetByBuilder)
83 {
84     RCSResourceAttributes attrs;
85     attrs[KEY] = 100;
86
87     auto serverResource = RCSResourceObject::Builder(RESOURCE_URI, RESOURCE_TYPE, "").
88             setAttributes(attrs).build();
89
90     RCSResourceObject::LockGuard lock{ serverResource, RCSResourceObject::AutoNotifyPolicy::NEVER };
91     EXPECT_EQ(attrs, serverResource->getAttributes());
92 }
93
94 TEST_F(ResourceObjectBuilderTest, TypesAddedInBuilderWillBeBound)
95 {
96     int count = 0;
97     mocks.OnCallFunc(OCPlatform::bindTypeToResource).Do(
98             [&count](const OCResourceHandle&, const std::string&)
99             {
100                 ++count;
101                 return OC_STACK_OK;
102             }
103     );
104
105     auto serverResource = RCSResourceObject::Builder(RESOURCE_URI, RESOURCE_TYPE, "").
106             addType("1").addType("2").build();
107
108     EXPECT_EQ(2, count);
109 }
110
111 TEST_F(ResourceObjectBuilderTest, InterfaceAddedInBuilderWillBeBound)
112 {
113     int count = 0;
114     mocks.OnCallFunc(OCPlatform::bindInterfaceToResource).Do(
115             [&count](const OCResourceHandle&, const std::string&)
116             {
117                 ++count;
118                 return OC_STACK_OK;
119             }
120     );
121
122     auto serverResource = RCSResourceObject::Builder(RESOURCE_URI, RESOURCE_TYPE, "").
123             addInterface("1").addInterface("2").build();
124
125     EXPECT_EQ(2, count);
126 }
127
128 class ResourceObjectTest: public TestWithMock
129 {
130 public:
131     RCSResourceObject::Ptr server;
132
133 protected:
134     void SetUp()
135     {
136         TestWithMock::SetUp();
137
138         initMocks();
139
140         server = RCSResourceObject::Builder(RESOURCE_URI, RESOURCE_TYPE, "").build();
141
142         initResourceObject();
143     }
144
145     virtual void initMocks()
146     {
147         mocks.OnCallFuncOverload(static_cast< registerResource >(OCPlatform::registerResource)).
148                 Return(OC_STACK_OK);
149
150         mocks.OnCallFunc(OCPlatform::unregisterResource).Return(OC_STACK_OK);
151     }
152
153     virtual void initResourceObject() {
154         server->setAutoNotifyPolicy(RCSResourceObject::AutoNotifyPolicy::NEVER);
155     }
156 };
157
158 TEST_F(ResourceObjectTest, AccessAttributesWithLock)
159 {
160     {
161         RCSResourceObject::LockGuard lock{ server };
162         auto& attr = server->getAttributes();
163         attr[KEY] = VALUE;
164     }
165
166     ASSERT_EQ(VALUE, server->getAttribute<int>(KEY));
167 }
168
169 TEST_F(ResourceObjectTest, ThrowIfTryToAccessAttributesWithoutGuard)
170 {
171     ASSERT_THROW(server->getAttributes(), NoLockException);
172 }
173
174 TEST_F(ResourceObjectTest, SettingAttributesWithinGuardDoesntCauseDeadLock)
175 {
176     {
177         RCSResourceObject::LockGuard guard{ server };
178         server->setAttribute(KEY, VALUE);
179     }
180
181     ASSERT_EQ(VALUE, server->getAttribute<int>(KEY));
182 }
183
184 TEST_F(ResourceObjectTest, SettingNestedAttributesIsSameToGettingNestedAttributes)
185 {
186     RCSResourceAttributes lightAttributes;
187
188     lightAttributes["red"]=50;
189     lightAttributes["blue"]=100;
190     lightAttributes["green"]=150;
191
192     server->setAttribute(KEY, lightAttributes);
193
194     ASSERT_EQ(lightAttributes, server->getAttribute<RCSResourceAttributes>(KEY));
195 }
196
197 TEST_F(ResourceObjectTest, SettingNestedVectorAttributesIsSameToGettingNestedVectorAttributes)
198 {
199     vector<int> arr11 = {0,1}, arr12 = {4,5}, arr13 ={7,8};
200     vector<vector<int>> arr21 = { arr11, arr12 }, arr22 = { arr12, arr13 };
201     vector<vector<vector<int>>> arr31={ arr21, arr22 };
202
203     server->setAttribute(KEY, arr31);
204
205     ASSERT_EQ(arr31, server->getAttributeValue(KEY));
206 }
207
208 TEST_F(ResourceObjectTest, ThrowIfResourceToBindIsInvalid)
209 {
210     ASSERT_THROW(server->bindResource(server), RCSInvalidParameterException);
211 }
212
213 TEST_F(ResourceObjectTest, ThrowIfBindResourceFailed)
214 {
215     mocks.OnCallFunc(OCBindResource).Return(OC_STACK_ERROR);
216
217     ASSERT_THROW(server->bindResource(
218             RCSResourceObject::Builder("a/temp", RESOURCE_TYPE, "").build()), RCSPlatformException);
219 }
220
221 TEST_F(ResourceObjectTest, ThrowIfResourceToUnbindIsInvalid)
222 {
223     ASSERT_THROW(server->unbindResource(server), RCSInvalidParameterException);
224 }
225
226 TEST_F(ResourceObjectTest, BoundResourceCanBeRetrieved)
227 {
228     mocks.OnCallFunc(OCBindResource).Return(OC_STACK_OK);
229
230     auto boundResource = RCSResourceObject::Builder("a/temp", RESOURCE_TYPE, "").build();
231     server->bindResource(boundResource);
232
233     ASSERT_EQ(boundResource, server->getBoundResources()[0]);
234 }
235
236
237 class AutoNotifyTest: public ResourceObjectTest
238 {
239 protected:
240     void initMocks()
241     {
242         mocks.OnCallFuncOverload(static_cast< NotifyAllObservers >(
243                 OCPlatform::notifyAllObservers)).Return(OC_STACK_OK);
244     }
245
246     virtual void initResourceObject() {
247         // intended blank
248     }
249 };
250
251 TEST_F(AutoNotifyTest, DefalutAutoNotifyPolicyIsUpdated)
252 {
253     ASSERT_EQ(RCSResourceObject::AutoNotifyPolicy::UPDATED, server->getAutoNotifyPolicy());
254 }
255
256 TEST_F(AutoNotifyTest, AutoNotifyPolicyCanBeSet)
257 {
258     server->setAutoNotifyPolicy(RCSResourceObject::AutoNotifyPolicy::NEVER);
259
260     ASSERT_EQ(RCSResourceObject::AutoNotifyPolicy::NEVER, server->getAutoNotifyPolicy());
261 }
262
263 TEST_F(AutoNotifyTest, WithUpdatedPolicy_NeverBeNotifiedIfAttributeIsNotChanged)
264 {
265     server->setAutoNotifyPolicy(RCSResourceObject::AutoNotifyPolicy::UPDATED);
266     server->setAttribute(KEY, VALUE);
267
268     mocks.NeverCallFuncOverload(static_cast< NotifyAllObservers >(
269             OC::OCPlatform::notifyAllObservers));
270
271     server->setAttribute(KEY, VALUE);
272 }
273
274 TEST_F(AutoNotifyTest, WithUpdatedPolicy_WillBeNotifiedIfAttributeIsChanged)
275 {
276     server->setAutoNotifyPolicy(RCSResourceObject::AutoNotifyPolicy::UPDATED);
277     server->setAttribute(KEY, VALUE);
278
279     mocks.ExpectCallFuncOverload(static_cast< NotifyAllObservers >(
280             OC::OCPlatform::notifyAllObservers)).Return(OC_STACK_OK);
281
282     server->setAttribute(KEY, VALUE + 1);
283 }
284
285 TEST_F(AutoNotifyTest, WithUpdatedPolicy_WillBeNotifiedIfValueIsAdded)
286 {
287     constexpr char newKey[]{ "newKey" };
288     server->setAutoNotifyPolicy(RCSResourceObject::AutoNotifyPolicy::UPDATED);
289
290     mocks.ExpectCallFuncOverload(static_cast< NotifyAllObservers >(
291             OC::OCPlatform::notifyAllObservers)).Return(OC_STACK_OK);
292
293     server->setAttribute(newKey, VALUE);
294 }
295
296 TEST_F(AutoNotifyTest, WithNeverPolicy_NeverBeNotifiedEvenIfAttributeIsChanged)
297 {
298     server->setAutoNotifyPolicy(RCSResourceObject::AutoNotifyPolicy::NEVER);
299
300     mocks.NeverCallFuncOverload(static_cast< NotifyAllObservers >(
301             OC::OCPlatform::notifyAllObservers));
302
303     RCSResourceObject::LockGuard lock{ server };
304     server->setAttribute(KEY, VALUE);
305 }
306
307 TEST_F(AutoNotifyTest, WithUpdatePolicy_WillBeNotifiedIfAttributeIsDeleted)
308 {
309     server->setAutoNotifyPolicy(RCSResourceObject::AutoNotifyPolicy::UPDATED);
310     server->setAttribute(KEY, VALUE);
311
312     mocks.ExpectCallFuncOverload(static_cast< NotifyAllObservers >(
313             OC::OCPlatform::notifyAllObservers)).Return(OC_STACK_OK);
314
315     server->removeAttribute(KEY);
316 }
317
318 class AutoNotifyWithGuardTest: public AutoNotifyTest
319 {
320 };
321
322 TEST_F(AutoNotifyWithGuardTest, GuardFollowsServerPolicyByDefault)
323 {
324     server->setAutoNotifyPolicy(RCSResourceObject::AutoNotifyPolicy::UPDATED);
325
326     mocks.ExpectCallFuncOverload(static_cast< NotifyAllObservers >(
327             OC::OCPlatform::notifyAllObservers)).Return(OC_STACK_OK);
328
329     RCSResourceObject::LockGuard guard{ server };
330     server->setAttribute(KEY, VALUE);
331 }
332
333 TEST_F(AutoNotifyWithGuardTest, GuardCanOverridePolicy)
334 {
335     server->setAutoNotifyPolicy(RCSResourceObject::AutoNotifyPolicy::ALWAYS);
336
337     mocks.NeverCallFuncOverload(static_cast< NotifyAllObservers >(
338             OC::OCPlatform::notifyAllObservers));
339
340     RCSResourceObject::LockGuard guard{ server, RCSResourceObject::AutoNotifyPolicy::NEVER };
341     server->getAttributes()[KEY] = VALUE;
342 }
343
344 TEST_F(AutoNotifyWithGuardTest, GuardInvokesNotifyWhenDestroyed)
345 {
346     server->setAutoNotifyPolicy(RCSResourceObject::AutoNotifyPolicy::NEVER);
347
348     mocks.ExpectCallFuncOverload(static_cast< NotifyAllObservers >(
349             OC::OCPlatform::notifyAllObservers)).Return(OC_STACK_OK);
350
351     {
352         RCSResourceObject::LockGuard guard{ server, RCSResourceObject::AutoNotifyPolicy::ALWAYS };
353         server->setAttribute(KEY, VALUE);
354     }
355
356     mocks.NeverCallFuncOverload(static_cast< NotifyAllObservers >(
357                OC::OCPlatform::notifyAllObservers)).Return(OC_STACK_OK);
358
359     server->setAttribute(KEY, VALUE);
360 }
361
362 class ResourceObjectHandlingRequestTest: public ResourceObjectTest
363 {
364 public:
365     EntityHandler handler;
366
367     static constexpr OCRequestHandle fakeRequestHandle =
368             reinterpret_cast<OCRequestHandle>(0x1234);
369     static constexpr OCResourceHandle fakeResourceHandle =
370             reinterpret_cast<OCResourceHandle>(0x4321);
371
372 public:
373     OCResourceRequest::Ptr createRequest(OCMethod method = OC_REST_GET, OCRepresentation ocRep =
374             OCRepresentation{}, const string& interface="")
375     {
376         auto request = make_shared<OCResourceRequest>();
377
378         OCEntityHandlerRequest ocEntityHandlerRequest;
379         memset(&ocEntityHandlerRequest, 0, sizeof(OCEntityHandlerRequest));
380         OC::MessageContainer mc;
381
382         mc.addRepresentation(ocRep);
383
384         ocEntityHandlerRequest.requestHandle = fakeRequestHandle;
385         ocEntityHandlerRequest.resource = fakeResourceHandle;
386         ocEntityHandlerRequest.method = method;
387         ocEntityHandlerRequest.payload = reinterpret_cast<OCPayload*>(mc.getPayload());
388
389         if(!interface.empty())
390         {
391             const string query = string("if=" + interface);
392             ocEntityHandlerRequest.query = const_cast<char *> (query.c_str());
393         }
394
395         formResourceRequest(OC_REQUEST_FLAG, &ocEntityHandlerRequest, request);
396
397         return request;
398     }
399
400 protected:
401     OCStackResult registerResourceFake(OCResourceHandle&, string&, const string&,
402             const string&, EntityHandler handler, uint8_t)
403     {
404         this->handler = handler;
405         return OC_STACK_OK;
406     }
407
408     void initMocks()
409     {
410         mocks.OnCallFuncOverload(
411             static_cast<registerResource>(OCPlatform::registerResource)).Do(
412                     bind(&ResourceObjectHandlingRequestTest::registerResourceFake,
413                             this, _1, _2, _3, _4, _5, _6));
414         mocks.OnCallFunc(OCPlatform::unregisterResource).Return(OC_STACK_OK);
415     }
416 };
417
418 TEST_F(ResourceObjectHandlingRequestTest, CallSendResponseWhenReceiveRequest)
419 {
420     mocks.ExpectCallFunc(OCPlatform::sendResponse).Return(OC_STACK_OK);
421
422     ASSERT_EQ(OC_EH_OK, handler(createRequest()));
423 }
424
425 TEST_F(ResourceObjectHandlingRequestTest, ReturnErrorCodeWhenSendResponseFailed)
426 {
427     mocks.ExpectCallFunc(OCPlatform::sendResponse).Return(OC_STACK_ERROR);
428
429     ASSERT_EQ(OC_EH_ERROR, handler(createRequest()));
430 }
431
432 TEST_F(ResourceObjectHandlingRequestTest, SendResponseWithSameHandlesPassedByRequest)
433 {
434     mocks.ExpectCallFunc(OCPlatform::sendResponse).Match(
435             [](const shared_ptr<OCResourceResponse> response)
436             {
437                 return response->getRequestHandle() == fakeRequestHandle &&
438                         response->getResourceHandle() == fakeResourceHandle;
439             }
440     ).Return(OC_STACK_OK);
441
442     ASSERT_EQ(OC_EH_OK, handler(createRequest()));
443 }
444
445 TEST_F(ResourceObjectHandlingRequestTest, SendResponseWithRCSResponseResults)
446 {
447     constexpr int errorCode{ 1999 };
448
449     server->setGetRequestHandler(
450             [](const RCSRequest&, RCSResourceAttributes&) -> RCSGetResponse
451             {
452                 return RCSGetResponse::create(errorCode);
453             }
454     );
455
456     mocks.ExpectCallFunc(OCPlatform::sendResponse).Match(
457             [](const shared_ptr<OCResourceResponse> response)
458             {
459                 return response->getErrorCode() == errorCode;
460             }
461     ).Return(OC_STACK_OK);
462
463     ASSERT_EQ(OC_EH_OK, handler(createRequest()));
464 }
465
466 TEST_F(ResourceObjectHandlingRequestTest, SendSetResponseWithCustomAttrs)
467 {
468     constexpr int errorCode{ 1999 };
469     constexpr char value[]{ "VALUE" };
470
471     server->setSetRequestHandler(
472             [](const RCSRequest&, RCSResourceAttributes&) -> RCSSetResponse
473             {
474                 RCSResourceAttributes attrs;
475                 attrs[KEY] = value;
476                 return RCSSetResponse::create(attrs, errorCode);
477             }
478     );
479
480     mocks.ExpectCallFunc(OCPlatform::sendResponse).Match(
481             [](const shared_ptr<OCResourceResponse> response)
482             {
483                 return value == response->getResourceRepresentation()[KEY].getValue<std::string>()
484                         && response->getErrorCode() == errorCode;
485             }
486     ).Return(OC_STACK_OK);
487
488     ASSERT_EQ(OC_EH_OK, handler(createRequest(OC_REST_POST)));
489 }
490
491 TEST_F(ResourceObjectHandlingRequestTest, SeparateResponseIsSlowResponse)
492 {
493     server->setGetRequestHandler(
494             [](const RCSRequest&, RCSResourceAttributes&) -> RCSGetResponse
495             {
496                 return RCSGetResponse::separate();
497             }
498     );
499
500     ASSERT_EQ(OC_EH_SLOW, handler(createRequest()));
501 }
502
503 TEST_F(ResourceObjectHandlingRequestTest, SetMethodOfSeparateResponseInvokesSendResponse)
504 {
505     RCSRequest aRequest;
506     server->setGetRequestHandler(
507             [&aRequest](const RCSRequest& request, RCSResourceAttributes&) -> RCSGetResponse
508             {
509                 aRequest = request;
510                 return RCSGetResponse::separate();
511             }
512     );
513     handler(createRequest(OC_REST_GET));
514
515     mocks.ExpectCallFunc(OCPlatform::sendResponse).Return(OC_STACK_OK);
516
517     RCSSeparateResponse(aRequest).set();
518 }
519
520 TEST_F(ResourceObjectHandlingRequestTest, SetMethodOfSeparateResponseThrowsIfTheResourceIsDestroyed)
521 {
522     RCSRequest aRequest;
523     server->setGetRequestHandler(
524             [&aRequest](const RCSRequest& request, RCSResourceAttributes&) -> RCSGetResponse
525             {
526                 aRequest = request;
527                 return RCSGetResponse::separate();
528             }
529     );
530     handler(createRequest(OC_REST_GET));
531
532     RCSSeparateResponse resp(aRequest);
533
534     server.reset();
535
536     EXPECT_THROW(resp.set(), RCSBadRequestException);
537 }
538
539 static bool checkResponse(const OCRepresentation& ocRep, const RCSResourceAttributes& rcsAttr,
540             const std::vector<std::string>& interfaces,
541             const std::vector<std::string>& resourceTypes, const std::string& resourceUri)
542 {
543     return resourceUri == ocRep.getUri() &&
544            interfaces == ocRep.getResourceInterfaces() &&
545            resourceTypes == ocRep.getResourceTypes() &&
546            rcsAttr == ResourceAttributesConverter::fromOCRepresentation(ocRep);
547 }
548
549 static bool compareResponse(const OCRepresentation& ocRep1, const OCRepresentation& ocRep2)
550 {
551     return ocRep1.getUri() == ocRep2.getUri() &&
552            ocRep1.getResourceInterfaces() == ocRep2.getResourceInterfaces() &&
553            ocRep1.getResourceTypes() == ocRep2.getResourceTypes() &&
554            ResourceAttributesConverter::fromOCRepresentation(ocRep1) ==
555                    ResourceAttributesConverter::fromOCRepresentation(ocRep2);
556 }
557
558 class ResourceObjectInterfaceHandlerTest: public ResourceObjectHandlingRequestTest
559 {
560 public:
561     void initServer(vector<string> interfaces,
562                 const std::string& defaultInterface = BASELINE_INTERFACE)
563     {
564         auto initBuilder = RCSResourceObject::Builder(RESOURCE_URI, RESOURCE_TYPE,
565                 BASELINE_INTERFACE);
566
567         for(const auto& itf : interfaces)
568         {
569             initBuilder.addInterface(itf);
570         }
571
572         RCSResourceAttributes rcsAttr;
573         rcsAttr[KEY] = 2;
574         initBuilder.setAttributes(rcsAttr);
575         initBuilder.setDefaultInterface(defaultInterface);
576
577         server = initBuilder.build();
578         server->setAutoNotifyPolicy(RCSResourceObject::AutoNotifyPolicy::NEVER);
579         server->setSetRequestHandlerPolicy(RCSResourceObject::SetRequestHandlerPolicy::ACCEPTANCE);
580     }
581
582 protected:
583
584     void SetUp()
585     {
586         TestWithMock::SetUp();
587
588         initMocks();
589     }
590
591     void initMocks()
592     {
593         ResourceObjectHandlingRequestTest::initMocks();
594
595         mocks.OnCallFunc(OCPlatform::bindInterfaceToResource).Return(OC_STACK_OK);
596     }
597 };
598
599 TEST_F(ResourceObjectInterfaceHandlerTest, GetResponseForBaselineContainsAllPropertiesOfServer)
600 {
601     initServer({BASELINE_INTERFACE});
602
603     OCRepresentation ocRep;
604
605     mocks.ExpectCallFunc(OCPlatform::sendResponse).Match(
606             [=](const shared_ptr<OCResourceResponse> response)
607             {
608                 RCSResourceObject::LockGuard guard{ server };
609
610                 return checkResponse(response->getResourceRepresentation(),
611                         server->getAttributes(), server->getInterfaces(), server->getTypes(),
612                         server->getUri());
613
614             }
615     ).Return(OC_STACK_OK);
616
617     handler(createRequest(OC_REST_GET, ocRep, BASELINE_INTERFACE));
618 }
619
620 TEST_F(ResourceObjectInterfaceHandlerTest, SetResponseForActuatorContainsOnlyRequestedAttributes)
621 {
622     initServer({ACTUATOR_INTERFACE});
623
624     OCRepresentation ocRep;
625     ocRep[KEY] = VALUE;
626
627     mocks.ExpectCallFunc(OCPlatform::sendResponse).Match(
628             [&ocRep](const shared_ptr<OCResourceResponse> response)
629             {
630                 return checkResponse(response->getResourceRepresentation(),
631                         ResourceAttributesConverter::fromOCRepresentation(ocRep), {}, {}, "");
632             }
633     ).Return(OC_STACK_OK);
634
635     handler(createRequest(OC_REST_POST, ocRep, ACTUATOR_INTERFACE));
636 }
637
638 TEST_F(ResourceObjectInterfaceHandlerTest, SetResponseForBaselineContainsAppliedAttributes)
639 {
640     initServer({BASELINE_INTERFACE});
641
642     OCRepresentation ocRep;
643     ocRep["NEWKEY"] = std::string("NEWVALUE");
644
645     mocks.ExpectCallFunc(OCPlatform::sendResponse).Match(
646             [=](const shared_ptr<OCResourceResponse> response)
647             {
648                 RCSResourceObject::LockGuard guard{ server };
649
650                 return checkResponse(response->getResourceRepresentation(),
651                         server->getAttributes(), server->getInterfaces(), server->getTypes(),
652                         server->getUri());
653             }
654     ).Return(OC_STACK_OK);
655
656     handler(createRequest(OC_REST_POST, ocRep, BASELINE_INTERFACE));
657 }
658
659 TEST_F(ResourceObjectInterfaceHandlerTest, GetResponseForCustomEqualsResponseForDefault)
660 {
661     initServer({CUSTOM_INTERFACE});
662
663     OCRepresentation ocRep;
664     OCRepresentation repArray[2];
665     int cnt = 0;
666
667     mocks.OnCallFunc(OCPlatform::sendResponse).Do(
668             [&repArray, &cnt](const shared_ptr<OCResourceResponse> response)
669             {
670                 repArray[cnt++] = response->getResourceRepresentation();
671                 return OC_STACK_OK;
672             }
673     );
674
675     handler(createRequest(OC_REST_GET, ocRep, CUSTOM_INTERFACE));
676     handler(createRequest(OC_REST_GET, ocRep, server->getDefaultInterface()));
677
678     EXPECT_EQ(cnt, 2);
679     EXPECT_TRUE(compareResponse(repArray[0], repArray[1]));
680 }
681
682 TEST_F(ResourceObjectInterfaceHandlerTest, SetRequestForSensorGotNoHandler)
683 {
684     initServer({SENSOR_INTERFACE});
685
686     OCRepresentation ocRep;
687     ocRep[KEY] = VALUE;
688
689     EXPECT_EQ(OC_EH_ERROR, handler(createRequest(OC_REST_POST, ocRep, SENSOR_INTERFACE)));
690 }
691
692 TEST_F(ResourceObjectInterfaceHandlerTest, ThrowIfDefaultInterfaceIsInvalid)
693 {
694     auto builder = RCSResourceObject::Builder(RESOURCE_URI, RESOURCE_TYPE, BASELINE_INTERFACE);
695
696     ASSERT_THROW(builder.setDefaultInterface(ACTUATOR_INTERFACE), RCSBadRequestException);
697 }
698
699 TEST_F(ResourceObjectInterfaceHandlerTest, SettingDefaultInterfaceEqualsGetDefaultInterface)
700 {
701     initServer({SENSOR_INTERFACE}, BASELINE_INTERFACE);
702
703     EXPECT_EQ(BASELINE_INTERFACE, server->getDefaultInterface());
704 }
705
706
707
708 class SetRequestHandlerPolicyTest: public ResourceObjectHandlingRequestTest
709 {
710 public:
711     typedef OCStackResult (*SendResponse)(std::shared_ptr<OCResourceResponse>);
712
713 public:
714     OCRepresentation createOCRepresentation()
715     {
716         OCRepresentation ocRep;
717         ocRep[KEY] = VALUE;
718         return ocRep;
719     }
720
721     void initMocks()
722     {
723         ResourceObjectHandlingRequestTest::initMocks();
724         mocks.OnCallFunc(OCPlatform::sendResponse).Return(OC_STACK_OK);
725     }
726 };
727
728 TEST_F(SetRequestHandlerPolicyTest, DefalutSetRequestHandlerPolicyIsNever)
729 {
730     ASSERT_EQ(RCSResourceObject::SetRequestHandlerPolicy::NEVER,
731                 server->getSetRequestHandlerPolicy());
732 }
733
734 TEST_F(SetRequestHandlerPolicyTest, SetRequestHandlerPolicyCanBeSet)
735 {
736     server->setSetRequestHandlerPolicy(RCSResourceObject::SetRequestHandlerPolicy::ACCEPTANCE);
737
738     ASSERT_EQ(RCSResourceObject::SetRequestHandlerPolicy::ACCEPTANCE,
739                 server->getSetRequestHandlerPolicy());
740 }
741
742 TEST_F(SetRequestHandlerPolicyTest, WithNeverPolicy_DeniedIfKeyIsNew)
743 {
744     server->setSetRequestHandlerPolicy(RCSResourceObject::SetRequestHandlerPolicy::NEVER);
745
746     handler(createRequest(OC_REST_POST, createOCRepresentation()));
747
748     RCSResourceObject::LockGuard guard{ server };
749     ASSERT_FALSE(server->getAttributes().contains(KEY));
750 }
751
752 TEST_F(SetRequestHandlerPolicyTest, WithAcceptancePolicy_AcceptedEvenIfKeyIsNew)
753 {
754     server->setSetRequestHandlerPolicy(RCSResourceObject::SetRequestHandlerPolicy::ACCEPTANCE);
755
756     handler(createRequest(OC_REST_POST, createOCRepresentation()));
757
758     RCSResourceObject::LockGuard guard{ server };
759     ASSERT_TRUE(server->getAttributes().contains(KEY));
760 }
761
762
763
764 class ResourceObjectSynchronizationTest: public ResourceObjectHandlingRequestTest
765 {
766 public:
767
768     static void withLock(RCSResourceObject::Ptr serverResource, int count)
769     {
770         for (int i=0; i<count; ++i)
771         {
772             RCSResourceObject::LockGuard lock{ serverResource };
773
774             auto& attrs = serverResource->getAttributes();
775
776             attrs[KEY] = attrs[KEY].get<int>() + 1;
777         }
778     }
779
780     static void withSetter(RCSResourceObject::Ptr serverResource, int count)
781     {
782         for (int i=0; i<count; ++i)
783         {
784             RCSResourceObject::LockGuard lock{ serverResource };
785
786             serverResource->setAttribute(KEY, serverResource->getAttribute<int>(KEY) + 1);
787         }
788     }
789 };
790
791 TEST_F(ResourceObjectSynchronizationTest, MultipleAccessToServerResource)
792 {
793     int expected { 0 };
794     vector<thread> threads;
795
796     server->setAttribute(KEY, 0);
797
798     for (int i = 20; i >= 0; --i) {
799         int count = 5000 + i * 100;
800         threads.push_back(thread { withLock, server, count });
801         expected += count;
802     }
803
804     for (int i = 20; i >= 0; --i) {
805         int count = 5000 + i * 100;
806         threads.push_back(thread { withSetter, server, count });
807         expected +=count;
808     }
809
810     for (auto& t : threads)
811     {
812         t.join();
813     }
814
815     ASSERT_EQ(expected, server->getAttribute<int>(KEY));
816 }
817
818 TEST_F(ResourceObjectSynchronizationTest, MultipleAccessToServerResourceWithRequests)
819 {
820     int expected { 0 };
821     vector<thread> threads;
822
823     mocks.OnCallFunc(OCPlatform::sendResponse).Return(OC_STACK_OK);
824
825     server->setAttribute(KEY, 0);
826
827     for (int i = 20; i >= 0; --i) {
828         int count = 5000 + i * 100;
829         threads.push_back(thread{ withLock, server, count });
830         expected += count;
831     }
832
833     for (int i = 20; i >= 0; --i) {
834         int count = 5000 + i * 100;
835         threads.push_back(thread{ withSetter, server, count });
836         expected +=count;
837     }
838
839     threads.push_back(thread{
840         [this]()
841         {
842             for (int i=0; i<10000; ++i)
843             {
844                 if (i % 5 == 0) handler(createRequest(OC_REST_OBSERVE));
845                 handler(createRequest((i & 1) ? OC_REST_GET : OC_REST_POST));
846             }
847         }
848     });
849
850     for (auto& t : threads)
851     {
852         t.join();
853     }
854
855     ASSERT_EQ(expected, server->getAttribute<int>(KEY));
856 }
857
858
859
860 class AttributeUpdatedListenerTest: public ResourceObjectHandlingRequestTest
861 {
862 public:
863     typedef OCStackResult (*SendResponse)(std::shared_ptr<OCResourceResponse>);
864
865 public:
866     OCRepresentation createOCRepresentation(void)
867     {
868         OCRepresentation ocRep;
869         ocRep[KEY] = VALUE;
870         return ocRep;
871     }
872
873 protected:
874     void SetUp()
875     {
876         ResourceObjectHandlingRequestTest::SetUp();
877         mocks.OnCallFunc(OCPlatform::sendResponse).Return(OC_STACK_OK);
878
879         server->setAttribute(KEY, 0);
880     }
881 };
882
883 class AttributeUpdatedListener
884 {
885 public:
886     virtual void onUpdated(const OIC::Service::RCSResourceAttributes::Value&,
887         const OIC::Service::RCSResourceAttributes::Value&)=0;
888
889     virtual ~AttributeUpdatedListener() {}
890 };
891
892
893 TEST_F(AttributeUpdatedListenerTest, RemoveListenerReturnsFalseIfListenerIsNotAdded)
894 {
895     ASSERT_FALSE(server->removeAttributeUpdatedListener(KEY));
896 }
897
898 TEST_F(AttributeUpdatedListenerTest, RemoveListenerReturnsTrueIfListenerIsAdded)
899 {
900     auto listener = mocks.Mock< AttributeUpdatedListener >();
901
902     server->addAttributeUpdatedListener(KEY,
903             std::bind(&AttributeUpdatedListener::onUpdated, listener, _1, _2));
904
905     ASSERT_TRUE(server->removeAttributeUpdatedListener(KEY));
906 }
907
908 TEST_F(AttributeUpdatedListenerTest, AddListenerRunsAddedFunction)
909 {
910     auto listener = mocks.Mock< AttributeUpdatedListener >();
911
912     server->addAttributeUpdatedListener(KEY,
913             std::bind(&AttributeUpdatedListener::onUpdated, listener, _1, _2));
914
915     mocks.ExpectCall(listener, AttributeUpdatedListener::onUpdated);
916
917     handler(createRequest(OC_REST_POST, createOCRepresentation()));
918 }
919
920 TEST_F(AttributeUpdatedListenerTest, ListenerWithSameKeyOverridesPreviousOne)
921 {
922     auto first = mocks.Mock< AttributeUpdatedListener >();
923     auto second = mocks.Mock< AttributeUpdatedListener >();
924
925     mocks.NeverCall(first, AttributeUpdatedListener::onUpdated);
926     mocks.ExpectCall(second, AttributeUpdatedListener::onUpdated);
927
928     server->addAttributeUpdatedListener(KEY,
929             std::bind(&AttributeUpdatedListener::onUpdated, first, _1, _2));
930     server->addAttributeUpdatedListener(KEY,
931             std::bind(&AttributeUpdatedListener::onUpdated, second, _1, _2));
932
933     handler(createRequest(OC_REST_POST, createOCRepresentation()));
934 }
935
936 TEST_F(AttributeUpdatedListenerTest, RemovedListenerNotBeInvoked)
937 {
938     auto listener = mocks.Mock< AttributeUpdatedListener >();
939     server->addAttributeUpdatedListener(KEY,
940             std::bind(&AttributeUpdatedListener::onUpdated, listener, _1, _2));
941
942     mocks.NeverCall(listener, AttributeUpdatedListener::onUpdated);
943
944     server->removeAttributeUpdatedListener(KEY);
945
946     handler(createRequest(OC_REST_POST, createOCRepresentation()));
947 }