6#include <gtest/gtest.h>
23 test_dir_ = std::filesystem::temp_directory_path() /
"monitoring_test";
24 std::filesystem::create_directories(
test_dir_);
35 std::vector<metrics_snapshot> snapshots;
41 snap1.
add_metric(
"requests_per_second", 150.0);
44 snapshots.push_back(snap1);
53 snapshots.push_back(snap2);
62 snapshots.push_back(snap3);
74 valid_config.
path =
"/tmp/test.json";
75 valid_config.
type = storage_backend_type::file_json;
79 auto validation = valid_config.
validate();
80 EXPECT_TRUE(validation.is_ok());
84 invalid_path.
type = storage_backend_type::file_json;
87 auto path_validation = invalid_path.
validate();
88 EXPECT_FALSE(path_validation.is_ok());
89 EXPECT_EQ(path_validation.error().code,
static_cast<int>(monitoring_error_code::invalid_configuration));
93 memory_config.
type = storage_backend_type::memory_buffer;
96 auto memory_validation = memory_config.
validate();
97 EXPECT_TRUE(memory_validation.is_ok());
104 EXPECT_FALSE(capacity_validation.is_ok());
105 EXPECT_EQ(capacity_validation.error().code,
static_cast<int>(monitoring_error_code::invalid_capacity));
109 invalid_batch.
path =
"/tmp/test";
112 auto batch_validation = invalid_batch.
validate();
113 EXPECT_FALSE(batch_validation.is_ok());
117 batch_too_large.
path =
"/tmp/test";
120 auto batch_large_validation = batch_too_large.
validate();
121 EXPECT_FALSE(batch_large_validation.is_ok());
126 config.
type = storage_backend_type::file_json;
127 config.
path = (test_dir_ /
"test.json").
string();
133 EXPECT_EQ(backend.
size(), 0);
137 for (
const auto& snapshot : test_snapshots_) {
138 auto store_result = backend.
store(snapshot);
139 EXPECT_TRUE(store_result.is_ok());
142 EXPECT_EQ(backend.
size(), 3);
145 auto retrieve_result = backend.
retrieve(0);
146 EXPECT_TRUE(retrieve_result.is_ok());
150 EXPECT_TRUE(range_result.is_ok());
151 EXPECT_EQ(range_result.value().size(), 2);
154 auto flush_result = backend.
flush();
155 EXPECT_TRUE(flush_result.is_ok());
158 auto clear_result = backend.
clear();
159 EXPECT_TRUE(clear_result.is_ok());
160 EXPECT_EQ(backend.
size(), 0);
165 config.
type = storage_backend_type::file_json;
166 config.
path = (test_dir_ /
"capacity_test.json").
string();
172 for (
const auto& snapshot : test_snapshots_) {
173 auto store_result = backend.
store(snapshot);
174 EXPECT_TRUE(store_result.is_ok());
178 EXPECT_EQ(backend.
size(), 2);
182 EXPECT_EQ(stats[
"total_snapshots"], 2);
183 EXPECT_EQ(stats[
"capacity"], 2);
190 json_config.
type = storage_backend_type::file_json;
191 json_config.
path = (test_dir_ /
"test.json").
string();
195 auto store_result = json_backend.
store(test_snapshots_[0]);
196 EXPECT_TRUE(store_result.is_ok());
198 auto retrieve_result = json_backend.
retrieve(0);
199 EXPECT_TRUE(retrieve_result.is_ok());
205 binary_config.
type = storage_backend_type::file_binary;
206 binary_config.
path = (test_dir_ /
"test.bin").
string();
210 auto store_result = binary_backend.
store(test_snapshots_[0]);
211 EXPECT_TRUE(store_result.is_ok());
213 auto retrieve_result = binary_backend.
retrieve(0);
214 EXPECT_TRUE(retrieve_result.is_ok());
220 csv_config.
type = storage_backend_type::file_csv;
221 csv_config.
path = (test_dir_ /
"test.csv").
string();
225 auto store_result = csv_backend.
store(test_snapshots_[0]);
226 EXPECT_TRUE(store_result.is_ok());
228 auto retrieve_result = csv_backend.
retrieve(0);
229 EXPECT_TRUE(retrieve_result.is_ok());
235 config.
type = storage_backend_type::memory_buffer;
241 for (
const auto& snapshot : test_snapshots_) {
242 auto store_result = backend.
store(snapshot);
243 EXPECT_TRUE(store_result.is_ok());
246 EXPECT_EQ(backend.
size(), 3);
252 auto retrieve_result = backend.
retrieve(0);
253 EXPECT_TRUE(retrieve_result.is_ok());
256 EXPECT_TRUE(range_result.is_ok());
258 auto clear_result = backend.
clear();
259 EXPECT_TRUE(clear_result.is_ok());
260 EXPECT_EQ(backend.
size(), 0);
265 config.
type = storage_backend_type::database_sqlite;
266 config.
path = (test_dir_ /
"test.db").
string();
274 EXPECT_GE(backend.
size(), 0);
277 for (
const auto& snapshot : test_snapshots_) {
278 auto store_result = backend.
store(snapshot);
279 EXPECT_TRUE(store_result.is_ok());
282 EXPECT_EQ(backend.
size(), 3);
285 auto retrieve_result = backend.
retrieve(0);
286 EXPECT_TRUE(retrieve_result.is_ok());
290 EXPECT_TRUE(range_result.is_ok());
293 auto flush_result = backend.
flush();
294 EXPECT_TRUE(flush_result.is_ok());
297 auto clear_result = backend.
clear();
298 EXPECT_TRUE(clear_result.is_ok());
299 EXPECT_EQ(backend.
size(), 0);
303 EXPECT_EQ(stats[
"stored_count"], 0);
304 EXPECT_EQ(stats[
"capacity"], 100);
305 EXPECT_EQ(stats[
"connected"], 1);
312 sqlite_config.
type = storage_backend_type::database_sqlite;
313 sqlite_config.
path = (test_dir_ /
"sqlite.db").
string();
317 auto store_result = sqlite_backend.
store(test_snapshots_[0]);
318 EXPECT_TRUE(store_result.is_ok());
324 pg_config.
type = storage_backend_type::database_postgresql;
325 pg_config.
host =
"localhost";
326 pg_config.
port = 5432;
333 auto store_result = pg_backend.
store(test_snapshots_[0]);
334 EXPECT_TRUE(store_result.is_ok());
340 mysql_config.
type = storage_backend_type::database_mysql;
341 mysql_config.
host =
"localhost";
342 mysql_config.
port = 3306;
344 mysql_config.
username =
"test_user";
345 mysql_config.
password =
"test_pass";
349 auto store_result = mysql_backend.
store(test_snapshots_[0]);
350 EXPECT_TRUE(store_result.is_ok());
356 config.
type = storage_backend_type::cloud_s3;
357 config.
path =
"test-monitoring-bucket";
363 EXPECT_EQ(backend.
capacity(), 1000);
364 EXPECT_EQ(backend.
size(), 0);
367 for (
const auto& snapshot : test_snapshots_) {
368 auto store_result = backend.
store(snapshot);
369 EXPECT_TRUE(store_result.is_ok());
372 EXPECT_EQ(backend.
size(), 3);
375 auto retrieve_result = backend.
retrieve(0);
376 EXPECT_TRUE(retrieve_result.is_ok());
380 EXPECT_TRUE(range_result.is_ok());
381 EXPECT_LE(range_result.value().size(), 2);
384 auto flush_result = backend.
flush();
385 EXPECT_TRUE(flush_result.is_ok());
388 auto clear_result = backend.
clear();
389 EXPECT_TRUE(clear_result.is_ok());
390 EXPECT_EQ(backend.
size(), 0);
397 s3_config.
type = storage_backend_type::cloud_s3;
398 s3_config.
path =
"s3-test-bucket";
402 auto store_result = s3_backend.
store(test_snapshots_[0]);
403 EXPECT_TRUE(store_result.is_ok());
409 gcs_config.
type = storage_backend_type::cloud_gcs;
410 gcs_config.
path =
"gcs-test-bucket";
414 auto store_result = gcs_backend.
store(test_snapshots_[0]);
415 EXPECT_TRUE(store_result.is_ok());
421 azure_config.
type = storage_backend_type::cloud_azure_blob;
422 azure_config.
path =
"azure-test-container";
426 auto store_result = azure_backend.
store(test_snapshots_[0]);
427 EXPECT_TRUE(store_result.is_ok());
435 file_config.
type = storage_backend_type::file_json;
436 file_config.
path = (test_dir_ /
"factory_test.json").
string();
440 EXPECT_TRUE(backend);
442 auto store_result = backend->store(test_snapshots_[0]);
443 EXPECT_TRUE(store_result.is_ok());
449 db_config.
type = storage_backend_type::database_sqlite;
450 db_config.
path = (test_dir_ /
"factory_test.db").
string();
454 EXPECT_TRUE(backend);
456 auto store_result = backend->store(test_snapshots_[0]);
457 EXPECT_TRUE(store_result.is_ok());
463 cloud_config.
type = storage_backend_type::cloud_s3;
464 cloud_config.
path =
"factory-test-bucket";
468 EXPECT_TRUE(backend);
470 auto store_result = backend->store(test_snapshots_[0]);
471 EXPECT_TRUE(store_result.is_ok());
480 EXPECT_FALSE(backend);
486 EXPECT_EQ(supported.size(), 10);
488 EXPECT_TRUE(std::find(supported.begin(), supported.end(),
489 storage_backend_type::file_json) != supported.end());
490 EXPECT_TRUE(std::find(supported.begin(), supported.end(),
491 storage_backend_type::database_sqlite) != supported.end());
492 EXPECT_TRUE(std::find(supported.begin(), supported.end(),
493 storage_backend_type::cloud_s3) != supported.end());
494 EXPECT_TRUE(std::find(supported.begin(), supported.end(),
495 storage_backend_type::memory_buffer) != supported.end());
502 (test_dir_ /
"helper_test.json").
string(),
503 storage_backend_type::file_json,
505 EXPECT_TRUE(backend);
507 auto store_result = backend->store(test_snapshots_[0]);
508 EXPECT_TRUE(store_result.is_ok());
514 storage_backend_type::database_sqlite,
515 (test_dir_ /
"helper_test.db").
string(),
517 EXPECT_TRUE(backend);
519 auto store_result = backend->store(test_snapshots_[0]);
520 EXPECT_TRUE(store_result.is_ok());
526 storage_backend_type::cloud_s3,
527 "helper-test-bucket");
528 EXPECT_TRUE(backend);
530 auto store_result = backend->store(test_snapshots_[0]);
531 EXPECT_TRUE(store_result.is_ok());
540 invalid_config.
type = storage_backend_type::file_json;
541 invalid_config.
path =
"/invalid/path/that/does/not/exist/file.json";
548 auto store_result = backend.
store(test_snapshots_[0]);
550 }
catch (
const std::exception&) {
559 config.
type = storage_backend_type::memory_buffer;
564 auto retrieve_result = backend.
retrieve(999);
565 EXPECT_FALSE(retrieve_result.is_ok());
566 EXPECT_EQ(retrieve_result.error().code,
static_cast<int>(monitoring_error_code::not_found));
572 config.
type = storage_backend_type::memory_buffer;
578 std::vector<std::thread> store_threads;
579 std::atomic<int> successful_stores{0};
581 for (
int i = 0; i < 10; ++i) {
582 store_threads.emplace_back([&, i]() {
584 snapshot.
source_id =
"thread_" + std::to_string(i);
585 snapshot.
add_metric(
"value",
static_cast<double>(i));
587 auto result = backend.
store(snapshot);
588 if (result.is_ok()) {
594 for (
auto& thread : store_threads) {
598 EXPECT_EQ(successful_stores.load(), 10);
599 EXPECT_EQ(backend.
size(), 10);
602 std::vector<std::thread> retrieve_threads;
603 std::atomic<int> successful_retrievals{0};
605 for (
int i = 0; i < 5; ++i) {
606 retrieve_threads.emplace_back([&, i]() {
608 if (result.is_ok()) {
609 successful_retrievals++;
614 for (
auto& thread : retrieve_threads) {
618 EXPECT_EQ(successful_retrievals.load(), 5);
623 config.
type = storage_backend_type::memory_buffer;
629 for (
int i = 0; i < 100; ++i) {
631 snapshot.
source_id =
"generator_" + std::to_string(i);
634 for (
int j = 0; j < 10; ++j) {
635 snapshot.
add_metric(
"metric_" + std::to_string(j),
static_cast<double>(i * 10 + j));
638 auto store_result = backend.
store(snapshot);
639 EXPECT_TRUE(store_result.is_ok());
643 EXPECT_EQ(backend.
size(), 50);
647 EXPECT_TRUE(range_result.is_ok());
648 EXPECT_EQ(range_result.value().size(), 25);
std::vector< metrics_snapshot > create_test_snapshots()
std::vector< metrics_snapshot > test_snapshots_
std::filesystem::path test_dir_
Cloud storage backend (stub implementation)
common::Result< bool > store(const metrics_snapshot &snapshot) override
common::Result< std::vector< metrics_snapshot > > retrieve_range(size_t start, size_t count) override
common::Result< metrics_snapshot > retrieve(size_t index) override
size_t capacity() const override
common::Result< bool > clear() override
common::Result< bool > flush() override
size_t size() const override
Database storage backend (stub implementation)
size_t capacity() const override
common::Result< bool > flush() override
size_t size() const override
common::Result< bool > store(const metrics_snapshot &snapshot) override
std::unordered_map< std::string, size_t > get_stats() const override
common::Result< std::vector< metrics_snapshot > > retrieve_range(size_t start, size_t count) override
common::Result< bool > clear() override
common::Result< metrics_snapshot > retrieve(size_t index) override
File storage backend for metrics snapshots.
common::Result< metrics_snapshot > retrieve(size_t index) override
size_t capacity() const override
common::Result< bool > clear() override
common::Result< std::vector< metrics_snapshot > > retrieve_range(size_t start, size_t count) override
common::Result< bool > flush() override
std::unordered_map< std::string, size_t > get_stats() const override
size_t size() const override
common::Result< bool > store(const metrics_snapshot &snapshot) override
static std::unique_ptr< snapshot_storage_backend > create_backend(const storage_config &config)
Create a storage backend based on configuration.
static std::vector< storage_backend_type > get_supported_backends()
Get list of supported backend types.
Core monitoring system interface definitions.
std::unique_ptr< snapshot_storage_backend > create_database_storage(storage_backend_type type, const std::string &path, const std::string &table)
Create a database storage backend.
std::unique_ptr< snapshot_storage_backend > create_cloud_storage(storage_backend_type type, const std::string &bucket)
Create a cloud storage backend.
std::unique_ptr< snapshot_storage_backend > create_file_storage(const std::string &path, storage_backend_type type, size_t capacity)
Create a file storage backend.
storage_backend_type
Storage backend types.
Storage backend type definitions for metric persistence.
Complete snapshot of metrics at a point in time.
std::chrono::system_clock::time_point capture_time
void add_metric(const std::string &name, double value)
Add a metric to the snapshot.
storage_backend_type type
std::string database_name
common::Result< bool > validate() const
Validate configuration.
TEST_F(StorageBackendsTest, StorageConfigValidation)