1 //******************************************************************
3 // Copyright 2015 Samsung Electronics All Rights Reserved.
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
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
11 // http://www.apache.org/licenses/LICENSE-2.0
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.
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
21 #include <UnitTestHelper.h>
23 #include <RCSResourceObject.h>
25 #include <OCPlatform.h>
28 using namespace std::placeholders;
30 using namespace OIC::Service;
33 typedef OCStackResult (*registerResource)(OCResourceHandle&, string&, const string&, const string&,
34 EntityHandler, uint8_t );
36 typedef OCStackResult (*NotifyAllObservers)(OCResourceHandle);
38 constexpr char RESOURCE_URI[]{ "a/test" };
39 constexpr char RESOURCE_TYPE[]{ "resourcetype" };
40 constexpr char KEY[]{ "key" };
41 constexpr int value{ 100 };
43 TEST(ResourceObjectBuilderCreateTest, ThrowIfUriIsInvalid)
45 ASSERT_THROW(RCSResourceObject::Builder("", "", "").build(), RCSPlatformException);
48 class ResourceObjectBuilderTest: public TestWithMock
53 TestWithMock::SetUp();
55 mocks.OnCallFuncOverload(static_cast< registerResource >(OCPlatform::registerResource))
60 TEST_F(ResourceObjectBuilderTest, RegisterResourceWhenCallCreate)
62 mocks.ExpectCallFuncOverload(static_cast< registerResource >(OCPlatform::registerResource))
65 RCSResourceObject::Builder(RESOURCE_URI, RESOURCE_TYPE, "").build();
68 TEST_F(ResourceObjectBuilderTest, ResourceServerHasPropertiesSetByBuilder)
70 auto serverResource = RCSResourceObject::Builder(RESOURCE_URI, RESOURCE_TYPE, "").
71 setDiscoverable(false).setObservable(true).build();
73 EXPECT_FALSE(serverResource->isDiscoverable());
74 EXPECT_TRUE(serverResource->isObservable());
77 TEST_F(ResourceObjectBuilderTest, ResourceServerHasAttrsSetByBuilder)
79 RCSResourceAttributes attrs;
82 auto serverResource = RCSResourceObject::Builder(RESOURCE_URI, RESOURCE_TYPE, "").
83 setAttributes(attrs).build();
85 RCSResourceObject::LockGuard lock{ serverResource, RCSResourceObject::AutoNotifyPolicy::NEVER };
86 EXPECT_EQ(attrs, serverResource->getAttributes());
90 class ResourceObjectTest: public TestWithMock
93 RCSResourceObject::Ptr server;
98 TestWithMock::SetUp();
102 server = RCSResourceObject::Builder(RESOURCE_URI, RESOURCE_TYPE, "").build();
104 initResourceObject();
107 virtual void initMocks()
109 mocks.OnCallFuncOverload(static_cast< registerResource >(OCPlatform::registerResource)).
112 mocks.OnCallFunc(OCPlatform::unregisterResource).Return(OC_STACK_OK);
115 virtual void initResourceObject() {
116 server->setAutoNotifyPolicy(RCSResourceObject::AutoNotifyPolicy::NEVER);
120 TEST_F(ResourceObjectTest, AccessAttributesWithLock)
123 RCSResourceObject::LockGuard lock{ server };
124 auto& attr = server->getAttributes();
128 ASSERT_EQ(value, server->getAttribute<int>(KEY));
131 TEST_F(ResourceObjectTest, ThrowIfTryToAccessAttributesWithoutGuard)
133 ASSERT_THROW(server->getAttributes(), NoLockException);
136 TEST_F(ResourceObjectTest, SettingAttributesWithinGuardDoesntCauseDeadLock)
139 RCSResourceObject::LockGuard guard{ server };
140 server->setAttribute(KEY, value);
143 ASSERT_EQ(value, server->getAttribute<int>(KEY));
146 TEST_F(ResourceObjectTest, SettingNestedAttributesIsSameToGettingNestedAttributes)
148 RCSResourceAttributes lightAttributes;
150 lightAttributes["red"]=50;
151 lightAttributes["blue"]=100;
152 lightAttributes["green"]=150;
154 server->setAttribute(KEY, lightAttributes);
156 ASSERT_EQ(lightAttributes, server->getAttribute<RCSResourceAttributes>(KEY));
159 TEST_F(ResourceObjectTest, SettingNestedVectorAttributesIsSameToGettingNestedVectorAttributes)
161 vector<int> arr11 = {0,1}, arr12 = {4,5}, arr13 ={7,8};
162 vector<vector<int>> arr21 = { arr11, arr12 }, arr22 = { arr12, arr13 };
163 vector<vector<vector<int>>> arr31={ arr21, arr22 };
165 server->setAttribute(KEY, arr31);
167 ASSERT_EQ(arr31, server->getAttribute<vector<vector<vector<int>>>>(KEY));
171 class AutoNotifyTest: public ResourceObjectTest
176 mocks.OnCallFuncOverload(static_cast< NotifyAllObservers >(
177 OCPlatform::notifyAllObservers)).Return(OC_STACK_OK);
180 virtual void initResourceObject() {
185 TEST_F(AutoNotifyTest, DefalutAutoNotifyPolicyIsUpdated)
187 ASSERT_EQ(RCSResourceObject::AutoNotifyPolicy::UPDATED, server->getAutoNotifyPolicy());
190 TEST_F(AutoNotifyTest, AutoNotifyPolicyCanBeSet)
192 server->setAutoNotifyPolicy(RCSResourceObject::AutoNotifyPolicy::NEVER);
194 ASSERT_EQ(RCSResourceObject::AutoNotifyPolicy::NEVER, server->getAutoNotifyPolicy());
197 TEST_F(AutoNotifyTest, WithUpdatedPolicy_NeverBeNotifiedIfAttributeIsNotChanged)
199 server->setAutoNotifyPolicy(RCSResourceObject::AutoNotifyPolicy::UPDATED);
200 server->setAttribute(KEY, value);
202 mocks.NeverCallFuncOverload(static_cast< NotifyAllObservers >(
203 OC::OCPlatform::notifyAllObservers));
205 server->setAttribute(KEY, value);
208 TEST_F(AutoNotifyTest, WithUpdatedPolicy_WillBeNotifiedIfAttributeIsChanged)
210 server->setAutoNotifyPolicy(RCSResourceObject::AutoNotifyPolicy::UPDATED);
211 server->setAttribute(KEY, value);
213 mocks.ExpectCallFuncOverload(static_cast< NotifyAllObservers >(
214 OC::OCPlatform::notifyAllObservers)).Return(OC_STACK_OK);
216 server->setAttribute(KEY, value + 1);
219 TEST_F(AutoNotifyTest, WithUpdatedPolicy_WillBeNotifiedIfValueIsAdded)
221 constexpr char newKey[]{ "newKey" };
222 server->setAutoNotifyPolicy(RCSResourceObject::AutoNotifyPolicy::UPDATED);
224 mocks.ExpectCallFuncOverload(static_cast< NotifyAllObservers >(
225 OC::OCPlatform::notifyAllObservers)).Return(OC_STACK_OK);
227 server->setAttribute(newKey, value);
230 TEST_F(AutoNotifyTest, WithNeverPolicy_NeverBeNotifiedEvenIfAttributeIsChanged)
232 server->setAutoNotifyPolicy(RCSResourceObject::AutoNotifyPolicy::NEVER);
234 mocks.NeverCallFuncOverload(static_cast< NotifyAllObservers >(
235 OC::OCPlatform::notifyAllObservers));
237 RCSResourceObject::LockGuard lock{ server };
238 server->setAttribute(KEY, value);
241 TEST_F(AutoNotifyTest, WithUpdatePolicy_WillBeNotifiedIfAttributeIsDeleted)
243 server->setAutoNotifyPolicy(RCSResourceObject::AutoNotifyPolicy::UPDATED);
244 server->setAttribute(KEY, value);
246 mocks.ExpectCallFuncOverload(static_cast< NotifyAllObservers >(
247 OC::OCPlatform::notifyAllObservers)).Return(OC_STACK_OK);
249 server->removeAttribute(KEY);
252 class AutoNotifyWithGuardTest: public AutoNotifyTest
256 TEST_F(AutoNotifyWithGuardTest, GuardFollowsServerPolicyByDefault)
258 server->setAutoNotifyPolicy(RCSResourceObject::AutoNotifyPolicy::UPDATED);
260 mocks.ExpectCallFuncOverload(static_cast< NotifyAllObservers >(
261 OC::OCPlatform::notifyAllObservers)).Return(OC_STACK_OK);
263 RCSResourceObject::LockGuard guard{ server };
264 server->setAttribute(KEY, value);
267 TEST_F(AutoNotifyWithGuardTest, GuardCanOverridePolicy)
269 server->setAutoNotifyPolicy(RCSResourceObject::AutoNotifyPolicy::ALWAYS);
271 mocks.NeverCallFuncOverload(static_cast< NotifyAllObservers >(
272 OC::OCPlatform::notifyAllObservers));
274 RCSResourceObject::LockGuard guard{ server, RCSResourceObject::AutoNotifyPolicy::NEVER };
275 server->getAttributes()[KEY] = value;
278 TEST_F(AutoNotifyWithGuardTest, GuardInvokesNotifyWhenDestroyed)
280 server->setAutoNotifyPolicy(RCSResourceObject::AutoNotifyPolicy::NEVER);
282 mocks.ExpectCallFuncOverload(static_cast< NotifyAllObservers >(
283 OC::OCPlatform::notifyAllObservers)).Return(OC_STACK_OK);
286 RCSResourceObject::LockGuard guard{ server, RCSResourceObject::AutoNotifyPolicy::ALWAYS };
287 server->setAttribute(KEY, value);
290 mocks.NeverCallFuncOverload(static_cast< NotifyAllObservers >(
291 OC::OCPlatform::notifyAllObservers)).Return(OC_STACK_OK);
293 server->setAttribute(KEY, value);
298 class ResourceObjectHandlingRequestTest: public ResourceObjectTest
301 EntityHandler handler;
303 static constexpr OCRequestHandle fakeRequestHandle =
304 reinterpret_cast<OCRequestHandle>(0x1234);
305 static constexpr OCResourceHandle fakeResourceHandle =
306 reinterpret_cast<OCResourceHandle>(0x4321);
309 OCResourceRequest::Ptr createRequest(OCMethod method = OC_REST_GET, OCRepresentation ocRep =
312 auto request = make_shared<OCResourceRequest>();
314 OCEntityHandlerRequest ocEntityHandlerRequest;
315 memset(&ocEntityHandlerRequest, 0, sizeof(OCEntityHandlerRequest));
316 OC::MessageContainer mc;
318 mc.addRepresentation(ocRep);
320 ocEntityHandlerRequest.requestHandle = fakeRequestHandle;
321 ocEntityHandlerRequest.resource = fakeResourceHandle;
322 ocEntityHandlerRequest.method = method;
323 ocEntityHandlerRequest.payload = reinterpret_cast<OCPayload*>(mc.getPayload());
325 formResourceRequest(OC_REQUEST_FLAG, &ocEntityHandlerRequest, request);
331 OCStackResult registerResourceFake(OCResourceHandle&, string&, const string&,
332 const string&, EntityHandler handler, uint8_t)
334 this->handler = handler;
340 mocks.OnCallFuncOverload(
341 static_cast<registerResource>(OCPlatform::registerResource)).Do(
342 bind(&ResourceObjectHandlingRequestTest::registerResourceFake,
343 this, _1, _2, _3, _4, _5, _6));
344 mocks.OnCallFunc(OCPlatform::unregisterResource).Return(OC_STACK_OK);
348 TEST_F(ResourceObjectHandlingRequestTest, CallSendResponseWhenReceiveRequest)
350 mocks.ExpectCallFunc(OCPlatform::sendResponse).Return(OC_STACK_OK);
352 ASSERT_EQ(OC_EH_OK, handler(createRequest()));
355 TEST_F(ResourceObjectHandlingRequestTest, ReturnErrorCodeWhenSendResponseFailed)
357 mocks.ExpectCallFunc(OCPlatform::sendResponse).Return(OC_STACK_ERROR);
359 ASSERT_EQ(OC_EH_ERROR, handler(createRequest()));
362 TEST_F(ResourceObjectHandlingRequestTest, SendResponseWithSameHandlesPassedByRequest)
364 mocks.ExpectCallFunc(OCPlatform::sendResponse).Match(
365 [](const shared_ptr<OCResourceResponse> response)
367 return response->getRequestHandle() == fakeRequestHandle &&
368 response->getResourceHandle() == fakeResourceHandle;
370 ).Return(OC_STACK_OK);
372 ASSERT_EQ(OC_EH_OK, handler(createRequest()));
375 TEST_F(ResourceObjectHandlingRequestTest, SendResponseWithRCSResponseResults)
377 constexpr int errorCode{ 1999 };
379 server->setGetRequestHandler(
380 [](const RCSRequest&, RCSResourceAttributes&) -> RCSGetResponse
382 return RCSGetResponse::create(errorCode);
386 mocks.ExpectCallFunc(OCPlatform::sendResponse).Match(
387 [](const shared_ptr<OCResourceResponse> response)
389 return response->getErrorCode() == errorCode;
391 ).Return(OC_STACK_OK);
393 ASSERT_EQ(OC_EH_OK, handler(createRequest()));
396 TEST_F(ResourceObjectHandlingRequestTest, SendSetResponseWithCustomAttrs)
398 constexpr int errorCode{ 1999 };
399 constexpr char value[]{ "value" };
401 server->setSetRequestHandler(
402 [](const RCSRequest&, RCSResourceAttributes&) -> RCSSetResponse
404 RCSResourceAttributes attrs;
406 return RCSSetResponse::create(attrs, errorCode);
410 mocks.ExpectCallFunc(OCPlatform::sendResponse).Match(
411 [](const shared_ptr<OCResourceResponse> response)
413 return value == response->getResourceRepresentation()[KEY].getValue<std::string>()
414 && response->getErrorCode() == errorCode;
416 ).Return(OC_STACK_OK);
418 ASSERT_EQ(OC_EH_OK, handler(createRequest(OC_REST_PUT)));
422 class SetRequestHandlerPolicyTest: public ResourceObjectHandlingRequestTest
425 typedef OCStackResult (*SendResponse)(std::shared_ptr<OCResourceResponse>);
428 OCRepresentation createOCRepresentation()
430 OCRepresentation ocRep;
432 vector<string> interface{"oic.if.baseline"};
433 vector<string> type{"core.light"};
435 ocRep.setUri(RESOURCE_URI);
436 ocRep.setResourceInterfaces(interface);
437 ocRep.setResourceTypes(type);
444 ResourceObjectHandlingRequestTest::initMocks();
445 mocks.OnCallFunc(OCPlatform::sendResponse).Return(OC_STACK_OK);
449 TEST_F(SetRequestHandlerPolicyTest, DefalutSetRequestHandlerPolicyIsNever)
451 ASSERT_EQ(RCSResourceObject::SetRequestHandlerPolicy::NEVER,
452 server->getSetRequestHandlerPolicy());
455 TEST_F(SetRequestHandlerPolicyTest, SetRequestHandlerPolicyCanBeSet)
457 server->setSetRequestHandlerPolicy(RCSResourceObject::SetRequestHandlerPolicy::ACCEPTANCE);
459 ASSERT_EQ(RCSResourceObject::SetRequestHandlerPolicy::ACCEPTANCE,
460 server->getSetRequestHandlerPolicy());
463 TEST_F(SetRequestHandlerPolicyTest, WithNeverPolicy_NotAddedIfReceivedNewKeyValuePair)
465 OCRepresentation ocRep = createOCRepresentation();
466 ocRep.setValue("NewKey", value);
467 server->setSetRequestHandlerPolicy(RCSResourceObject::SetRequestHandlerPolicy::NEVER);
469 handler(createRequest(OC_REST_PUT, ocRep));
471 RCSResourceObject::LockGuard guard{ server };
472 ASSERT_FALSE((server->getAttributes()).contains("NewKey"));
475 TEST_F(SetRequestHandlerPolicyTest, WithAcceptancePolicy_WillBeAddedIfReceivedNewKeyValuePair)
477 OCRepresentation ocRep = createOCRepresentation();
478 ocRep.setValue("NewKey", value);
479 server->setSetRequestHandlerPolicy(RCSResourceObject::SetRequestHandlerPolicy::ACCEPTANCE);
481 handler(createRequest(OC_REST_PUT, ocRep));
483 RCSResourceObject::LockGuard guard{ server };
484 ASSERT_TRUE((server->getAttributes()).contains("NewKey"));
488 class ResourceObjectSynchronizationTest: public ResourceObjectHandlingRequestTest
492 static void withLock(RCSResourceObject::Ptr serverResource, int count)
494 for (int i=0; i<count; ++i)
496 RCSResourceObject::LockGuard lock{ serverResource };
498 auto& attrs = serverResource->getAttributes();
500 attrs[KEY] = attrs[KEY].get<int>() + 1;
504 static void withSetter(RCSResourceObject::Ptr serverResource, int count)
506 for (int i=0; i<count; ++i)
508 RCSResourceObject::LockGuard lock{ serverResource };
510 serverResource->setAttribute(KEY, serverResource->getAttribute<int>(KEY) + 1);
515 TEST_F(ResourceObjectSynchronizationTest, MultipleAccessToServerResource)
518 vector<thread> threads;
520 server->setAttribute(KEY, 0);
522 for (int i = 20; i >= 0; --i) {
523 int count = 5000 + i * 100;
524 threads.push_back(thread { withLock, server, count });
528 for (int i = 20; i >= 0; --i) {
529 int count = 5000 + i * 100;
530 threads.push_back(thread { withSetter, server, count });
534 for (auto& t : threads)
539 ASSERT_EQ(expected, server->getAttribute<int>(KEY));
542 TEST_F(ResourceObjectSynchronizationTest, MultipleAccessToServerResourceWithRequests)
545 vector<thread> threads;
547 mocks.OnCallFunc(OCPlatform::sendResponse).Return(OC_STACK_OK);
549 server->setAttribute(KEY, 0);
551 for (int i = 20; i >= 0; --i) {
552 int count = 5000 + i * 100;
553 threads.push_back(thread{ withLock, server, count });
557 for (int i = 20; i >= 0; --i) {
558 int count = 5000 + i * 100;
559 threads.push_back(thread{ withSetter, server, count });
563 threads.push_back(thread{
566 for (int i=0; i<10000; ++i)
568 if (i % 5 == 0) handler(createRequest(OC_REST_OBSERVE));
569 handler(createRequest((i & 1) ? OC_REST_GET : OC_REST_PUT));
574 for (auto& t : threads)
579 ASSERT_EQ(expected, server->getAttribute<int>(KEY));
583 class AttributeUpdatedListenerTest: public ResourceObjectHandlingRequestTest
586 typedef OCStackResult (*SendResponse)(std::shared_ptr<OCResourceResponse>);
589 OCRepresentation createOCRepresentation(void)
591 OCRepresentation ocRep;
593 vector<string> interface{"oic.if.baseline"};
594 vector<string> type{"core.light"};
596 ocRep.setUri(RESOURCE_URI);
597 ocRep.setResourceInterfaces(interface);
598 ocRep.setResourceTypes(type);
606 ResourceObjectHandlingRequestTest::initMocks();
607 mocks.OnCallFunc(OCPlatform::sendResponse).Return(OC_STACK_OK);
611 class FunctionsForAttributeUpdatedListener
614 virtual void fCalled(const OIC::Service::RCSResourceAttributes::Value&,
615 const OIC::Service::RCSResourceAttributes::Value&)=0;
616 virtual void fNotCalled(const OIC::Service::RCSResourceAttributes::Value&,
617 const OIC::Service::RCSResourceAttributes::Value&)=0;
620 TEST_F(AttributeUpdatedListenerTest, AddListenerRunsAddedFunction)
622 FunctionsForAttributeUpdatedListener *ptrMock =
623 mocks.Mock<FunctionsForAttributeUpdatedListener>();
625 server->setAttribute(KEY, 0);
627 mocks.ExpectCall(ptrMock, FunctionsForAttributeUpdatedListener::fCalled);
629 server->addAttributeUpdatedListener(KEY,
630 (std::bind(&FunctionsForAttributeUpdatedListener::fCalled, ptrMock, _1, _2)));
632 handler(createRequest(OC_REST_PUT, createOCRepresentation()));
635 TEST_F(AttributeUpdatedListenerTest, AddListenerRunsAccordingToLastAddedFunction)
637 FunctionsForAttributeUpdatedListener *ptrMock =
638 mocks.Mock<FunctionsForAttributeUpdatedListener>();
640 string duplicateKEY(KEY);
641 server->setAttribute(KEY, 0);
643 mocks.ExpectCall(ptrMock, FunctionsForAttributeUpdatedListener::fCalled);
644 mocks.NeverCall(ptrMock, FunctionsForAttributeUpdatedListener::fNotCalled);
646 server->addAttributeUpdatedListener(duplicateKEY,
647 (std::bind(&FunctionsForAttributeUpdatedListener::fNotCalled, ptrMock, _1, _2)));
648 server->addAttributeUpdatedListener(KEY,
649 (std::bind(&FunctionsForAttributeUpdatedListener::fCalled, ptrMock, _1, _2)));
651 handler(createRequest(OC_REST_PUT, createOCRepresentation()));
654 TEST_F(AttributeUpdatedListenerTest, RemoveListenerReturnsTrueIfListenerIsNotAdded)
656 ASSERT_FALSE(server->removeAttributeUpdatedListener(KEY));
659 TEST_F(AttributeUpdatedListenerTest, RemoveListenerReturnsTrueIfListenerIsAdded)
661 FunctionsForAttributeUpdatedListener *ptrMock =
662 mocks.Mock<FunctionsForAttributeUpdatedListener>();
664 server->addAttributeUpdatedListener(KEY,
665 (std::bind(&FunctionsForAttributeUpdatedListener::fNotCalled, ptrMock, _1, _2)));
667 ASSERT_TRUE(server->removeAttributeUpdatedListener(KEY));
670 TEST_F(AttributeUpdatedListenerTest, RemoveListenerNeverRunsRemovedFunc)
672 FunctionsForAttributeUpdatedListener *ptrMock =
673 mocks.Mock<FunctionsForAttributeUpdatedListener>();
675 mocks.NeverCall(ptrMock, FunctionsForAttributeUpdatedListener::fNotCalled);
677 server->setAttribute(KEY, 0);
678 server->addAttributeUpdatedListener(KEY,
679 (std::bind(&FunctionsForAttributeUpdatedListener::fNotCalled, ptrMock, _1, _2)));
680 server->removeAttributeUpdatedListener(KEY);
682 handler(createRequest(OC_REST_PUT, createOCRepresentation()));