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, WithAlwaysPolicy_WillBeNotifiedEvenIfAttributeIsNotChanged)
219 server->setAutoNotifyPolicy(ResourceObject::AutoNotifyPolicy::ALWAYS);
220 server->setAttribute(KEY, value);
222 mocks.ExpectCallFuncOverload(static_cast< NotifyAllObservers >(
223 OC::OCPlatform::notifyAllObservers)).Return(OC_STACK_OK);
225 server->setAttribute(KEY, value);
229 class AutoNotifyWithGuardTest: public AutoNotifyTest
233 TEST_F(AutoNotifyWithGuardTest, GuardFollowsServerPolicyByDefault)
235 server->setAutoNotifyPolicy(ResourceObject::AutoNotifyPolicy::UPDATED);
237 mocks.ExpectCallFuncOverload(static_cast< NotifyAllObservers >(
238 OC::OCPlatform::notifyAllObservers)).Return(OC_STACK_OK);
240 ResourceObject::LockGuard guard{ server };
241 server->setAttribute(KEY, value);
244 TEST_F(AutoNotifyWithGuardTest, GuardCanOverridePolicy)
246 server->setAutoNotifyPolicy(ResourceObject::AutoNotifyPolicy::ALWAYS);
248 mocks.NeverCallFuncOverload(static_cast< NotifyAllObservers >(
249 OC::OCPlatform::notifyAllObservers));
251 ResourceObject::LockGuard guard{ server, ResourceObject::AutoNotifyPolicy::NEVER };
252 server->getAttributes()[KEY] = value;
255 TEST_F(AutoNotifyWithGuardTest, GuardInvokesNotifyWhenDestroyed)
257 server->setAutoNotifyPolicy(ResourceObject::AutoNotifyPolicy::NEVER);
259 mocks.ExpectCallFuncOverload(static_cast< NotifyAllObservers >(
260 OC::OCPlatform::notifyAllObservers)).Return(OC_STACK_OK);
263 ResourceObject::LockGuard guard{ server, ResourceObject::AutoNotifyPolicy::ALWAYS };
264 server->setAttribute(KEY, value);
267 mocks.NeverCallFuncOverload(static_cast< NotifyAllObservers >(
268 OC::OCPlatform::notifyAllObservers)).Return(OC_STACK_OK);
270 server->setAttribute(KEY, value);
275 class ResourceObjectHandlingRequestTest: public ResourceObjectTest
278 EntityHandler handler;
280 static constexpr OCRequestHandle fakeRequestHandle =
281 reinterpret_cast<OCRequestHandle>(0x1234);
282 static constexpr OCResourceHandle fakeResourceHandle =
283 reinterpret_cast<OCResourceHandle>(0x4321);
286 OCResourceRequest::Ptr createRequest(OCMethod method = OC_REST_GET, OCRepresentation ocRep =
289 auto request = make_shared<OCResourceRequest>();
291 OCEntityHandlerRequest ocEntityHandlerRequest { 0 };
292 OC::MessageContainer mc;
294 mc.addRepresentation(ocRep);
296 ocEntityHandlerRequest.requestHandle = fakeRequestHandle;
297 ocEntityHandlerRequest.resource = fakeResourceHandle;
298 ocEntityHandlerRequest.method = method;
299 ocEntityHandlerRequest.payload = reinterpret_cast<OCPayload*>(mc.getPayload());
301 formResourceRequest(OC_REQUEST_FLAG, &ocEntityHandlerRequest, request);
307 OCStackResult registerResourceFake(OCResourceHandle&, string&, const string&,
308 const string&, EntityHandler handler, uint8_t)
310 this->handler = handler;
316 mocks.OnCallFuncOverload(
317 static_cast<registerResource>(OCPlatform::registerResource)).Do(
318 bind(&ResourceObjectHandlingRequestTest::registerResourceFake,
319 this, _1, _2, _3, _4, _5, _6));
320 mocks.OnCallFunc(OCPlatform::unregisterResource).Return(OC_STACK_OK);
324 TEST_F(ResourceObjectHandlingRequestTest, CallSendResponseWhenReceiveRequest)
326 mocks.ExpectCallFunc(OCPlatform::sendResponse).Return(OC_STACK_OK);
328 ASSERT_EQ(OC_EH_OK, handler(createRequest()));
331 TEST_F(ResourceObjectHandlingRequestTest, ReturnErrorCodeWhenSendResponseFailed)
333 mocks.ExpectCallFunc(OCPlatform::sendResponse).Return(OC_STACK_ERROR);
335 ASSERT_EQ(OC_EH_ERROR, handler(createRequest()));
338 TEST_F(ResourceObjectHandlingRequestTest, SendResponseWithSameHandlesPassedByRequest)
340 mocks.ExpectCallFunc(OCPlatform::sendResponse).Match(
341 [](const shared_ptr<OCResourceResponse> response)
343 return response->getRequestHandle() == fakeRequestHandle &&
344 response->getResourceHandle() == fakeResourceHandle;
346 ).Return(OC_STACK_OK);
348 ASSERT_EQ(OC_EH_OK, handler(createRequest()));
351 TEST_F(ResourceObjectHandlingRequestTest, SendResponseWithRCSResponseResults)
353 constexpr int errorCode{ 1999 };
354 constexpr OCEntityHandlerResult result{ OC_EH_SLOW };
356 server->setGetRequestHandler(
357 [](const RCSRequest&, ResourceAttributes&) -> RCSGetResponse
359 return RCSGetResponse::create(result, errorCode);
363 mocks.ExpectCallFunc(OCPlatform::sendResponse).Match(
364 [](const shared_ptr<OCResourceResponse> response)
366 return response->getErrorCode() == errorCode &&
367 response->getResponseResult() == result;
369 ).Return(OC_STACK_OK);
371 ASSERT_EQ(OC_EH_OK, handler(createRequest()));
374 TEST_F(ResourceObjectHandlingRequestTest, SendSetResponseWithCustomAttrsAndResults)
376 constexpr int errorCode{ 1999 };
377 constexpr OCEntityHandlerResult result{ OC_EH_SLOW };
378 constexpr char value[]{ "value" };
380 server->setSetRequestHandler(
381 [](const RCSRequest&, ResourceAttributes&) -> RCSSetResponse
383 ResourceAttributes attrs;
385 return RCSSetResponse::create(attrs, result, errorCode);
389 mocks.ExpectCallFunc(OCPlatform::sendResponse).Match(
390 [](const shared_ptr<OCResourceResponse> response)
392 return value == response->getResourceRepresentation()[KEY].getValue<std::string>()
393 && response->getErrorCode() == errorCode
394 && response->getResponseResult() == result;
396 ).Return(OC_STACK_OK);
398 ASSERT_EQ(OC_EH_OK, handler(createRequest(OC_REST_PUT)));
402 class SetRequestHandlerPolicyTest: public ResourceObjectHandlingRequestTest
405 typedef OCStackResult (*SendResponse)(std::shared_ptr<OCResourceResponse>);
408 OCRepresentation createOCRepresentation()
410 OCRepresentation ocRep;
412 vector<string> interface{"oic.if.baseline"};
413 vector<string> type{"core.light"};
415 ocRep.setUri(RESOURCE_URI);
416 ocRep.setResourceInterfaces(interface);
417 ocRep.setResourceTypes(type);
424 ResourceObjectHandlingRequestTest::initMocks();
425 mocks.OnCallFunc(OCPlatform::sendResponse).Return(OC_STACK_OK);
429 TEST_F(SetRequestHandlerPolicyTest, DefalutSetRequestHandlerPolicyIsNever)
431 ASSERT_EQ(ResourceObject::SetRequestHandlerPolicy::NEVER,
432 server->getSetRequestHandlerPolicy());
435 TEST_F(SetRequestHandlerPolicyTest, SetRequestHandlerPolicyCanBeSet)
437 server->setSetRequestHandlerPolicy(ResourceObject::SetRequestHandlerPolicy::ACCEPTANCE);
439 ASSERT_EQ(ResourceObject::SetRequestHandlerPolicy::ACCEPTANCE,
440 server->getSetRequestHandlerPolicy());
443 TEST_F(SetRequestHandlerPolicyTest, WithNeverPolicy_NotAddedIfReceivedNewKeyValuePair)
445 OCRepresentation ocRep = createOCRepresentation();
446 ocRep.setValue("NewKey", value);
447 server->setSetRequestHandlerPolicy(ResourceObject::SetRequestHandlerPolicy::NEVER);
449 handler(createRequest(OC_REST_PUT, ocRep));
451 ResourceObject::LockGuard guard{ server };
452 ASSERT_FALSE((server->getAttributes()).contains("NewKey"));
455 TEST_F(SetRequestHandlerPolicyTest, WithAcceptancePolicy_WillBeAddedIfReceivedNewKeyValuePair)
457 OCRepresentation ocRep = createOCRepresentation();
458 ocRep.setValue("NewKey", value);
459 server->setSetRequestHandlerPolicy(ResourceObject::SetRequestHandlerPolicy::ACCEPTANCE);
461 handler(createRequest(OC_REST_PUT, ocRep));
463 ResourceObject::LockGuard guard{ server };
464 ASSERT_TRUE((server->getAttributes()).contains("NewKey"));
468 class ResourceObjectSynchronizationTest: public ResourceObjectHandlingRequestTest
472 static void withLock(ResourceObject::Ptr serverResource, int count)
474 for (int i=0; i<count; ++i)
476 ResourceObject::LockGuard lock{ serverResource };
478 auto& attrs = serverResource->getAttributes();
480 attrs[KEY] = attrs[KEY].get<int>() + 1;
484 static void withSetter(ResourceObject::Ptr serverResource, int count)
486 for (int i=0; i<count; ++i)
488 ResourceObject::LockGuard lock{ serverResource };
490 serverResource->setAttribute(KEY, serverResource->getAttribute<int>(KEY) + 1);
495 TEST_F(ResourceObjectSynchronizationTest, MultipleAccessToServerResource)
498 vector<thread> threads;
500 server->setAttribute(KEY, 0);
502 for (int i = 20; i >= 0; --i) {
503 int count = 5000 + i * 100;
504 threads.push_back(thread { withLock, server, count });
508 for (int i = 20; i >= 0; --i) {
509 int count = 5000 + i * 100;
510 threads.push_back(thread { withSetter, server, count });
514 for (auto& t : threads)
519 ASSERT_EQ(expected, server->getAttribute<int>(KEY));
522 TEST_F(ResourceObjectSynchronizationTest, MultipleAccessToServerResourceWithRequests)
525 vector<thread> threads;
527 mocks.OnCallFunc(OCPlatform::sendResponse).Return(OC_STACK_OK);
529 server->setAttribute(KEY, 0);
531 for (int i = 20; i >= 0; --i) {
532 int count = 5000 + i * 100;
533 threads.push_back(thread{ withLock, server, count });
537 for (int i = 20; i >= 0; --i) {
538 int count = 5000 + i * 100;
539 threads.push_back(thread{ withSetter, server, count });
543 threads.push_back(thread{
546 for (int i=0; i<10000; ++i)
548 if (i % 5 == 0) handler(createRequest(OC_REST_OBSERVE));
549 handler(createRequest((i & 1) ? OC_REST_GET : OC_REST_PUT));
554 for (auto& t : threads)
559 ASSERT_EQ(expected, server->getAttribute<int>(KEY));