Add extracted tools: CitrineOS, OpenOCPP, ShapeShifter
- CitrineOS core extracted (CSMS OCPP 2.0.1) - OpenOCPP extracted (firmware OCPP 1.6J/2.0.1) - ShapeShifter library installed (pip install -e) - ShapeShifter specification extracted - EVerest extracted TODO updated with progress
This commit is contained in:
43
tools/EVerest-main/modules/Misc/ErrorHistory/BUILD.bazel
Normal file
43
tools/EVerest-main/modules/Misc/ErrorHistory/BUILD.bazel
Normal file
@@ -0,0 +1,43 @@
|
||||
load("@rules_cc//cc:defs.bzl", "cc_test")
|
||||
load("//modules:module.bzl", "cc_everest_module")
|
||||
load("//third-party/bazel/toolchains:defs.bzl", "CROSS_TEST_INCOMPATIBLE")
|
||||
|
||||
cc_everest_module(
|
||||
name = "ErrorHistory",
|
||||
srcs = glob([
|
||||
"*.cpp",
|
||||
"*.hpp",
|
||||
]),
|
||||
impls = ["error_history"],
|
||||
deps = [
|
||||
"//lib/everest/sqlite:everest-sqlite",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "ErrorHistory_test",
|
||||
target_compatible_with = CROSS_TEST_INCOMPATIBLE,
|
||||
srcs = glob(
|
||||
[
|
||||
"tests/*.cpp",
|
||||
"tests/*.hpp",
|
||||
"ErrorDatabaseSqlite.*",
|
||||
],
|
||||
exclude = [
|
||||
"main/car_simulatorImpl.*",
|
||||
"main/car_simulation.*",
|
||||
],
|
||||
),
|
||||
local_defines = [
|
||||
"BUILD_TZ_LIB=ON",
|
||||
"USE_SYSTEM_TZ_DB=ON",
|
||||
"USE_OS_TZDB=1",
|
||||
"USE_AUTOLOAD=0",
|
||||
"HAS_REMOTE_API=0",
|
||||
],
|
||||
deps = [
|
||||
"//lib/everest/framework",
|
||||
"//lib/everest/log:liblog",
|
||||
"@catch2//:catch2_main",
|
||||
],
|
||||
)
|
||||
36
tools/EVerest-main/modules/Misc/ErrorHistory/CMakeLists.txt
Normal file
36
tools/EVerest-main/modules/Misc/ErrorHistory/CMakeLists.txt
Normal file
@@ -0,0 +1,36 @@
|
||||
#
|
||||
# AUTO GENERATED - MARKED REGIONS WILL BE KEPT
|
||||
# template version 3
|
||||
#
|
||||
|
||||
# module setup:
|
||||
# - ${MODULE_NAME}: module name
|
||||
ev_setup_cpp_module()
|
||||
|
||||
# ev@bcc62523-e22b-41d7-ba2f-825b493a3c97:v1
|
||||
option(BUILD_TESTING "Run unit tests" OFF)
|
||||
set(CMAKE_PREFIX_PATH "/usr/lib/x86_64-linux-gnu" ${CMAKE_PREFIX_PATH})
|
||||
|
||||
find_package(SQLite3 REQUIRED)
|
||||
|
||||
target_link_libraries(${MODULE_NAME}
|
||||
PRIVATE
|
||||
SQLite::SQLite3
|
||||
everest::sqlite
|
||||
)
|
||||
target_sources(${MODULE_NAME}
|
||||
PRIVATE
|
||||
"ErrorDatabaseSqlite.cpp"
|
||||
)
|
||||
# ev@bcc62523-e22b-41d7-ba2f-825b493a3c97:v1
|
||||
|
||||
target_sources(${MODULE_NAME}
|
||||
PRIVATE
|
||||
"error_history/error_historyImpl.cpp"
|
||||
)
|
||||
|
||||
# ev@c55432ab-152c-45a9-9d2e-7281d50c69c3:v1
|
||||
if(EVEREST_CORE_BUILD_TESTING)
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
# ev@c55432ab-152c-45a9-9d2e-7281d50c69c3:v1
|
||||
@@ -0,0 +1,320 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
|
||||
#include "ErrorDatabaseSqlite.hpp"
|
||||
|
||||
#include <everest/database/exceptions.hpp>
|
||||
#include <everest/database/sqlite/connection.hpp>
|
||||
#include <everest/database/sqlite/statement.hpp>
|
||||
#include <everest/exceptions.hpp>
|
||||
#include <everest/logging.hpp>
|
||||
|
||||
#include <utils/date.hpp>
|
||||
|
||||
#include <set>
|
||||
|
||||
namespace module {
|
||||
|
||||
ErrorDatabaseSqlite::ErrorDatabaseSqlite(const fs::path& db_path_, const bool reset_) :
|
||||
db_path(fs::absolute(db_path_)) {
|
||||
BOOST_LOG_FUNCTION();
|
||||
std::lock_guard<std::mutex> lock(this->db_mutex);
|
||||
|
||||
bool reset = reset_ || !fs::exists(this->db_path);
|
||||
if (reset) {
|
||||
EVLOG_info << "Resetting database";
|
||||
this->reset_database();
|
||||
} else {
|
||||
EVLOG_info << "Using database at " << this->db_path;
|
||||
try {
|
||||
this->check_database();
|
||||
} catch (const std::exception& e) {
|
||||
EVLOG_error << "Error checking database: " << e.what();
|
||||
EVLOG_info << "Resetting database";
|
||||
this->reset_database();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ErrorDatabaseSqlite::check_database() {
|
||||
BOOST_LOG_FUNCTION();
|
||||
EVLOG_info << "Checking database";
|
||||
try {
|
||||
auto db = std::make_shared<everest::db::sqlite::Connection>(this->db_path);
|
||||
if (!db->open_connection()) {
|
||||
EVLOG_error << "Error opening database";
|
||||
throw everest::db::ConnectionException(db->get_error_message());
|
||||
}
|
||||
std::string sql = "SELECT name";
|
||||
sql += " FROM sqlite_schema";
|
||||
sql += " WHERE type = 'table' AND name NOT LIKE 'sqlite_%';";
|
||||
auto stmt = db->new_statement(sql);
|
||||
bool has_errors_table = false;
|
||||
int status;
|
||||
while ((status = stmt->step()) == SQLITE_ROW) {
|
||||
std::string table_name = stmt->column_text(0);
|
||||
if (table_name == "errors") {
|
||||
if (has_errors_table) {
|
||||
throw Everest::EverestConfigError("Database contains multiple errors tables");
|
||||
}
|
||||
has_errors_table = true;
|
||||
EVLOG_debug << "Found errors table";
|
||||
} else {
|
||||
EVLOG_warning << "Found unknown table: " << table_name;
|
||||
}
|
||||
}
|
||||
if (status != SQLITE_DONE) {
|
||||
throw Everest::EverestConfigError(db->get_error_message());
|
||||
}
|
||||
if (!has_errors_table) {
|
||||
throw Everest::EverestConfigError("Database does not contain errors table");
|
||||
}
|
||||
sql = "PRAGMA table_info(errors);";
|
||||
auto stmt2 = db->new_statement(sql);
|
||||
std::set<std::string> columns;
|
||||
while ((status = stmt2->step()) == SQLITE_ROW) {
|
||||
auto variant = stmt2->column_variant("name");
|
||||
columns.insert(std::get<std::string>(variant));
|
||||
}
|
||||
std::set<std::string> required_columns = {
|
||||
"uuid", "type", "description", "message", "origin_module", "origin_implementation",
|
||||
"timestamp", "severity", "state", "sub_type", "vendor_id"};
|
||||
if (status != SQLITE_DONE) {
|
||||
throw Everest::EverestConfigError(db->get_error_message());
|
||||
}
|
||||
if (columns != required_columns) {
|
||||
throw Everest::EverestConfigError("Errors table does not contain all required columns");
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
EVLOG_error << "Error checking database: " << e.what();
|
||||
}
|
||||
}
|
||||
|
||||
void ErrorDatabaseSqlite::reset_database() {
|
||||
BOOST_LOG_FUNCTION();
|
||||
fs::path database_directory = this->db_path.parent_path();
|
||||
if (!fs::exists(database_directory)) {
|
||||
fs::create_directories(database_directory);
|
||||
}
|
||||
if (fs::exists(this->db_path)) {
|
||||
fs::remove(this->db_path);
|
||||
}
|
||||
try {
|
||||
everest::db::sqlite::Connection db(this->db_path);
|
||||
if (!db.open_connection()) {
|
||||
EVLOG_error << "Error opening database during reset";
|
||||
throw everest::db::ConnectionException(db.get_error_message());
|
||||
}
|
||||
std::string sql = "CREATE TABLE errors("
|
||||
"uuid TEXT PRIMARY KEY NOT NULL,"
|
||||
"type TEXT NOT NULL,"
|
||||
"description TEXT NOT NULL,"
|
||||
"message TEXT NOT NULL,"
|
||||
"origin_module TEXT NOT NULL,"
|
||||
"origin_implementation TEXT NOT NULL,"
|
||||
"timestamp TEXT NOT NULL,"
|
||||
"severity TEXT NOT NULL,"
|
||||
"state TEXT NOT NULL,"
|
||||
"sub_type TEXT NOT NULL,"
|
||||
"vendor_id TEXT NOT NULL);";
|
||||
|
||||
if (!db.execute_statement(sql)) {
|
||||
EVLOG_error << "Error creating database during reset";
|
||||
throw everest::db::QueryExecutionException(db.get_error_message());
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
EVLOG_error << "Error resetting the database: " << e.what();
|
||||
}
|
||||
}
|
||||
|
||||
void ErrorDatabaseSqlite::add_error(Everest::error::ErrorPtr error) {
|
||||
std::lock_guard<std::mutex> lock(this->db_mutex);
|
||||
this->add_error_without_mutex(error);
|
||||
}
|
||||
|
||||
void ErrorDatabaseSqlite::add_error_without_mutex(Everest::error::ErrorPtr error) {
|
||||
BOOST_LOG_FUNCTION();
|
||||
try {
|
||||
everest::db::sqlite::Connection db(this->db_path);
|
||||
if (!db.open_connection()) {
|
||||
EVLOG_error << "Error opening database";
|
||||
throw everest::db::ConnectionException(db.get_error_message());
|
||||
}
|
||||
std::string sql = "INSERT INTO errors(uuid, type, description, message, origin_module, origin_implementation, "
|
||||
"timestamp, severity, state, sub_type, vendor_id) VALUES(";
|
||||
sql += "?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11);";
|
||||
auto stmt = db.new_statement(sql);
|
||||
stmt->bind_text(1, error->uuid.to_string(), everest::db::sqlite::SQLiteString::Transient);
|
||||
stmt->bind_text(2, error->type);
|
||||
stmt->bind_text(3, error->description);
|
||||
stmt->bind_text(4, error->message);
|
||||
stmt->bind_text(5, error->origin.module_id);
|
||||
stmt->bind_text(6, error->origin.implementation_id);
|
||||
stmt->bind_text(7, Everest::Date::to_rfc3339(error->timestamp), everest::db::sqlite::SQLiteString::Transient);
|
||||
stmt->bind_text(8, Everest::error::severity_to_string(error->severity),
|
||||
everest::db::sqlite::SQLiteString::Transient);
|
||||
stmt->bind_text(9, Everest::error::state_to_string(error->state), everest::db::sqlite::SQLiteString::Transient);
|
||||
stmt->bind_text(10, error->sub_type);
|
||||
stmt->bind_text(11, error->vendor_id);
|
||||
if (stmt->step() != SQLITE_DONE) {
|
||||
throw everest::db::QueryExecutionException(db.get_error_message());
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
EVLOG_error << "Error adding error to database: " << e.what();
|
||||
}
|
||||
}
|
||||
|
||||
std::string ErrorDatabaseSqlite::filter_to_sql_condition(const Everest::error::ErrorFilter& filter) {
|
||||
std::string condition{};
|
||||
switch (filter.get_filter_type()) {
|
||||
case Everest::error::FilterType::State: {
|
||||
condition = "(state = '" + Everest::error::state_to_string(filter.get_state_filter()) + "')";
|
||||
} break;
|
||||
case Everest::error::FilterType::Origin: {
|
||||
condition = "(origin_module = '" + filter.get_origin_filter().module_id + "' AND " +
|
||||
"origin_implementation = '" + filter.get_origin_filter().implementation_id + "')";
|
||||
} break;
|
||||
case Everest::error::FilterType::Type: {
|
||||
condition = "(type = '" + filter.get_type_filter().value + "')";
|
||||
} break;
|
||||
case Everest::error::FilterType::Severity: {
|
||||
switch (filter.get_severity_filter()) {
|
||||
case Everest::error::SeverityFilter::LOW_GE: {
|
||||
condition = "(severity = '" + Everest::error::severity_to_string(Everest::error::Severity::Low) +
|
||||
"' OR severity = '" + Everest::error::severity_to_string(Everest::error::Severity::Medium) +
|
||||
"' OR severity = '" + Everest::error::severity_to_string(Everest::error::Severity::High) + "')";
|
||||
} break;
|
||||
case Everest::error::SeverityFilter::MEDIUM_GE: {
|
||||
condition = "(severity = '" + Everest::error::severity_to_string(Everest::error::Severity::Medium) +
|
||||
"' OR severity = '" + Everest::error::severity_to_string(Everest::error::Severity::High) + "')";
|
||||
} break;
|
||||
case Everest::error::SeverityFilter::HIGH_GE: {
|
||||
condition = "(severity = '" + Everest::error::severity_to_string(Everest::error::Severity::High) + "')";
|
||||
} break;
|
||||
}
|
||||
} break;
|
||||
case Everest::error::FilterType::TimePeriod: {
|
||||
condition = "(timestamp BETWEEN '" + Everest::Date::to_rfc3339(filter.get_time_period_filter().from) +
|
||||
"' AND '" + Everest::Date::to_rfc3339(filter.get_time_period_filter().to) + "')";
|
||||
} break;
|
||||
case Everest::error::FilterType::Handle: {
|
||||
condition = "(uuid = '" + filter.get_handle_filter().to_string() + "')";
|
||||
} break;
|
||||
case Everest::error::FilterType::SubType: {
|
||||
condition = "(sub_type = '" + filter.get_sub_type_filter().value + "')";
|
||||
} break;
|
||||
case Everest::error::FilterType::VendorId: {
|
||||
condition = "(vendor_id = '" + filter.get_vendor_id_filter().value + "')";
|
||||
} break;
|
||||
}
|
||||
return condition;
|
||||
}
|
||||
|
||||
std::optional<std::string>
|
||||
ErrorDatabaseSqlite::filters_to_sql_condition(const std::list<Everest::error::ErrorFilter>& filters) {
|
||||
std::optional<std::string> condition = std::nullopt;
|
||||
if (!filters.empty()) {
|
||||
auto it = filters.begin();
|
||||
condition = filter_to_sql_condition(*it);
|
||||
it++;
|
||||
while (it != filters.end()) {
|
||||
condition = condition.value() + " AND " + ErrorDatabaseSqlite::filter_to_sql_condition(*it);
|
||||
it++;
|
||||
}
|
||||
}
|
||||
return condition;
|
||||
}
|
||||
|
||||
std::list<Everest::error::ErrorPtr>
|
||||
ErrorDatabaseSqlite::get_errors(const std::list<Everest::error::ErrorFilter>& filters) const {
|
||||
std::lock_guard<std::mutex> lock(this->db_mutex);
|
||||
return this->get_errors(ErrorDatabaseSqlite::filters_to_sql_condition(filters));
|
||||
}
|
||||
|
||||
std::list<Everest::error::ErrorPtr> ErrorDatabaseSqlite::get_errors(const std::optional<std::string>& condition) const {
|
||||
BOOST_LOG_FUNCTION();
|
||||
std::list<Everest::error::ErrorPtr> result;
|
||||
try {
|
||||
everest::db::sqlite::Connection db(this->db_path);
|
||||
if (!db.open_connection()) {
|
||||
EVLOG_error << "Error opening database";
|
||||
throw everest::db::ConnectionException(db.get_error_message());
|
||||
}
|
||||
std::string sql = "SELECT * FROM errors";
|
||||
if (condition.has_value()) {
|
||||
sql += " WHERE " + condition.value();
|
||||
}
|
||||
EVLOG_debug << "Executing SQL statement: " << sql;
|
||||
auto stmt = db.new_statement(sql);
|
||||
int status;
|
||||
while ((status = stmt->step()) == SQLITE_ROW) {
|
||||
const Everest::error::ErrorType err_type(std::get<std::string>(stmt->column_variant("type")));
|
||||
const std::string err_description = std::get<std::string>(stmt->column_variant("description"));
|
||||
const std::string err_msg = std::get<std::string>(stmt->column_variant("message"));
|
||||
const std::string err_origin_module_id = std::get<std::string>(stmt->column_variant("origin_module"));
|
||||
const std::string err_origin_impl_id = std::get<std::string>(stmt->column_variant("origin_implementation"));
|
||||
const ImplementationIdentifier err_origin(err_origin_module_id, err_origin_impl_id);
|
||||
const Everest::error::Error::time_point err_timestamp =
|
||||
Everest::Date::from_rfc3339(std::get<std::string>(stmt->column_variant("timestamp")));
|
||||
const Everest::error::Severity err_severity =
|
||||
Everest::error::string_to_severity(std::get<std::string>(stmt->column_variant("severity")));
|
||||
const Everest::error::State err_state =
|
||||
Everest::error::string_to_state(std::get<std::string>(stmt->column_variant("state")));
|
||||
const Everest::error::ErrorHandle err_handle(
|
||||
Everest::error::ErrorHandle(std::get<std::string>(stmt->column_variant("uuid"))));
|
||||
const Everest::error::ErrorSubType err_sub_type(std::get<std::string>(stmt->column_variant("sub_type")));
|
||||
const std::string err_vendor_id = std::get<std::string>(stmt->column_variant("vendor_id"));
|
||||
Everest::error::ErrorPtr error = std::make_shared<Everest::error::Error>(
|
||||
err_type, err_sub_type, err_msg, err_description, err_origin, err_vendor_id, err_severity,
|
||||
err_timestamp, err_handle, err_state);
|
||||
result.push_back(error);
|
||||
}
|
||||
if (status != SQLITE_DONE) {
|
||||
throw everest::db::QueryExecutionException(db.get_error_message());
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
EVLOG_error << "Error getting errors from database: " << e.what();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::list<Everest::error::ErrorPtr>
|
||||
ErrorDatabaseSqlite::edit_errors(const std::list<Everest::error::ErrorFilter>& filters, EditErrorFunc edit_func) {
|
||||
std::lock_guard<std::mutex> lock(this->db_mutex);
|
||||
std::list<Everest::error::ErrorPtr> result = this->remove_errors_without_mutex(filters);
|
||||
for (Everest::error::ErrorPtr& error : result) {
|
||||
edit_func(error);
|
||||
this->add_error_without_mutex(error);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::list<Everest::error::ErrorPtr>
|
||||
ErrorDatabaseSqlite::remove_errors(const std::list<Everest::error::ErrorFilter>& filters) {
|
||||
std::lock_guard<std::mutex> lock(this->db_mutex);
|
||||
return this->remove_errors_without_mutex(filters);
|
||||
}
|
||||
|
||||
std::list<Everest::error::ErrorPtr>
|
||||
ErrorDatabaseSqlite::remove_errors_without_mutex(const std::list<Everest::error::ErrorFilter>& filters) {
|
||||
BOOST_LOG_FUNCTION();
|
||||
std::optional<std::string> condition = ErrorDatabaseSqlite::filters_to_sql_condition(filters);
|
||||
std::list<Everest::error::ErrorPtr> result = this->get_errors(condition);
|
||||
try {
|
||||
everest::db::sqlite::Connection db(this->db_path);
|
||||
if (!db.open_connection()) {
|
||||
EVLOG_error << "Error opening database";
|
||||
throw everest::db::ConnectionException(db.get_error_message());
|
||||
}
|
||||
std::string sql = "DELETE FROM errors";
|
||||
if (condition.has_value()) {
|
||||
sql += " WHERE " + condition.value();
|
||||
}
|
||||
db.execute_statement(sql);
|
||||
} catch (const std::exception& e) {
|
||||
EVLOG_error << "Error removing errors from database: " << e.what();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace module
|
||||
@@ -0,0 +1,43 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
|
||||
#ifndef ERROR_HISTORY_ERROR_DATABASE_SQLITE_HPP
|
||||
#define ERROR_HISTORY_ERROR_DATABASE_SQLITE_HPP
|
||||
|
||||
#include <utils/error/error_database.hpp>
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
namespace module {
|
||||
|
||||
class ErrorDatabaseSqlite : public Everest::error::ErrorDatabase {
|
||||
public:
|
||||
explicit ErrorDatabaseSqlite(const fs::path& db_path_, const bool reset_ = false);
|
||||
|
||||
std::list<Everest::error::ErrorPtr>
|
||||
get_errors(const std::list<Everest::error::ErrorFilter>& filters) const override;
|
||||
|
||||
void add_error(Everest::error::ErrorPtr error) override;
|
||||
std::list<Everest::error::ErrorPtr> edit_errors(const std::list<Everest::error::ErrorFilter>& filters,
|
||||
EditErrorFunc edit_func) override;
|
||||
std::list<Everest::error::ErrorPtr> remove_errors(const std::list<Everest::error::ErrorFilter>& filters) override;
|
||||
|
||||
private:
|
||||
void add_error_without_mutex(Everest::error::ErrorPtr error);
|
||||
std::list<Everest::error::ErrorPtr>
|
||||
remove_errors_without_mutex(const std::list<Everest::error::ErrorFilter>& filters);
|
||||
std::list<Everest::error::ErrorPtr> get_errors(const std::optional<std::string>& condition) const;
|
||||
static std::string filter_to_sql_condition(const Everest::error::ErrorFilter& filter);
|
||||
static std::optional<std::string> filters_to_sql_condition(const std::list<Everest::error::ErrorFilter>& filters);
|
||||
|
||||
void reset_database();
|
||||
void check_database();
|
||||
const fs::path db_path;
|
||||
mutable std::mutex db_mutex;
|
||||
};
|
||||
|
||||
} // namespace module
|
||||
|
||||
#endif // ERROR_HISTORY_ERROR_DATABASE_SQLITE_HPP
|
||||
@@ -0,0 +1,15 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#include "ErrorHistory.hpp"
|
||||
|
||||
namespace module {
|
||||
|
||||
void ErrorHistory::init() {
|
||||
invoke_init(*p_error_history);
|
||||
}
|
||||
|
||||
void ErrorHistory::ready() {
|
||||
invoke_ready(*p_error_history);
|
||||
}
|
||||
|
||||
} // namespace module
|
||||
@@ -0,0 +1,58 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#ifndef ERROR_HISTORY_HPP
|
||||
#define ERROR_HISTORY_HPP
|
||||
|
||||
//
|
||||
// AUTO GENERATED - MARKED REGIONS WILL BE KEPT
|
||||
// template version 2
|
||||
//
|
||||
|
||||
#include "ld-ev.hpp"
|
||||
|
||||
// headers for provided interface implementations
|
||||
#include <generated/interfaces/error_history/Implementation.hpp>
|
||||
|
||||
// ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1
|
||||
// insert your custom include headers here
|
||||
// ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1
|
||||
|
||||
namespace module {
|
||||
|
||||
struct Conf {};
|
||||
|
||||
class ErrorHistory : public Everest::ModuleBase {
|
||||
public:
|
||||
ErrorHistory() = delete;
|
||||
ErrorHistory(const ModuleInfo& info, std::unique_ptr<error_historyImplBase> p_error_history, Conf& config) :
|
||||
ModuleBase(info), p_error_history(std::move(p_error_history)), config(config){};
|
||||
|
||||
const std::unique_ptr<error_historyImplBase> p_error_history;
|
||||
const Conf& config;
|
||||
|
||||
// ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1
|
||||
// insert your public definitions here
|
||||
// ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1
|
||||
|
||||
protected:
|
||||
// ev@4714b2ab-a24f-4b95-ab81-36439e1478de:v1
|
||||
// insert your protected definitions here
|
||||
// ev@4714b2ab-a24f-4b95-ab81-36439e1478de:v1
|
||||
|
||||
private:
|
||||
friend class LdEverest;
|
||||
void init();
|
||||
void ready();
|
||||
|
||||
// ev@211cfdbe-f69a-4cd6-a4ec-f8aaa3d1b6c8:v1
|
||||
// insert your private definitions here
|
||||
// ev@211cfdbe-f69a-4cd6-a4ec-f8aaa3d1b6c8:v1
|
||||
};
|
||||
|
||||
// ev@087e516b-124c-48df-94fb-109508c7cda9:v1
|
||||
// insert other definitions here
|
||||
// ev@087e516b-124c-48df-94fb-109508c7cda9:v1
|
||||
|
||||
} // namespace module
|
||||
|
||||
#endif // ERROR_HISTORY_HPP
|
||||
@@ -0,0 +1,127 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
|
||||
#include "error_historyImpl.hpp"
|
||||
|
||||
#include "../ErrorDatabaseSqlite.hpp"
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
namespace module {
|
||||
namespace error_history {
|
||||
|
||||
void error_historyImpl::init() {
|
||||
this->db = std::make_shared<ErrorDatabaseSqlite>(this->config.database_path);
|
||||
|
||||
Everest::error::StateFilter state_filter(Everest::error::State::Active);
|
||||
Everest::error::ErrorFilter error_filter(state_filter);
|
||||
this->db->edit_errors(
|
||||
{error_filter}, [](Everest::error::ErrorPtr error) { error->state = Everest::error::State::ClearedByReboot; });
|
||||
subscribe_global_all_errors(
|
||||
[this](const Everest::error::Error& error) { this->handle_global_all_errors(error); },
|
||||
[this](const Everest::error::Error& error) { this->handle_global_all_errors_cleared(error); });
|
||||
}
|
||||
|
||||
void error_historyImpl::ready() {
|
||||
}
|
||||
|
||||
Everest::error::StateFilter convert_state_filter(types::error_history::State filter) {
|
||||
switch (filter) {
|
||||
case types::error_history::State::Active:
|
||||
return Everest::error::StateFilter::Active;
|
||||
case types::error_history::State::ClearedByModule:
|
||||
return Everest::error::StateFilter::ClearedByModule;
|
||||
case types::error_history::State::ClearedByReboot:
|
||||
return Everest::error::StateFilter::ClearedByReboot;
|
||||
}
|
||||
throw std::out_of_range("No known enum conversion from enum type types::error_history::State to enum type "
|
||||
"Everest::error::StateFilter");
|
||||
}
|
||||
|
||||
Everest::error::SeverityFilter convert_severity_filter(types::error_history::SeverityFilter filter) {
|
||||
switch (filter) {
|
||||
case types::error_history::SeverityFilter::LOW_GE:
|
||||
return Everest::error::SeverityFilter::LOW_GE;
|
||||
case types::error_history::SeverityFilter::MEDIUM_GE:
|
||||
return Everest::error::SeverityFilter::MEDIUM_GE;
|
||||
case types::error_history::SeverityFilter::HIGH_GE:
|
||||
return Everest::error::SeverityFilter::HIGH_GE;
|
||||
}
|
||||
throw std::out_of_range("No known enum conversion from enum type types::error_history::SeverityFilter to enum type "
|
||||
"Everest::error::SeverityFilter");
|
||||
}
|
||||
|
||||
std::vector<types::error_history::ErrorObject>
|
||||
error_historyImpl::handle_get_errors(types::error_history::FilterArguments& filters) {
|
||||
std::list<Everest::error::ErrorFilter> error_filters;
|
||||
if (filters.state_filter.has_value()) {
|
||||
Everest::error::StateFilter state_filter = convert_state_filter(filters.state_filter.value());
|
||||
error_filters.push_back(Everest::error::ErrorFilter(state_filter));
|
||||
}
|
||||
if (filters.origin_filter.has_value()) {
|
||||
Everest::error::OriginFilter origin_filter(filters.origin_filter.value().module_id,
|
||||
filters.origin_filter.value().implementation_id);
|
||||
error_filters.push_back(Everest::error::ErrorFilter(origin_filter));
|
||||
}
|
||||
if (filters.type_filter.has_value()) {
|
||||
Everest::error::TypeFilter type_filter(filters.type_filter.value());
|
||||
error_filters.push_back(Everest::error::ErrorFilter(type_filter));
|
||||
}
|
||||
if (filters.severity_filter.has_value()) {
|
||||
Everest::error::SeverityFilter severity_filter = convert_severity_filter(filters.severity_filter.value());
|
||||
error_filters.push_back(Everest::error::ErrorFilter(severity_filter));
|
||||
}
|
||||
if (filters.timeperiod_filter.has_value()) {
|
||||
Everest::error::TimePeriodFilter timeperiod_filter;
|
||||
timeperiod_filter.from = Everest::Date::from_rfc3339(filters.timeperiod_filter.value().timestamp_from);
|
||||
timeperiod_filter.to = Everest::Date::from_rfc3339(filters.timeperiod_filter.value().timestamp_to);
|
||||
error_filters.push_back(Everest::error::ErrorFilter(timeperiod_filter));
|
||||
}
|
||||
if (filters.handle_filter.has_value()) {
|
||||
Everest::error::HandleFilter handle_filter(filters.handle_filter.value());
|
||||
error_filters.push_back(Everest::error::ErrorFilter(handle_filter));
|
||||
}
|
||||
std::list<Everest::error::ErrorPtr> errors = this->db->get_errors(error_filters);
|
||||
std::vector<types::error_history::ErrorObject> result;
|
||||
std::transform(errors.begin(), errors.end(), std::back_inserter(result), [](Everest::error::ErrorPtr error) {
|
||||
types::error_history::ErrorObject error_object;
|
||||
error_object.uuid = error->uuid.to_string();
|
||||
error_object.timestamp = Everest::Date::to_rfc3339(error->timestamp);
|
||||
std::string string_state = Everest::error::state_to_string(error->state);
|
||||
error_object.state = types::error_history::string_to_state(string_state);
|
||||
std::string string_severity = Everest::error::severity_to_string(error->severity);
|
||||
error_object.severity = types::error_history::string_to_severity(string_severity);
|
||||
error_object.type = error->type;
|
||||
error_object.sub_type = error->sub_type;
|
||||
error_object.origin.module_id = error->origin.module_id;
|
||||
error_object.origin.implementation_id = error->origin.implementation_id;
|
||||
error_object.message = error->message;
|
||||
error_object.description = error->description;
|
||||
return error_object;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
void error_historyImpl::handle_global_all_errors(const Everest::error::Error& error) {
|
||||
Everest::error::ErrorPtr error_ptr = std::make_shared<Everest::error::Error>(error);
|
||||
this->db->add_error(error_ptr);
|
||||
}
|
||||
|
||||
void error_historyImpl::handle_global_all_errors_cleared(const Everest::error::Error& error) {
|
||||
Everest::error::HandleFilter handle_filter(error.uuid);
|
||||
Everest::error::ErrorFilter error_filter(handle_filter);
|
||||
int edited_errors =
|
||||
this->db
|
||||
->edit_errors({error_filter},
|
||||
[](Everest::error::ErrorPtr error) { error->state = Everest::error::State::ClearedByModule; })
|
||||
.size();
|
||||
if (edited_errors == 0) {
|
||||
EVLOG_error << "ErrorHistory: Error with uuid " << error.uuid.to_string() << " not found in database.";
|
||||
} else if (edited_errors > 1) {
|
||||
EVLOG_error << "ErrorHistory: Multiple errors with uuid " << error.uuid.to_string() << " found in database.";
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace error_history
|
||||
} // namespace module
|
||||
@@ -0,0 +1,68 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#ifndef ERROR_HISTORY_ERROR_HISTORY_IMPL_HPP
|
||||
#define ERROR_HISTORY_ERROR_HISTORY_IMPL_HPP
|
||||
|
||||
//
|
||||
// AUTO GENERATED - MARKED REGIONS WILL BE KEPT
|
||||
// template version 3
|
||||
//
|
||||
|
||||
#include <generated/interfaces/error_history/Implementation.hpp>
|
||||
|
||||
#include "../ErrorHistory.hpp"
|
||||
|
||||
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
|
||||
#include "../ErrorDatabaseSqlite.hpp"
|
||||
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
|
||||
|
||||
namespace module {
|
||||
namespace error_history {
|
||||
|
||||
struct Conf {
|
||||
std::string database_path;
|
||||
};
|
||||
|
||||
class error_historyImpl : public error_historyImplBase {
|
||||
public:
|
||||
error_historyImpl() = delete;
|
||||
error_historyImpl(Everest::ModuleAdapter* ev, const Everest::PtrContainer<ErrorHistory>& mod, Conf& config) :
|
||||
error_historyImplBase(ev, "error_history"), mod(mod), config(config){};
|
||||
|
||||
// ev@8ea32d28-373f-4c90-ae5e-b4fcc74e2a61:v1
|
||||
friend class ErrorDatabaseSqlite; // for write access to db
|
||||
// ev@8ea32d28-373f-4c90-ae5e-b4fcc74e2a61:v1
|
||||
|
||||
protected:
|
||||
// command handler functions (virtual)
|
||||
virtual std::vector<types::error_history::ErrorObject>
|
||||
handle_get_errors(types::error_history::FilterArguments& filters) override;
|
||||
|
||||
// ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1
|
||||
// insert your protected definitions here
|
||||
// ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1
|
||||
|
||||
private:
|
||||
const Everest::PtrContainer<ErrorHistory>& mod;
|
||||
const Conf& config;
|
||||
|
||||
virtual void init() override;
|
||||
virtual void ready() override;
|
||||
|
||||
// ev@3370e4dd-95f4-47a9-aaec-ea76f34a66c9:v1
|
||||
// insert your private definitions here
|
||||
void handle_global_all_errors(const Everest::error::Error& error);
|
||||
void handle_global_all_errors_cleared(const Everest::error::Error& error);
|
||||
|
||||
std::shared_ptr<ErrorDatabaseSqlite> db;
|
||||
// ev@3370e4dd-95f4-47a9-aaec-ea76f34a66c9:v1
|
||||
};
|
||||
|
||||
// ev@3d7da0ad-02c2-493d-9920-0bbbd56b9876:v1
|
||||
// insert other definitions here
|
||||
// ev@3d7da0ad-02c2-493d-9920-0bbbd56b9876:v1
|
||||
|
||||
} // namespace error_history
|
||||
} // namespace module
|
||||
|
||||
#endif // ERROR_HISTORY_ERROR_HISTORY_IMPL_HPP
|
||||
14
tools/EVerest-main/modules/Misc/ErrorHistory/manifest.yaml
Normal file
14
tools/EVerest-main/modules/Misc/ErrorHistory/manifest.yaml
Normal file
@@ -0,0 +1,14 @@
|
||||
description: This module provides a persistent error history
|
||||
provides:
|
||||
error_history:
|
||||
description: Error history
|
||||
interface: error_history
|
||||
config:
|
||||
database_path:
|
||||
type: string
|
||||
description: Absolute path to the database file
|
||||
enable_global_errors: true
|
||||
metadata:
|
||||
license: https://opensource.org/licenses/Apache-2.0
|
||||
authors:
|
||||
- Andreas Heinrich
|
||||
@@ -0,0 +1,30 @@
|
||||
set(TARGET_NAME ${PROJECT_NAME}_module_error_history_tests)
|
||||
add_executable(${TARGET_NAME})
|
||||
|
||||
target_sources(${TARGET_NAME}
|
||||
PRIVATE
|
||||
error_database_sqlite_tests.cpp
|
||||
../ErrorDatabaseSqlite.cpp
|
||||
helpers.cpp
|
||||
)
|
||||
|
||||
# target_include_directories(module_error_history_tests
|
||||
# PRIVATE
|
||||
# )
|
||||
|
||||
target_link_libraries(${TARGET_NAME}
|
||||
PRIVATE
|
||||
everest::framework
|
||||
everest::log
|
||||
everest::sqlite
|
||||
SQLite::SQLite3
|
||||
Catch2::Catch2WithMain
|
||||
)
|
||||
if(NOT DISABLE_EDM)
|
||||
list(APPEND CMAKE_MODULE_PATH ${CPM_PACKAGE_catch2_SOURCE_DIR}/extras)
|
||||
include(Catch)
|
||||
catch_discover_tests(${TARGET_NAME})
|
||||
endif()
|
||||
|
||||
add_test(${TARGET_NAME} ${TARGET_NAME})
|
||||
ev_register_test_target(${TARGET_NAME})
|
||||
@@ -0,0 +1,288 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#include "../ErrorDatabaseSqlite.hpp"
|
||||
#include "helpers.hpp"
|
||||
|
||||
SCENARIO("Check ErrorDatabaseSqlite class", "[!throws]") {
|
||||
GIVEN("An ErrorDatabaseSqlite object") {
|
||||
const std::string bin_dir = get_bin_dir().string() + "/";
|
||||
const std::string db_name = get_unique_db_name();
|
||||
TestDatabase db(bin_dir + "/databases/" + db_name, true);
|
||||
WHEN("Getting all errors") {
|
||||
THEN("The database should be empty") {
|
||||
auto errors = db.get_errors(std::list<Everest::error::ErrorFilter>());
|
||||
REQUIRE(errors.empty());
|
||||
}
|
||||
}
|
||||
WHEN("Adding an error") {
|
||||
std::vector<Everest::error::ErrorPtr> test_errors = {std::make_shared<Everest::error::Error>(
|
||||
"test_type", "test_sub_type", "test_message", "test_description",
|
||||
ImplementationIdentifier("test_origin_module", "test_origin_implementation"), "everest-test",
|
||||
Everest::error::Severity::Low, date::utc_clock::now(), Everest::error::UUID(),
|
||||
Everest::error::State::Active)};
|
||||
db.add_error(test_errors.at(0));
|
||||
THEN("The error should be in the database") {
|
||||
check_expected_errors_in_list(test_errors, db.get_errors(std::list<Everest::error::ErrorFilter>()));
|
||||
}
|
||||
}
|
||||
WHEN("Adding multiple errors") {
|
||||
std::vector<Everest::error::ErrorPtr> test_errors = {
|
||||
std::make_shared<Everest::error::Error>(
|
||||
"test_type_a", "test_sub_type_a", "test_message_a", "test_description_a",
|
||||
ImplementationIdentifier("test_origin_module_a", "test_origin_implementation_a"), "everest-test",
|
||||
Everest::error::Severity::High, date::utc_clock::now(), Everest::error::UUID(),
|
||||
Everest::error::State::ClearedByModule),
|
||||
std::make_shared<Everest::error::Error>(
|
||||
"test_type_b", "test_sub_type_b", "test_message_b", "test_description_b",
|
||||
ImplementationIdentifier("test_origin_module_b", "test_origin_implementation_b"), "everest-test",
|
||||
Everest::error::Severity::Medium, date::utc_clock::now(), Everest::error::UUID(),
|
||||
Everest::error::State::ClearedByReboot)};
|
||||
for (Everest::error::ErrorPtr error : test_errors) {
|
||||
db.add_error(error);
|
||||
}
|
||||
THEN("The errors should be in the database") {
|
||||
auto errors = db.get_errors(std::list<Everest::error::ErrorFilter>());
|
||||
check_expected_errors_in_list(test_errors, errors);
|
||||
}
|
||||
}
|
||||
}
|
||||
GIVEN("12 Errors in a connected ErrorDatabaseSqlite object") {
|
||||
const std::string bin_dir = get_bin_dir().string() + "/";
|
||||
const std::string db_name = get_unique_db_name();
|
||||
TestDatabase db(bin_dir + "/databases/" + db_name, true);
|
||||
std::vector<Everest::error::ErrorPtr> test_errors = get_test_errors();
|
||||
for (Everest::error::ErrorPtr error : test_errors) {
|
||||
db.add_error(error);
|
||||
}
|
||||
WHEN("Getting all errors") {
|
||||
auto errors = db.get_errors(std::list<Everest::error::ErrorFilter>());
|
||||
THEN("The result should contain all 12 errors") {
|
||||
check_expected_errors_in_list(test_errors, errors);
|
||||
}
|
||||
}
|
||||
WHEN("Getting all errors with StateFilter") {
|
||||
auto errors = db.get_errors({Everest::error::ErrorFilter(Everest::error::StateFilter::Active)});
|
||||
THEN("The result should contain specific errors") {
|
||||
std::vector<Everest::error::ErrorPtr> expected_errors({test_errors[3], test_errors[4], test_errors[5]});
|
||||
check_expected_errors_in_list(expected_errors, errors);
|
||||
}
|
||||
}
|
||||
WHEN("Getting all errors with OriginFilter") {
|
||||
auto errors = db.get_errors({Everest::error::ErrorFilter(
|
||||
Everest::error::OriginFilter("test_origin_module_a", "test_origin_implementation_a"))});
|
||||
THEN("The result should contain specific errors") {
|
||||
std::vector<Everest::error::ErrorPtr> expected_errors(
|
||||
{test_errors[0], test_errors[2], test_errors[4], test_errors[6], test_errors[8], test_errors[10]});
|
||||
check_expected_errors_in_list(expected_errors, errors);
|
||||
}
|
||||
}
|
||||
WHEN("Getting all errors with TypeFilter") {
|
||||
auto errors = db.get_errors({Everest::error::ErrorFilter(Everest::error::TypeFilter("test_type_c"))});
|
||||
THEN("The result should contain specific errors") {
|
||||
std::vector<Everest::error::ErrorPtr> expected_errors(
|
||||
{test_errors[2], test_errors[3], test_errors[4], test_errors[5], test_errors[9], test_errors[10]});
|
||||
check_expected_errors_in_list(expected_errors, errors);
|
||||
}
|
||||
}
|
||||
WHEN("Getting all errors with SeverityFilter") {
|
||||
auto errors = db.get_errors({Everest::error::ErrorFilter(Everest::error::SeverityFilter::MEDIUM_GE)});
|
||||
THEN("The result should contain specific errors") {
|
||||
std::vector<Everest::error::ErrorPtr> expected_errors({test_errors[4], test_errors[5], test_errors[6],
|
||||
test_errors[7], test_errors[8], test_errors[9],
|
||||
test_errors[10], test_errors[11]});
|
||||
check_expected_errors_in_list(expected_errors, errors);
|
||||
}
|
||||
}
|
||||
WHEN("Getting all errors with TimePeriodFilter") {
|
||||
auto errors = db.get_errors({Everest::error::ErrorFilter(
|
||||
Everest::error::TimePeriodFilter{date::utc_clock::now() + std::chrono::minutes(150),
|
||||
date::utc_clock::now() + std::chrono::minutes(270)})});
|
||||
THEN("The result should contain specific errors") {
|
||||
std::vector<Everest::error::ErrorPtr> expected_errors({test_errors[3], test_errors[4]});
|
||||
check_expected_errors_in_list(expected_errors, errors);
|
||||
}
|
||||
}
|
||||
WHEN("Getting all errors with HandleFilter") {
|
||||
auto errors =
|
||||
db.get_errors({Everest::error::ErrorFilter(Everest::error::HandleFilter(test_errors[4]->uuid))});
|
||||
THEN("The result should contain specific errors") {
|
||||
std::vector<Everest::error::ErrorPtr> expected_errors({test_errors[4]});
|
||||
check_expected_errors_in_list(expected_errors, errors);
|
||||
}
|
||||
}
|
||||
WHEN("Getting all errors with multiple filters") {
|
||||
auto errors = db.get_errors({Everest::error::ErrorFilter(Everest::error::StateFilter::Active),
|
||||
Everest::error::ErrorFilter(Everest::error::OriginFilter(
|
||||
"test_origin_module_a", "test_origin_implementation_a"))});
|
||||
THEN("The result should contain specific errors") {
|
||||
std::vector<Everest::error::ErrorPtr> expected_errors({test_errors[4]});
|
||||
check_expected_errors_in_list(expected_errors, errors);
|
||||
}
|
||||
}
|
||||
WHEN("Filtering all errors out") {
|
||||
auto errors = db.get_errors({
|
||||
Everest::error::ErrorFilter(Everest::error::StateFilter::ClearedByModule),
|
||||
Everest::error::ErrorFilter(
|
||||
Everest::error::OriginFilter("test_origin_module_a", "test_origin_implementation_a")),
|
||||
Everest::error::ErrorFilter(Everest::error::TypeFilter("test_type_c")),
|
||||
Everest::error::ErrorFilter(Everest::error::SeverityFilter::HIGH_GE),
|
||||
});
|
||||
THEN("The result should contain no errors") {
|
||||
REQUIRE(errors.empty());
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("Edit error type") {
|
||||
std::list<Everest::error::ErrorFilter> filters = {
|
||||
Everest::error::ErrorFilter(Everest::error::HandleFilter(test_errors[4]->uuid))};
|
||||
Everest::error::ErrorDatabase::EditErrorFunc edit_func = [](Everest::error::ErrorPtr error) {
|
||||
error->type = "new_type";
|
||||
};
|
||||
REQUIRE(db.get_errors(filters).size() > 0);
|
||||
db.edit_errors(filters, edit_func);
|
||||
THEN("The error should be edited") {
|
||||
auto errors = db.get_errors(filters);
|
||||
REQUIRE(errors.size() == 1);
|
||||
REQUIRE(errors.front()->type == "new_type");
|
||||
}
|
||||
}
|
||||
WHEN("Edit error state") {
|
||||
std::list<Everest::error::ErrorFilter> filters = {
|
||||
Everest::error::ErrorFilter(Everest::error::HandleFilter(test_errors[4]->uuid))};
|
||||
Everest::error::ErrorDatabase::EditErrorFunc edit_func = [](Everest::error::ErrorPtr error) {
|
||||
error->state = Everest::error::State::ClearedByModule;
|
||||
};
|
||||
REQUIRE(db.get_errors(filters).size() > 0);
|
||||
db.edit_errors(filters, edit_func);
|
||||
THEN("The error should be edited") {
|
||||
auto errors = db.get_errors(filters);
|
||||
REQUIRE(errors.size() == 1);
|
||||
REQUIRE(errors.front()->state == Everest::error::State::ClearedByModule);
|
||||
}
|
||||
}
|
||||
WHEN("Edit error severity") {
|
||||
std::list<Everest::error::ErrorFilter> filters = {
|
||||
Everest::error::ErrorFilter(Everest::error::HandleFilter(test_errors[4]->uuid))};
|
||||
Everest::error::ErrorDatabase::EditErrorFunc edit_func = [](Everest::error::ErrorPtr error) {
|
||||
error->severity = Everest::error::Severity::High;
|
||||
};
|
||||
REQUIRE(db.get_errors(filters).size() > 0);
|
||||
db.edit_errors(filters, edit_func);
|
||||
THEN("The error should be edited") {
|
||||
auto errors = db.get_errors(filters);
|
||||
REQUIRE(errors.size() == 1);
|
||||
REQUIRE(errors.front()->severity == Everest::error::Severity::High);
|
||||
}
|
||||
}
|
||||
WHEN("Edit error message") {
|
||||
std::list<Everest::error::ErrorFilter> filters = {
|
||||
Everest::error::ErrorFilter(Everest::error::HandleFilter(test_errors[4]->uuid))};
|
||||
Everest::error::ErrorDatabase::EditErrorFunc edit_func = [](Everest::error::ErrorPtr error) {
|
||||
error->message = "new_message";
|
||||
};
|
||||
REQUIRE(db.get_errors(filters).size() > 0);
|
||||
db.edit_errors(filters, edit_func);
|
||||
THEN("The error should be edited") {
|
||||
auto errors = db.get_errors(filters);
|
||||
REQUIRE(errors.size() == 1);
|
||||
REQUIRE(errors.front()->message == "new_message");
|
||||
}
|
||||
}
|
||||
WHEN("Edit error description") {
|
||||
std::list<Everest::error::ErrorFilter> filters = {
|
||||
Everest::error::ErrorFilter(Everest::error::HandleFilter(test_errors[4]->uuid))};
|
||||
Everest::error::ErrorDatabase::EditErrorFunc edit_func = [](Everest::error::ErrorPtr error) {
|
||||
error->description = "new_description";
|
||||
};
|
||||
REQUIRE(db.get_errors(filters).size() > 0);
|
||||
db.edit_errors(filters, edit_func);
|
||||
THEN("The error should be edited") {
|
||||
auto errors = db.get_errors(filters);
|
||||
REQUIRE(errors.size() == 1);
|
||||
REQUIRE(errors.front()->description == "new_description");
|
||||
}
|
||||
}
|
||||
WHEN("Edit error origin") {
|
||||
std::list<Everest::error::ErrorFilter> filters = {
|
||||
Everest::error::ErrorFilter(Everest::error::HandleFilter(test_errors[4]->uuid))};
|
||||
Everest::error::ErrorDatabase::EditErrorFunc edit_func = [](Everest::error::ErrorPtr error) {
|
||||
error->origin = ImplementationIdentifier("new_origin_module", "new_origin_implementation");
|
||||
};
|
||||
REQUIRE(db.get_errors(filters).size() > 0);
|
||||
db.edit_errors(filters, edit_func);
|
||||
THEN("The error should be edited") {
|
||||
auto errors = db.get_errors(filters);
|
||||
REQUIRE(errors.size() == 1);
|
||||
REQUIRE(errors.front()->origin ==
|
||||
ImplementationIdentifier("new_origin_module", "new_origin_implementation"));
|
||||
}
|
||||
}
|
||||
WHEN("Edit error timestamp") {
|
||||
std::list<Everest::error::ErrorFilter> filters = {
|
||||
Everest::error::ErrorFilter(Everest::error::HandleFilter(test_errors[4]->uuid))};
|
||||
auto new_timestamp = date::utc_clock::now() + std::chrono::hours(10);
|
||||
Everest::error::ErrorDatabase::EditErrorFunc edit_func = [&new_timestamp](Everest::error::ErrorPtr error) {
|
||||
error->timestamp = new_timestamp;
|
||||
};
|
||||
REQUIRE(db.get_errors(filters).size() > 0);
|
||||
db.edit_errors(filters, edit_func);
|
||||
THEN("The error should be edited") {
|
||||
auto errors = db.get_errors(filters);
|
||||
REQUIRE(errors.size() == 1);
|
||||
REQUIRE(Everest::Date::to_rfc3339(errors.front()->timestamp) ==
|
||||
Everest::Date::to_rfc3339(new_timestamp));
|
||||
}
|
||||
}
|
||||
WHEN("Edit error uuid") {
|
||||
Everest::error::UUID new_uuid;
|
||||
std::list<Everest::error::ErrorFilter> filters = {
|
||||
Everest::error::ErrorFilter(Everest::error::HandleFilter(test_errors[4]->uuid))};
|
||||
Everest::error::ErrorDatabase::EditErrorFunc edit_func = [&new_uuid](Everest::error::ErrorPtr error) {
|
||||
error->uuid = new_uuid;
|
||||
};
|
||||
REQUIRE(db.get_errors(filters).size() > 0);
|
||||
db.edit_errors(filters, edit_func);
|
||||
THEN("The error should be edited") {
|
||||
auto errors = db.get_errors(filters);
|
||||
REQUIRE(errors.size() == 0);
|
||||
errors = db.get_errors({Everest::error::ErrorFilter(Everest::error::HandleFilter(new_uuid))});
|
||||
REQUIRE(errors.size() == 1);
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("Remove error") {
|
||||
std::list<Everest::error::ErrorFilter> filters = {
|
||||
Everest::error::ErrorFilter(Everest::error::HandleFilter(test_errors[4]->uuid))};
|
||||
REQUIRE(db.get_errors(filters).size() > 0);
|
||||
db.remove_errors(filters);
|
||||
THEN("The error should be removed") {
|
||||
auto errors = db.get_errors(filters);
|
||||
REQUIRE(errors.size() == 0);
|
||||
}
|
||||
}
|
||||
WHEN("Remove multiple errors") {
|
||||
std::list<Everest::error::ErrorFilter> filters = {
|
||||
Everest::error::ErrorFilter(Everest::error::StateFilter::Active),
|
||||
Everest::error::ErrorFilter(
|
||||
Everest::error::OriginFilter("test_origin_module_c", "test_origin_implementation_c"))};
|
||||
REQUIRE(db.get_errors(filters).size() > 0);
|
||||
db.remove_errors(filters);
|
||||
THEN("The errors should be removed") {
|
||||
auto errors = db.get_errors(filters);
|
||||
REQUIRE(errors.size() == 0);
|
||||
}
|
||||
}
|
||||
WHEN("Remove all errors") {
|
||||
std::list<Everest::error::ErrorFilter> filters = {};
|
||||
REQUIRE(db.get_errors(filters).size() > 0);
|
||||
db.remove_errors(filters);
|
||||
THEN("The errors should be removed") {
|
||||
auto errors = db.get_errors(filters);
|
||||
REQUIRE(errors.size() == 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
134
tools/EVerest-main/modules/Misc/ErrorHistory/tests/helpers.cpp
Normal file
134
tools/EVerest-main/modules/Misc/ErrorHistory/tests/helpers.cpp
Normal file
@@ -0,0 +1,134 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
|
||||
#include "helpers.hpp"
|
||||
|
||||
#include <catch2/catch_all.hpp>
|
||||
#include <utils/error.hpp>
|
||||
|
||||
fs::path get_bin_dir() {
|
||||
return fs::canonical("/proc/self/exe").parent_path();
|
||||
}
|
||||
|
||||
std::string get_unique_db_name() {
|
||||
return "error_database_sqlite_" + Everest::error::UUID().to_string() + ".db";
|
||||
}
|
||||
|
||||
std::vector<Everest::error::ErrorPtr> get_test_errors() {
|
||||
return {// index 0
|
||||
std::make_shared<Everest::error::Error>(
|
||||
"test_type_a", "test_sub_type_a", "test_message_a", "test_description_a",
|
||||
ImplementationIdentifier("test_origin_module_a", "test_origin_implementation_a"), "everest-test",
|
||||
Everest::error::Severity::Low, date::utc_clock::now(), Everest::error::UUID(),
|
||||
Everest::error::State::ClearedByModule),
|
||||
// index 1
|
||||
std::make_shared<Everest::error::Error>(
|
||||
"test_type_b", "test_sub_type_b", "test_message_b", "test_description_b",
|
||||
ImplementationIdentifier("test_origin_module_b", "test_origin_implementation_b"), "everest-test",
|
||||
Everest::error::Severity::Low, date::utc_clock::now() + std::chrono::hours(1), Everest::error::UUID(),
|
||||
Everest::error::State::ClearedByModule),
|
||||
// index 2
|
||||
std::make_shared<Everest::error::Error>(
|
||||
"test_type_c", "test_sub_type_c", "test_message_c", "test_description_c",
|
||||
ImplementationIdentifier("test_origin_module_a", "test_origin_implementation_a"), "everest-test",
|
||||
Everest::error::Severity::Low, date::utc_clock::now() + std::chrono::hours(2), Everest::error::UUID(),
|
||||
Everest::error::State::ClearedByModule),
|
||||
// index 3
|
||||
std::make_shared<Everest::error::Error>(
|
||||
"test_type_c", "test_sub_type_c", "test_message_c", "test_description_c",
|
||||
ImplementationIdentifier("test_origin_module_c", "test_origin_implementation_c"), "everest-test",
|
||||
Everest::error::Severity::Low, date::utc_clock::now() + std::chrono::hours(3), Everest::error::UUID(),
|
||||
Everest::error::State::Active),
|
||||
// index 4
|
||||
std::make_shared<Everest::error::Error>(
|
||||
"test_type_c", "test_sub_type_a", "test_message_c", "test_description_c",
|
||||
ImplementationIdentifier("test_origin_module_a", "test_origin_implementation_a"), "everest-test",
|
||||
Everest::error::Severity::Medium, date::utc_clock::now() + std::chrono::hours(4),
|
||||
Everest::error::UUID(), Everest::error::State::Active),
|
||||
// index 5
|
||||
std::make_shared<Everest::error::Error>(
|
||||
"test_type_c", "test_sub_type_a", "test_message_c", "test_description_c",
|
||||
ImplementationIdentifier("test_origin_module_c", "test_origin_implementation_c"), "everest-test",
|
||||
Everest::error::Severity::Medium, date::utc_clock::now() + std::chrono::hours(5),
|
||||
Everest::error::UUID(), Everest::error::State::Active),
|
||||
// index 6
|
||||
std::make_shared<Everest::error::Error>(
|
||||
"test_type_a", "test_sub_type_a", "test_message_a", "test_description_a",
|
||||
ImplementationIdentifier("test_origin_module_a", "test_origin_implementation_a"), "everest-test",
|
||||
Everest::error::Severity::Medium, date::utc_clock::now() + std::chrono::hours(6),
|
||||
Everest::error::UUID(), Everest::error::State::ClearedByReboot),
|
||||
// index 7
|
||||
std::make_shared<Everest::error::Error>(
|
||||
"test_type_a", "test_sub_type_a", "test_message_a", "test_description_a",
|
||||
ImplementationIdentifier("test_origin_module_c", "test_origin_implementation_c"), "everest-test",
|
||||
Everest::error::Severity::Medium, date::utc_clock::now() + std::chrono::hours(7),
|
||||
Everest::error::UUID(), Everest::error::State::ClearedByReboot),
|
||||
// index 8
|
||||
std::make_shared<Everest::error::Error>(
|
||||
"test_type_a", "test_sub_type_a", "test_message_a", "test_description_a",
|
||||
ImplementationIdentifier("test_origin_module_a", "test_origin_implementation_a"), "everest-test",
|
||||
Everest::error::Severity::High, date::utc_clock::now() + std::chrono::hours(8), Everest::error::UUID(),
|
||||
Everest::error::State::ClearedByReboot),
|
||||
// index 9
|
||||
std::make_shared<Everest::error::Error>(
|
||||
"test_type_c", "test_sub_type_c", "test_message_c", "test_description_c",
|
||||
ImplementationIdentifier("test_origin_module_c", "test_origin_implementation_c"), "everest-test",
|
||||
Everest::error::Severity::High, date::utc_clock::now() + std::chrono::hours(9), Everest::error::UUID(),
|
||||
Everest::error::State::ClearedByReboot),
|
||||
// index 10
|
||||
std::make_shared<Everest::error::Error>(
|
||||
"test_type_c", "test_sub_type_c", "test_message_c", "test_description_c",
|
||||
ImplementationIdentifier("test_origin_module_a", "test_origin_implementation_a"), "everest-test",
|
||||
Everest::error::Severity::High, date::utc_clock::now() + std::chrono::hours(10), Everest::error::UUID(),
|
||||
Everest::error::State::ClearedByReboot),
|
||||
// index 11
|
||||
std::make_shared<Everest::error::Error>(
|
||||
"test_type_b", "test_sub_type_b", "test_message_b", "test_description_b",
|
||||
ImplementationIdentifier("test_origin_module_c", "test_origin_implementation_c"), "everest-test",
|
||||
Everest::error::Severity::High, date::utc_clock::now() + std::chrono::hours(11), Everest::error::UUID(),
|
||||
Everest::error::State::ClearedByReboot)};
|
||||
}
|
||||
|
||||
void check_expected_errors_in_list(const std::vector<Everest::error::ErrorPtr>& expected_errors,
|
||||
const std::list<Everest::error::ErrorPtr>& errors) {
|
||||
REQUIRE(expected_errors.size() == errors.size());
|
||||
for (Everest::error::ErrorPtr exp_err : expected_errors) {
|
||||
auto result = std::find_if(errors.begin(), errors.end(), [&exp_err](const Everest::error::ErrorPtr& err) {
|
||||
return exp_err->uuid == err->uuid;
|
||||
});
|
||||
REQUIRE(result != errors.end());
|
||||
REQUIRE((*result)->type == exp_err->type);
|
||||
REQUIRE((*result)->message == exp_err->message);
|
||||
REQUIRE((*result)->description == exp_err->description);
|
||||
REQUIRE((*result)->origin == exp_err->origin);
|
||||
REQUIRE((*result)->severity == exp_err->severity);
|
||||
REQUIRE(Everest::Date::to_rfc3339((*result)->timestamp) == Everest::Date::to_rfc3339(exp_err->timestamp));
|
||||
REQUIRE((*result)->state == exp_err->state);
|
||||
}
|
||||
}
|
||||
|
||||
TestDatabase::TestDatabase(const fs::path& db_path_, const bool reset_) :
|
||||
db_path(db_path_), db(std::make_unique<module::ErrorDatabaseSqlite>(db_path_, reset_)) {
|
||||
}
|
||||
|
||||
TestDatabase::~TestDatabase() {
|
||||
fs::remove(db_path);
|
||||
}
|
||||
|
||||
void TestDatabase::add_error(Everest::error::ErrorPtr error) {
|
||||
db->add_error(error);
|
||||
}
|
||||
|
||||
std::list<Everest::error::ErrorPtr>
|
||||
TestDatabase::get_errors(const std::list<Everest::error::ErrorFilter>& filters) const {
|
||||
return db->get_errors(filters);
|
||||
}
|
||||
|
||||
std::list<Everest::error::ErrorPtr> TestDatabase::edit_errors(const std::list<Everest::error::ErrorFilter>& filters,
|
||||
Everest::error::ErrorDatabase::EditErrorFunc edit_func) {
|
||||
return db->edit_errors(filters, edit_func);
|
||||
}
|
||||
|
||||
std::list<Everest::error::ErrorPtr> TestDatabase::remove_errors(const std::list<Everest::error::ErrorFilter>& filters) {
|
||||
return db->remove_errors(filters);
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#ifndef ERROR_HISTORY_TESTS_HELPERS_HPP
|
||||
#define ERROR_HISTORY_TESTS_HELPERS_HPP
|
||||
|
||||
#include "../ErrorDatabaseSqlite.hpp"
|
||||
#include <filesystem>
|
||||
#include <list>
|
||||
#include <utils/error.hpp>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
///
|
||||
/// \brief get the path to the binary directory
|
||||
/// \return the path to the binary directory
|
||||
///
|
||||
fs::path get_bin_dir();
|
||||
|
||||
///
|
||||
/// \brief get a unique database name
|
||||
/// \return a unique database name
|
||||
///
|
||||
std::string get_unique_db_name();
|
||||
|
||||
///
|
||||
/// \brief get a vector of test errors
|
||||
/// \return a vector of test errors
|
||||
///
|
||||
std::vector<Everest::error::ErrorPtr> get_test_errors();
|
||||
|
||||
///
|
||||
/// \brief check if the given errors are equal
|
||||
/// \param expected_errors the expected errors
|
||||
/// \param errors the errors to check
|
||||
///
|
||||
void check_expected_errors_in_list(const std::vector<Everest::error::ErrorPtr>& expected_errors,
|
||||
const std::list<Everest::error::ErrorPtr>& errors);
|
||||
|
||||
///
|
||||
/// \brief wrapper class for the ErrorDatabaseSqlite class
|
||||
/// This class is used to test the ErrorDatabaseSqlite class
|
||||
/// It proxies the ErrorDatabaseSqlite class, but
|
||||
/// the destructor deletes the database file
|
||||
///
|
||||
class TestDatabase {
|
||||
public:
|
||||
explicit TestDatabase(const fs::path& db_path_, const bool reset_ = false);
|
||||
~TestDatabase();
|
||||
void add_error(Everest::error::ErrorPtr error);
|
||||
std::list<Everest::error::ErrorPtr> get_errors(const std::list<Everest::error::ErrorFilter>& filters) const;
|
||||
std::list<Everest::error::ErrorPtr> edit_errors(const std::list<Everest::error::ErrorFilter>& filters,
|
||||
Everest::error::ErrorDatabase::EditErrorFunc edit_func);
|
||||
std::list<Everest::error::ErrorPtr> remove_errors(const std::list<Everest::error::ErrorFilter>& filters);
|
||||
|
||||
private:
|
||||
std::unique_ptr<module::ErrorDatabaseSqlite> db;
|
||||
const fs::path db_path;
|
||||
};
|
||||
|
||||
#endif // ERROR_HISTORY_TESTS_HELPERS_HPP
|
||||
Reference in New Issue
Block a user