2017-12-19 00:04:06 +00:00
|
|
|
/**
|
2016-02-11 19:48:58 +00:00
|
|
|
* Copyright (c) 2014-present, Facebook, Inc.
|
2016-01-21 08:23:05 +00:00
|
|
|
* All rights reserved.
|
|
|
|
*
|
2017-12-19 00:04:06 +00:00
|
|
|
* This source code is licensed under both the Apache 2.0 license (found in the
|
|
|
|
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
|
|
|
* in the COPYING file in the root directory of this source tree).
|
|
|
|
* You may select, at your option, one of the above-listed licenses.
|
2016-01-21 08:23:05 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <gtest/gtest.h>
|
|
|
|
|
|
|
|
#include <osquery/database.h>
|
|
|
|
|
2018-03-21 16:39:50 +00:00
|
|
|
#include "osquery/core/json.h"
|
2016-06-09 17:49:26 +00:00
|
|
|
#include "osquery/tests/test_util.h"
|
2016-01-21 08:23:05 +00:00
|
|
|
|
2018-03-21 16:39:50 +00:00
|
|
|
#include <osquery/logger.h>
|
|
|
|
|
2018-06-02 19:38:29 +00:00
|
|
|
#include <limits>
|
|
|
|
|
2018-03-21 16:39:50 +00:00
|
|
|
namespace rj = rapidjson;
|
|
|
|
|
2016-01-21 08:23:05 +00:00
|
|
|
namespace osquery {
|
|
|
|
|
|
|
|
class DatabaseTests : public testing::Test {};
|
|
|
|
|
2018-06-02 19:38:29 +00:00
|
|
|
TEST_F(DatabaseTests, test_set_value_str) {
|
|
|
|
auto s = setDatabaseValue(kLogs, "str", "{}");
|
2016-01-21 08:23:05 +00:00
|
|
|
EXPECT_TRUE(s.ok());
|
|
|
|
}
|
|
|
|
|
2018-06-02 19:38:29 +00:00
|
|
|
TEST_F(DatabaseTests, test_set_value_int) {
|
|
|
|
auto s = setDatabaseValue(kLogs, "int", -1);
|
|
|
|
EXPECT_TRUE(s.ok());
|
|
|
|
}
|
2016-01-21 08:23:05 +00:00
|
|
|
|
2018-06-02 19:38:29 +00:00
|
|
|
TEST_F(DatabaseTests, test_set_value_mix1) {
|
|
|
|
auto s = setDatabaseValue(kLogs, "intstr", -1);
|
|
|
|
EXPECT_TRUE(s.ok());
|
2016-01-21 08:23:05 +00:00
|
|
|
|
2018-06-02 19:38:29 +00:00
|
|
|
s = setDatabaseValue(kLogs, "intstr", "{}");
|
|
|
|
EXPECT_TRUE(s.ok());
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(DatabaseTests, test_set_value_mix2) {
|
|
|
|
auto s = setDatabaseValue(kLogs, "strint", "{}");
|
2016-01-21 08:23:05 +00:00
|
|
|
EXPECT_TRUE(s.ok());
|
|
|
|
|
2018-06-02 19:38:29 +00:00
|
|
|
s = setDatabaseValue(kLogs, "strint", -1);
|
|
|
|
EXPECT_TRUE(s.ok());
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(DatabaseTests, test_get_value_does_not_exist) {
|
2016-01-21 08:23:05 +00:00
|
|
|
// Unknown keys return failed, but will return empty data.
|
2018-06-02 19:38:29 +00:00
|
|
|
std::string value;
|
|
|
|
auto s = getDatabaseValue(kLogs, "does_not_exist", value);
|
2016-01-21 08:23:05 +00:00
|
|
|
EXPECT_FALSE(s.ok());
|
|
|
|
EXPECT_TRUE(value.empty());
|
|
|
|
}
|
|
|
|
|
2018-06-02 19:38:29 +00:00
|
|
|
TEST_F(DatabaseTests, test_get_value_str) {
|
|
|
|
std::string expected;
|
|
|
|
for (unsigned char i = std::numeric_limits<unsigned char>::min();
|
|
|
|
i < std::numeric_limits<unsigned char>::max();
|
|
|
|
i++) {
|
|
|
|
if (std::isprint(i)) {
|
|
|
|
expected += i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
setDatabaseValue(kLogs, "str", expected);
|
|
|
|
|
|
|
|
std::string value;
|
|
|
|
auto s = getDatabaseValue(kLogs, "str", value);
|
|
|
|
|
|
|
|
EXPECT_TRUE(s.ok());
|
|
|
|
EXPECT_EQ(value, expected);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(DatabaseTests, test_get_value_int) {
|
|
|
|
int expected = std::numeric_limits<int>::min();
|
|
|
|
setDatabaseValue(kLogs, "int", expected);
|
|
|
|
|
|
|
|
int value = 0;
|
|
|
|
auto s = getDatabaseValue(kLogs, "int", value);
|
|
|
|
|
|
|
|
EXPECT_TRUE(s.ok());
|
|
|
|
EXPECT_EQ(value, expected);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(DatabaseTests, test_get_value_mix1) {
|
|
|
|
int expected = std::numeric_limits<int>::max();
|
|
|
|
setDatabaseValue(kLogs, "strint", "{}");
|
|
|
|
setDatabaseValue(kLogs, "strint", expected);
|
|
|
|
|
|
|
|
int value;
|
|
|
|
auto s = getDatabaseValue(kLogs, "strint", value);
|
|
|
|
|
|
|
|
EXPECT_TRUE(s.ok());
|
|
|
|
EXPECT_EQ(value, expected);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(DatabaseTests, test_get_value_mix2) {
|
|
|
|
std::string expected = "{}";
|
|
|
|
setDatabaseValue(kLogs, "intstr", -1);
|
|
|
|
setDatabaseValue(kLogs, "intstr", expected);
|
|
|
|
|
|
|
|
std::string value;
|
|
|
|
auto s = getDatabaseValue(kLogs, "intstr", value);
|
|
|
|
|
|
|
|
EXPECT_TRUE(s.ok());
|
|
|
|
EXPECT_EQ(value, expected);
|
|
|
|
}
|
|
|
|
|
2016-01-21 08:23:05 +00:00
|
|
|
TEST_F(DatabaseTests, test_scan_values) {
|
|
|
|
setDatabaseValue(kLogs, "1", "0");
|
2018-06-02 19:38:29 +00:00
|
|
|
setDatabaseValue(kLogs, "2", 0);
|
2016-01-21 08:23:05 +00:00
|
|
|
setDatabaseValue(kLogs, "3", "0");
|
|
|
|
|
|
|
|
std::vector<std::string> keys;
|
|
|
|
auto s = scanDatabaseKeys(kLogs, keys);
|
|
|
|
EXPECT_TRUE(s.ok());
|
|
|
|
EXPECT_GT(keys.size(), 2U);
|
|
|
|
|
|
|
|
keys.clear();
|
2018-06-02 19:38:29 +00:00
|
|
|
s = scanDatabaseKeys(kLogs, keys, 3);
|
2016-01-21 08:23:05 +00:00
|
|
|
EXPECT_TRUE(s.ok());
|
2018-06-02 19:38:29 +00:00
|
|
|
EXPECT_EQ(keys.size(), 3U);
|
2016-01-21 08:23:05 +00:00
|
|
|
}
|
|
|
|
|
2018-06-02 19:38:29 +00:00
|
|
|
TEST_F(DatabaseTests, test_delete_values_str) {
|
2016-01-21 08:23:05 +00:00
|
|
|
setDatabaseValue(kLogs, "k", "0");
|
|
|
|
|
|
|
|
std::string value;
|
|
|
|
getDatabaseValue(kLogs, "k", value);
|
|
|
|
EXPECT_FALSE(value.empty());
|
|
|
|
|
|
|
|
auto s = deleteDatabaseValue(kLogs, "k");
|
|
|
|
EXPECT_TRUE(s.ok());
|
|
|
|
|
|
|
|
// Make sure the key has been deleted.
|
|
|
|
value.clear();
|
|
|
|
s = getDatabaseValue(kLogs, "k", value);
|
|
|
|
EXPECT_FALSE(s.ok());
|
|
|
|
EXPECT_TRUE(value.empty());
|
|
|
|
}
|
2018-03-21 16:39:50 +00:00
|
|
|
|
2018-06-02 19:38:29 +00:00
|
|
|
TEST_F(DatabaseTests, test_delete_values_int) {
|
|
|
|
int expected = 0;
|
|
|
|
setDatabaseValue(kLogs, "k", expected);
|
|
|
|
|
|
|
|
int value;
|
|
|
|
getDatabaseValue(kLogs, "k", value);
|
|
|
|
EXPECT_EQ(value, expected);
|
|
|
|
|
|
|
|
auto s = deleteDatabaseValue(kLogs, "k");
|
|
|
|
EXPECT_TRUE(s.ok());
|
|
|
|
|
|
|
|
// Make sure the key has been deleted.
|
|
|
|
value = -5;
|
|
|
|
s = getDatabaseValue(kLogs, "k", value);
|
|
|
|
EXPECT_FALSE(s.ok());
|
|
|
|
EXPECT_EQ(value, -5);
|
|
|
|
}
|
|
|
|
|
2018-04-24 20:39:22 +00:00
|
|
|
TEST_F(DatabaseTests, test_ptree_upgrade_to_rj_empty_v0v1) {
|
|
|
|
auto empty_results{"{}"};
|
|
|
|
auto status = setDatabaseValue(kQueries, "old_empty_results", empty_results);
|
|
|
|
EXPECT_TRUE(status.ok());
|
|
|
|
|
|
|
|
// Stage our database to be pre-upgrade to ensure the logic runs
|
|
|
|
status = setDatabaseValue(kPersistentSettings, "results_version", "0");
|
|
|
|
EXPECT_TRUE(status.ok());
|
|
|
|
|
|
|
|
status = upgradeDatabase();
|
|
|
|
EXPECT_TRUE(status.ok());
|
|
|
|
|
|
|
|
std::string new_empty_list;
|
|
|
|
status = getDatabaseValue(kQueries, "old_empty_results", new_empty_list);
|
|
|
|
EXPECT_TRUE(status.ok());
|
|
|
|
|
|
|
|
rj::Document empty_list;
|
|
|
|
EXPECT_FALSE(empty_list.Parse(new_empty_list).HasParseError());
|
|
|
|
EXPECT_TRUE(empty_list.IsArray());
|
|
|
|
|
|
|
|
// Expect our DB upgrade logic to have been set
|
|
|
|
std::string db_results_version{""};
|
|
|
|
getDatabaseValue(kPersistentSettings, "results_version", db_results_version);
|
|
|
|
EXPECT_EQ(db_results_version, kDatabaseResultsVersion);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(DatabaseTests, test_ptree_upgrade_to_rj_results_v0v1) {
|
2018-03-21 16:39:50 +00:00
|
|
|
auto bad_json =
|
|
|
|
"{\"\":{\"disabled\":\"0\",\"network_name\":\"BTWifi-Starbucks\"},\"\":{"
|
|
|
|
"\"disabled\":\"0\",\"network_name\":\"Lobo-Guest\"},\"\":{\"disabled\":"
|
|
|
|
"\"0\",\"network_name\":\"GoogleGuest\"}}";
|
|
|
|
auto status = setDatabaseValue(kQueries, "bad_wifi_json", bad_json);
|
|
|
|
EXPECT_TRUE(status.ok());
|
|
|
|
|
|
|
|
// Add an integer value to ensure we don't munge non-json objects
|
|
|
|
status = setDatabaseValue(kQueries, "bad_wifi_jsonepoch", "1521583712");
|
2018-04-24 20:39:22 +00:00
|
|
|
EXPECT_TRUE(status.ok());
|
|
|
|
|
|
|
|
// Stage our database to be pre-upgrade to ensure the logic runs
|
|
|
|
status = setDatabaseValue(kPersistentSettings, "results_version", "0");
|
|
|
|
EXPECT_TRUE(status.ok());
|
2018-03-21 16:39:50 +00:00
|
|
|
|
|
|
|
rj::Document bad_doc;
|
|
|
|
|
|
|
|
// Potential bug with RJ, in that parsing should fail with empty keys
|
|
|
|
// EXPECT_TRUE(bad_doc.Parse(bad_json).HasParseError());
|
|
|
|
EXPECT_FALSE(bad_doc.IsArray());
|
|
|
|
|
|
|
|
status = upgradeDatabase();
|
|
|
|
EXPECT_TRUE(status.ok());
|
|
|
|
|
|
|
|
std::string good_json;
|
|
|
|
status = getDatabaseValue(kQueries, "bad_wifi_json", good_json);
|
|
|
|
EXPECT_TRUE(status.ok());
|
|
|
|
|
|
|
|
rj::Document clean_doc;
|
|
|
|
EXPECT_FALSE(clean_doc.Parse(good_json).HasParseError());
|
|
|
|
EXPECT_TRUE(clean_doc.IsArray());
|
|
|
|
EXPECT_EQ(clean_doc.Size(), 3U);
|
|
|
|
|
|
|
|
// Ensure our non-json thing was not destroyed
|
|
|
|
std::string query_epoch{""};
|
|
|
|
status = getDatabaseValue(kQueries, "bad_wifi_jsonepoch", query_epoch);
|
|
|
|
LOG(INFO) << query_epoch;
|
|
|
|
auto ulepoch = std::stoull(query_epoch);
|
|
|
|
EXPECT_EQ(ulepoch, 1521583712U);
|
2018-04-24 20:39:22 +00:00
|
|
|
|
|
|
|
// Expect our DB upgrade logic to have been set
|
|
|
|
std::string db_results_version{""};
|
|
|
|
getDatabaseValue(kPersistentSettings, "results_version", db_results_version);
|
|
|
|
EXPECT_EQ(db_results_version, kDatabaseResultsVersion);
|
2018-03-21 16:39:50 +00:00
|
|
|
}
|
2016-01-21 08:23:05 +00:00
|
|
|
}
|