Handling history detected by scan on cloud 31/74331/7
authorKyungwook Tak <k.tak@samsung.com>
Tue, 14 Jun 2016 02:16:18 +0000 (11:16 +0900)
committerKyungwook Tak <k.tak@samsung.com>
Thu, 16 Jun 2016 08:47:43 +0000 (17:47 +0900)
Add table to db schema to manage separately to ordinary app scanning.
It's for giving detected/ignored/judge malwares because those work based
on history in db.

Change-Id: I78fec4b61ed7838298ec156dc2452ed7c4e64c6c
Signed-off-by: Kyungwook Tak <k.tak@samsung.com>
data/scripts/create_schema.sql
data/scripts/drop_all.sql
src/framework/db/manager.cpp
src/framework/db/manager.h
src/framework/db/query.h
src/framework/service/cs-logic.cpp
src/framework/service/iloader.cpp
test/engine/content-screening/sample-engine.cpp
test/test-api-content-screening-async.cpp

index 453bc64..f690928 100644 (file)
@@ -63,6 +63,18 @@ CREATE TABLE IF NOT EXISTS DETECTED_MALWARE (
        UNIQUE(file_path)
 );
 
+CREATE TABLE IF NOT EXISTS DETECTED_MALWARE_CLOUD (
+       idx INTEGER NOT NULL,
+       pkg_id TEXT NOT NULL,
+       data_version TEXT NOT NULL,
+       malware_name TEXT NOT NULL,
+       detailed_url TEXT NOT NULL,
+       severity INTEGER NOT NULL,
+       detected_time INTEGER NOT NULL,
+
+       FOREIGN KEY(idx) REFERENCES NAMES(idx) ON DELETE CASCADE
+);
+
 CREATE TABLE IF NOT EXISTS PACKAGE_INFO (
        pkg_id TEXT NOT NULL,
        idx INTEGER NOT NULL,
@@ -73,6 +85,11 @@ CREATE TABLE IF NOT EXISTS PACKAGE_INFO (
        FOREIGN KEY(worst_filepath_idx) REFERENCES DETECTED_MALWARE(filepath_idx) ON DELETE CASCADE
 );
 
+CREATE VIEW IF NOT EXISTS [join_detecteds_cloud_by_name] AS
+       SELECT N.name, D.data_version, D.malware_name, D.detailed_url, D.severity,
+                       D.detected_time, D.pkg_id, N.is_ignored
+               FROM NAMES AS N INNER JOIN DETECTED_MALWARE_CLOUD AS D ON N.idx = D.idx;
+
 CREATE VIEW IF NOT EXISTS [join_p_d] AS
        SELECT N.idx, N.name, D.file_path, D.data_version, D.malware_name, D.detailed_url,
                        D.severity, D.detected_time, P.pkg_id
@@ -100,5 +117,6 @@ CREATE VIEW IF NOT EXISTS [join_detecteds_by_file_path] AS
                        AS J INNER JOIN NAMES AS N ON J.idx = N.idx;
 
 CREATE INDEX IF NOT EXISTS d_name_index ON DETECTED_MALWARE(idx);
+CREATE INDEX IF NOT EXISTS c_name_index ON DETECTED_MALWARE_CLOUD(idx);
 CREATE INDEX IF NOT EXISTS p_name_index ON PACKAGE_INFO(idx);
 CREATE INDEX IF NOT EXISTS p_filepath_index ON PACKAGE_INFO(worst_filepath_idx);
index de854d4..ea2a355 100644 (file)
@@ -1,12 +1,15 @@
 DROP INDEX IF EXISTS d_name_index;
+DROP INDEX IF EXISTS c_name_index;
 DROP INDEX IF EXISTS p_name_index;
 DROP INDEX IF EXISTS p_filepath_index;
 
+DROP VIEW IF EXISTS join_detecteds_cloud_by_name;
 DROP VIEW IF EXISTS join_detecteds_by_file_path;
 DROP VIEW IF EXISTS join_detecteds_by_name;
 DROP VIEW IF EXISTS join_p_d;
 
 DROP TABLE IF EXISTS PACKAGE_INFO;
+DROP TABLE IF EXISTS DETECTED_MALWARE_CLOUD;
 DROP TABLE IF EXISTS DETECTED_MALWARE;
 DROP TABLE IF EXISTS NAMES;
 DROP TABLE IF EXISTS SCAN_REQUEST;
index d8aa1a5..5c64e01 100644 (file)
@@ -65,6 +65,24 @@ RowShPtr extractRow(Statement &stmt)
        return row;
 }
 
+RowShPtr extractRowCloud(Statement &stmt)
+{
+       RowShPtr row = std::make_shared<Row>();
+
+       row->targetName = stmt.getText(); // name.
+       row->fileInAppPath.clear();
+       row->dataVersion = stmt.getText(); // data_version
+       row->malwareName = stmt.getText(); // malware_name
+       row->detailedUrl = stmt.getText(); // detailed_url
+       row->severity = static_cast<csr_cs_severity_level_e>(stmt.getInt()); // severity
+       row->ts = static_cast<time_t>(stmt.getInt64()); // detected_time
+       row->pkgId = stmt.getText(); // pkg_id
+       row->isApp = true;
+       row->isIgnored = static_cast<bool>(stmt.getInt());
+
+       return row;
+}
+
 } // namespace anonymous
 
 Manager::Manager(const std::string &dbfile, const std::string &scriptsDir) :
@@ -278,6 +296,17 @@ RowShPtr Manager::getDetectedByNameOnPath(const std::string &path)
        return extractRow(stmt);
 }
 
+RowShPtr Manager::getDetectedCloudByNameOnPath(const std::string &path)
+{
+       Statement stmt(this->m_conn, Query::SEL_DETECTED_CLOUD_BY_NAME_ON_PATH);
+       stmt.bind(path);
+
+       if (!stmt.step())
+               return nullptr;
+
+       return extractRowCloud(stmt);
+}
+
 RowShPtrs Manager::getDetectedByNameOnDir(const std::string &dir)
 {
        Statement stmt(this->m_conn, Query::SEL_DETECTED_BY_NAME_ON_DIR);
@@ -291,6 +320,53 @@ RowShPtrs Manager::getDetectedByNameOnDir(const std::string &dir)
        return rows;
 }
 
+RowShPtrs Manager::getDetectedCloudByNameOnDir(const std::string &dir)
+{
+       Statement stmt(this->m_conn, Query::SEL_DETECTED_CLOUD_BY_NAME_ON_DIR);
+       stmt.bind(dir);
+
+       RowShPtrs rows;
+       while (stmt.step())
+               rows.emplace_back(extractRowCloud(stmt));
+
+       return rows;
+}
+
+RowShPtrs Manager::getDetectedAllByNameOnDir(const std::string &dir)
+{
+       auto normals = this->getDetectedByNameOnDir(dir);
+       auto clouds = this->getDetectedCloudByNameOnDir(dir);
+
+       if (clouds.empty())
+               return normals;
+
+       RowShPtrs rows;
+
+       for (const auto &cloud : clouds) {
+               bool found = false;
+               auto it = normals.begin();
+
+               while (it != normals.end()) {
+                       if ((*it)->targetName == cloud->targetName) {
+                               rows.emplace_back(std::move(*it));
+                               it = normals.erase(it);
+                               found = true;
+                               break;
+                       } else {
+                               ++it;
+                       }
+               }
+
+               if (!found)
+                       rows.push_back(cloud);
+       }
+
+       for (auto &&normal : normals)
+               rows.emplace_back(std::move(normal));
+
+       return rows;
+}
+
 RowShPtrs Manager::getDetectedByFilepathOnDir(const std::string &dir)
 {
        Statement stmt(this->m_conn, Query::SEL_DETECTED_BY_FILEPATH_ON_DIR);
@@ -350,6 +426,21 @@ void Manager::insertDetected(const CsDetected &d, const std::string &filepath,
        stmt.exec();
 }
 
+void Manager::insertDetectedCloud(const CsDetected &d, const std::string &pkgId,
+                                                                 const std::string &name, const std::string &dataVersion)
+{
+       Statement stmt(this->m_conn, Query::INS_DETECTED_CLOUD);
+
+       stmt.bind(name);
+       stmt.bind(pkgId);
+       stmt.bind(dataVersion);
+       stmt.bind(d.malwareName);
+       stmt.bind(d.detailedUrl);
+       stmt.bind(static_cast<int>(d.severity));
+       stmt.bind(static_cast<sqlite3_int64>(d.ts));
+       stmt.exec();
+}
+
 void Manager::insertWorst(const std::string &pkgId, const std::string &name,
                                                  const std::string &filepath)
 {
index 4fbc0ba..5cd8cf7 100644 (file)
@@ -62,13 +62,18 @@ public:
 
        // DETECTED_MALWARE_FILE & USER_RESPONSE
        RowShPtr getDetectedByNameOnPath(const std::string &path);
+       RowShPtr getDetectedCloudByNameOnPath(const std::string &path);
        RowShPtrs getDetectedByNameOnDir(const std::string &dir);
+       RowShPtrs getDetectedCloudByNameOnDir(const std::string &dir);
+       RowShPtrs getDetectedAllByNameOnDir(const std::string &dir);
        RowShPtrs getDetectedByFilepathOnDir(const std::string &dir);
        RowShPtr getWorstByPkgPath(const std::string &pkgPath);
 
        void insertName(const std::string &name);
-       void insertDetected(const CsDetected &, const std::string &filename,
+       void insertDetected(const CsDetected &d, const std::string &filename,
                                                const std::string &dataVersion);
+       void insertDetectedCloud(const CsDetected &d, const std::string &pkgId,
+                                                        const std::string &name, const std::string &dataVersion);
        void insertWorst(const std::string &pkgId, const std::string &name,
                                         const std::string &filepath);
 
index 524c6ee..bab73b1 100644 (file)
@@ -50,12 +50,24 @@ const std::string DEL_SCAN_REQUEST_BY_DIR =
 const std::string DEL_SCAN_REQUEST =
        "delete from SCAN_REQUEST";
 
+const std::string SEL_DETECTED_CLOUD_BY_NAME_ON_PATH =
+       "select name, data_version, malware_name, detailed_url, severity, detected_time,"
+       "       pkg_id, is_ignored"
+       " from join_detecteds_cloud_by_name"
+       " where name = ?";
+
 const std::string SEL_DETECTED_BY_NAME_ON_PATH =
        "select name, file_path, data_version, malware_name, detailed_url, severity,"
        "       detected_time, pkg_id, is_ignored"
        " from join_detecteds_by_name"
        " where name = ?";
 
+const std::string SEL_DETECTED_CLOUD_BY_NAME_ON_DIR =
+       "select name, data_version, malware_name, detailed_url, severity, detected_time,"
+       "       pkg_id, is_ignored"
+       " from join_detecteds_cloud_by_name"
+       " where name like ? || '%'";
+
 const std::string SEL_DETECTED_BY_NAME_ON_DIR =
        "select name, file_path, data_version, malware_name, detailed_url, severity,"
        "       detected_time, pkg_id, is_ignored"
@@ -77,6 +89,12 @@ const std::string SEL_WORST_BY_PKGPATH =
 const std::string INS_NAME =
        "insert or replace into NAMES(name) values(?)";
 
+const std::string INS_DETECTED_CLOUD =
+       "insert or replace into DETECTED_MALWARE_CLOUD(idx, pkg_id, data_version,"
+       "                                              malware_name, detailed_url, severity,"
+       "                                              detected_time)"
+       " values((select idx from NAMES where name = ?), ?, ?, ?, ?, ?, ?)";
+
 const std::string INS_DETECTED =
        "insert or replace into DETECTED_MALWARE(file_path, idx, data_version, malware_name,"
        "                                        detailed_url, severity, detected_time)"
index 3a7e541..bd38f22 100644 (file)
@@ -186,6 +186,9 @@ RawBuffer CsLogic::scanAppOnCloud(const CsContext &context,
        detected.isApp = true;
        detected.pkgId = pkgId;
 
+       this->m_db->insertName(pkgPath);
+       this->m_db->insertDetectedCloud(detected, pkgId, pkgPath, this->m_dataVersion);
+
        return this->handleAskUser(context, detected);
 }
 
@@ -499,7 +502,7 @@ RawBuffer CsLogic::getScannableFiles(const std::string &dir)
 
        if (lastScanTime != -1) {
                // for case: scan history exist and not modified.
-               for (auto &row : this->m_db->getDetectedByNameOnDir(File::getPkgPath(dir))) {
+               for (auto &row : this->m_db->getDetectedAllByNameOnDir(File::getPkgPath(dir))) {
                        try {
                                auto fileptr = File::create(row->targetName);
 
@@ -563,13 +566,22 @@ RawBuffer CsLogic::judgeStatus(const std::string &filepath, csr_cs_action_e acti
 
        auto history = this->m_db->getDetectedByNameOnPath(targetName);
 
+       bool isCloudHistory = false;
+
        if (!history) {
-               ERROR("Target to be judged doesn't exist in db. name: " << targetName);
-               return BinaryQueue::Serialize(CSR_ERROR_INVALID_PARAMETER).pop();
+               history = this->m_db->getDetectedCloudByNameOnPath(targetName);
+
+               if (!history) {
+                       ERROR("Target to be judged doesn't exist in db. name: " << targetName);
+                       return BinaryQueue::Serialize(CSR_ERROR_INVALID_PARAMETER).pop();
+               }
+
+               isCloudHistory = true;
        }
 
        // file create based on fileInAppPath(for app target, it is worst detected)
-       if (File::createIfModified(history->fileInAppPath, static_cast<time_t>(history->ts)))
+       if (!isCloudHistory && File::createIfModified(history->fileInAppPath,
+                                                                                                 static_cast<time_t>(history->ts)))
                ThrowExc(CSR_ERROR_FILE_CHANGED,
                                 "File[" << history->fileInAppPath << "] modified since db delta inserted."
                                 " Don't refresh detected history to know that it's changed since the"
@@ -611,6 +623,8 @@ RawBuffer CsLogic::getDetected(const std::string &filepath)
        }
 
        auto row = this->m_db->getDetectedByNameOnPath(target);
+       if (!row)
+               row = this->m_db->getDetectedCloudByNameOnPath(target);
 
        if (row && !row->isIgnored)
                return BinaryQueue::Serialize(CSR_ERROR_NONE, row).pop();
@@ -626,8 +640,8 @@ RawBuffer CsLogic::getDetectedList(const StrSet &_dirSet)
 
        Db::RowShPtrs rows;
        for (const auto &dir : dirSet) {
-               for (auto &row : this->m_db->getDetectedByNameOnDir(dir)) {
-                       if (!isReadable(row->targetName)) {
+               for (auto &row : this->m_db->getDetectedAllByNameOnDir(dir)) {
+                       if (!row->fileInAppPath.empty() && !isReadable(row->targetName)) {
                                WARN("Exclude not-accessable malware detected file from the list: " <<
                                         row->targetName);
                                this->m_db->deleteDetectedByNameOnPath(row->targetName);
@@ -656,6 +670,8 @@ RawBuffer CsLogic::getIgnored(const std::string &filepath)
        }
 
        auto row = this->m_db->getDetectedByNameOnPath(target);
+       if (!row)
+               row = this->m_db->getDetectedCloudByNameOnPath(target);
 
        if (row && row->isIgnored)
                return BinaryQueue::Serialize(CSR_ERROR_NONE, row).pop();
@@ -671,8 +687,8 @@ RawBuffer CsLogic::getIgnoredList(const StrSet &_dirSet)
 
        Db::RowShPtrs rows;
        for (const auto &dir : dirSet) {
-               for (auto &row : this->m_db->getDetectedByNameOnDir(dir)) {
-                       if (!isReadable(row->targetName)) {
+               for (auto &row : this->m_db->getDetectedAllByNameOnDir(dir)) {
+                       if (!row->fileInAppPath.empty() && !isReadable(row->targetName)) {
                                WARN("Exclude not-accessable malware detected file from the list: " <<
                                         row->targetName);
                                this->m_db->deleteDetectedByNameOnPath(row->targetName);
index 534a6d2..ec778c4 100644 (file)
@@ -35,17 +35,29 @@ void ILoader::toException(int ee, bool internalErrorToString)
        case CSRE_ERROR_NONE:
                return;
 
+       case CSRE_ERROR_INVALID_PARAMETER:
+               ThrowExc(CSR_ERROR_ENGINE_INTERNAL, "CSRE_ERROR_INVALID_PARAMETER!");
+
        case CSRE_ERROR_OUT_OF_MEMORY:
                throw std::bad_alloc();
 
+       case CSRE_ERROR_INVALID_HANDLE:
+               ThrowExc(CSR_ERROR_ENGINE_INTERNAL, "CSRE_ERROR_INVALID_HANDLE!");
+
+       case CSRE_ERROR_ENGINE_NOT_ACTIVATED:
+               ThrowExc(CSR_ERROR_ENGINE_NOT_ACTIVATED, "engine is not activated yet");
+
        case CSRE_ERROR_PERMISSION_DENIED:
                ThrowExc(CSR_ERROR_ENGINE_PERMISSION, "access denied related to engine");
 
        case CSRE_ERROR_FILE_NOT_FOUND:
                ThrowExc(CSR_ERROR_FILE_DO_NOT_EXIST, "file not found.");
 
-       case CSRE_ERROR_ENGINE_NOT_ACTIVATED:
-               ThrowExc(CSR_ERROR_ENGINE_NOT_ACTIVATED, "engine is not activated yet");
+       case CSRE_ERROR_NO_DATA:
+               ThrowExc(CSR_ERROR_ENGINE_INTERNAL, "CSRE_ERROR_NO_DATA!");
+
+       case CSRE_ERROR_UNKNOWN:
+               ThrowExc(CSR_ERROR_ENGINE_INTERNAL, "CSRE_ERROR_UNKNOWN!");
 
        default:
                if (internalErrorToString) {
index 0964fa3..a97b5b4 100644 (file)
@@ -445,7 +445,6 @@ int csre_cs_scan_app_on_cloud(csre_cs_context_h handle,
        if (handle == nullptr || app_root_dir == nullptr || pdetected == nullptr)
                return CSRE_ERROR_INVALID_PARAMETER;
 
-       int ret;
        csre_cs_detected_h detected = nullptr;
        csre_cs_detected_h most_detected = nullptr;
        csre_cs_severity_level_e most = CSRE_CS_SEVERITY_LOW;
@@ -453,8 +452,12 @@ int csre_cs_scan_app_on_cloud(csre_cs_context_h handle,
        std::unique_ptr<DIR, std::function<int(DIR *)>> dirp(opendir(app_root_dir),
                        closedir);
 
-       if (!dirp)
-               return CSRE_ERROR_FILE_NOT_FOUND;
+       if (!dirp) {
+               // silently skip the subdirectory in app_root_dir that unable to open because of
+               // having no permission
+               *pdetected = nullptr;
+               return CSRE_ERROR_NONE;
+       }
 
        struct dirent entry;
        struct dirent *result;
@@ -465,6 +468,8 @@ int csre_cs_scan_app_on_cloud(csre_cs_context_h handle,
                fullpath += "/";
                fullpath += filename;
 
+               int ret = CSRE_ERROR_NONE;
+
                if (entry.d_type & (DT_REG | DT_LNK))
                        ret = csre_cs_scan_file(handle, fullpath.c_str(), &detected);
                else if ((entry.d_type & DT_DIR)
@@ -492,9 +497,9 @@ int csre_cs_scan_app_on_cloud(csre_cs_context_h handle,
                }
        }
 
-       *pdetected = reinterpret_cast<csre_cs_detected_h>(detected);
+       *pdetected = most_detected;
 
-       return ret;
+       return CSRE_ERROR_NONE;
 }
 
 //==============================================================================
index 95467f1..dfc02f4 100644 (file)
@@ -252,12 +252,12 @@ BOOST_AUTO_TEST_CASE(scan_files_async_positive)
                TEST_FILE_HIGH, MALWARE_HIGH_NAME, MALWARE_HIGH_SEVERITY, MALWARE_HIGH_DETAILED_URL);
        ASSERT_DETECTED_IN_LIST_EXT(testCtx.detectedList, TEST_FILE_HIGH, false, "");
 
-       ASSERT_DETECTED_IN_LIST(testCtx.detectedList,
-               TEST_FILE_MEDIUM, MALWARE_MEDIUM_NAME, MALWARE_MEDIUM_SEVERITY, MALWARE_MEDIUM_DETAILED_URL);
+       ASSERT_DETECTED_IN_LIST(testCtx.detectedList, TEST_FILE_MEDIUM, MALWARE_MEDIUM_NAME,
+                                                       MALWARE_MEDIUM_SEVERITY, MALWARE_MEDIUM_DETAILED_URL);
        ASSERT_DETECTED_IN_LIST_EXT(testCtx.detectedList, TEST_FILE_MEDIUM, false, "");
 
-       ASSERT_DETECTED_IN_LIST(testCtx.detectedList,
-               TEST_FILE_LOW, MALWARE_LOW_NAME, MALWARE_LOW_SEVERITY, MALWARE_LOW_DETAILED_URL);
+       ASSERT_DETECTED_IN_LIST(testCtx.detectedList, TEST_FILE_LOW, MALWARE_LOW_NAME,
+                                                       MALWARE_LOW_SEVERITY, MALWARE_LOW_DETAILED_URL);
        ASSERT_DETECTED_IN_LIST_EXT(testCtx.detectedList, TEST_FILE_LOW, false, "");
 
        EXCEPTION_GUARD_END
@@ -793,17 +793,23 @@ BOOST_AUTO_TEST_CASE(delta_scan_changed_after_scan)
        BOOST_REQUIRE_MESSAGE(testRescanCtx.scannedCnt >= 1,
                        "reinstalled app(non-malicious wgt) should be counted in scanned.");
 
-       ASSERT_DETECTED_IN_LIST(testRescanCtx.detectedList,
-               TEST_WGT_APP_ROOT(), MALWARE_HIGH_NAME, MALWARE_HIGH_SEVERITY, MALWARE_HIGH_DETAILED_URL);
-       ASSERT_DETECTED_IN_LIST_EXT(testRescanCtx.detectedList, TEST_WGT_APP_ROOT(), true, TEST_WGT_PKG_ID);
+       ASSERT_DETECTED_IN_LIST(testRescanCtx.detectedList, TEST_WGT_APP_ROOT(),
+                                                       MALWARE_HIGH_NAME, MALWARE_HIGH_SEVERITY,
+                                                       MALWARE_HIGH_DETAILED_URL);
+       ASSERT_DETECTED_IN_LIST_EXT(testRescanCtx.detectedList, TEST_WGT_APP_ROOT(), true,
+                                                               TEST_WGT_PKG_ID);
 
-       ASSERT_DETECTED_IN_LIST(testRescanCtx.detectedList,
-               TEST_TPK_APP_ROOT(), MALWARE_HIGH_NAME, MALWARE_HIGH_SEVERITY, MALWARE_HIGH_DETAILED_URL);
-       ASSERT_DETECTED_IN_LIST_EXT(testRescanCtx.detectedList, TEST_TPK_APP_ROOT(), true, TEST_TPK_PKG_ID);
+       ASSERT_DETECTED_IN_LIST(testRescanCtx.detectedList, TEST_TPK_APP_ROOT(),
+                                                       MALWARE_HIGH_NAME, MALWARE_HIGH_SEVERITY,
+                                                       MALWARE_HIGH_DETAILED_URL);
+       ASSERT_DETECTED_IN_LIST_EXT(testRescanCtx.detectedList, TEST_TPK_APP_ROOT(), true,
+                                                               TEST_TPK_PKG_ID);
 
-       ASSERT_DETECTED_IN_LIST(testRescanCtx.detectedList,
-               TEST_FAKE_APP_FILE(), MALWARE_HIGH_NAME, MALWARE_HIGH_SEVERITY, MALWARE_HIGH_DETAILED_URL);
-       ASSERT_DETECTED_IN_LIST_EXT(testRescanCtx.detectedList, TEST_FAKE_APP_FILE(), false, "");
+       ASSERT_DETECTED_IN_LIST(testRescanCtx.detectedList, TEST_FAKE_APP_FILE(),
+                                                       MALWARE_HIGH_NAME, MALWARE_HIGH_SEVERITY,
+                                                       MALWARE_HIGH_DETAILED_URL);
+       ASSERT_DETECTED_IN_LIST_EXT(testRescanCtx.detectedList, TEST_FAKE_APP_FILE(), false,
+                                                               "");
 
        uninstall_test_apps();
 
@@ -1000,4 +1006,78 @@ BOOST_AUTO_TEST_CASE(async_api_returning_and_callback_race)
        EXCEPTION_GUARD_END
 }
 
+BOOST_AUTO_TEST_CASE(scan_app_on_cloud)
+{
+       EXCEPTION_GUARD_START
+
+       BOOST_MESSAGE("Only valid for engines which supports scan on cloud feature");
+
+       auto c = Test::Context<csr_cs_context_h>();
+       auto context = c.get();
+
+       install_test_files();
+       install_test_apps();
+
+       set_default_callback(context);
+       ASSERT_SUCCESS(csr_cs_set_scan_on_cloud(context, true));
+
+       AsyncTestContext testCtx;
+
+       ASSERT_SUCCESS(csr_cs_scan_dir_async(context, TEST_DIR_APPS(), &testCtx));
+
+       std::unique_lock<std::mutex> l(testCtx.m);
+       testCtx.cv.wait(l);
+       l.unlock();
+
+       ASSERT_CALLBACK(testCtx, -1, -1, 1, 0, 0);
+
+       ASSERT_DETECTED_IN_LIST(testCtx.detectedList, TEST_WGT_APP_ROOT(),
+                                                       MALWARE_HIGH_NAME, MALWARE_HIGH_SEVERITY,
+                                                       MALWARE_HIGH_DETAILED_URL);
+       ASSERT_DETECTED_IN_LIST_EXT(testCtx.detectedList, TEST_WGT_APP_ROOT(), true,
+                                                               TEST_WGT_PKG_ID);
+
+       ASSERT_DETECTED_IN_LIST(testCtx.detectedList, TEST_TPK_APP_ROOT(),
+                                                       MALWARE_HIGH_NAME, MALWARE_HIGH_SEVERITY,
+                                                       MALWARE_HIGH_DETAILED_URL);
+       ASSERT_DETECTED_IN_LIST_EXT(testCtx.detectedList, TEST_TPK_APP_ROOT(), true,
+                                                               TEST_TPK_PKG_ID);
+
+       ASSERT_DETECTED_IN_LIST(testCtx.detectedList, TEST_FAKE_APP_FILE(),
+                                                       MALWARE_HIGH_NAME, MALWARE_HIGH_SEVERITY,
+                                                       MALWARE_HIGH_DETAILED_URL);
+       ASSERT_DETECTED_IN_LIST_EXT(testCtx.detectedList, TEST_FAKE_APP_FILE(), false, "");
+
+       const char *dirs[1] = {
+               TEST_DIR_APPS()
+       };
+       csr_cs_malware_list_h malwares = nullptr;
+       size_t count = 0;
+
+       ASSERT_SUCCESS(csr_cs_get_detected_malwares(context, dirs, 1, &malwares, &count));
+       CHECK_IS_NOT_NULL(malwares);
+
+       std::vector<csr_cs_malware_h> malware_vec;
+       for (size_t i = 0; i < count; ++i) {
+               csr_cs_malware_h malware = nullptr;
+               ASSERT_SUCCESS(csr_cs_malware_list_get_malware(malwares, i, &malware));
+
+               malware_vec.push_back(malware);
+       }
+
+       ASSERT_DETECTED_IN_LIST(malware_vec, TEST_WGT_APP_ROOT(), MALWARE_HIGH_NAME,
+                                                       MALWARE_HIGH_SEVERITY, MALWARE_HIGH_DETAILED_URL);
+       ASSERT_DETECTED_IN_LIST_EXT(malware_vec, TEST_WGT_APP_ROOT(), true, TEST_WGT_PKG_ID);
+
+       ASSERT_DETECTED_IN_LIST(malware_vec, TEST_TPK_APP_ROOT(), MALWARE_HIGH_NAME,
+                                                       MALWARE_HIGH_SEVERITY, MALWARE_HIGH_DETAILED_URL);
+       ASSERT_DETECTED_IN_LIST_EXT(malware_vec, TEST_TPK_APP_ROOT(), true, TEST_TPK_PKG_ID);
+
+       ASSERT_DETECTED_IN_LIST(malware_vec, TEST_FAKE_APP_FILE(), MALWARE_HIGH_NAME,
+                                                       MALWARE_HIGH_SEVERITY, MALWARE_HIGH_DETAILED_URL);
+       ASSERT_DETECTED_IN_LIST_EXT(malware_vec, TEST_FAKE_APP_FILE(), false, "");
+
+       EXCEPTION_GUARD_END
+}
+
 BOOST_AUTO_TEST_SUITE_END()