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());
89 TEST_F(ResourceObjectBuilderTest, TypesAddedInBuilderWillBeBound)
92 mocks.OnCallFunc(OCPlatform::bindTypeToResource).Do(
93 [&count](const OCResourceHandle&, const std::string&)
100 auto serverResource = RCSResourceObject::Builder(RESOURCE_URI, RESOURCE_TYPE, "").
101 addType("1").addType("2").build();
106 TEST_F(ResourceObjectBuilderTest, InterfaceAddedInBuilderWillBeBound)
109 mocks.OnCallFunc(OCPlatform::bindInterfaceToResource).Do(
110 [&count](const OCResourceHandle&, const std::string&)
117 auto serverResource = RCSResourceObject::Builder(RESOURCE_URI, RESOURCE_TYPE, "").
118 addInterface("1").addInterface("2").build();
123 class ResourceObjectTest: public TestWithMock
126 RCSResourceObject::Ptr server;
131 TestWithMock::SetUp();
135 server = RCSResourceObject::Builder(RESOURCE_URI, RESOURCE_TYPE, "").build();
137 initResourceObject();
140 virtual void initMocks()
142 mocks.OnCallFuncOverload(static_cast< registerResource >(OCPlatform::registerResource)).
145 mocks.OnCallFunc(OCPlatform::unregisterResource).Return(OC_STACK_OK);
148 virtual void initResourceObject() {
149 server->setAutoNotifyPolicy(RCSResourceObject::AutoNotifyPolicy::NEVER);
153 TEST_F(ResourceObjectTest, AccessAttributesWithLock)
156 RCSResourceObject::LockGuard lock{ server };
157 auto& attr = server->getAttributes();
161 ASSERT_EQ(VALUE, server->getAttribute<int>(KEY));
164 TEST_F(ResourceObjectTest, ThrowIfTryToAccessAttributesWithoutGuard)
166 ASSERT_THROW(server->getAttributes(), NoLockException);
169 TEST_F(ResourceObjectTest, SettingAttributesWithinGuardDoesntCauseDeadLock)
172 RCSResourceObject::LockGuard guard{ server };
173 server->setAttribute(KEY, VALUE);
176 ASSERT_EQ(VALUE, server->getAttribute<int>(KEY));
179 TEST_F(ResourceObjectTest, SettingNestedAttributesIsSameToGettingNestedAttributes)
181 RCSResourceAttributes lightAttributes;
183 lightAttributes["red"]=50;
184 lightAttributes["blue"]=100;
185 lightAttributes["green"]=150;
187 server->setAttribute(KEY, lightAttributes);
189 ASSERT_EQ(lightAttributes, server->getAttribute<RCSResourceAttributes>(KEY));
192 TEST_F(ResourceObjectTest, SettingNestedVectorAttributesIsSameToGettingNestedVectorAttributes)
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 };
198 server->setAttribute(KEY, arr31);
200 ASSERT_EQ(arr31, server->getAttributeValue(KEY));
203 TEST_F(ResourceObjectTest, ThrowIfResourceToBindIsInvalid)
205 ASSERT_THROW(server->bindResource(server), RCSInvalidParameterException);
208 TEST_F(ResourceObjectTest, ThrowIfBindResourceFailed)
210 mocks.OnCallFunc(OCBindResource).Return(OC_STACK_ERROR);
212 ASSERT_THROW(server->bindResource(
213 RCSResourceObject::Builder("a/temp", RESOURCE_TYPE, "").build()), RCSPlatformException);
216 TEST_F(ResourceObjectTest, ThrowIfResourceToUnbindIsInvalid)
218 ASSERT_THROW(server->unbindResource(server), RCSInvalidParameterException);
221 TEST_F(ResourceObjectTest, BoundResourceCanBeRetrieved)
223 mocks.OnCallFunc(OCBindResource).Return(OC_STACK_OK);
225 auto boundResource = RCSResourceObject::Builder("a/temp", RESOURCE_TYPE, "").build();
226 server->bindResource(boundResource);
228 ASSERT_EQ(boundResource, server->getBoundResources()[0]);
232 class AutoNotifyTest: public ResourceObjectTest
237 mocks.OnCallFuncOverload(static_cast< NotifyAllObservers >(
238 OCPlatform::notifyAllObservers)).Return(OC_STACK_OK);
241 virtual void initResourceObject() {
246 TEST_F(AutoNotifyTest, DefalutAutoNotifyPolicyIsUpdated)
248 ASSERT_EQ(RCSResourceObject::AutoNotifyPolicy::UPDATED, server->getAutoNotifyPolicy());
251 TEST_F(AutoNotifyTest, AutoNotifyPolicyCanBeSet)
253 server->setAutoNotifyPolicy(RCSResourceObject::AutoNotifyPolicy::NEVER);
255 ASSERT_EQ(RCSResourceObject::AutoNotifyPolicy::NEVER, server->getAutoNotifyPolicy());
258 TEST_F(AutoNotifyTest, WithUpdatedPolicy_NeverBeNotifiedIfAttributeIsNotChanged)
260 server->setAutoNotifyPolicy(RCSResourceObject::AutoNotifyPolicy::UPDATED);
261 server->setAttribute(KEY, VALUE);
263 mocks.NeverCallFuncOverload(static_cast< NotifyAllObservers >(
264 OC::OCPlatform::notifyAllObservers));
266 server->setAttribute(KEY, VALUE);
269 TEST_F(AutoNotifyTest, WithUpdatedPolicy_WillBeNotifiedIfAttributeIsChanged)
271 server->setAutoNotifyPolicy(RCSResourceObject::AutoNotifyPolicy::UPDATED);
272 server->setAttribute(KEY, VALUE);
274 mocks.ExpectCallFuncOverload(static_cast< NotifyAllObservers >(
275 OC::OCPlatform::notifyAllObservers)).Return(OC_STACK_OK);
277 server->setAttribute(KEY, VALUE + 1);
280 TEST_F(AutoNotifyTest, WithUpdatedPolicy_WillBeNotifiedIfValueIsAdded)
282 constexpr char newKey[]{ "newKey" };
283 server->setAutoNotifyPolicy(RCSResourceObject::AutoNotifyPolicy::UPDATED);
285 mocks.ExpectCallFuncOverload(static_cast< NotifyAllObservers >(
286 OC::OCPlatform::notifyAllObservers)).Return(OC_STACK_OK);
288 server->setAttribute(newKey, VALUE);
291 TEST_F(AutoNotifyTest, WithNeverPolicy_NeverBeNotifiedEvenIfAttributeIsChanged)
293 server->setAutoNotifyPolicy(RCSResourceObject::AutoNotifyPolicy::NEVER);
295 mocks.NeverCallFuncOverload(static_cast< NotifyAllObservers >(
296 OC::OCPlatform::notifyAllObservers));
298 RCSResourceObject::LockGuard lock{ server };
299 server->setAttribute(KEY, VALUE);
302 TEST_F(AutoNotifyTest, WithUpdatePolicy_WillBeNotifiedIfAttributeIsDeleted)
304 server->setAutoNotifyPolicy(RCSResourceObject::AutoNotifyPolicy::UPDATED);
305 server->setAttribute(KEY, VALUE);
307 mocks.ExpectCallFuncOverload(static_cast< NotifyAllObservers >(
308 OC::OCPlatform::notifyAllObservers)).Return(OC_STACK_OK);
310 server->removeAttribute(KEY);
313 class AutoNotifyWithGuardTest: public AutoNotifyTest
317 TEST_F(AutoNotifyWithGuardTest, GuardFollowsServerPolicyByDefault)
319 server->setAutoNotifyPolicy(RCSResourceObject::AutoNotifyPolicy::UPDATED);
321 mocks.ExpectCallFuncOverload(static_cast< NotifyAllObservers >(
322 OC::OCPlatform::notifyAllObservers)).Return(OC_STACK_OK);
324 RCSResourceObject::LockGuard guard{ server };
325 server->setAttribute(KEY, VALUE);
328 TEST_F(AutoNotifyWithGuardTest, GuardCanOverridePolicy)
330 server->setAutoNotifyPolicy(RCSResourceObject::AutoNotifyPolicy::ALWAYS);
332 mocks.NeverCallFuncOverload(static_cast< NotifyAllObservers >(
333 OC::OCPlatform::notifyAllObservers));
335 RCSResourceObject::LockGuard guard{ server, RCSResourceObject::AutoNotifyPolicy::NEVER };
336 server->getAttributes()[KEY] = VALUE;
339 TEST_F(AutoNotifyWithGuardTest, GuardInvokesNotifyWhenDestroyed)
341 server->setAutoNotifyPolicy(RCSResourceObject::AutoNotifyPolicy::NEVER);
343 mocks.ExpectCallFuncOverload(static_cast< NotifyAllObservers >(
344 OC::OCPlatform::notifyAllObservers)).Return(OC_STACK_OK);
347 RCSResourceObject::LockGuard guard{ server, RCSResourceObject::AutoNotifyPolicy::ALWAYS };
348 server->setAttribute(KEY, VALUE);
351 mocks.NeverCallFuncOverload(static_cast< NotifyAllObservers >(
352 OC::OCPlatform::notifyAllObservers)).Return(OC_STACK_OK);
354 server->setAttribute(KEY, VALUE);
359 class ResourceObjectHandlingRequestTest: public ResourceObjectTest
362 EntityHandler handler;
364 static constexpr OCRequestHandle fakeRequestHandle =
365 reinterpret_cast<OCRequestHandle>(0x1234);
366 static constexpr OCResourceHandle fakeResourceHandle =
367 reinterpret_cast<OCResourceHandle>(0x4321);
370 OCResourceRequest::Ptr createRequest(OCMethod method = OC_REST_GET, OCRepresentation ocRep =
373 auto request = make_shared<OCResourceRequest>();
375 OCEntityHandlerRequest ocEntityHandlerRequest;
376 memset(&ocEntityHandlerRequest, 0, sizeof(OCEntityHandlerRequest));
377 OC::MessageContainer mc;
379 mc.addRepresentation(ocRep);
381 ocEntityHandlerRequest.requestHandle = fakeRequestHandle;
382 ocEntityHandlerRequest.resource = fakeResourceHandle;
383 ocEntityHandlerRequest.method = method;
384 ocEntityHandlerRequest.payload = reinterpret_cast<OCPayload*>(mc.getPayload());
386 formResourceRequest(OC_REQUEST_FLAG, &ocEntityHandlerRequest, request);
392 OCStackResult registerResourceFake(OCResourceHandle&, string&, const string&,
393 const string&, EntityHandler handler, uint8_t)
395 this->handler = handler;
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);
409 TEST_F(ResourceObjectHandlingRequestTest, CallSendResponseWhenReceiveRequest)
411 mocks.ExpectCallFunc(OCPlatform::sendResponse).Return(OC_STACK_OK);
413 ASSERT_EQ(OC_EH_OK, handler(createRequest()));
416 TEST_F(ResourceObjectHandlingRequestTest, ReturnErrorCodeWhenSendResponseFailed)
418 mocks.ExpectCallFunc(OCPlatform::sendResponse).Return(OC_STACK_ERROR);
420 ASSERT_EQ(OC_EH_ERROR, handler(createRequest()));
423 TEST_F(ResourceObjectHandlingRequestTest, SendResponseWithSameHandlesPassedByRequest)
425 mocks.ExpectCallFunc(OCPlatform::sendResponse).Match(
426 [](const shared_ptr<OCResourceResponse> response)
428 return response->getRequestHandle() == fakeRequestHandle &&
429 response->getResourceHandle() == fakeResourceHandle;
431 ).Return(OC_STACK_OK);
433 ASSERT_EQ(OC_EH_OK, handler(createRequest()));
436 TEST_F(ResourceObjectHandlingRequestTest, SendResponseWithRCSResponseResults)
438 constexpr int errorCode{ 1999 };
440 server->setGetRequestHandler(
441 [](const RCSRequest&, RCSResourceAttributes&) -> RCSGetResponse
443 return RCSGetResponse::create(errorCode);
447 mocks.ExpectCallFunc(OCPlatform::sendResponse).Match(
448 [](const shared_ptr<OCResourceResponse> response)
450 return response->getErrorCode() == errorCode;
452 ).Return(OC_STACK_OK);
454 ASSERT_EQ(OC_EH_OK, handler(createRequest()));
457 TEST_F(ResourceObjectHandlingRequestTest, SendSetResponseWithCustomAttrs)
459 constexpr int errorCode{ 1999 };
460 constexpr char value[]{ "VALUE" };
462 server->setSetRequestHandler(
463 [](const RCSRequest&, RCSResourceAttributes&) -> RCSSetResponse
465 RCSResourceAttributes attrs;
467 return RCSSetResponse::create(attrs, errorCode);
471 mocks.ExpectCallFunc(OCPlatform::sendResponse).Match(
472 [](const shared_ptr<OCResourceResponse> response)
474 return value == response->getResourceRepresentation()[KEY].getValue<std::string>()
475 && response->getErrorCode() == errorCode;
477 ).Return(OC_STACK_OK);
479 ASSERT_EQ(OC_EH_OK, handler(createRequest(OC_REST_POST)));
484 class SetRequestHandlerPolicyTest: public ResourceObjectHandlingRequestTest
487 typedef OCStackResult (*SendResponse)(std::shared_ptr<OCResourceResponse>);
490 OCRepresentation createOCRepresentation()
492 OCRepresentation ocRep;
499 ResourceObjectHandlingRequestTest::initMocks();
500 mocks.OnCallFunc(OCPlatform::sendResponse).Return(OC_STACK_OK);
504 TEST_F(SetRequestHandlerPolicyTest, DefalutSetRequestHandlerPolicyIsNever)
506 ASSERT_EQ(RCSResourceObject::SetRequestHandlerPolicy::NEVER,
507 server->getSetRequestHandlerPolicy());
510 TEST_F(SetRequestHandlerPolicyTest, SetRequestHandlerPolicyCanBeSet)
512 server->setSetRequestHandlerPolicy(RCSResourceObject::SetRequestHandlerPolicy::ACCEPTANCE);
514 ASSERT_EQ(RCSResourceObject::SetRequestHandlerPolicy::ACCEPTANCE,
515 server->getSetRequestHandlerPolicy());
518 TEST_F(SetRequestHandlerPolicyTest, WithNeverPolicy_DeniedIfKeyIsNew)
520 server->setSetRequestHandlerPolicy(RCSResourceObject::SetRequestHandlerPolicy::NEVER);
522 handler(createRequest(OC_REST_POST, createOCRepresentation()));
524 RCSResourceObject::LockGuard guard{ server };
525 ASSERT_FALSE(server->getAttributes().contains(KEY));
528 TEST_F(SetRequestHandlerPolicyTest, WithAcceptancePolicy_AcceptedEvenIfKeyIsNew)
530 server->setSetRequestHandlerPolicy(RCSResourceObject::SetRequestHandlerPolicy::ACCEPTANCE);
532 handler(createRequest(OC_REST_POST, createOCRepresentation()));
534 RCSResourceObject::LockGuard guard{ server };
535 ASSERT_TRUE(server->getAttributes().contains(KEY));
540 class ResourceObjectSynchronizationTest: public ResourceObjectHandlingRequestTest
544 static void withLock(RCSResourceObject::Ptr serverResource, int count)
546 for (int i=0; i<count; ++i)
548 RCSResourceObject::LockGuard lock{ serverResource };
550 auto& attrs = serverResource->getAttributes();
552 attrs[KEY] = attrs[KEY].get<int>() + 1;
556 static void withSetter(RCSResourceObject::Ptr serverResource, int count)
558 for (int i=0; i<count; ++i)
560 RCSResourceObject::LockGuard lock{ serverResource };
562 serverResource->setAttribute(KEY, serverResource->getAttribute<int>(KEY) + 1);
567 TEST_F(ResourceObjectSynchronizationTest, MultipleAccessToServerResource)
570 vector<thread> threads;
572 server->setAttribute(KEY, 0);
574 for (int i = 20; i >= 0; --i) {
575 int count = 5000 + i * 100;
576 threads.push_back(thread { withLock, server, count });
580 for (int i = 20; i >= 0; --i) {
581 int count = 5000 + i * 100;
582 threads.push_back(thread { withSetter, server, count });
586 for (auto& t : threads)
591 ASSERT_EQ(expected, server->getAttribute<int>(KEY));
594 TEST_F(ResourceObjectSynchronizationTest, MultipleAccessToServerResourceWithRequests)
597 vector<thread> threads;
599 mocks.OnCallFunc(OCPlatform::sendResponse).Return(OC_STACK_OK);
601 server->setAttribute(KEY, 0);
603 for (int i = 20; i >= 0; --i) {
604 int count = 5000 + i * 100;
605 threads.push_back(thread{ withLock, server, count });
609 for (int i = 20; i >= 0; --i) {
610 int count = 5000 + i * 100;
611 threads.push_back(thread{ withSetter, server, count });
615 threads.push_back(thread{
618 for (int i=0; i<10000; ++i)
620 if (i % 5 == 0) handler(createRequest(OC_REST_OBSERVE));
621 handler(createRequest((i & 1) ? OC_REST_GET : OC_REST_POST));
626 for (auto& t : threads)
631 ASSERT_EQ(expected, server->getAttribute<int>(KEY));
636 class AttributeUpdatedListenerTest: public ResourceObjectHandlingRequestTest
639 typedef OCStackResult (*SendResponse)(std::shared_ptr<OCResourceResponse>);
642 OCRepresentation createOCRepresentation(void)
644 OCRepresentation ocRep;
652 ResourceObjectHandlingRequestTest::SetUp();
653 mocks.OnCallFunc(OCPlatform::sendResponse).Return(OC_STACK_OK);
655 server->setAttribute(KEY, 0);
659 class AttributeUpdatedListener
662 virtual void onUpdated(const OIC::Service::RCSResourceAttributes::Value&,
663 const OIC::Service::RCSResourceAttributes::Value&)=0;
665 virtual ~AttributeUpdatedListener() {}
669 TEST_F(AttributeUpdatedListenerTest, RemoveListenerReturnsFalseIfListenerIsNotAdded)
671 ASSERT_FALSE(server->removeAttributeUpdatedListener(KEY));
674 TEST_F(AttributeUpdatedListenerTest, RemoveListenerReturnsTrueIfListenerIsAdded)
676 auto listener = mocks.Mock< AttributeUpdatedListener >();
678 server->addAttributeUpdatedListener(KEY,
679 std::bind(&AttributeUpdatedListener::onUpdated, listener, _1, _2));
681 ASSERT_TRUE(server->removeAttributeUpdatedListener(KEY));
684 TEST_F(AttributeUpdatedListenerTest, AddListenerRunsAddedFunction)
686 auto listener = mocks.Mock< AttributeUpdatedListener >();
688 server->addAttributeUpdatedListener(KEY,
689 std::bind(&AttributeUpdatedListener::onUpdated, listener, _1, _2));
691 mocks.ExpectCall(listener, AttributeUpdatedListener::onUpdated);
693 handler(createRequest(OC_REST_POST, createOCRepresentation()));
696 TEST_F(AttributeUpdatedListenerTest, ListenerWithSameKeyOverridesPreviousOne)
698 auto first = mocks.Mock< AttributeUpdatedListener >();
699 auto second = mocks.Mock< AttributeUpdatedListener >();
701 mocks.NeverCall(first, AttributeUpdatedListener::onUpdated);
702 mocks.ExpectCall(second, AttributeUpdatedListener::onUpdated);
704 server->addAttributeUpdatedListener(KEY,
705 std::bind(&AttributeUpdatedListener::onUpdated, first, _1, _2));
706 server->addAttributeUpdatedListener(KEY,
707 std::bind(&AttributeUpdatedListener::onUpdated, second, _1, _2));
709 handler(createRequest(OC_REST_POST, createOCRepresentation()));
712 TEST_F(AttributeUpdatedListenerTest, RemovedListenerNotBeInvoked)
714 auto listener = mocks.Mock< AttributeUpdatedListener >();
715 server->addAttributeUpdatedListener(KEY,
716 std::bind(&AttributeUpdatedListener::onUpdated, listener, _1, _2));
718 mocks.NeverCall(listener, AttributeUpdatedListener::onUpdated);
720 server->removeAttributeUpdatedListener(KEY);
722 handler(createRequest(OC_REST_POST, createOCRepresentation()));