Merge branch 'master' into cloud-interface
[platform/upstream/iotivity.git] / service / resource-encapsulation / unittests / ResourceClientTest.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 "OCResource.h"
24
25 #include "RCSRemoteResourceObject.h"
26 #include "RCSDiscoveryManager.h"
27 #include "RCSResourceObject.h"
28 #include "RCSAddress.h"
29 #include "RCSRequest.h"
30
31 #include <condition_variable>
32 #include <mutex>
33
34 using namespace OIC::Service;
35 using namespace OC;
36
37 constexpr char RESOURCEURI[]{ "/a/TemperatureSensor" };
38 constexpr char RESOURCETYPE[]{ "resource.type" };
39 constexpr char RESOURCEINTERFACE[]{ "oic.if.baseline" };
40
41 constexpr char ATTR_KEY[]{ "Temperature" };
42 constexpr int ATTR_VALUE{ 0 };
43
44 constexpr int DEFAULT_WAITING_TIME_IN_MILLIS = 3000;
45
46 void getRemoteAttributesCallback(const RCSResourceAttributes&, int) {}
47 void setRemoteAttributesCallback(const RCSResourceAttributes&, int) {}
48 void setRemoteRepresentationCallback(const HeaderOpts&, const RCSRepresentation&, int) {}
49 void resourceStateChanged(ResourceState) { }
50 void cacheUpdatedCallback(const RCSResourceAttributes&) {}
51
52 class RemoteResourceObjectTest: public TestWithMock
53 {
54 public:
55     RCSResourceObject::Ptr server;
56     RCSRemoteResourceObject::Ptr object;
57
58 public:
59     void Proceed()
60     {
61         cond.notify_all();
62     }
63
64     void Wait(int waitingTime = DEFAULT_WAITING_TIME_IN_MILLIS)
65     {
66         std::unique_lock< std::mutex > lock{ mutex };
67         cond.wait_for(lock, std::chrono::milliseconds{ waitingTime });
68     }
69
70 protected:
71     void SetUp()
72     {
73         TestWithMock::SetUp();
74
75         CreateResource();
76
77         WaitUntilDiscovered();
78
79         ASSERT_NE(object, nullptr);
80     }
81
82     void TearDown()
83     {
84         TestWithMock::TearDown();
85
86         // This method is to make sure objects disposed.
87         WaitForPtrBeingUnique();
88     }
89
90 private:
91     void CreateResource()
92     {
93         server = RCSResourceObject::Builder(RESOURCEURI, RESOURCETYPE, RESOURCEINTERFACE).build();
94         server->setAttribute(ATTR_KEY, ATTR_VALUE);
95     }
96
97     void WaitUntilDiscovered()
98     {
99         for (int i=0; i<10 && !object; ++i)
100         {
101             auto discoveryTask = RCSDiscoveryManager::getInstance()->discoverResourceByType(
102                     RCSAddress::multicast(), RESOURCETYPE,
103                     std::bind(&RemoteResourceObjectTest::resourceDiscovered, this,
104                             std::placeholders::_1));
105             Wait(1000);
106             discoveryTask->cancel();
107         }
108     }
109
110     void WaitForPtrBeingUnique()
111     {
112         while((object && !object.unique()) || (server && !server.unique()))
113         {
114             std::this_thread::sleep_for(std::chrono::milliseconds{ 100 });
115         }
116     }
117
118     void resourceDiscovered(RCSRemoteResourceObject::Ptr resourceObject)
119     {
120         object = resourceObject;
121
122         Proceed();
123     }
124
125 private:
126     std::condition_variable cond;
127     std::mutex mutex;
128 };
129
130 TEST_F(RemoteResourceObjectTest, GetRemoteAttributesDoesNotAllowEmptyFunction)
131 {
132     ASSERT_THROW(object->getRemoteAttributes({ }), RCSInvalidParameterException);
133 }
134
135 TEST_F(RemoteResourceObjectTest, GetRemoteAttributesGetsAttributesOfServer)
136 {
137     mocks.ExpectCallFunc(getRemoteAttributesCallback).Match(
138             [this](const RCSResourceAttributes& attrs, int)
139             {
140                 RCSResourceObject::LockGuard lock{ server };
141                 return attrs == server->getAttributes();
142             }
143     ).Do([this](const RCSResourceAttributes&, int){ Proceed(); });
144
145     object->getRemoteAttributes(getRemoteAttributesCallback);
146
147     Wait();
148 }
149
150 TEST_F(RemoteResourceObjectTest, SetRemoteAttributesDoesNotAllowEmptyFunction)
151 {
152     ASSERT_THROW(object->setRemoteAttributes({ }, { }), RCSInvalidParameterException);
153 }
154
155 TEST_F(RemoteResourceObjectTest, SetRemoteAttributesSetsAttributesOfServer)
156 {
157     constexpr int newValue = ATTR_VALUE + 1;
158     RCSResourceAttributes newAttrs;
159     newAttrs[ATTR_KEY] = newValue;
160
161     mocks.ExpectCallFunc(setRemoteAttributesCallback).
162             Do([this](const RCSResourceAttributes&, int){ Proceed(); });
163
164     object->setRemoteAttributes(newAttrs, setRemoteAttributesCallback);
165     Wait();
166
167     ASSERT_EQ(newValue, server->getAttributeValue(ATTR_KEY));
168 }
169
170 TEST_F(RemoteResourceObjectTest, SetRemoteRepresentationDoesNotAllowEmptyFunction)
171 {
172     RCSQueryParams queryParams;
173     RCSRepresentation rcsRep;
174     ASSERT_THROW(object->set(queryParams, rcsRep, {}), RCSInvalidParameterException);
175 }
176
177 TEST_F(RemoteResourceObjectTest, SetRemoteRepresentationSetsRepresentationOfServer)
178 {
179     RCSRepresentation rcsRep;
180     RCSQueryParams queryParams;
181     constexpr int newValue = ATTR_VALUE + 1;
182     RCSResourceAttributes newAttrs;
183     newAttrs[ATTR_KEY] = newValue;
184
185     rcsRep.setAttributes(newAttrs);
186
187     mocks.ExpectCallFunc(setRemoteRepresentationCallback).
188             Do([this](const HeaderOpts&, const RCSRepresentation&, int){ Proceed(); });
189
190     object->set(queryParams, rcsRep, setRemoteRepresentationCallback);
191     Wait();
192
193     ASSERT_EQ(newValue, server->getAttributeValue(ATTR_KEY));
194 }
195
196 TEST_F(RemoteResourceObjectTest, QueryParamsForGetWillBePassedToBase)
197 {
198     class CustomHandler
199     {
200     public:
201         virtual RCSGetResponse handle(const RCSRequest&, RCSResourceAttributes&) = 0;
202         virtual ~CustomHandler() {}
203     };
204
205     constexpr char PARAM_KEY[] { "aKey" };
206     constexpr char VALUE[] { "value" };
207
208     object->get(RCSQueryParams().setResourceInterface(RESOURCEINTERFACE).setResourceType(RESOURCETYPE).
209             put(PARAM_KEY, VALUE),
210             [](const HeaderOpts&, const RCSRepresentation&, int){});
211
212     auto mockHandler = mocks.Mock< CustomHandler >();
213
214     mocks.ExpectCall(mockHandler, CustomHandler::handle).
215             Match([](const RCSRequest& request, RCSResourceAttributes&)
216             {
217                 return request.getInterface() == RESOURCEINTERFACE &&
218                         request.getQueryParams().at(PARAM_KEY) == VALUE;
219             }
220     ).
221             Do([this](const RCSRequest&, RCSResourceAttributes&)
222             {
223                 Proceed();
224                 return RCSGetResponse::defaultAction();
225             }
226     );
227
228     server->setGetRequestHandler(std::bind(&CustomHandler::handle, mockHandler,
229             std::placeholders::_1, std::placeholders::_2));
230
231     Wait();
232 }
233
234 TEST_F(RemoteResourceObjectTest, MonitoringIsNotStartedByDefault)
235 {
236     ASSERT_FALSE(object->isMonitoring());
237 }
238
239 TEST_F(RemoteResourceObjectTest, StartMonitoringThrowsIfFunctionIsEmpty)
240 {
241     ASSERT_THROW(object->startMonitoring({ }), RCSInvalidParameterException);
242 }
243
244 TEST_F(RemoteResourceObjectTest, IsMonitoringReturnsTrueAfterStartMonitoring)
245 {
246     object->startMonitoring(resourceStateChanged);
247
248     ASSERT_TRUE(object->isMonitoring());
249 }
250
251 TEST_F(RemoteResourceObjectTest, StartMonitoringThrowsIfTryingToStartAgain)
252 {
253     object->startMonitoring(resourceStateChanged);
254
255     ASSERT_THROW(object->startMonitoring(resourceStateChanged), RCSBadRequestException);
256 }
257
258 TEST_F(RemoteResourceObjectTest, DefaultStateIsNone)
259 {
260     ASSERT_EQ(ResourceState::NONE, object->getState());
261 }
262
263 TEST_F(RemoteResourceObjectTest, CachingIsNotStartedByDefault)
264 {
265     ASSERT_FALSE(object->isCaching());
266 }
267
268 TEST_F(RemoteResourceObjectTest, IsCachingReturnsTrueAfterStartCaching)
269 {
270     object->startCaching(cacheUpdatedCallback);
271
272     ASSERT_TRUE(object->isCaching());
273 }
274
275 TEST_F(RemoteResourceObjectTest, StartCachingThrowsIfTryingToStartAgain)
276 {
277     object->startCaching(cacheUpdatedCallback);
278
279     ASSERT_THROW(object->startCaching(), RCSBadRequestException);
280 }
281
282 TEST_F(RemoteResourceObjectTest, DefaultCacheStateIsNone)
283 {
284     ASSERT_EQ(CacheState::NONE, object->getCacheState());
285 }
286
287 TEST_F(RemoteResourceObjectTest, CacheStateIsUnreadyAfterStartCaching)
288 {
289     object->startCaching();
290
291     ASSERT_EQ(CacheState::UNREADY, object->getCacheState());
292 }
293
294 TEST_F(RemoteResourceObjectTest, CacheStateIsReadyAfterCacheUpdated)
295 {
296     mocks.ExpectCallFunc(cacheUpdatedCallback).
297                 Do([this](const RCSResourceAttributes&){ Proceed(); });
298
299     object->startCaching(cacheUpdatedCallback);
300     Wait();
301
302     ASSERT_EQ(CacheState::READY, object->getCacheState());
303 }
304
305 TEST_F(RemoteResourceObjectTest, IsCachedAvailableReturnsTrueWhenCacheIsReady)
306 {
307     mocks.ExpectCallFunc(cacheUpdatedCallback).
308                 Do([this](const RCSResourceAttributes&){ Proceed(); });
309
310     object->startCaching(cacheUpdatedCallback);
311     Wait();
312
313     ASSERT_TRUE(object->isCachedAvailable());
314 }
315
316 TEST_F(RemoteResourceObjectTest, DISABLED_CacheUpdatedCallbackBeCalledWheneverCacheUpdated)
317 {
318     mocks.OnCallFunc(cacheUpdatedCallback).
319             Do([this](const RCSResourceAttributes&){ Proceed(); });
320     object->startCaching(cacheUpdatedCallback);
321     Wait();
322
323     mocks.ExpectCallFunc(cacheUpdatedCallback).
324             Do([this](const RCSResourceAttributes&){ Proceed(); });
325
326     server->setAttribute(ATTR_KEY, ATTR_VALUE + 1);
327
328     Wait();
329 }
330
331 TEST_F(RemoteResourceObjectTest, DISABLED_CacheUpdatedCallbackBeCalledWithUpdatedAttributes)
332 {
333     constexpr int newValue = ATTR_VALUE + 1;
334
335     mocks.OnCallFunc(cacheUpdatedCallback).
336             Do([this](const RCSResourceAttributes&){ Proceed(); });
337     object->startCaching(cacheUpdatedCallback);
338     Wait();
339
340     mocks.ExpectCallFunc(cacheUpdatedCallback).
341             Match([this](const RCSResourceAttributes& attrs){
342                 return attrs.at(ATTR_KEY) == newValue;
343             }).
344             Do([this](const RCSResourceAttributes&){ Proceed(); });
345
346     server->setAttribute(ATTR_KEY, newValue);
347
348     Wait();
349 }
350
351 TEST_F(RemoteResourceObjectTest, GetCachedAttributesThrowsIfCachingIsNotStarted)
352 {
353     ASSERT_THROW(object->getCachedAttributes(), RCSBadRequestException);
354 }
355
356 TEST_F(RemoteResourceObjectTest, CachedAttributesHasSameAttributesWithServer)
357 {
358     mocks.OnCallFunc(cacheUpdatedCallback).
359             Do([this](const RCSResourceAttributes&){ Proceed(); });
360     object->startCaching(cacheUpdatedCallback);
361     Wait();
362
363     RCSResourceObject::LockGuard lock{ server };
364
365     ASSERT_EQ(object->getCachedAttributes(), server->getAttributes());
366 }
367
368 TEST_F(RemoteResourceObjectTest, GetCachedAttributeThrowsIfCachingIsNotStarted)
369 {
370     ASSERT_THROW(object->getCachedAttribute(ATTR_KEY), RCSBadRequestException);
371 }
372
373 TEST_F(RemoteResourceObjectTest, GetCachedAttributeThrowsIfKeyIsInvalid)
374 {
375     mocks.OnCallFunc(cacheUpdatedCallback).
376             Do([this](const RCSResourceAttributes&){ Proceed(); });
377     object->startCaching(cacheUpdatedCallback);
378     Wait();
379
380     ASSERT_THROW(object->getCachedAttribute(""), RCSInvalidKeyException);
381 }
382
383 TEST_F(RemoteResourceObjectTest, HasSameUriWithServer)
384 {
385     EXPECT_EQ(RESOURCEURI, object->getUri());
386 }
387
388 TEST_F(RemoteResourceObjectTest, HasSameTypeWithServer)
389 {
390     EXPECT_EQ(RESOURCETYPE, object->getTypes()[0]);
391 }
392
393 TEST_F(RemoteResourceObjectTest, HasSameInterfaceWithServer)
394 {
395     EXPECT_EQ(RESOURCEINTERFACE, object->getInterfaces()[0]);
396 }
397
398 TEST_F(RemoteResourceObjectTest, GetValidOCResourceTest)
399 {
400     std::shared_ptr<OC::OCResource> ocRes = RCSRemoteResourceObject::toOCResource(object);
401
402     EXPECT_NE(nullptr, ocRes);
403
404     EXPECT_EQ(RESOURCEURI, ocRes->uri());
405 }
406