Merge branch 'master' into windows-port
[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             auto discoveryTask = RCSDiscoveryManager::getInstance()->discoverResourceByType(
99                     RCSAddress::multicast(), RESOURCETYPE,
100                     std::bind(&RemoteResourceObjectTest::resourceDiscovered, this,
101                             std::placeholders::_1));
102             Wait(1000);
103             discoveryTask->cancel();
104         }
105     }
106
107     void WaitForPtrBeingUnique()
108     {
109         while((object && !object.unique()) || (server && !server.unique()))
110         {
111             std::this_thread::sleep_for(std::chrono::milliseconds{ 100 });
112         }
113     }
114
115     void resourceDiscovered(RCSRemoteResourceObject::Ptr resourceObject)
116     {
117         object = resourceObject;
118
119         Proceed();
120     }
121
122 private:
123     std::condition_variable cond;
124     std::mutex mutex;
125 };
126
127 TEST_F(RemoteResourceObjectTest, GetRemoteAttributesDoesNotAllowEmptyFunction)
128 {
129     ASSERT_THROW(object->getRemoteAttributes({ }), RCSInvalidParameterException);
130 }
131
132 TEST_F(RemoteResourceObjectTest, GetRemoteAttributesGetsAttributesOfServer)
133 {
134     mocks.ExpectCallFunc(getRemoteAttributesCallback).Match(
135             [this](const RCSResourceAttributes& attrs, int)
136             {
137                 RCSResourceObject::LockGuard lock{ server };
138                 return attrs == server->getAttributes();
139             }
140     ).Do([this](const RCSResourceAttributes&, int){ Proceed(); });
141
142     object->getRemoteAttributes(getRemoteAttributesCallback);
143
144     Wait();
145 }
146
147 TEST_F(RemoteResourceObjectTest, SetRemoteAttributesDoesNotAllowEmptyFunction)
148 {
149     ASSERT_THROW(object->setRemoteAttributes({ }, { }), RCSInvalidParameterException);
150 }
151
152 TEST_F(RemoteResourceObjectTest, SetRemoteAttributesSetsAttributesOfServer)
153 {
154     constexpr int newValue = ATTR_VALUE + 1;
155     RCSResourceAttributes newAttrs;
156     newAttrs[ATTR_KEY] = newValue;
157
158     mocks.ExpectCallFunc(setRemoteAttributesCallback).
159             Do([this](const RCSResourceAttributes&, int){ Proceed(); });
160
161     object->setRemoteAttributes(newAttrs, setRemoteAttributesCallback);
162     Wait();
163
164     ASSERT_EQ(newValue, server->getAttributeValue(ATTR_KEY));
165 }
166
167 TEST_F(RemoteResourceObjectTest, QueryParamsForGetWillBePassedToBase)
168 {
169     class CustomHandler
170     {
171     public:
172         virtual RCSGetResponse handle(const RCSRequest&, RCSResourceAttributes&) = 0;
173         virtual ~CustomHandler() {}
174     };
175
176     constexpr char PARAM_KEY[] { "aKey" };
177     constexpr char VALUE[] { "value" };
178
179     object->get(RCSQueryParams().setResourceInterface(RESOURCEINTERFACE).setResourceType(RESOURCETYPE).
180             put(PARAM_KEY, VALUE),
181             [](const HeaderOpts&, const RCSRepresentation&, int){});
182
183     auto mockHandler = mocks.Mock< CustomHandler >();
184
185     mocks.ExpectCall(mockHandler, CustomHandler::handle).
186             Match([](const RCSRequest& request, RCSResourceAttributes&)
187             {
188                 return request.getInterface() == RESOURCEINTERFACE &&
189                         request.getQueryParams().at(PARAM_KEY) == VALUE;
190             }
191     ).
192             Do([this](const RCSRequest&, RCSResourceAttributes&)
193             {
194                 Proceed();
195                 return RCSGetResponse::defaultAction();
196             }
197     );
198
199     server->setGetRequestHandler(std::bind(&CustomHandler::handle, mockHandler,
200             std::placeholders::_1, std::placeholders::_2));
201
202     Wait();
203 }
204
205 TEST_F(RemoteResourceObjectTest, MonitoringIsNotStartedByDefault)
206 {
207     ASSERT_FALSE(object->isMonitoring());
208 }
209
210 TEST_F(RemoteResourceObjectTest, StartMonitoringThrowsIfFunctionIsEmpty)
211 {
212     ASSERT_THROW(object->startMonitoring({ }), RCSInvalidParameterException);
213 }
214
215 TEST_F(RemoteResourceObjectTest, IsMonitoringReturnsTrueAfterStartMonitoring)
216 {
217     object->startMonitoring(resourceStateChanged);
218
219     ASSERT_TRUE(object->isMonitoring());
220 }
221
222 TEST_F(RemoteResourceObjectTest, StartMonitoringThrowsIfTryingToStartAgain)
223 {
224     object->startMonitoring(resourceStateChanged);
225
226     ASSERT_THROW(object->startMonitoring(resourceStateChanged), RCSBadRequestException);
227 }
228
229 TEST_F(RemoteResourceObjectTest, DefaultStateIsNone)
230 {
231     ASSERT_EQ(ResourceState::NONE, object->getState());
232 }
233
234 TEST_F(RemoteResourceObjectTest, CachingIsNotStartedByDefault)
235 {
236     ASSERT_FALSE(object->isCaching());
237 }
238
239 TEST_F(RemoteResourceObjectTest, IsCachingReturnsTrueAfterStartCaching)
240 {
241     object->startCaching(cacheUpdatedCallback);
242
243     ASSERT_TRUE(object->isCaching());
244 }
245
246 TEST_F(RemoteResourceObjectTest, StartCachingThrowsIfTryingToStartAgain)
247 {
248     object->startCaching(cacheUpdatedCallback);
249
250     ASSERT_THROW(object->startCaching(), RCSBadRequestException);
251 }
252
253 TEST_F(RemoteResourceObjectTest, DefaultCacheStateIsNone)
254 {
255     ASSERT_EQ(CacheState::NONE, object->getCacheState());
256 }
257
258 TEST_F(RemoteResourceObjectTest, CacheStateIsUnreadyAfterStartCaching)
259 {
260     object->startCaching();
261
262     ASSERT_EQ(CacheState::UNREADY, object->getCacheState());
263 }
264
265 TEST_F(RemoteResourceObjectTest, CacheStateIsReadyAfterCacheUpdated)
266 {
267     mocks.ExpectCallFunc(cacheUpdatedCallback).
268                 Do([this](const RCSResourceAttributes&){ Proceed(); });
269
270     object->startCaching(cacheUpdatedCallback);
271     Wait();
272
273     ASSERT_EQ(CacheState::READY, object->getCacheState());
274 }
275
276 TEST_F(RemoteResourceObjectTest, IsCachedAvailableReturnsTrueWhenCacheIsReady)
277 {
278     mocks.ExpectCallFunc(cacheUpdatedCallback).
279                 Do([this](const RCSResourceAttributes&){ Proceed(); });
280
281     object->startCaching(cacheUpdatedCallback);
282     Wait();
283
284     ASSERT_TRUE(object->isCachedAvailable());
285 }
286
287 TEST_F(RemoteResourceObjectTest, DISABLED_CacheUpdatedCallbackBeCalledWheneverCacheUpdated)
288 {
289     mocks.OnCallFunc(cacheUpdatedCallback).
290             Do([this](const RCSResourceAttributes&){ Proceed(); });
291     object->startCaching(cacheUpdatedCallback);
292     Wait();
293
294     mocks.ExpectCallFunc(cacheUpdatedCallback).
295             Do([this](const RCSResourceAttributes&){ Proceed(); });
296
297     server->setAttribute(ATTR_KEY, ATTR_VALUE + 1);
298
299     Wait();
300 }
301
302 TEST_F(RemoteResourceObjectTest, DISABLED_CacheUpdatedCallbackBeCalledWithUpdatedAttributes)
303 {
304     constexpr int newValue = ATTR_VALUE + 1;
305
306     mocks.OnCallFunc(cacheUpdatedCallback).
307             Do([this](const RCSResourceAttributes&){ Proceed(); });
308     object->startCaching(cacheUpdatedCallback);
309     Wait();
310
311     mocks.ExpectCallFunc(cacheUpdatedCallback).
312             Match([this](const RCSResourceAttributes& attrs){
313                 return attrs.at(ATTR_KEY) == newValue;
314             }).
315             Do([this](const RCSResourceAttributes&){ Proceed(); });
316
317     server->setAttribute(ATTR_KEY, newValue);
318
319     Wait();
320 }
321
322 TEST_F(RemoteResourceObjectTest, GetCachedAttributesThrowsIfCachingIsNotStarted)
323 {
324     ASSERT_THROW(object->getCachedAttributes(), RCSBadRequestException);
325 }
326
327 TEST_F(RemoteResourceObjectTest, CachedAttributesHasSameAttributesWithServer)
328 {
329     mocks.OnCallFunc(cacheUpdatedCallback).
330             Do([this](const RCSResourceAttributes&){ Proceed(); });
331     object->startCaching(cacheUpdatedCallback);
332     Wait();
333
334     RCSResourceObject::LockGuard lock{ server };
335
336     ASSERT_EQ(object->getCachedAttributes(), server->getAttributes());
337 }
338
339 TEST_F(RemoteResourceObjectTest, GetCachedAttributeThrowsIfCachingIsNotStarted)
340 {
341     ASSERT_THROW(object->getCachedAttribute(ATTR_KEY), RCSBadRequestException);
342 }
343
344 TEST_F(RemoteResourceObjectTest, GetCachedAttributeThrowsIfKeyIsInvalid)
345 {
346     mocks.OnCallFunc(cacheUpdatedCallback).
347             Do([this](const RCSResourceAttributes&){ Proceed(); });
348     object->startCaching(cacheUpdatedCallback);
349     Wait();
350
351     ASSERT_THROW(object->getCachedAttribute(""), RCSInvalidKeyException);
352 }
353
354 TEST_F(RemoteResourceObjectTest, HasSameUriWithServer)
355 {
356     EXPECT_EQ(RESOURCEURI, object->getUri());
357 }
358
359 TEST_F(RemoteResourceObjectTest, HasSameTypeWithServer)
360 {
361     EXPECT_EQ(RESOURCETYPE, object->getTypes()[0]);
362 }
363
364 TEST_F(RemoteResourceObjectTest, HasSameInterfaceWithServer)
365 {
366     EXPECT_EQ(RESOURCEINTERFACE, object->getInterfaces()[0]);
367 }
368