Skip to content

Commit

Permalink
Added some correctness checks
Browse files Browse the repository at this point in the history
  • Loading branch information
Ómar Högni Guðmarsson committed Jun 20, 2024
1 parent 1fb0768 commit 94c5beb
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 16 deletions.
52 changes: 43 additions & 9 deletions exes/themis/inc/alarm_database.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@
#include <array>
#include <cstddef>
#include <filesystem>
#include <map>
#include <optional>
#include <string>
#include <tfc/logger.hpp>
#include <tfc/progbase.hpp>
#include <tfc/snitch/common.hpp>
#include <map>

namespace tfc::themis {

Expand Down Expand Up @@ -170,21 +170,45 @@ ON Alarms.sha1sum = AlarmTranslations.sha1sum;
std::string_view description,
std::string_view details) -> void {
auto query = fmt::format(
"INSERT INTO AlarmTranslations(sha1sum, alarm_id, locale, description, details) SELECT DISTINCT sha1sum, {}, '{}','{}','{}' FROM Alarms where alarm_id = {}",
"INSERT INTO AlarmTranslations(sha1sum, alarm_id, locale, description, details) SELECT DISTINCT sha1sum, {}, "
"'{}','{}','{}' FROM Alarms where alarm_id = {}",
alarm_id, locale, description, details, alarm_id);
db_ << query;
}

[[nodiscard]] auto is_alarm_active(snitch::api::alarm_id_t alarm_id) -> bool {
std::int64_t count = 0;
db_ << fmt::format("SELECT COUNT(*) FROM AlarmActivations WHERE alarm_id = {} AND activation_level = 1;", alarm_id) >>
[&](std::int64_t c) { count = c; };
return count > 0;
}

[[nodiscard]] auto is_activation_high(snitch::api::alarm_id_t activation_id) -> bool {
bool active = false;
db_ << fmt::format("SELECT activation_level FROM AlarmActivations WHERE activation_id = {} AND activation_level = 1;", activation_id) >>
[&](bool a) { active = a;};
return active;
}

[[nodiscard]] auto active_alarm_count() -> std::uint64_t {
std::uint64_t count = 0;
db_ << "SELECT COUNT(*) FROM AlarmActivations WHERE activation_level = 1;" >> [&](std::uint64_t c) { count = c; };
return count;
}

/**
* @brief Set an alarm in the database
* @param alarm_id the id of the alarm
* @param variables the variables for this activation
* @param tp an optional timepoint
* @return the activation_id
*/
auto set_alarm(snitch::api::alarm_id_t alarm_id,
[[nodiscard]] auto set_alarm(snitch::api::alarm_id_t alarm_id,
const std::unordered_map<std::string, std::string>& variables,
std::optional<tfc::snitch::api::time_point> tp = {}) -> std::uint64_t {
if (is_alarm_active(alarm_id)){
throw std::runtime_error("Alarm is already active");
}
db_ << "BEGIN;";
std::uint64_t activation_id;
try {
Expand All @@ -204,7 +228,11 @@ ON Alarms.sha1sum = AlarmTranslations.sha1sum;
return activation_id;
}
auto reset_alarm(snitch::api::alarm_id_t activation_id, std::optional<tfc::snitch::api::time_point> tp = {}) -> void {
db_ << fmt::format("UPDATE AlarmActivations SET activation_level = 0, reset_time = {} WHERE activation_id = {};", milliseconds_since_epoch(tp), activation_id);
if (!is_activation_high(activation_id)){
throw std::runtime_error("Cannot reset an inactive activation");
}
db_ << fmt::format("UPDATE AlarmActivations SET activation_level = 0, reset_time = {} WHERE activation_id = {};",
milliseconds_since_epoch(tp), activation_id);
}

[[nodiscard]] auto list_activations(std::string_view locale,
Expand All @@ -219,6 +247,7 @@ ON Alarms.sha1sum = AlarmTranslations.sha1sum;
activation_id,
Alarms.alarm_id,
activation_time,
reset_time,
activation_level,
primary_text.details,
primary_text.description,
Expand All @@ -245,7 +274,8 @@ WHERE activation_time >= {} AND activation_time <= {})",

std::vector<tfc::snitch::api::activation> activations;

db_ << populated_query >> [&](std::uint64_t activation_id, snitch::api::alarm_id_t alarm_id, std::int64_t activation_time,
db_ << populated_query >> [&](std::uint64_t activation_id, snitch::api::alarm_id_t alarm_id,
std::int64_t activation_time, std::optional<std::int64_t> reset_time,
bool activation_level, std::optional<std::string> primary_details,
std::optional<std::string> primary_description, std::optional<std::string> backup_details,
std::optional<std::string> backup_description, std::optional<std::string> tlocale,
Expand All @@ -256,11 +286,15 @@ WHERE activation_time >= {} AND activation_time <= {})",
std::string details = primary_details.value_or(backup_details.value());
std::string description = primary_description.value_or(backup_description.value());
bool in_locale = primary_description.has_value() && primary_details.has_value();
activations.emplace_back(alarm_id, activation_id, description, details, tlocale.value(),
activation_level, static_cast<tfc::snitch::level_e>(alarm_level), alarm_latching,
timepoint_from_milliseconds(activation_time), in_locale);
std::optional<time_point> final_reset_time = std::nullopt;
if (reset_time.has_value()) {
final_reset_time = timepoint_from_milliseconds(reset_time.value());
}
activations.emplace_back(alarm_id, activation_id, description, details, tlocale.value(), activation_level,
static_cast<tfc::snitch::level_e>(alarm_level), alarm_latching,
timepoint_from_milliseconds(activation_time), final_reset_time, in_locale);
};
for(auto& activation : activations) {
for (auto& activation : activations) {
// TODO: This is not great would be better to do this in a large query
// As of now we are doing a query for each activation to get the variables
std::vector<std::pair<std::string, std::string>> variables;
Expand Down
4 changes: 2 additions & 2 deletions exes/themis/inc/dbus_interface.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ class interface {
});

interface_->register_method(std::string(methods::set_alarm),
[&](snitch::api::alarm_id_t alarm_id, const std::unordered_map<std::string, std::string>& args) -> void {
database.set_alarm(alarm_id, args);
[&](snitch::api::alarm_id_t alarm_id, const std::unordered_map<std::string, std::string>& args) -> std::uint64_t {
return database.set_alarm(alarm_id, args);
});
interface_->register_method(std::string(methods::reset_alarm),
[&](snitch::api::alarm_id_t alarm_id) -> void {
Expand Down
49 changes: 45 additions & 4 deletions exes/themis/tests/themis_database_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ auto main(int argc, char** argv) -> int {
alarm_db.reset_alarm(activation_id);
}
// Insert an invalid activation
expect(throws([&]{alarm_db.set_alarm(999, {}); }));
expect(throws([&]{[[maybe_unused]] auto _ = alarm_db.set_alarm(999, {}); }));

// Verify our inserts
activations = alarm_db.list_activations(
Expand All @@ -121,7 +121,7 @@ auto main(int argc, char** argv) -> int {
tfc::themis::alarm_database alarm_db(true);
auto insert_id = alarm_db.register_alarm_en("tfc_id", "description", "details", false, tfc::snitch::level_e::info);
alarm_db.add_alarm_translation(alarm_db.list_alarms().at(0).alarm_id, "es", "spanish description", "spanish details");
alarm_db.set_alarm(insert_id, {});
[[maybe_unused]] auto _ = alarm_db.set_alarm(insert_id, {});
auto activations = alarm_db.list_activations(
"is", 0, 10000, tfc::snitch::level_e::info, tfc::snitch::api::active_e::active,
tfc::themis::alarm_database::timepoint_from_milliseconds(0),
Expand All @@ -145,7 +145,7 @@ auto main(int argc, char** argv) -> int {
// Add a variable alarm
auto var_alarm_id = alarm_db.register_alarm_en("tfc_id", "{var}", "{var}", false, tfc::snitch::level_e::info);
expect(alarm_db.list_alarms().size() == 1);
alarm_db.set_alarm(var_alarm_id, {{ "var", "10.0"}});
[[maybe_unused]] auto _ = alarm_db.set_alarm(var_alarm_id, {{ "var", "10.0"}});
auto activations = alarm_db.list_activations(
"en", 0, 10000, tfc::snitch::level_e::info, tfc::snitch::api::active_e::active,
tfc::themis::alarm_database::timepoint_from_milliseconds(0),
Expand All @@ -158,7 +158,7 @@ auto main(int argc, char** argv) -> int {
var_alarm_id = alarm_db.register_alarm_en("tfc_id", "description {var} {var2} {var3}", "details {var} {var2} {var3}", false, tfc::snitch::level_e::warning);
expect(alarm_db.list_alarms().size() == 2);
alarm_db.add_alarm_translation(var_alarm_id, "es", "spanish description {var} {var2} {var3}", "spanish details {var} {var2} {var3}");
alarm_db.set_alarm(var_alarm_id, {{ "var", "10.0"}, {"var2", "20.0"}, {"var3", "30.0"}});
_ = alarm_db.set_alarm(var_alarm_id, {{ "var", "10.0"}, {"var2", "20.0"}, {"var3", "30.0"}});
activations = alarm_db.list_activations(
"en", 0, 10000, tfc::snitch::level_e::warning, tfc::snitch::api::active_e::active,
tfc::themis::alarm_database::timepoint_from_milliseconds(0),
Expand All @@ -184,4 +184,45 @@ auto main(int argc, char** argv) -> int {
expect(activations.at(0).description == "description 10.0 20.0 30.0") << activations.at(0).description;
expect(activations.at(0).details == "details 10.0 20.0 30.0") << activations.at(0).details;
};
"Test the millisecond time storage"_test = []{
auto min_time = alarm_database::timepoint_from_milliseconds(std::numeric_limits<std::int64_t>::min());
auto max_time = alarm_database::timepoint_from_milliseconds(std::numeric_limits<std::int64_t>::max());
auto time = alarm_database::timepoint_from_milliseconds(0);
expect(time.time_since_epoch().count() == 0);
time = alarm_database::timepoint_from_milliseconds(1000);
expect(time.time_since_epoch().count() == 1000);
time = alarm_database::timepoint_from_milliseconds(1000000);
expect(time.time_since_epoch().count() == 1000000);
time = alarm_database::timepoint_from_milliseconds(1000000000);
expect(time.time_since_epoch().count() == 1000000000);
time = alarm_database::timepoint_from_milliseconds(1000000000000);
expect(time.time_since_epoch().count() == 1000000000000);
time = alarm_database::timepoint_from_milliseconds(1000000000000000);
expect(time.time_since_epoch().count() == 1000000000000000);

tfc::themis::alarm_database db(true);
auto alarm_id = db.register_alarm_en("tfc_id", "description", "details", false, tfc::snitch::level_e::info);
time = alarm_database::timepoint_from_milliseconds(1);
auto activation_id = db.set_alarm(alarm_id, {}, time);
auto activations = db.list_activations("en", 0, 10000, tfc::snitch::level_e::info, tfc::snitch::api::active_e::all, min_time, max_time);
expect(activations.size() == 1);
expect(activations.at(0).set_timestamp == time);
expect(!activations.at(0).reset_timestamp.has_value());
auto reset_time = alarm_database::timepoint_from_milliseconds(2);
db.reset_alarm(activation_id, reset_time);
activations = db.list_activations("en", 0, 10000, tfc::snitch::level_e::info, tfc::snitch::api::active_e::all, min_time, max_time);
expect(!db.is_alarm_active(alarm_id));
expect(activations.size() == 1);
expect(activations.at(0).set_timestamp == time);
expect(activations.at(0).reset_timestamp.has_value());
expect(activations.at(0).reset_timestamp == reset_time);
};
"You should not be able to set an already set alarm"_test = []{
tfc::themis::alarm_database db(true);
auto alarm_id = db.register_alarm_en("tfc_id", "description", "details", false, tfc::snitch::level_e::info);
auto activation_id = db.set_alarm(alarm_id, {});
expect(throws([&]{[[maybe_unused]] auto _ = db.set_alarm(alarm_id, {}); }));
db.reset_alarm(activation_id);
expect(throws([&]{ db.reset_alarm(activation_id, {}); }));
};
}
3 changes: 2 additions & 1 deletion libs/snitch/inc/public/tfc/snitch/common.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ struct activation {
bool active{};
level_e lvl{ level_e::unknown };
bool latching{};
time_point timestamp;
time_point set_timestamp;
std::optional<time_point> reset_timestamp;
bool in_requested_locale;
};
namespace dbus {
Expand Down

0 comments on commit 94c5beb

Please sign in to comment.