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 <ResourceObject.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(ResourceObject::Builder("", "", "").build(), PlatformException);
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 ResourceObject::Builder(RESOURCE_URI, RESOURCE_TYPE, "").build();
68 TEST_F(ResourceObjectBuilderTest, ResourceServerHasPropertiesSetByBuilder)
70 auto serverResource = ResourceObject::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 ResourceAttributes attrs;
82 auto serverResource = ResourceObject::Builder(RESOURCE_URI, RESOURCE_TYPE, "").
83 setAttributes(attrs).build();
85 ResourceObject::LockGuard lock{ serverResource, ResourceObject::AutoNotifyPolicy::NEVER };
86 EXPECT_EQ(attrs, serverResource->getAttributes());
90 class ResourceObjectTest: public TestWithMock
93 ResourceObject::Ptr server;
98 TestWithMock::SetUp();
102 server = ResourceObject::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(ResourceObject::AutoNotifyPolicy::NEVER);
120 TEST_F(ResourceObjectTest, AccessAttributesWithLock)
123 ResourceObject::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 ResourceObject::LockGuard guard{ server };
140 server->setAttribute(KEY, value);
143 ASSERT_EQ(value, server->getAttribute<int>(KEY));
147 class AutoNotifyTest: public ResourceObjectTest
152 mocks.OnCallFuncOverload(static_cast< NotifyAllObservers >(
153 OCPlatform::notifyAllObservers)).Return(OC_STACK_OK);
156 virtual void initResourceObject() {
161 TEST_F(AutoNotifyTest, DefalutAutoNotifyPolicyIsUpdated)
163 ASSERT_EQ(ResourceObject::AutoNotifyPolicy::UPDATED, server->getAutoNotifyPolicy());
166 TEST_F(AutoNotifyTest, AutoNotifyPolicyCanBeSet)
168 server->setAutoNotifyPolicy(ResourceObject::AutoNotifyPolicy::NEVER);
170 ASSERT_EQ(ResourceObject::AutoNotifyPolicy::NEVER, server->getAutoNotifyPolicy());
173 TEST_F(AutoNotifyTest, WithUpdatedPolicy_NeverBeNotifiedIfAttributeIsNotChanged)
175 server->setAutoNotifyPolicy(ResourceObject::AutoNotifyPolicy::UPDATED);
176 server->setAttribute(KEY, value);
178 mocks.NeverCallFuncOverload(static_cast< NotifyAllObservers >(
179 OC::OCPlatform::notifyAllObservers));
181 server->setAttribute(KEY, value);
184 TEST_F(AutoNotifyTest, WithUpdatedPolicy_WillBeNotifiedIfAttributeIsChanged)
186 server->setAutoNotifyPolicy(ResourceObject::AutoNotifyPolicy::UPDATED);
187 server->setAttribute(KEY, value);
189 mocks.ExpectCallFuncOverload(static_cast< NotifyAllObservers >(
190 OC::OCPlatform::notifyAllObservers)).Return(OC_STACK_OK);
192 server->setAttribute(KEY, value + 1);
195 TEST_F(AutoNotifyTest, WithUpdatedPolicy_WillBeNotifiedIfValueIsAdded)
197 constexpr char newKey[]{ "newKey" };
198 server->setAutoNotifyPolicy(ResourceObject::AutoNotifyPolicy::UPDATED);
200 mocks.ExpectCallFuncOverload(static_cast< NotifyAllObservers >(
201 OC::OCPlatform::notifyAllObservers)).Return(OC_STACK_OK);
203 server->setAttribute(newKey, value);
206 TEST_F(AutoNotifyTest, WithNeverPolicy_NeverBeNotifiedEvenIfAttributeIsChanged)
208 server->setAutoNotifyPolicy(ResourceObject::AutoNotifyPolicy::NEVER);
210 mocks.NeverCallFuncOverload(static_cast< NotifyAllObservers >(
211 OC::OCPlatform::notifyAllObservers));
213 ResourceObject::LockGuard lock{ server };
214 server->setAttribute(KEY, value);
217 TEST_F(AutoNotifyTest, WithUpdatePolicy_WillBeNotifiedIfAttributeIsDeleted)
219 server->setAutoNotifyPolicy(ResourceObject::AutoNotifyPolicy::UPDATED);
220 server->setAttribute(KEY, value);
222 mocks.ExpectCallFuncOverload(static_cast< NotifyAllObservers >(
223 OC::OCPlatform::notifyAllObservers)).Return(OC_STACK_OK);
225 server->removeAttribute(KEY);
228 class AutoNotifyWithGuardTest: public AutoNotifyTest
232 TEST_F(AutoNotifyWithGuardTest, GuardFollowsServerPolicyByDefault)
234 server->setAutoNotifyPolicy(ResourceObject::AutoNotifyPolicy::UPDATED);
236 mocks.ExpectCallFuncOverload(static_cast< NotifyAllObservers >(
237 OC::OCPlatform::notifyAllObservers)).Return(OC_STACK_OK);
239 ResourceObject::LockGuard guard{ server };
240 server->setAttribute(KEY, value);
243 TEST_F(AutoNotifyWithGuardTest, GuardCanOverridePolicy)
245 server->setAutoNotifyPolicy(ResourceObject::AutoNotifyPolicy::ALWAYS);
247 mocks.NeverCallFuncOverload(static_cast< NotifyAllObservers >(
248 OC::OCPlatform::notifyAllObservers));
250 ResourceObject::LockGuard guard{ server, ResourceObject::AutoNotifyPolicy::NEVER };
251 server->getAttributes()[KEY] = value;
254 TEST_F(AutoNotifyWithGuardTest, GuardInvokesNotifyWhenDestroyed)
256 server->setAutoNotifyPolicy(ResourceObject::AutoNotifyPolicy::NEVER);
258 mocks.ExpectCallFuncOverload(static_cast< NotifyAllObservers >(
259 OC::OCPlatform::notifyAllObservers)).Return(OC_STACK_OK);
262 ResourceObject::LockGuard guard{ server, ResourceObject::AutoNotifyPolicy::ALWAYS };
263 server->setAttribute(KEY, value);
266 mocks.NeverCallFuncOverload(static_cast< NotifyAllObservers >(
267 OC::OCPlatform::notifyAllObservers)).Return(OC_STACK_OK);
269 server->setAttribute(KEY, value);
274 class ResourceObjectHandlingRequestTest: public ResourceObjectTest
277 EntityHandler handler;
279 static constexpr OCRequestHandle fakeRequestHandle =
280 reinterpret_cast<OCRequestHandle>(0x1234);
281 static constexpr OCResourceHandle fakeResourceHandle =
282 reinterpret_cast<OCResourceHandle>(0x4321);
285 OCResourceRequest::Ptr createRequest(OCMethod method = OC_REST_GET, OCRepresentation ocRep =
288 auto request = make_shared<OCResourceRequest>();
290 OCEntityHandlerRequest ocEntityHandlerRequest { 0 };
291 OC::MessageContainer mc;
293 mc.addRepresentation(ocRep);
295 ocEntityHandlerRequest.requestHandle = fakeRequestHandle;
296 ocEntityHandlerRequest.resource = fakeResourceHandle;
297 ocEntityHandlerRequest.method = method;
298 ocEntityHandlerRequest.payload = reinterpret_cast<OCPayload*>(mc.getPayload());
300 formResourceRequest(OC_REQUEST_FLAG, &ocEntityHandlerRequest, request);
306 OCStackResult registerResourceFake(OCResourceHandle&, string&, const string&,
307 const string&, EntityHandler handler, uint8_t)
309 this->handler = handler;
315 mocks.OnCallFuncOverload(
316 static_cast<registerResource>(OCPlatform::registerResource)).Do(
317 bind(&ResourceObjectHandlingRequestTest::registerResourceFake,
318 this, _1, _2, _3, _4, _5, _6));
319 mocks.OnCallFunc(OCPlatform::unregisterResource).Return(OC_STACK_OK);
323 TEST_F(ResourceObjectHandlingRequestTest, CallSendResponseWhenReceiveRequest)
325 mocks.ExpectCallFunc(OCPlatform::sendResponse).Return(OC_STACK_OK);
327 ASSERT_EQ(OC_EH_OK, handler(createRequest()));
330 TEST_F(ResourceObjectHandlingRequestTest, ReturnErrorCodeWhenSendResponseFailed)
332 mocks.ExpectCallFunc(OCPlatform::sendResponse).Return(OC_STACK_ERROR);
334 ASSERT_EQ(OC_EH_ERROR, handler(createRequest()));
337 TEST_F(ResourceObjectHandlingRequestTest, SendResponseWithSameHandlesPassedByRequest)
339 mocks.ExpectCallFunc(OCPlatform::sendResponse).Match(
340 [](const shared_ptr<OCResourceResponse> response)
342 return response->getRequestHandle() == fakeRequestHandle &&
343 response->getResourceHandle() == fakeResourceHandle;
345 ).Return(OC_STACK_OK);
347 ASSERT_EQ(OC_EH_OK, handler(createRequest()));
350 TEST_F(ResourceObjectHandlingRequestTest, SendResponseWithRCSResponseResults)
352 constexpr int errorCode{ 1999 };
353 constexpr OCEntityHandlerResult result{ OC_EH_SLOW };
355 server->setGetRequestHandler(
356 [](const RCSRequest&, ResourceAttributes&) -> RCSGetResponse
358 return RCSGetResponse::create(result, errorCode);
362 mocks.ExpectCallFunc(OCPlatform::sendResponse).Match(
363 [](const shared_ptr<OCResourceResponse> response)
365 return response->getErrorCode() == errorCode &&
366 response->getResponseResult() == result;
368 ).Return(OC_STACK_OK);
370 ASSERT_EQ(OC_EH_OK, handler(createRequest()));
373 TEST_F(ResourceObjectHandlingRequestTest, SendSetResponseWithCustomAttrsAndResults)
375 constexpr int errorCode{ 1999 };
376 constexpr OCEntityHandlerResult result{ OC_EH_SLOW };
377 constexpr char value[]{ "value" };
379 server->setSetRequestHandler(
380 [](const RCSRequest&, ResourceAttributes&) -> RCSSetResponse
382 ResourceAttributes attrs;
384 return RCSSetResponse::create(attrs, result, errorCode);
388 mocks.ExpectCallFunc(OCPlatform::sendResponse).Match(
389 [](const shared_ptr<OCResourceResponse> response)
391 return value == response->getResourceRepresentation()[KEY].getValue<std::string>()
392 && response->getErrorCode() == errorCode
393 && response->getResponseResult() == result;
395 ).Return(OC_STACK_OK);
397 ASSERT_EQ(OC_EH_OK, handler(createRequest(OC_REST_PUT)));
401 class SetRequestHandlerPolicyTest: public ResourceObjectHandlingRequestTest
404 typedef OCStackResult (*SendResponse)(std::shared_ptr<OCResourceResponse>);
407 OCRepresentation createOCRepresentation()
409 OCRepresentation ocRep;
411 vector<string> interface{"oic.if.baseline"};
412 vector<string> type{"core.light"};
414 ocRep.setUri(RESOURCE_URI);
415 ocRep.setResourceInterfaces(interface);
416 ocRep.setResourceTypes(type);
423 ResourceObjectHandlingRequestTest::initMocks();
424 mocks.OnCallFunc(OCPlatform::sendResponse).Return(OC_STACK_OK);
428 TEST_F(SetRequestHandlerPolicyTest, DefalutSetRequestHandlerPolicyIsNever)
430 ASSERT_EQ(ResourceObject::SetRequestHandlerPolicy::NEVER,
431 server->getSetRequestHandlerPolicy());
434 TEST_F(SetRequestHandlerPolicyTest, SetRequestHandlerPolicyCanBeSet)
436 server->setSetRequestHandlerPolicy(ResourceObject::SetRequestHandlerPolicy::ACCEPTANCE);
438 ASSERT_EQ(ResourceObject::SetRequestHandlerPolicy::ACCEPTANCE,
439 server->getSetRequestHandlerPolicy());
442 TEST_F(SetRequestHandlerPolicyTest, WithNeverPolicy_NotAddedIfReceivedNewKeyValuePair)
444 OCRepresentation ocRep = createOCRepresentation();
445 ocRep.setValue("NewKey", value);
446 server->setSetRequestHandlerPolicy(ResourceObject::SetRequestHandlerPolicy::NEVER);
448 handler(createRequest(OC_REST_PUT, ocRep));
450 ResourceObject::LockGuard guard{ server };
451 ASSERT_FALSE((server->getAttributes()).contains("NewKey"));
454 TEST_F(SetRequestHandlerPolicyTest, WithAcceptancePolicy_WillBeAddedIfReceivedNewKeyValuePair)
456 OCRepresentation ocRep = createOCRepresentation();
457 ocRep.setValue("NewKey", value);
458 server->setSetRequestHandlerPolicy(ResourceObject::SetRequestHandlerPolicy::ACCEPTANCE);
460 handler(createRequest(OC_REST_PUT, ocRep));
462 ResourceObject::LockGuard guard{ server };
463 ASSERT_TRUE((server->getAttributes()).contains("NewKey"));
467 class ResourceObjectSynchronizationTest: public ResourceObjectHandlingRequestTest
471 static void withLock(ResourceObject::Ptr serverResource, int count)
473 for (int i=0; i<count; ++i)
475 ResourceObject::LockGuard lock{ serverResource };
477 auto& attrs = serverResource->getAttributes();
479 attrs[KEY] = attrs[KEY].get<int>() + 1;
483 static void withSetter(ResourceObject::Ptr serverResource, int count)
485 for (int i=0; i<count; ++i)
487 ResourceObject::LockGuard lock{ serverResource };
489 serverResource->setAttribute(KEY, serverResource->getAttribute<int>(KEY) + 1);
494 TEST_F(ResourceObjectSynchronizationTest, MultipleAccessToServerResource)
497 vector<thread> threads;
499 server->setAttribute(KEY, 0);
501 for (int i = 20; i >= 0; --i) {
502 int count = 5000 + i * 100;
503 threads.push_back(thread { withLock, server, count });
507 for (int i = 20; i >= 0; --i) {
508 int count = 5000 + i * 100;
509 threads.push_back(thread { withSetter, server, count });
513 for (auto& t : threads)
518 ASSERT_EQ(expected, server->getAttribute<int>(KEY));
521 TEST_F(ResourceObjectSynchronizationTest, MultipleAccessToServerResourceWithRequests)
524 vector<thread> threads;
526 mocks.OnCallFunc(OCPlatform::sendResponse).Return(OC_STACK_OK);
528 server->setAttribute(KEY, 0);
530 for (int i = 20; i >= 0; --i) {
531 int count = 5000 + i * 100;
532 threads.push_back(thread{ withLock, server, count });
536 for (int i = 20; i >= 0; --i) {
537 int count = 5000 + i * 100;
538 threads.push_back(thread{ withSetter, server, count });
542 threads.push_back(thread{
545 for (int i=0; i<10000; ++i)
547 if (i % 5 == 0) handler(createRequest(OC_REST_OBSERVE));
548 handler(createRequest((i & 1) ? OC_REST_GET : OC_REST_PUT));
553 for (auto& t : threads)
558 ASSERT_EQ(expected, server->getAttribute<int>(KEY));
562 class AttributeUpdatedListenerTest: public ResourceObjectHandlingRequestTest
565 typedef OCStackResult (*SendResponse)(std::shared_ptr<OCResourceResponse>);
568 OCRepresentation createOCRepresentation(void)
570 OCRepresentation ocRep;
572 vector<string> interface{"oic.if.baseline"};
573 vector<string> type{"core.light"};
575 ocRep.setUri(RESOURCE_URI);
576 ocRep.setResourceInterfaces(interface);
577 ocRep.setResourceTypes(type);
585 ResourceObjectHandlingRequestTest::initMocks();
586 mocks.OnCallFunc(OCPlatform::sendResponse).Return(OC_STACK_OK);
590 TEST_F(AttributeUpdatedListenerTest, AddListenerReturnsTrueIfListenerIsCalled)
594 server->setAttribute(KEY, 0);
595 OCRepresentation ocRep = createOCRepresentation();
597 server->addAttributeUpdatedListener(KEY,
598 [&called](const OIC::Service::ResourceAttributes::Value&,
599 const OIC::Service::ResourceAttributes::Value& )
604 handler(ResourceObjectHandlingRequestTest::createRequest(OC_REST_PUT, ocRep));
609 TEST_F(AttributeUpdatedListenerTest, AddListenerisChangedAccordingToLastAddedFunction)
611 int called=0, expected=100;
613 server->setAttribute(KEY,0);
614 OCRepresentation ocRep = createOCRepresentation();
616 server->addAttributeUpdatedListener("key",
617 [&called](const OIC::Service::ResourceAttributes::Value&,
618 const OIC::Service::ResourceAttributes::Value&)
623 server->addAttributeUpdatedListener(KEY,
624 [&called](const OIC::Service::ResourceAttributes::Value&,
625 const OIC::Service::ResourceAttributes::Value&)
630 handler(ResourceObjectHandlingRequestTest::createRequest(OC_REST_PUT, ocRep));
632 ASSERT_EQ(expected, called);
635 TEST_F(AttributeUpdatedListenerTest, RemoveListenerReturnsTrueIfListenerIsNotAdded)
637 ASSERT_FALSE(server->removeAttributeUpdatedListener(KEY));
640 TEST_F(AttributeUpdatedListenerTest, RemoveListenerReturnsTrueIfListenerIsAdded)
642 server->addAttributeUpdatedListener(KEY,
643 [](const OIC::Service::ResourceAttributes::Value&,
644 const OIC::Service::ResourceAttributes::Value&)
648 ASSERT_TRUE(server->removeAttributeUpdatedListener(KEY));