test : add system_info_init_db_test 44/238244/6
authorKichan Kwon <k_c.kwon@samsung.com>
Tue, 7 Jul 2020 10:20:51 +0000 (19:20 +0900)
committerKichan Kwon <k_c.kwon@samsung.com>
Thu, 13 Aug 2020 08:17:53 +0000 (17:17 +0900)
Change-Id: I8f02ab2d6df029e50309ca1a10d3cb3e690d8be9
Signed-off-by: Kichan Kwon <k_c.kwon@samsung.com>
packaging/capi-system-info.spec
test/CMakeLists.txt
test/init_db/CMakeLists.txt [new file with mode: 0755]
test/init_db/feature.cpp [new file with mode: 0644]
test/init_db/feature.h [new file with mode: 0644]
test/init_db/system_info_init_db_test.cpp [new file with mode: 0644]
test/init_db/system_info_init_db_test.h [new file with mode: 0644]
test/init_db/tester.cpp [new file with mode: 0644]
test/init_db/tester.h [new file with mode: 0644]
test/init_db/util.cpp [new file with mode: 0644]
test/init_db/util.h [new file with mode: 0644]

index 97c2702c2a892176f729da1888cf8fb686912dae..4b08b80982d5324add85fb691d5d2559f1aeada9 100644 (file)
@@ -128,6 +128,8 @@ install -m 0644 gcov-obj/* %{buildroot}%{_datadir}/gcov/obj
 %files test
 # API test
 %{_bindir}/system_info_test
+# Init DB test
+%{_bindir}/system_info_init_db_test
 # Plugin test
 %attr(0755,root,-) %{_bindir}/system_info_external_plugin_test.sh
 %{_libdir}/libsystem_info_plugins/libsystem_info_test_plugin.so
index cca96c48c6cc104a77814a102ee42759343a8e1a..fe263b74fbf66bd58554b4ef78ff60b54e839051 100755 (executable)
@@ -2,6 +2,7 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
 
 SET(TESTS
        api
+       init_db
        plugin
 )
 
diff --git a/test/init_db/CMakeLists.txt b/test/init_db/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..9bbd44b
--- /dev/null
@@ -0,0 +1,27 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+
+SET(INIT_DB_TEST "system_info_init_db_test")
+
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
+AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR} SRCS)
+
+INCLUDE(FindPkgConfig)
+pkg_check_modules(init_db_test_pkgs REQUIRED
+               libxml-2.0
+)
+
+FOREACH(flag ${init_db_test_pkgs_CXXFLAGS})
+       SET(EXTRA_CXXFLAGS "${EXTRA_CXXFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+SET(EXTRA_CXXFLAGS "${EXTRA_CXXFLAGS} -g -fno-omit-frame-pointer -finstrument-functions -fpie")
+
+SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_CXXFLAGS}")
+
+SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed -pie")
+
+ADD_EXECUTABLE(${INIT_DB_TEST} ${SRCS})
+ADD_DEPENDENCIES(${INIT_DB_TEST} ${fw_name})
+TARGET_LINK_LIBRARIES(${INIT_DB_TEST} ${init_db_test_pkgs_LDFLAGS} "-L${CMAKE_SOURCE_DIR} -lcapi-system-info")
+
+INSTALL(TARGETS ${INIT_DB_TEST} DESTINATION bin)
diff --git a/test/init_db/feature.cpp b/test/init_db/feature.cpp
new file mode 100644 (file)
index 0000000..b5f81b7
--- /dev/null
@@ -0,0 +1,221 @@
+#include <algorithm>
+#include <iomanip>
+#include <iostream>
+#include <climits>
+#include <cstdlib>
+#include <string>
+#include <sstream>
+
+#include <system_info.h>
+
+#include "system_info_init_db_test.h"
+#include "feature.h"
+#include "util.h"
+
+/********** Feature **********/
+
+Feature::ModType Feature::getModType(void)
+{
+       return (ModType)(rand() % static_cast<int>(ModType::NUM_TYPE));
+}
+
+/********** BoolFeature **********/
+
+BoolFeature::BoolFeature(std::string k, std::string v) : Feature(k)
+{
+       if (!v.compare(STRBOOL_TRUE))
+               value = true;
+       else if (!v.compare(STRBOOL_FALSE))
+               value = false;
+       else {
+               LOG("Invalid value : key(%s), value(%s)", k.c_str(), v.c_str());
+               value = false;
+       }
+}
+
+int BoolFeature::modifyValue(void)
+{
+       switch (getModType()) {
+       case ModType::NONE:
+               break;
+       case ModType::EXPAND:
+               value = false;
+               break;
+       case ModType::SHRINK:
+               value = true;
+               break;
+       default:
+               LOG("Invalid modType");
+               return EINVAL;
+       }
+
+       return util.updateDB(key, STRTYPE_BOOL, value ? STRBOOL_TRUE : STRBOOL_FALSE);
+}
+
+int BoolFeature::verifyValue(void)
+{
+       int ret;
+       bool output;
+
+       ret = system_info_get_platform_bool(key.c_str(), &output);
+       if (ret != SYSTEM_INFO_ERROR_NONE) {
+               LOG("system_info_get_platform_bool failed (%d)", ret);
+               return ret;
+       }
+
+       if (value != output) {
+               LOG("Failed to verify value : key(%s), value(%s), expected(%s)",
+                               key.c_str(),
+                               output ? STRBOOL_TRUE : STRBOOL_FALSE,
+                               value ? STRBOOL_TRUE : STRBOOL_FALSE);
+               return -1;
+       }
+
+       return SUCCEED;
+}
+
+/********** IntFeature **********/
+
+IntFeature::IntFeature(std::string k, std::string v) : Feature(k)
+{
+       value = stoi(v);
+}
+
+int IntFeature::modifyValue(void)
+{
+       switch (getModType()) {
+       case ModType::NONE:
+               break;
+       case ModType::EXPAND:
+               if (value < (INT_MAX / 128))
+                       value *= 128;
+               else
+                       value = INT_MAX;
+               break;
+       case ModType::SHRINK:
+               value /= 128;
+               break;
+       default:
+               LOG("Invalid modType");
+               break;
+       }
+
+       return util.updateDB(key, STRTYPE_INT, std::to_string(value));
+}
+
+int IntFeature::verifyValue(void)
+{
+       int ret;
+       int output;
+
+       ret = system_info_get_platform_int(key.c_str(), &output);
+       if (ret != SYSTEM_INFO_ERROR_NONE) {
+               LOG("system_info_get_platform_int failed (%d)", ret);
+               return ret;
+       }
+
+       if (value != output) {
+               LOG("Failed to verify value : key(%s), value(%d), expected(%d)",
+                               key.c_str(), output, value);
+               return -1;
+       }
+
+       return SUCCEED;
+}
+
+/********** DoubleFeature **********/
+
+DoubleFeature::DoubleFeature(std::string k, std::string v) : Feature(k)
+{
+       value = stod(v);
+}
+
+int DoubleFeature::modifyValue(void)
+{
+       std::ostringstream oss;
+
+       switch (getModType()) {
+       case ModType::NONE:
+               break;
+       case ModType::EXPAND:
+               value *= 128.0;
+               break;
+       case ModType::SHRINK:
+               value /= 128.0;
+               break;
+       default:
+               LOG("Invalid modType");
+               break;
+       }
+
+       // Set the decimal precision
+       oss << std::fixed << std::setprecision(15) << value;
+
+       return util.updateDB(key, STRTYPE_DOUBLE, oss.str());
+}
+
+int DoubleFeature::verifyValue(void)
+{
+       int ret;
+       double output;
+
+       ret = system_info_get_platform_double(key.c_str(), &output);
+       if (ret != SYSTEM_INFO_ERROR_NONE) {
+               LOG("system_info_get_platform_double failed (%d)", ret);
+               return ret;
+       }
+
+       if (value != output) {
+               LOG("Failed to verify value : key(%s), value(%.16lf), expected(%.16lf)",
+                               key.c_str(), output, value);
+               return -1;
+       }
+
+       return SUCCEED;
+}
+
+/********** StringFeature **********/
+
+StringFeature::StringFeature(std::string k, std::string v) : Feature(k)
+{
+       value = v;
+}
+
+int StringFeature::modifyValue(void)
+{
+       switch (getModType()) {
+       case ModType::NONE:
+               break;
+       case ModType::EXPAND:
+               value += value;
+               break;
+       case ModType::SHRINK:
+               value.resize(std::max(value.length() / 2, (size_t)1));
+               break;
+       default:
+               LOG("Invalid modType");
+               break;
+       }
+
+       return util.updateDB(key, STRTYPE_STRING, value);
+}
+
+int StringFeature::verifyValue(void)
+{
+       int ret;
+       char *output = nullptr;
+
+       ret = system_info_get_platform_string(key.c_str(), &output);
+       if (ret != SYSTEM_INFO_ERROR_NONE) {
+               LOG("system_info_get_platform_string failed (%d)", ret);
+               return ret;
+       }
+
+       if (value.compare(output)) {
+               LOG("Failed to verify value : key(%s), value(%s), expected(%s)",
+                               key.c_str(), output, value.c_str());
+               return -1;
+       }
+
+       return SUCCEED;
+}
diff --git a/test/init_db/feature.h b/test/init_db/feature.h
new file mode 100644 (file)
index 0000000..07489af
--- /dev/null
@@ -0,0 +1,87 @@
+#ifndef __FEATURE_H__
+#define __FEATURE_H__
+
+#include <string>
+#include <vector>
+
+class Feature {
+public:
+       Feature(std::string k) : key(k) {}
+       virtual ~Feature() {};
+
+       /**
+        * @brief  Modify value
+        * @retval SUCCEED on success, otherwise an error value
+        */
+       virtual int modifyValue(void) = 0;
+
+       /**
+        * @brief  Compare system-info result with DB
+        * @retval SUCCEED on success, otherwise an error value
+        */
+       virtual int verifyValue(void) = 0;
+
+protected:
+       std::string key;
+
+       enum class ModType {
+               NONE = 0,  // Don't modify
+               EXPAND,    // Increase value length
+               SHRINK,    // Decrease value length
+               NUM_TYPE
+       };
+
+       /**
+        * @brief  Decide the value modification type
+        * @retval Refer to ModType
+        */
+       ModType getModType(void);
+};
+
+extern std::vector<Feature *>featureList;
+
+class BoolFeature : public Feature {
+public:
+       BoolFeature(std::string k, std::string v);
+
+       int modifyValue(void);
+       int verifyValue(void);
+
+private:
+       bool value;
+};
+
+class IntFeature : public Feature {
+public:
+       IntFeature(std::string k, std::string v);
+
+       int modifyValue(void);
+       int verifyValue(void);
+
+private:
+       int value;
+};
+
+class DoubleFeature : public Feature {
+public:
+       DoubleFeature(std::string k, std::string v);
+
+       int modifyValue(void);
+       int verifyValue(void);
+
+private:
+       double value;
+};
+
+class StringFeature : public Feature {
+public:
+       StringFeature(std::string k, std::string v);
+
+       int modifyValue(void);
+       int verifyValue(void);
+
+private:
+       std::string value;
+};
+
+#endif /* __FEATURE_H__ */
diff --git a/test/init_db/system_info_init_db_test.cpp b/test/init_db/system_info_init_db_test.cpp
new file mode 100644 (file)
index 0000000..7d4bd4a
--- /dev/null
@@ -0,0 +1,122 @@
+#include <cstdlib>
+#include <ctime>
+#include <vector>
+
+#include <unistd.h>
+
+#include "feature.h"
+#include "system_info_init_db_test.h"
+#include "tester.h"
+#include "util.h"
+
+Util util;
+std::vector<Feature *> featureList;
+
+static int initialize(void)
+{
+       int ret;
+
+       // Move original RO DB
+       if (access(SYSTEM_INFO_DB_RO_PATH, F_OK) == 0) {
+               ret = util.forkAndExec("mv", SYSTEM_INFO_DB_RO_PATH, BACKUP_DB_RO_PATH, nullptr);
+               if (ret != SUCCEED) {
+                       LOG("Failed to move original RO DB (%d)", ret);
+                       return ret;
+               }
+       }
+
+       // Move original RW DB
+       if (access(SYSTEM_INFO_DB_RW_PATH, F_OK) == 0) {
+               ret = util.forkAndExec("mv", SYSTEM_INFO_DB_RW_PATH, BACKUP_DB_RW_PATH, nullptr);
+               if (ret != SUCCEED) {
+                       LOG("Failed to move original RW DB (%d)", ret);
+                       return ret;
+               }
+       }
+
+       // Read model-config
+       ret = util.readModelConfig();
+       if (ret != SUCCEED) {
+               LOG("Failed to read model-config (%d)", ret);
+               return ret;
+       }
+
+       srand(time(nullptr));
+
+       return SUCCEED;
+}
+
+static void finalize(void)
+{
+       int ret;
+
+       // Free feature list
+       for (auto feature : featureList)
+               delete(feature);
+       featureList.clear();
+
+       // Remove test RW DB
+       if (access(SYSTEM_INFO_DB_RW_PATH, F_OK) == 0) {
+               ret = util.forkAndExec("rm", "-rf", SYSTEM_INFO_DB_RW_PATH, nullptr);
+               if (ret != SUCCEED) {
+                       LOG("Failed to remove RW DB (%d)", ret);
+                       goto handle_ro_db;
+               }
+       }
+
+       // Put back original RW DB
+       if (access(BACKUP_DB_RW_PATH, F_OK) == 0) {
+               ret = util.forkAndExec("mv", BACKUP_DB_RW_PATH, SYSTEM_INFO_DB_RW_PATH, nullptr);
+               if (ret != SUCCEED)
+                       LOG("Failed to move original RW DB (%d)", ret);
+       }
+
+handle_ro_db:
+       // Remove test RO DB
+       if (access(SYSTEM_INFO_DB_RO_PATH, F_OK) == 0) {
+               ret = util.forkAndExec("rm", "-rf", SYSTEM_INFO_DB_RO_PATH, nullptr);
+               if (ret != SUCCEED) {
+                       LOG("Failed to remove RO DB (%d)", ret);
+                       return;
+               }
+       }
+
+       // Put back original RO DB
+       if (access(BACKUP_DB_RO_PATH, F_OK) == 0) {
+               ret = util.forkAndExec("mv", BACKUP_DB_RO_PATH, SYSTEM_INFO_DB_RO_PATH, nullptr);
+               if (ret != SUCCEED)
+                       LOG("Failed to move original RO DB (%d)", ret);
+       }
+}
+
+int main(int argc, char *argv[])
+{
+       int ret;
+
+       LOG("========== Start system_info_init_db test ==========\n");
+
+       ret = initialize();
+       if (ret != SUCCEED) {
+               LOG("Failed to initialize (%d)", ret);
+               finalize();
+               return ret;
+       }
+
+       Tester *testerList[] = {
+               new CreateDB(),
+               new InsertKey(),
+               new ModifyValue(),
+               new VerifyValue(),
+               new CreateRWDB(),
+       };
+
+       for (auto tester : testerList) {
+               tester->test();
+               delete(tester);
+       }
+
+       finalize();
+
+       LOG("========== End system_info_init_db test ==========");
+       return 0;
+}
diff --git a/test/init_db/system_info_init_db_test.h b/test/init_db/system_info_init_db_test.h
new file mode 100644 (file)
index 0000000..5d45018
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef __SYSTEM_INFO_INIT_DB_TEST_H__
+#define __SYSTEM_INFO_INIT_DB_TEST_H__
+
+#define INIT_DB "system_info_init_db"
+
+#define SUCCEED 0
+
+#define LOG(fmt, arg...) printf(fmt "\n", ##arg)
+
+#define BACKUP_DB_RO_PATH SYSTEM_INFO_DB_RO_PATH "_backup"
+#define BACKUP_DB_RW_PATH SYSTEM_INFO_DB_RW_PATH "_backup"
+
+#define STRTYPE_BOOL   "bool"
+#define STRTYPE_INT    "int"
+#define STRTYPE_DOUBLE "double"
+#define STRTYPE_STRING "string"
+
+#define STRBOOL_FALSE "false"
+#define STRBOOL_TRUE  "true"
+
+#endif /* __SYSTEM_INFO_INIT_DB_TEST_H__ */
diff --git a/test/init_db/tester.cpp b/test/init_db/tester.cpp
new file mode 100644 (file)
index 0000000..0a16659
--- /dev/null
@@ -0,0 +1,141 @@
+#include "feature.h"
+#include "system_info_init_db_test.h"
+#include "tester.h"
+#include "util.h"
+
+/********** Tester **********/
+
+void Tester::test(void)
+{
+       int ret;
+
+       LOG("[%s] Start", name.c_str());
+
+       ret = run();
+
+       LOG("[%s] Result : %d(%s)\n", name.c_str(), ret,
+                       ret == SUCCEED ? "\x1b[32mPASSED\x1b[0m" : "\x1b[31mFAILED\x1b[0m");
+}
+
+/********** CreateDB **********/
+
+int CreateDB::run(void)
+{
+       return util.forkAndExec(INIT_DB, nullptr);
+}
+
+/********** InsertKey **********/
+
+int InsertKey::run(void)
+{
+       int ret;
+       int dice;
+       std::string keyPrefix = "http://tizen.org/test/test.key.";
+       std::string key;
+       std::string type;
+       std::string value;
+       int valueLen;
+       Feature *feature = nullptr;
+
+       for (int keyIndex = 0; keyIndex < 100; keyIndex++) {
+               key = keyPrefix + std::to_string(keyIndex);
+
+               dice = (double)rand() / RAND_MAX * 2000000;     // 0 ~ 2M
+
+               /**
+                * In current, most of model-config features have boolean type.
+                * So, we insert other type features more.
+                */
+               switch (dice % 10) {
+               case 0:
+                       // Bool
+                       type = STRTYPE_BOOL;
+                       value = (dice % 2 == 1) ? STRBOOL_TRUE : STRBOOL_FALSE;
+                       feature = new BoolFeature(key, value);
+                       break;
+               case 1:
+               case 2:
+               case 3:
+                       // Int
+                       type = STRTYPE_INT;
+                       value = std::to_string(dice - 1000000); // -1M ~ 1M
+                       feature = new IntFeature(key, value);
+                       break;
+               case 4:
+               case 5:
+               case 6:
+                       // Double
+                       type = STRTYPE_DOUBLE;
+                       value = std::to_string(dice - 1000000.0);       // -1.0M ~ 1.0M
+                       feature = new DoubleFeature(key, value);
+                       break;
+               case 7:
+               case 8:
+               case 9:
+                       // String
+                       type = STRTYPE_STRING;
+                       valueLen = (dice % 100) + 1;    // 1 ~ 100
+                       value.clear();
+                       value.reserve(valueLen);
+                       do {
+                               value += 't';
+                       } while (--valueLen);
+                       feature = new StringFeature(key, value);
+                       break;
+               default:
+                       LOG("Invalid dice value (%d)", dice);
+                       return EIO;
+               }
+
+               featureList.push_back(feature);
+
+               ret = util.updateDB(key, type, value);
+               if (ret != SUCCEED) {
+                       LOG("Failed to insert key(%d)", ret);
+                       return ret;
+               }
+       }
+
+       return SUCCEED;
+}
+
+/********** ModifyValue **********/
+
+int ModifyValue::run(void)
+{
+       int ret;
+
+       for (auto feature : featureList) {
+               ret = feature->modifyValue();
+               if (ret != SUCCEED) {
+                       LOG("Failed to modify value (%d)", ret);
+                       return ret;
+               }
+       }
+
+       return SUCCEED;
+}
+
+/********** VerifyValue **********/
+
+int VerifyValue::run(void)
+{
+       int ret;
+
+       for (auto feature : featureList) {
+               ret = feature->verifyValue();
+               if (ret != SUCCEED) {
+                       LOG("Failed to verify value (%d)", ret);
+                       return ret;
+               }
+       }
+
+       return SUCCEED;
+}
+
+/********** CreateRWDB **********/
+
+int CreateRWDB::run(void)
+{
+       return util.forkAndExec(INIT_DB, "-i", MODEL_CONFIG_RO_PATH, "-o", SYSTEM_INFO_DB_RW_PATH, nullptr);
+}
diff --git a/test/init_db/tester.h b/test/init_db/tester.h
new file mode 100644 (file)
index 0000000..54b7e64
--- /dev/null
@@ -0,0 +1,67 @@
+#ifndef __TESTER_H__
+#define __TESTER_H__
+
+#include <string>
+
+class Tester {
+public:
+       Tester(std::string n) : name(n) {}
+       virtual ~Tester() {}
+
+       /**
+        * @brief  Test and print result
+        */
+       void test(void);
+
+protected:
+       /**
+        * @brief  Run test
+        * @retval SUCCEED on succeed, otherwise an error number
+        */
+       virtual int run(void) = 0;
+
+private:
+       std::string name;
+};
+
+class CreateDB : public Tester {
+public:
+       CreateDB() : Tester("Create DB") {}
+
+protected:
+       int run(void);
+};
+
+class InsertKey : public Tester {
+public:
+       InsertKey() : Tester("Insert key") {}
+
+protected:
+       int run(void);
+};
+
+class ModifyValue : public Tester {
+public:
+       ModifyValue() : Tester("Modify value") {}
+
+protected:
+       int run(void);
+};
+
+class VerifyValue : public Tester {
+public:
+       VerifyValue() : Tester("Verify value") {}
+
+protected:
+       int run(void);
+};
+
+class CreateRWDB : public Tester {
+public:
+       CreateRWDB() : Tester("Create RW DB") {}
+
+protected:
+       int run(void);
+};
+
+#endif /* __TESTER_H__ */
diff --git a/test/init_db/util.cpp b/test/init_db/util.cpp
new file mode 100644 (file)
index 0000000..0fde55e
--- /dev/null
@@ -0,0 +1,194 @@
+#include <cstdarg>
+#include <cstdlib>
+
+#include <libxml/xmlmemory.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "feature.h"
+#include "system_info_init_db_test.h"
+#include "util.h"
+
+int Util::forkAndExec(const char *argv, ...)
+{
+       int ret;
+       pid_t pid;
+       int status;
+       va_list ap;
+       const char *arr[256];
+       int numArg = 0;
+
+       pid = fork();
+       switch (pid) {
+       case -1:
+               LOG("fork failed");
+               return EIO;
+       case 0:
+               // Execute program
+               va_start(ap, argv);
+               while (argv && numArg < 255) {
+                       arr[numArg++] = argv;
+                       argv = va_arg(ap, const char *);
+               }
+               va_end(ap);
+               arr[numArg] = nullptr;
+
+               ret = execvp(arr[0], (char * const *)arr);
+               if (ret == -1) {
+                       LOG("execv for %s failed (%d)", arr[0], errno);
+                       ret = errno;
+               } else
+                       ret = SUCCEED;
+               exit(ret);
+               break;
+       default:
+               // Wait until child is terminated
+               if (wait(&status) == -1) {
+                       LOG("wait failed (%d)", errno);
+                       return errno;
+               }
+               if (WIFEXITED(status) && WEXITSTATUS(status) == SUCCEED)
+                       return SUCCEED;
+               else
+                       return EIO;
+               break;
+       }
+
+       return EFAULT;
+}
+
+int Util::updateDB(std::string key, std::string type, std::string value)
+{
+       return forkAndExec(INIT_DB,
+                       "-g", "platform",
+                       "-k", key.c_str(),
+                       "-t", type.c_str(),
+                       "-v", value.c_str(),
+                       nullptr);
+}
+
+int Util::readModelConfig(void)
+{
+       int ret;
+       xmlDocPtr doc = nullptr;
+       xmlNodePtr nodeRoot = nullptr;
+       xmlNodePtr nodeTag = nullptr;
+       xmlNodePtr nodeKey = nullptr;
+       xmlNode *nodeCur = nullptr;
+       xmlChar *propName = nullptr;
+       xmlChar *propType = nullptr;
+       xmlChar *propValue = nullptr;
+       std::string name;
+       std::string type;
+       std::string value;
+       Feature *feature = nullptr;
+       int numBoolKey = 0;
+       int numIntKey = 0;
+       int numDoubleKey = 0;
+       int numStringKey = 0;
+
+       // Read xml file
+       doc = xmlParseFile(MODEL_CONFIG_RO_PATH);
+       if (!doc) {
+               LOG("xmlParseFile failed");
+               return ENOENT;
+       }
+
+       nodeRoot = xmlDocGetRootElement(doc);
+       if (!nodeRoot) {
+               LOG("xmlDocGetRootElement failed");
+               ret = ENOENT;
+               goto clean;
+       }
+
+       if (xmlStrcmp(nodeRoot->name, (const xmlChar *)"model-config")) {
+               LOG("Failed to find model-config tag");
+               ret = ENOENT;
+               goto clean;
+       }
+
+       nodeTag = nodeRoot->xmlChildrenNode;
+
+       for (nodeCur = nodeTag; nodeCur; nodeCur = nodeCur->next) {
+               if (!xmlStrcmp(nodeCur->name, (const xmlChar *)"platform")) {
+                       nodeKey = nodeCur;
+                       break;
+               }
+       }
+
+       if (!nodeKey) {
+               LOG("Failed to find platform tag");
+               ret = ENOENT;
+               goto clean;
+       }
+
+       nodeKey = nodeKey->xmlChildrenNode;
+
+       // Store each model-config feature
+       for (nodeCur = nodeKey; nodeCur; nodeCur = nodeCur->next) {
+               propName = xmlGetProp(nodeCur, (const xmlChar *)"name");
+               propType = xmlGetProp(nodeCur, (const xmlChar *)"type");
+               propValue = xmlNodeListGetString(doc, nodeCur->xmlChildrenNode, 1);
+
+               if (!propName || !propType || !propValue) {
+                       if (!propName && !propType && !propValue)
+                               continue;
+
+                       LOG("Invalid feature : name(%s), type(%s), value(%s)",
+                                       (char *)propName, (char *)propType, (char *)propValue);
+                       ret = EIO;
+                       goto clean;
+               }
+
+               name.assign((char *)propName);
+               type.assign((char *)propType);
+               value.assign((char *)propValue);
+
+               if (!type.compare(STRTYPE_BOOL)) {
+                       feature = new BoolFeature(name, value);
+                       numBoolKey++;
+               } else if (!type.compare(STRTYPE_INT)) {
+                       feature = new IntFeature(name, value);
+                       numIntKey++;
+               } else if (!type.compare(STRTYPE_DOUBLE)) {
+                       feature = new DoubleFeature(name, value);
+                       numDoubleKey++;
+               } else if (!type.compare(STRTYPE_STRING)) {
+                       feature = new StringFeature(name, value);
+                       numStringKey++;
+               } else {
+                       LOG("Invalid type : key(%s), type(%s)", name.c_str(), type.c_str());
+                       ret = EINVAL;
+                       goto clean;
+               }
+
+               featureList.push_back(feature);
+
+               xmlFree(propValue);
+               xmlFree(propType);
+               xmlFree(propName);
+       }
+
+       LOG("Number of model-config platform key : Bool(%d), Int(%d), Double(%d), String(%d), Total(%d)\n",
+                       numBoolKey, numIntKey, numDoubleKey, numStringKey,
+                       numBoolKey + numIntKey + numDoubleKey + numStringKey);
+       ret = SUCCEED;
+
+clean:
+       if (propValue)
+               xmlFree(propValue);
+
+       if (propType)
+               xmlFree(propType);
+
+       if (propName)
+               xmlFree(propName);
+
+       if (doc)
+               xmlFreeDoc(doc);
+
+       return ret;
+}
diff --git a/test/init_db/util.h b/test/init_db/util.h
new file mode 100644 (file)
index 0000000..0cbb3b6
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef __UTIL_H__
+#define __UTIL_H__
+
+class Util {
+public:
+       /**
+        * @brief  Fork and execute program
+        * @retval SUCCEED on success, otherwise an error value
+        */
+       static int forkAndExec(const char *argv, ...);
+
+       /**
+        * @brief  Update system-info DB
+        * @retval SUCCEED on success, otherwise an error value
+        */
+       static int updateDB(std::string key, std::string type, std::string value);
+
+       /**
+        * @brief  Read model-config
+        * @detail Each feature is stored into the featureList
+        * @retval SUCCEED on success, otherwise an error value
+        */
+       static int readModelConfig(void);
+};
+
+extern Util util;
+
+#endif /* __UTIL_H__ */