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 "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 resourceStateChanged(ResourceState) { }
47 void cacheUpdatedCallback(const RCSResourceAttributes&) {}
48
49 class RemoteResourceObjectTest: public TestWithMock
50 {
51 public:
52     RCSResourceObject::Ptr server;
53     RCSRemoteResourceObject::Ptr object;
54
55 public:
56     void Proceed()
57     {
58         cond.notify_all();
59     }
60
61     void Wait(int waitingTime = DEFAULT_WAITING_TIME_IN_MILLIS)
62     {
63         std::unique_lock< std::mutex > lock{ mutex };
64         cond.wait_for(lock, std::chrono::milliseconds{ waitingTime });
65     }
66
67 protected:
68     void SetUp()
69     {
70         TestWithMock::SetUp();
71
72         CreateResource();
73
74         WaitUntilDiscovered();
75
76         ASSERT_NE(object, nullptr);
77     }
78
79     void TearDown()
80     {
81         TestWithMock::TearDown();
82
83         // This method is to make sure objects disposed.
84         WaitForPtrBeingUnique();
85     }
86
87 private:
88     void CreateResource()
89     {
90         server = RCSResourceObject::Builder(RESOURCEURI, RESOURCETYPE, RESOURCEINTERFACE).build();
91         server->setAttribute(ATTR_KEY, ATTR_VALUE);
92     }
93
94     void WaitUntilDiscovered()
95     {
96         for (int i=0; i<10 && !object; ++i)
97         {
98             const std::string uri  = "/oic/res";
99             auto discoveryTask = RCSDiscoveryManager::getInstance()->discoverResourceByType(
100                     RCSAddress::multicast(), uri, 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, QueryParamsForGetWillBePassedToBase)
169 {
170     class CustomHandler
171     {
172     public:
173         virtual RCSGetResponse handle(const RCSRequest&, RCSResourceAttributes&) = 0;
174         virtual ~CustomHandler() {}
175     };
176
177     constexpr char PARAM_KEY[] { "aKey" };
178     constexpr char VALUE[] { "value" };
179
180     object->get(RCSQueryParams().setResourceInterface(RESOURCEINTERFACE).setResourceType(RESOURCETYPE).
181             put(PARAM_KEY, VALUE),
182             [](const HeaderOpts&, const RCSRepresentation&, int){});
183
184     auto mockHandler = mocks.Mock< CustomHandler >();
185
186     mocks.ExpectCall(mockHandler, CustomHandler::handle).
187             Match([](const RCSRequest& request, RCSResourceAttributes&)
188             {
189                 return request.getInterface() == RESOURCEINTERFACE &&
190                         request.getQueryParams().at(PARAM_KEY) == VALUE;
191             }
192     ).
193             Do([this](const RCSRequest&, RCSResourceAttributes&)
194             {
195                 Proceed();
196                 return RCSGetResponse::defaultAction();
197             }
198     );
199
200     server->setGetRequestHandler(std::bind(&CustomHandler::handle, mockHandler,
201             std::placeholders::_1, std::placeholders::_2));
202
203     Wait();
204 }
205
206 TEST_F(RemoteResourceObjectTest, MonitoringIsNotStartedByDefault)
207 {
208     ASSERT_FALSE(object->isMonitoring());
209 }
210
211 TEST_F(RemoteResourceObjectTest, StartMonitoringThrowsIfFunctionIsEmpty)
212 {
213     ASSERT_THROW(object->startMonitoring({ }), RCSInvalidParameterException);
214 }
215
216 TEST_F(RemoteResourceObjectTest, IsMonitoringReturnsTrueAfterStartMonitoring)
217 {
218     object->startMonitoring(resourceStateChanged);
219
220     ASSERT_TRUE(object->isMonitoring());
221 }
222
223 TEST_F(RemoteResourceObjectTest, StartMonitoringThrowsIfTryingToStartAgain)
224 {
225     object->startMonitoring(resourceStateChanged);
226
227     ASSERT_THROW(object->startMonitoring(resourceStateChanged), RCSBadRequestException);
228 }
229
230 TEST_F(RemoteResourceObjectTest, DefaultStateIsNone)
231 {
232     ASSERT_EQ(ResourceState::NONE, object->getState());
233 }
234
235 TEST_F(RemoteResourceObjectTest, CachingIsNotStartedByDefault)
236 {
237     ASSERT_FALSE(object->isCaching());
238 }
239
240 TEST_F(RemoteResourceObjectTest, IsCachingReturnsTrueAfterStartCaching)
241 {
242     object->startCaching(cacheUpdatedCallback);
243
244     ASSERT_TRUE(object->isCaching());
245 }
246
247 TEST_F(RemoteResourceObjectTest, StartCachingThrowsIfTryingToStartAgain)
248 {
249     object->startCaching(cacheUpdatedCallback);
250
251     ASSERT_THROW(object->startCaching(), RCSBadRequestException);
252 }
253
254 TEST_F(RemoteResourceObjectTest, DefaultCacheStateIsNone)
255 {
256     ASSERT_EQ(CacheState::NONE, object->getCacheState());
257 }
258
259 TEST_F(RemoteResourceObjectTest, CacheStateIsUnreadyAfterStartCaching)
260 {
261     object->startCaching();
262
263     ASSERT_EQ(CacheState::UNREADY, object->getCacheState());
264 }
265
266 TEST_F(RemoteResourceObjectTest, CacheStateIsReadyAfterCacheUpdated)
267 {
268     mocks.ExpectCallFunc(cacheUpdatedCallback).
269                 Do([this](const RCSResourceAttributes&){ Proceed(); });
270
271     object->startCaching(cacheUpdatedCallback);
272     Wait();
273
274     ASSERT_EQ(CacheState::READY, object->getCacheState());
275 }
276
277 TEST_F(RemoteResourceObjectTest, IsCachedAvailableReturnsTrueWhenCacheIsReady)
278 {
279     mocks.ExpectCallFunc(cacheUpdatedCallback).
280                 Do([this](const RCSResourceAttributes&){ Proceed(); });
281
282     object->startCaching(cacheUpdatedCallback);
283     Wait();
284
285     ASSERT_TRUE(object->isCachedAvailable());
286 }
287
288 TEST_F(RemoteResourceObjectTest, DISABLED_CacheUpdatedCallbackBeCalledWheneverCacheUpdated)
289 {
290     mocks.OnCallFunc(cacheUpdatedCallback).
291             Do([this](const RCSResourceAttributes&){ Proceed(); });
292     object->startCaching(cacheUpdatedCallback);
293     Wait();
294
295     mocks.ExpectCallFunc(cacheUpdatedCallback).
296             Do([this](const RCSResourceAttributes&){ Proceed(); });
297
298     server->setAttribute(ATTR_KEY, ATTR_VALUE + 1);
299
300     Wait();
301 }
302
303 TEST_F(RemoteResourceObjectTest, DISABLED_CacheUpdatedCallbackBeCalledWithUpdatedAttributes)
304 {
305     constexpr int newValue = ATTR_VALUE + 1;
306
307     mocks.OnCallFunc(cacheUpdatedCallback).
308             Do([this](const RCSResourceAttributes&){ Proceed(); });
309     object->startCaching(cacheUpdatedCallback);
310     Wait();
311
312     mocks.ExpectCallFunc(cacheUpdatedCallback).
313             Match([this](const RCSResourceAttributes& attrs){
314                 return attrs.at(ATTR_KEY) == newValue;
315             }).
316             Do([this](const RCSResourceAttributes&){ Proceed(); });
317
318     server->setAttribute(ATTR_KEY, newValue);
319
320     Wait();
321 }
322
323 TEST_F(RemoteResourceObjectTest, GetCachedAttributesThrowsIfCachingIsNotStarted)
324 {
325     ASSERT_THROW(object->getCachedAttributes(), RCSBadRequestException);
326 }
327
328 TEST_F(RemoteResourceObjectTest, CachedAttributesHasSameAttributesWithServer)
329 {
330     mocks.OnCallFunc(cacheUpdatedCallback).
331             Do([this](const RCSResourceAttributes&){ Proceed(); });
332     object->startCaching(cacheUpdatedCallback);
333     Wait();
334
335     RCSResourceObject::LockGuard lock{ server };
336
337     ASSERT_EQ(object->getCachedAttributes(), server->getAttributes());
338 }
339
340 TEST_F(RemoteResourceObjectTest, GetCachedAttributeThrowsIfCachingIsNotStarted)
341 {
342     ASSERT_THROW(object->getCachedAttribute(ATTR_KEY), RCSBadRequestException);
343 }
344
345 TEST_F(RemoteResourceObjectTest, GetCachedAttributeThrowsIfKeyIsInvalid)
346 {
347     mocks.OnCallFunc(cacheUpdatedCallback).
348             Do([this](const RCSResourceAttributes&){ Proceed(); });
349     object->startCaching(cacheUpdatedCallback);
350     Wait();
351
352     ASSERT_THROW(object->getCachedAttribute(""), RCSInvalidKeyException);
353 }
354
355 TEST_F(RemoteResourceObjectTest, HasSameUriWithServer)
356 {
357     EXPECT_EQ(RESOURCEURI, object->getUri());
358 }
359
360 TEST_F(RemoteResourceObjectTest, HasSameTypeWithServer)
361 {
362     EXPECT_EQ(RESOURCETYPE, object->getTypes()[0]);
363 }
364
365 TEST_F(RemoteResourceObjectTest, HasSameInterfaceWithServer)
366 {
367     EXPECT_EQ(RESOURCEINTERFACE, object->getInterfaces()[0]);
368 }
369