Using libConfig structures for input in server
[platform/core/security/vasum.git] / tests / unit_tests / config / ut-configuration.cpp
1 /*
2  *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *  Contact: Michal Witanowski <m.witanowski@samsung.com>
5  *
6  *  Licensed under the Apache License, Version 2.0 (the "License");
7  *  you may not use this file except in compliance with the License.
8  *  You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *  Unless required by applicable law or agreed to in writing, software
13  *  distributed under the License is distributed on an "AS IS" BASIS,
14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *  See the License for the specific language governing permissions and
16  *  limitations under the License
17  */
18
19
20 /**
21  * @file
22  * @author  Michal Witanowski (m.witanowski@samsung.com)
23  * @brief   Unit test of Configuration
24  */
25
26 #include "config.hpp"
27 #include "ut.hpp"
28 #include "testconfig-example.hpp"
29 #include "config/manager.hpp"
30 #include "utils/scoped-dir.hpp"
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <fcntl.h>
34
35 namespace {
36
37 using namespace config;
38
39 const std::string UT_PATH = "/tmp/ut-config/";
40 const std::string DB_PATH = UT_PATH + "kvstore.db3";
41 const std::string DB_PREFIX = "ut";
42
43 // Floating point tolerance as a number of rounding errors
44 const int TOLERANCE = 1;
45
46 struct Fixture {
47     vasum::utils::ScopedDir mUTDirGuard;
48     Fixture() : mUTDirGuard(UT_PATH) {}
49 };
50
51 } // namespace
52
53 BOOST_FIXTURE_TEST_SUITE(ConfigurationSuite, Fixture)
54
55 BOOST_AUTO_TEST_CASE(FromJsonString)
56 {
57     TestConfig testConfig;
58
59     BOOST_REQUIRE_NO_THROW(loadFromJsonString(jsonTestString, testConfig));
60
61     BOOST_CHECK_EQUAL(12345, testConfig.intVal);
62     BOOST_CHECK_EQUAL(-1234567890123456789ll, testConfig.int64Val);
63     BOOST_CHECK_EQUAL(123456, testConfig.uint32Val);
64     BOOST_CHECK_EQUAL(1234567890123456789ll, testConfig.uint64Val);
65     BOOST_CHECK_EQUAL("blah", testConfig.stringVal);
66     BOOST_CHECK_CLOSE(-1.234, testConfig.doubleVal, TOLERANCE);
67     BOOST_CHECK_EQUAL(true, testConfig.boolVal);
68
69     BOOST_REQUIRE_EQUAL(0, testConfig.emptyIntVector.size());
70
71     BOOST_REQUIRE_EQUAL(3, testConfig.intVector.size());
72     BOOST_CHECK_EQUAL(1, testConfig.intVector[0]);
73     BOOST_CHECK_EQUAL(2, testConfig.intVector[1]);
74     BOOST_CHECK_EQUAL(3, testConfig.intVector[2]);
75
76     BOOST_REQUIRE_EQUAL(2, testConfig.stringVector.size());
77     BOOST_CHECK_EQUAL("a", testConfig.stringVector[0]);
78     BOOST_CHECK_EQUAL("b", testConfig.stringVector[1]);
79
80     BOOST_REQUIRE_EQUAL(3, testConfig.doubleVector.size());
81     BOOST_CHECK_CLOSE(0.0, testConfig.doubleVector[0], TOLERANCE);
82     BOOST_CHECK_CLOSE(1.0, testConfig.doubleVector[1], TOLERANCE);
83     BOOST_CHECK_CLOSE(2.0, testConfig.doubleVector[2], TOLERANCE);
84
85     BOOST_CHECK_EQUAL(54321, testConfig.subObj.intVal);
86     BOOST_CHECK_EQUAL(2,     testConfig.subObj.intVector.size());
87     BOOST_CHECK_EQUAL(1,     testConfig.subObj.intVector[0]);
88     BOOST_CHECK_EQUAL(2,     testConfig.subObj.intVector[1]);
89     BOOST_CHECK_EQUAL(234,   testConfig.subObj.subSubObj.intVal);
90
91     BOOST_REQUIRE_EQUAL(2, testConfig.subVector.size());
92     BOOST_CHECK_EQUAL(123, testConfig.subVector[0].intVal);
93     BOOST_CHECK_EQUAL(456, testConfig.subVector[1].intVal);
94     BOOST_CHECK_EQUAL(345, testConfig.subVector[0].subSubObj.intVal);
95     BOOST_CHECK_EQUAL(567, testConfig.subVector[1].subSubObj.intVal);
96     BOOST_CHECK_EQUAL(3,   testConfig.subVector[0].intVector[0]);
97     BOOST_CHECK_EQUAL(5,   testConfig.subVector[1].intVector[0]);
98     BOOST_CHECK_EQUAL(4,   testConfig.subVector[0].intVector[1]);
99     BOOST_CHECK_EQUAL(6,   testConfig.subVector[1].intVector[1]);
100
101     BOOST_CHECK(testConfig.union1.is<int>());
102     BOOST_CHECK_EQUAL(2, testConfig.union1.as<int>());
103
104     BOOST_CHECK(testConfig.union2.is<TestConfig::SubConfig>());
105     BOOST_CHECK_EQUAL(54321, testConfig.union2.as<TestConfig::SubConfig>().intVal);
106     BOOST_REQUIRE_EQUAL(1,   testConfig.union2.as<TestConfig::SubConfig>().intVector.size());
107     BOOST_CHECK_EQUAL(1,     testConfig.union2.as<TestConfig::SubConfig>().intVector[0]);
108     BOOST_CHECK_EQUAL(234,   testConfig.union2.as<TestConfig::SubConfig>().subSubObj.intVal);
109
110     BOOST_REQUIRE_EQUAL(2, testConfig.unions.size());
111     BOOST_CHECK(testConfig.unions[0].is<int>());
112     BOOST_CHECK_EQUAL(2, testConfig.unions[0].as<int>());
113
114     BOOST_CHECK(testConfig.unions[1].is<TestConfig::SubConfig>());
115     BOOST_CHECK_EQUAL(54321, testConfig.unions[1].as<TestConfig::SubConfig>().intVal);
116     BOOST_REQUIRE_EQUAL(1,   testConfig.unions[1].as<TestConfig::SubConfig>().intVector.size());
117     BOOST_CHECK_EQUAL(1,     testConfig.unions[1].as<TestConfig::SubConfig>().intVector[0]);
118     BOOST_CHECK_EQUAL(234,   testConfig.unions[1].as<TestConfig::SubConfig>().subSubObj.intVal);
119 }
120
121
122 BOOST_AUTO_TEST_CASE(ToJsonString)
123 {
124     TestConfig testConfig;
125     BOOST_REQUIRE_NO_THROW(loadFromJsonString(jsonTestString, testConfig));
126
127     std::string out = saveToJsonString(testConfig);
128     BOOST_CHECK_EQUAL(out, jsonTestString);
129
130     TestConfig::SubConfigOption unionConfig;
131     BOOST_CHECK_THROW(saveToJsonString(unionConfig), ConfigException);
132 }
133
134 namespace loadErrorsTest {
135
136 #define DECLARE_CONFIG(name, type) \
137     struct name { \
138         type field; \
139         CONFIG_REGISTER(field) \
140     };
141 DECLARE_CONFIG(IntConfig, int)
142 DECLARE_CONFIG(StringConfig, std::string)
143 DECLARE_CONFIG(DoubleConfig, double)
144 DECLARE_CONFIG(BoolConfig, bool)
145 DECLARE_CONFIG(ArrayConfig, std::vector<int>)
146 DECLARE_CONFIG(ObjectConfig, IntConfig)
147 #undef DECLARE_CONFIG
148 struct UnionConfig {
149     CONFIG_DECLARE_UNION
150     (
151             int,
152             bool
153     )
154 };
155
156 } // namespace loadErrorsTest
157
158 BOOST_AUTO_TEST_CASE(JsonLoadErrors)
159 {
160     using namespace loadErrorsTest;
161
162     IntConfig config;
163     BOOST_REQUIRE_NO_THROW(loadFromJsonString("{\"field\":1}", config));
164
165     BOOST_CHECK_THROW(loadFromJsonString("", config), ConfigException);
166     BOOST_CHECK_THROW(loadFromJsonString("{", config), ConfigException); // invalid json
167     BOOST_CHECK_THROW(loadFromJsonString("{}", config), ConfigException); // missing field
168
169     // invalid type
170
171     IntConfig intConfig;
172     BOOST_CHECK_NO_THROW(loadFromJsonString("{\"field\": 1}", intConfig));
173     BOOST_CHECK_THROW(loadFromJsonString("{\"field\": \"1\"}", intConfig), ConfigException);
174     BOOST_CHECK_THROW(loadFromJsonString("{\"field\": 1.0}", intConfig), ConfigException);
175     BOOST_CHECK_THROW(loadFromJsonString("{\"field\": true}", intConfig), ConfigException);
176     BOOST_CHECK_THROW(loadFromJsonString("{\"field\": []}", intConfig), ConfigException);
177     BOOST_CHECK_THROW(loadFromJsonString("{\"field\": {}}", intConfig), ConfigException);
178     BOOST_CHECK_THROW(loadFromJsonString("{\"field\": 1234567890123456789}", intConfig), ConfigException);
179     BOOST_CHECK_THROW(loadFromJsonString("{\"field\": -1234567890123456789}", intConfig), ConfigException);
180
181     StringConfig stringConfig;
182     BOOST_CHECK_THROW(loadFromJsonString("{\"field\": 1}", stringConfig), ConfigException);
183     BOOST_CHECK_NO_THROW(loadFromJsonString("{\"field\": \"1\"}", stringConfig));
184     BOOST_CHECK_THROW(loadFromJsonString("{\"field\": 1.0}", stringConfig), ConfigException);
185     BOOST_CHECK_THROW(loadFromJsonString("{\"field\": true}", stringConfig), ConfigException);
186     BOOST_CHECK_THROW(loadFromJsonString("{\"field\": []}", stringConfig), ConfigException);
187     BOOST_CHECK_THROW(loadFromJsonString("{\"field\": {}}", stringConfig), ConfigException);
188
189     DoubleConfig doubleConfig;
190     BOOST_CHECK_THROW(loadFromJsonString("{\"field\": 1}", doubleConfig), ConfigException);
191     BOOST_CHECK_THROW(loadFromJsonString("{\"field\": \"1\"}", doubleConfig), ConfigException);
192     BOOST_CHECK_NO_THROW(loadFromJsonString("{\"field\": 1.0}", doubleConfig));
193     BOOST_CHECK_THROW(loadFromJsonString("{\"field\": true}", doubleConfig), ConfigException);
194     BOOST_CHECK_THROW(loadFromJsonString("{\"field\": []}", doubleConfig), ConfigException);
195     BOOST_CHECK_THROW(loadFromJsonString("{\"field\": {}}", doubleConfig), ConfigException);
196
197     BoolConfig boolConfig;
198     BOOST_CHECK_THROW(loadFromJsonString("{\"field\": 1}", boolConfig), ConfigException);
199     BOOST_CHECK_THROW(loadFromJsonString("{\"field\": \"1\"}", boolConfig), ConfigException);
200     BOOST_CHECK_THROW(loadFromJsonString("{\"field\": 1.0}", boolConfig), ConfigException);
201     BOOST_CHECK_NO_THROW(loadFromJsonString("{\"field\": true}", boolConfig));
202     BOOST_CHECK_THROW(loadFromJsonString("{\"field\": []}", boolConfig), ConfigException);
203     BOOST_CHECK_THROW(loadFromJsonString("{\"field\": {}}", boolConfig), ConfigException);
204
205     ArrayConfig arrayConfig;
206     BOOST_CHECK_THROW(loadFromJsonString("{\"field\": 1}", arrayConfig), ConfigException);
207     BOOST_CHECK_THROW(loadFromJsonString("{\"field\": \"1\"}", arrayConfig), ConfigException);
208     BOOST_CHECK_THROW(loadFromJsonString("{\"field\": 1.0}", arrayConfig), ConfigException);
209     BOOST_CHECK_THROW(loadFromJsonString("{\"field\": true}", arrayConfig), ConfigException);
210     BOOST_CHECK_NO_THROW(loadFromJsonString("{\"field\": []}", arrayConfig));
211     BOOST_CHECK_THROW(loadFromJsonString("{\"field\": {}}", arrayConfig), ConfigException);
212
213     ObjectConfig objectConfig;
214     BOOST_CHECK_THROW(loadFromJsonString("{\"field\": 1}", objectConfig), ConfigException);
215     BOOST_CHECK_THROW(loadFromJsonString("{\"field\": \"1\"}", objectConfig), ConfigException);
216     BOOST_CHECK_THROW(loadFromJsonString("{\"field\": 1.0}", objectConfig), ConfigException);
217     BOOST_CHECK_THROW(loadFromJsonString("{\"field\": true}", objectConfig), ConfigException);
218     BOOST_CHECK_THROW(loadFromJsonString("{\"field\": []}", objectConfig), ConfigException);
219     BOOST_CHECK_THROW(loadFromJsonString("{\"field\": {}}", objectConfig), ConfigException);
220     BOOST_CHECK_NO_THROW(loadFromJsonString("{\"field\": {\"field\": 1}}", objectConfig));
221
222     UnionConfig unionConfig;
223     BOOST_CHECK_THROW(loadFromJsonString("{\"type\": \"long\", \"value\": 1}", unionConfig), ConfigException);
224     BOOST_CHECK_THROW(loadFromJsonString("{\"type\": \"int\"}", unionConfig), ConfigException);
225     BOOST_CHECK_NO_THROW(loadFromJsonString("{\"type\": \"int\", \"value\": 1}", unionConfig));
226     BOOST_CHECK_NO_THROW(loadFromJsonString("{\"type\": \"bool\", \"value\": true}", unionConfig));
227 }
228
229 namespace hasVisitableTest {
230
231 struct NotVisitable {};
232 struct Visitable {
233     template<typename V>
234     void accept(V v);
235 };
236 struct ConstVisitable {
237     template<typename V>
238     void accept(V v) const;
239 };
240 struct FullVisitable {
241     template<typename V>
242     void accept(V v);
243     template<typename V>
244     void accept(V v) const;
245 };
246 struct DerivedVisitable : FullVisitable {};
247 struct MissingArg {
248     template<typename V>
249     void accept();
250 };
251 struct WrongArg {
252     template<typename V>
253     void accept(int v);
254 };
255 struct NotFunction {
256     int accept;
257 };
258
259 } // namespace hasVisitableTest
260
261 BOOST_AUTO_TEST_CASE(HasVisibleInternalHelper)
262 {
263     using namespace hasVisitableTest;
264
265     static_assert(isVisitable<Visitable>::value, "");
266     static_assert(isVisitable<ConstVisitable>::value, "");
267     static_assert(isVisitable<FullVisitable>::value, "");
268     static_assert(isVisitable<DerivedVisitable>::value, "");
269
270     static_assert(!isVisitable<NotVisitable>::value, "");
271     static_assert(!isVisitable<MissingArg>::value, "");
272     static_assert(!isVisitable<WrongArg>::value, "");
273     static_assert(!isVisitable<NotFunction>::value, "");
274
275     BOOST_CHECK(isVisitable<Visitable>());
276 }
277
278 BOOST_AUTO_TEST_CASE(FromToKVStore)
279 {
280     TestConfig config;
281     loadFromJsonString(jsonTestString, config);
282
283     saveToKVStore(DB_PATH, config, DB_PREFIX);
284     TestConfig outConfig;
285     loadFromKVStore(DB_PATH, outConfig, DB_PREFIX);
286
287     std::string out = saveToJsonString(outConfig);
288     BOOST_CHECK_EQUAL(out, jsonTestString);
289 }
290
291 BOOST_AUTO_TEST_CASE(FromToFD)
292 {
293     TestConfig config;
294     loadFromJsonString(jsonTestString, config);
295     // Setup fd
296     std::string fifoPath = UT_PATH + "fdstore";
297     BOOST_CHECK(::mkfifo(fifoPath.c_str(), S_IWUSR | S_IRUSR) >= 0);
298     int fd = ::open(fifoPath.c_str(), O_RDWR);
299     BOOST_REQUIRE(fd >= 0);
300
301     // The test
302     saveToFD(fd, config);
303     TestConfig outConfig;
304     loadFromFD(fd, outConfig);
305     std::string out = saveToJsonString(outConfig);
306     BOOST_CHECK_EQUAL(out, jsonTestString);
307
308     // Cleanup
309     BOOST_CHECK(::close(fd) >= 0);
310 }
311
312 BOOST_AUTO_TEST_CASE(FromKVWithDefaults)
313 {
314     TestConfig config;
315     loadFromJsonString(jsonTestString, config);
316
317     // nothing in db
318     TestConfig outConfig1;
319     loadFromKVStoreWithJson(DB_PATH, jsonTestString, outConfig1, DB_PREFIX);
320
321     std::string out1 = saveToJsonString(outConfig1);
322     BOOST_CHECK_EQUAL(out1, jsonTestString);
323
324     // all in db
325     saveToKVStore(DB_PATH, config, DB_PREFIX);
326     TestConfig outConfig2;
327     loadFromKVStoreWithJson(DB_PATH, jsonEmptyTestString, outConfig2, DB_PREFIX);
328
329     std::string out2 = saveToJsonString(outConfig2);
330     BOOST_CHECK_EQUAL(out2, jsonTestString);
331 }
332
333 BOOST_AUTO_TEST_CASE(PartialConfig)
334 {
335     // check if partial config is fully supported
336     TestConfig config;
337     loadFromJsonString(jsonTestString, config);
338
339     // from string
340     {
341         PartialTestConfig partialConfig;
342         loadFromJsonString(jsonTestString, partialConfig);
343
344         BOOST_CHECK_EQUAL(config.stringVal, partialConfig.stringVal);
345         BOOST_CHECK(config.intVector == partialConfig.intVector);
346     }
347
348     // from kv
349     {
350         PartialTestConfig partialConfig;
351         saveToKVStore(DB_PATH, config, DB_PREFIX);
352         loadFromKVStore(DB_PATH, partialConfig, DB_PREFIX);
353
354         BOOST_CHECK_EQUAL(config.stringVal, partialConfig.stringVal);
355         BOOST_CHECK(config.intVector == partialConfig.intVector);
356     }
357
358     // from kv with defaults
359     {
360         PartialTestConfig partialConfig;
361         loadFromKVStoreWithJson(DB_PATH, jsonTestString, partialConfig, DB_PREFIX);
362
363         BOOST_CHECK_EQUAL(config.stringVal, partialConfig.stringVal);
364         BOOST_CHECK(config.intVector == partialConfig.intVector);
365     }
366
367     // save to kv
368     {
369         PartialTestConfig partialConfig;
370         partialConfig.stringVal = "partial";
371         partialConfig.intVector = {7};
372         config::saveToKVStore(DB_PATH, partialConfig, DB_PREFIX);
373     }
374
375     // from gvariant (partial is not supported!)
376     {
377         PartialTestConfig partialConfig;
378         std::unique_ptr<GVariant, decltype(&g_variant_unref)> v(saveToGVariant(config),
379                                                                 g_variant_unref);
380         BOOST_CHECK_THROW(loadFromGVariant(v.get(), partialConfig), ConfigException);
381     }
382 }
383
384 BOOST_AUTO_TEST_CASE(ConfigUnion)
385 {
386     TestConfig testConfig;
387     BOOST_REQUIRE_NO_THROW(loadFromJsonString(jsonTestString, testConfig));
388
389     BOOST_CHECK(testConfig.union1.is<int>());
390     BOOST_CHECK(!testConfig.union1.is<TestConfig::SubConfig>());
391     BOOST_CHECK_EQUAL(testConfig.union1.as<int>(), 2);
392     BOOST_CHECK(!testConfig.union2.is<int>());
393     BOOST_CHECK(testConfig.union2.is<TestConfig::SubConfig>());
394     TestConfig::SubConfig& subConfig = testConfig.union2.as<TestConfig::SubConfig>();
395     BOOST_CHECK_EQUAL(subConfig.intVal, 54321);
396     BOOST_CHECK(testConfig.unions[0].is<int>());
397     BOOST_CHECK(testConfig.unions[1].is<TestConfig::SubConfig>());
398     std::string out = saveToJsonString(testConfig);
399     BOOST_CHECK_EQUAL(out, jsonTestString);
400
401     //Check copy
402
403     std::vector<TestConfig::SubConfigOption> unions(2);
404     unions[0].set<int>(2);
405     //set from const lvalue reference (copy)
406     unions[1].set(testConfig.unions[1].as<const TestConfig::SubConfig>());
407     BOOST_CHECK(!testConfig.unions[1].as<TestConfig::SubConfig>().subSubObj.isMoved());
408     //set from lvalue reference (copy)
409     unions[1].set(testConfig.unions[1].as<TestConfig::SubConfig>());
410     BOOST_CHECK(!testConfig.unions[1].as<TestConfig::SubConfig>().subSubObj.isMoved());
411     //set from const rvalue reference (copy)
412     unions[1].set(std::move(testConfig.unions[1].as<const TestConfig::SubConfig>()));
413     BOOST_CHECK(!testConfig.unions[1].as<TestConfig::SubConfig>().subSubObj.isMoved());
414     //set rvalue reference (copy -- move is disabled)
415     unions[1].set(std::move(testConfig.unions[1].as<TestConfig::SubConfig>()));
416     BOOST_CHECK(!testConfig.unions[1].as<TestConfig::SubConfig>().subSubObj.isMoved());
417     //assign lvalue reference (copy)
418     testConfig.unions[1] = unions[1];
419     BOOST_CHECK(!unions[1].as<TestConfig::SubConfig>().subSubObj.isMoved());
420     //assign rvalue reference (copy -- move is disabled)
421     testConfig.unions[1] = std::move(unions[1]);
422     BOOST_CHECK(!unions[1].as<TestConfig::SubConfig>().subSubObj.isMoved());
423
424     testConfig.unions.clear();
425     testConfig.unions = unions;
426     out = saveToJsonString(testConfig);
427     BOOST_CHECK_EQUAL(out, jsonTestString);
428 }
429
430
431 BOOST_AUTO_TEST_CASE(GVariantVisitor)
432 {
433     TestConfig testConfig;
434     BOOST_REQUIRE_NO_THROW(loadFromJsonString(jsonTestString, testConfig));
435     std::unique_ptr<GVariant, decltype(&g_variant_unref)> v(saveToGVariant(testConfig),
436                                                             g_variant_unref);
437     TestConfig testConfig2;
438     loadFromGVariant(v.get(), testConfig2);
439     std::string out = saveToJsonString(testConfig2);
440     BOOST_CHECK_EQUAL(out, jsonTestString);
441
442     PartialTestConfig partialConfig;
443     partialConfig.stringVal = testConfig.stringVal;
444     partialConfig.intVector = testConfig.intVector;
445     v.reset(saveToGVariant(partialConfig));
446     BOOST_CHECK_THROW(loadFromGVariant(v.get(), testConfig), ConfigException);
447 }
448
449 BOOST_AUTO_TEST_SUITE_END()