From 6fc2fe5320838d5d70e6fb0f2bad2aa2c6a73200 Mon Sep 17 00:00:00 2001 From: Aleksei Nikiforov Date: Thu, 16 Jan 2020 11:45:25 +0300 Subject: [PATCH] Add serialization test --- CMakeLists.txt | 8 ++ test_audit_record.cpp | 206 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 214 insertions(+) create mode 100644 test_audit_record.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index ae0e8ee..c753f7d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,6 +15,8 @@ find_package(Boost REQUIRED COMPONENTS filesystem) find_package(ClickhouseCpp REQUIRED) pkg_check_modules(AUPARSE auparse REQUIRED) +include(GoogleTest) + include_directories(${Boost_INCLUDE_DIRS} ${AUPARSE_INCLUDE_DIRS}) set(SOURCES @@ -32,9 +34,15 @@ set(HEADERS utils.hpp ) +enable_testing() + add_executable( auditd-plugin-clickhouse ${SOURCES} ${HEADERS} ) target_link_libraries( auditd-plugin-clickhouse ${CLICKHOUSECPP_LIBRARIES} ${AUPARSE_LIBRARIES} Threads::Threads Boost::filesystem ) +add_executable( test-audit-record test_audit_record.cpp auditd-record.cpp logging.cpp utils.cpp auditd-record.hpp logging.hpp utils.hpp ) +target_link_libraries( test-audit-record ${CLICKHOUSECPP_LIBRARIES} ${AUPARSE_LIBRARIES} gtest gtest_main ) +add_test( NAME test-audit-record COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-audit-record ) + install(TARGETS auditd-plugin-clickhouse RUNTIME DESTINATION ${BIN_INSTALL_LIBEXEC} ) install(FILES auditd-plugin-clickhouse.conf DESTINATION ${SYSCONF_INSTALL_DIR}/audisp/plugins.d ) install(FILES auditd-clickhouse.conf auditd-clickhouse-datatypes.json DESTINATION ${SYSCONF_INSTALL_DIR}/audisp ) diff --git a/test_audit_record.cpp b/test_audit_record.cpp new file mode 100644 index 0000000..181b1ef --- /dev/null +++ b/test_audit_record.cpp @@ -0,0 +1,206 @@ +/* + * This is an auditd plugin for sending auditd data + * to clickhouse DB. + * Copyright (C) 2020 Aleksei Nikiforov + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include + +#include +#include +#include + +#include +#include + +#include + +#include "auditd-record.hpp" + +static AuditRecord generateTestRecord() +{ + AuditRecord original_record; + + original_record.time = 12345678; + original_record.milliseconds = 9876; + original_record.serial = 12345; + original_record.node = "test node name"; + + original_record.filename = "some random file name"; + + auto string_field = InterpretedStringRecordField::createRecord("string_record"); + string_field->setStringValue(std::string("string_record_value")); + original_record.fields[string_field->getName()] = string_field; + + auto integer_field = IntegerRecordField::createRecord("integer_record"); + integer_field->setIntValue(500); + integer_field->setStringValue(std::string("five hundred")); + original_record.fields[integer_field->getName()] = integer_field; + + auto array_field = InterpretedStringArrayRecordField::createRecord("array_record"); + array_field->setArrays({"first name", "second name"}, {"first value", "second value"}); + original_record.fields[array_field->getName()] = array_field; + + return original_record; +} + +TEST(AuditRecord, Serialization) +{ + AuditRecord original_record = generateTestRecord(); + + boost::property_tree::ptree ptree_data = original_record.toPtree(); + std::stringstream stream_data; + + boost::property_tree::write_json(stream_data, ptree_data); + + boost::property_tree::ptree ptree_restored_data; + + boost::property_tree::read_json(stream_data, ptree_restored_data); + + auto restored_record = AuditRecord::fromPtree(ptree_restored_data); + + EXPECT_EQ(original_record.time, restored_record.time); + EXPECT_EQ(original_record.milliseconds, restored_record.milliseconds); + EXPECT_EQ(original_record.serial, restored_record.serial); + EXPECT_EQ(original_record.node, restored_record.node); + + EXPECT_FALSE(original_record.filename.empty()); + EXPECT_TRUE (restored_record.filename.empty()); + + EXPECT_EQ(original_record.fields.size(), restored_record.fields.size()); + + for (auto iter = original_record.fields.begin(); iter != original_record.fields.end(); ++iter) + { + auto second_iter = restored_record.fields.find(iter->first); + EXPECT_TRUE(second_iter != restored_record.fields.end()); + + if (second_iter == restored_record.fields.end()) + { + continue; + } + + EXPECT_EQ(iter->second->getType(), second_iter->second->getType()); + + if (iter->second->getType() != second_iter->second->getType()) + { + continue; + } + + EXPECT_EQ(iter->second->getName(), second_iter->second->getName()); + + switch (iter->second->getType()) + { + case AbstractRecordField::Type::Int: + { + auto original_field = std::dynamic_pointer_cast(iter->second); + auto restored_field = std::dynamic_pointer_cast(second_iter->second); + + EXPECT_TRUE(original_field); + EXPECT_TRUE(restored_field); + + if ((!original_field) || (!restored_field)) + { + break; + } + + EXPECT_EQ(original_field->getIntValue(), restored_field->getIntValue()); + EXPECT_EQ(original_field->getStringValue(), restored_field->getStringValue()); + } + break; + + case AbstractRecordField::Type::String: + { + auto original_field = std::dynamic_pointer_cast(iter->second); + auto restored_field = std::dynamic_pointer_cast(second_iter->second); + + EXPECT_TRUE(original_field); + EXPECT_TRUE(restored_field); + + if ((!original_field) || (!restored_field)) + { + break; + } + + EXPECT_EQ(original_field->getStringValue(), restored_field->getStringValue()); + } + break; + + case AbstractRecordField::Type::InterpretedString: + { + auto original_field = std::dynamic_pointer_cast(iter->second); + auto restored_field = std::dynamic_pointer_cast(second_iter->second); + + EXPECT_TRUE(original_field); + EXPECT_TRUE(restored_field); + + if ((!original_field) || (!restored_field)) + { + break; + } + + EXPECT_EQ(original_field->getStringValue(), restored_field->getStringValue()); + } + break; + + case AbstractRecordField::Type::InterpretedStringArray: + { + auto original_field = std::dynamic_pointer_cast(iter->second); + auto restored_field = std::dynamic_pointer_cast(second_iter->second); + + EXPECT_TRUE(original_field); + EXPECT_TRUE(restored_field); + + if ((!original_field) || (!restored_field)) + { + break; + } + + auto original_names = original_field->getNamesArray(); + auto original_values = original_field->getValuesArray(); + auto restored_names = restored_field->getNamesArray(); + auto restored_values = restored_field->getValuesArray(); + + EXPECT_EQ(original_names.size(), restored_names.size()); + + if (original_names.size() == restored_names.size()) + { + auto original_iter = original_names.begin(); + auto restored_iter = restored_names.begin(); + + for ( ; (original_iter != original_names.end()) && (restored_iter != restored_names.end()); ++original_iter, ++restored_iter) + { + EXPECT_EQ(*original_iter, *restored_iter); + } + } + + EXPECT_EQ(original_values.size(), restored_values.size()); + + if (original_values.size() == restored_values.size()) + { + auto original_iter = original_values.begin(); + auto restored_iter = restored_values.begin(); + + for ( ; (original_iter != original_values.end()) && (restored_iter != restored_values.end()); ++original_iter, ++restored_iter) + { + EXPECT_EQ(*original_iter, *restored_iter); + } + } + } + break; + } + } +}