Merge branch 'master' into 'security-CKM' branch
[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 #include "RCSRemoteResourceObject.h"
23 #include "RCSDiscoveryManager.h"
24 #include "RCSResourceObject.h"
25 #include "PrimitiveResource.h"
26 #include <condition_variable>
27
28 #include <mutex>
29
30 using namespace OIC::Service;
31 using namespace OC;
32
33 constexpr char RESOURCEURI[]{ "/a/TemperatureSensor" };
34 constexpr char RESOURCETYPE[]{ "Resource.Hosting" };
35 constexpr char RESOURCEINTERFACE[]{ "oic.if.baseline" };
36
37 constexpr char ATTR_KEY[]{ "Temperature" };
38 constexpr int ATTR_VALUE{ 0 };
39
40 constexpr int DEFAULT_WAITING_TIME_IN_MILLIS = 3000;
41
42 void getRemoteAttributesCallback(const RCSResourceAttributes&) {}
43 void setRemoteAttributesCallback(const RCSResourceAttributes&) {}
44 void resourceStateChanged(ResourceState) { }
45 void cacheUpdatedCallback(const RCSResourceAttributes&) {}
46
47 class RemoteResourceObjectTest: public TestWithMock
48 {
49 public:
50     RCSResourceObject::Ptr server;
51     RCSRemoteResourceObject::Ptr object;
52     std::shared_ptr< bool > finished;
53
54 public:
55     void Proceed()
56     {
57         cond.notify_all();
58     }
59
60     void Wait(int waitingTime = DEFAULT_WAITING_TIME_IN_MILLIS)
61     {
62         std::unique_lock< std::mutex > lock{ mutex };
63         cond.wait_for(lock, std::chrono::milliseconds{ waitingTime });
64     }
65
66 protected:
67     void SetUp()
68     {
69         TestWithMock::SetUp();
70
71         finished = std::make_shared< bool >(false);
72
73         CreateResource();
74
75         WaitUntilDiscovered();
76     }
77
78     void TearDown()
79     {
80         TestWithMock::TearDown();
81
82         // This method is to make sure objects disposed.
83         WaitForPtrBeingUnique();
84
85         *finished = true;
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     bool checkObject()
96     {
97         std::lock_guard<std::mutex> lock{ mutexForObject };
98         return object == nullptr;
99     }
100
101     void WaitUntilDiscovered()
102     {
103         while (checkObject())
104         {
105             const std::string uri  = "/oic/res";
106             const std::string type = "Resource.Hosting";
107             RCSDiscoveryManager::getInstance()->discoverResourceByType(RCSAddress::multicast(),
108                      uri, type, std::bind(resourceDiscovered, this, finished,
109                            std::placeholders::_1));
110             Wait(1000);
111         }
112     }
113
114     void WaitForPtrBeingUnique()
115     {
116         while((object && !object.unique()) || (server && !server.unique()))
117         {
118             std::this_thread::sleep_for(std::chrono::milliseconds{ 100 });
119         }
120     }
121
122     // This callback is to protect crash from crashes caused by delayed callbacks
123     static void resourceDiscovered(RemoteResourceObjectTest* test,
124             std::shared_ptr< bool > finished, RCSRemoteResourceObject::Ptr resourceObject)
125     {
126         if (*finished) return;
127
128         {
129             std::lock_guard< std::mutex > lock{ test->mutexForObject };
130
131             if (test->object) return;
132
133             test->object = resourceObject;
134         }
135
136         test->Proceed();
137     }
138
139 private:
140     std::condition_variable cond;
141     std::mutex mutex;
142     std::mutex mutexForObject;
143 };
144
145 TEST_F(RemoteResourceObjectTest, GetRemoteAttributesDoesNotAllowEmptyFunction)
146 {
147     ASSERT_THROW(object->getRemoteAttributes({ }), InvalidParameterException);
148 }
149
150 TEST_F(RemoteResourceObjectTest, GetRemoteAttributesGetsAttributesOfServer)
151 {
152     mocks.ExpectCallFunc(getRemoteAttributesCallback).Match(
153             [this](const RCSResourceAttributes& attrs)
154             {
155                 RCSResourceObject::LockGuard lock{ server };
156                 return attrs == server->getAttributes();
157             }
158     ).Do([this](const RCSResourceAttributes&){ Proceed(); });
159
160     object->getRemoteAttributes(getRemoteAttributesCallback);
161
162     Wait();
163 }
164
165 TEST_F(RemoteResourceObjectTest, SetRemoteAttributesDoesNotAllowEmptyFunction)
166 {
167     ASSERT_THROW(object->setRemoteAttributes({ }, { }), InvalidParameterException);
168 }
169
170 TEST_F(RemoteResourceObjectTest, SetRemoteAttributesSetsAttributesOfServer)
171 {
172     constexpr int newValue = ATTR_VALUE + 1;
173     RCSResourceAttributes newAttrs;
174     newAttrs[ATTR_KEY] = newValue;
175
176     mocks.ExpectCallFunc(setRemoteAttributesCallback).
177             Do([this](const RCSResourceAttributes&){ Proceed(); });
178
179     object->setRemoteAttributes(newAttrs, setRemoteAttributesCallback);
180     Wait();
181
182     ASSERT_EQ(newValue, server->getAttributeValue(ATTR_KEY));
183 }
184
185 TEST_F(RemoteResourceObjectTest, MonitoringIsNotStartedByDefault)
186 {
187     ASSERT_FALSE(object->isMonitoring());
188 }
189
190 TEST_F(RemoteResourceObjectTest, StartMonitoringThrowsIfFunctionIsEmpty)
191 {
192     ASSERT_THROW(object->startMonitoring({ }), InvalidParameterException);
193 }
194
195 TEST_F(RemoteResourceObjectTest, IsMonitoringReturnsTrueAfterStartMonitoring)
196 {
197     object->startMonitoring(resourceStateChanged);
198
199     ASSERT_TRUE(object->isMonitoring());
200 }
201
202 TEST_F(RemoteResourceObjectTest, StartMonitoringThrowsIfTryingToStartAgain)
203 {
204     object->startMonitoring(resourceStateChanged);
205
206     ASSERT_THROW(object->startMonitoring(resourceStateChanged), BadRequestException);
207 }
208
209 TEST_F(RemoteResourceObjectTest, DefaultStateIsNone)
210 {
211     ASSERT_EQ(ResourceState::NONE, object->getState());
212 }
213
214 TEST_F(RemoteResourceObjectTest, CachingIsNotStartedByDefault)
215 {
216     ASSERT_FALSE(object->isCaching());
217 }
218
219 TEST_F(RemoteResourceObjectTest, IsCachingReturnsTrueAfterStartCaching)
220 {
221     object->startCaching(cacheUpdatedCallback);
222
223     ASSERT_TRUE(object->isCaching());
224 }
225
226 TEST_F(RemoteResourceObjectTest, StartCachingThrowsIfTryingToStartAgain)
227 {
228     object->startCaching(cacheUpdatedCallback);
229
230     ASSERT_THROW(object->startCaching(), BadRequestException);
231 }
232
233 TEST_F(RemoteResourceObjectTest, DefaultCacheStateIsNone)
234 {
235     ASSERT_EQ(CacheState::NONE, object->getCacheState());
236 }
237
238 TEST_F(RemoteResourceObjectTest, CacheStateIsUnreadyAfterStartCaching)
239 {
240     object->startCaching();
241
242     ASSERT_EQ(CacheState::UNREADY, object->getCacheState());
243 }
244
245 TEST_F(RemoteResourceObjectTest, CacheStateIsReadyAfterCacheUpdated)
246 {
247     mocks.ExpectCallFunc(cacheUpdatedCallback).
248                 Do([this](const RCSResourceAttributes&){ Proceed(); });
249
250     object->startCaching(cacheUpdatedCallback);
251     Wait();
252
253     ASSERT_EQ(CacheState::READY, object->getCacheState());
254 }
255
256 TEST_F(RemoteResourceObjectTest, IsCachedAvailableReturnsTrueWhenCacheIsReady)
257 {
258     mocks.ExpectCallFunc(cacheUpdatedCallback).
259                 Do([this](const RCSResourceAttributes&){ Proceed(); });
260
261     object->startCaching(cacheUpdatedCallback);
262     Wait();
263
264     ASSERT_TRUE(object->isCachedAvailable());
265 }
266
267 TEST_F(RemoteResourceObjectTest, DISABLED_CacheUpdatedCallbackBeCalledWheneverCacheUpdated)
268 {
269     mocks.OnCallFunc(cacheUpdatedCallback).
270             Do([this](const RCSResourceAttributes&){ Proceed(); });
271     object->startCaching(cacheUpdatedCallback);
272     Wait();
273
274     mocks.ExpectCallFunc(cacheUpdatedCallback).
275             Do([this](const RCSResourceAttributes&){ Proceed(); });
276
277     server->setAttribute(ATTR_KEY, ATTR_VALUE + 1);
278
279     Wait();
280 }
281
282 TEST_F(RemoteResourceObjectTest, DISABLED_CacheUpdatedCallbackBeCalledWithUpdatedAttributes)
283 {
284     constexpr int newValue = ATTR_VALUE + 1;
285
286     mocks.OnCallFunc(cacheUpdatedCallback).
287             Do([this](const RCSResourceAttributes&){ Proceed(); });
288     object->startCaching(cacheUpdatedCallback);
289     Wait();
290
291     mocks.ExpectCallFunc(cacheUpdatedCallback).
292             Match([this](const RCSResourceAttributes& attrs){
293                 return attrs.at(ATTR_KEY) == newValue;
294             }).
295             Do([this](const RCSResourceAttributes&){ Proceed(); });
296
297     server->setAttribute(ATTR_KEY, newValue);
298
299     Wait();
300 }
301
302 TEST_F(RemoteResourceObjectTest, GetCachedAttributesThrowsIfCachingIsNotStarted)
303 {
304     ASSERT_THROW(object->getCachedAttributes(), BadRequestException);
305 }
306
307 TEST_F(RemoteResourceObjectTest, CachedAttributesHasSameAttributesWithServer)
308 {
309     mocks.OnCallFunc(cacheUpdatedCallback).
310             Do([this](const RCSResourceAttributes&){ Proceed(); });
311     object->startCaching(cacheUpdatedCallback);
312     Wait();
313
314     RCSResourceObject::LockGuard lock{ server };
315
316     ASSERT_EQ(object->getCachedAttributes(), server->getAttributes());
317 }
318
319 TEST_F(RemoteResourceObjectTest, GetCachedAttributeThrowsIfCachingIsNotStarted)
320 {
321     ASSERT_THROW(object->getCachedAttribute(ATTR_KEY), BadRequestException);
322 }
323
324 TEST_F(RemoteResourceObjectTest, GetCachedAttributeThrowsIfKeyIsInvalid)
325 {
326     mocks.OnCallFunc(cacheUpdatedCallback).
327             Do([this](const RCSResourceAttributes&){ Proceed(); });
328     object->startCaching(cacheUpdatedCallback);
329     Wait();
330
331     ASSERT_THROW(object->getCachedAttribute(""), InvalidKeyException);
332 }
333
334 TEST_F(RemoteResourceObjectTest, HasSameUriWithServer)
335 {
336     EXPECT_EQ(RESOURCEURI, object->getUri());
337 }
338
339 TEST_F(RemoteResourceObjectTest, HasSameTypeWithServer)
340 {
341     EXPECT_EQ(RESOURCETYPE, object->getTypes()[0]);
342 }
343
344 TEST_F(RemoteResourceObjectTest, HasSameInterfaceWithServer)
345 {
346     EXPECT_EQ(RESOURCEINTERFACE, object->getInterfaces()[0]);
347 }
348