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