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