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