5#include <gtest/gtest.h>
36 return kcenon::common::make_error<int>(
static_cast<int>(monitoring_error_code::operation_failed),
37 "Simulated failure on attempt " + std::to_string(current_call));
39 return kcenon::common::ok(42);
45 return kcenon::common::make_error<int>(
static_cast<int>(monitoring_error_code::operation_failed),
"Always fails");
51 return kcenon::common::ok(100);
57 std::this_thread::sleep_for(
delay);
58 return kcenon::common::ok(200);
65 config.failure_threshold = 3;
69 EXPECT_EQ(breaker.get_state(), circuit_state::CLOSED);
72 EXPECT_TRUE(result.is_ok());
73 EXPECT_EQ(result.value(), 100);
74 EXPECT_EQ(breaker.get_state(), circuit_state::CLOSED);
75 EXPECT_EQ(call_count.load(), 1);
80 config.failure_threshold = 3;
85 for (
int i = 0; i < 3; ++i) {
87 EXPECT_TRUE(result.is_err());
90 EXPECT_EQ(breaker.get_state(), circuit_state::OPEN);
91 EXPECT_EQ(call_count.load(), 3);
95 EXPECT_TRUE(result.is_err());
96 EXPECT_EQ(call_count.load(), 3);
97 EXPECT_EQ(result.error().code,
static_cast<int>(monitoring_error_code::circuit_breaker_open));
102 config.failure_threshold = 2;
103 config.timeout = std::chrono::milliseconds(100);
108 for (
int i = 0; i < 2; ++i) {
111 EXPECT_EQ(breaker.get_state(), circuit_state::OPEN);
114 std::this_thread::sleep_for(std::chrono::milliseconds(150));
118 EXPECT_TRUE(result.is_ok());
119 EXPECT_EQ(breaker.get_state(), circuit_state::HALF_OPEN);
124 config.failure_threshold = 2;
125 config.success_threshold = 2;
126 config.timeout = std::chrono::milliseconds(50);
131 for (
int i = 0; i < 2; ++i) {
136 std::this_thread::sleep_for(std::chrono::milliseconds(100));
138 EXPECT_EQ(breaker.get_state(), circuit_state::HALF_OPEN);
142 EXPECT_TRUE(result.is_ok());
143 EXPECT_EQ(breaker.get_state(), circuit_state::CLOSED);
148 config.failure_threshold = 1;
154 EXPECT_EQ(breaker.get_state(), circuit_state::OPEN);
157 if (!breaker.allow_request()) {
158 auto result = kcenon::common::ok(999);
159 EXPECT_TRUE(result.is_ok());
160 EXPECT_EQ(result.value(), 999);
166 config.failure_threshold = 3;
175 auto stats = breaker.get_stats();
176 EXPECT_FALSE(stats.empty());
184 success_after_attempts = 2;
186 auto result = executor.
execute([
this]() {
return failing_operation(); });
188 EXPECT_TRUE(result.is_ok());
189 EXPECT_EQ(result.value(), 42);
190 EXPECT_EQ(call_count.load(), 3);
193 EXPECT_EQ(metrics.total_executions, 1);
194 EXPECT_EQ(metrics.successful_executions, 1);
195 EXPECT_EQ(metrics.total_retries, 2);
202 auto result = executor.
execute([
this]() {
return always_failing_operation(); });
204 EXPECT_TRUE(result.is_err());
205 EXPECT_EQ(call_count.load(), 2);
208 EXPECT_EQ(metrics.total_executions, 1);
209 EXPECT_EQ(metrics.failed_executions, 1);
210 EXPECT_EQ(metrics.total_retries, 1);
217 success_after_attempts = 2;
219 auto start = std::chrono::steady_clock::now();
220 auto result = executor.
execute([
this]() {
return failing_operation(); });
221 auto duration = std::chrono::steady_clock::now() - start;
223 EXPECT_TRUE(result.is_ok());
224 EXPECT_GE(duration, std::chrono::milliseconds(100));
231 success_after_attempts = 3;
233 auto result = executor.
execute([
this]() {
return failing_operation(); });
235 EXPECT_TRUE(result.is_ok());
236 EXPECT_EQ(call_count.load(), 4);
243 return error.code == monitoring_error_code::operation_timeout;
249 auto result = executor.
execute([
this]() {
return always_failing_operation(); });
251 EXPECT_TRUE(result.is_err());
252 EXPECT_EQ(call_count.load(), 1);
266 success_after_attempts = 1;
268 auto result = manager.
execute([
this]() {
return failing_operation(); });
270 EXPECT_TRUE(result.is_ok());
271 EXPECT_EQ(result.value(), 42);
272 EXPECT_EQ(call_count.load(), 2);
285 success_after_attempts = 2;
287 auto result = manager.
execute([
this]() {
return failing_operation(); });
289 EXPECT_TRUE(result.is_ok());
290 EXPECT_EQ(call_count.load(), 3);
301 auto result = manager.
execute([
this]() {
return always_succeeding_operation(); });
303 EXPECT_TRUE(result.is_ok());
304 EXPECT_EQ(result.value(), 100);
315 success_after_attempts = 2;
317 auto result = manager.
execute([
this]() {
return failing_operation(); });
319 EXPECT_TRUE(result.is_ok());
320 EXPECT_EQ(call_count.load(), 3);
332 [
this]() {
return slow_operation(std::chrono::milliseconds(500)); },
333 std::chrono::milliseconds(50)
336 EXPECT_TRUE(result.is_err());
337 EXPECT_EQ(result.error().code,
static_cast<int>(monitoring_error_code::operation_timeout));
350 manager.
execute([
this]() {
return always_succeeding_operation(); });
353 manager.
execute([
this]() {
return always_failing_operation(); });
356 EXPECT_EQ(metrics.total_operations, 2);
357 EXPECT_EQ(metrics.successful_operations, 1);
358 EXPECT_EQ(metrics.failed_operations, 1);
359 EXPECT_NEAR(metrics.get_overall_success_rate(), 0.5, 0.01);
371 EXPECT_TRUE(health.is_ok());
372 EXPECT_TRUE(health.value());
375 for (
int i = 0; i < 2; ++i) {
376 manager.
execute([
this]() {
return always_failing_operation(); });
381 EXPECT_TRUE(health.is_ok());
382 EXPECT_FALSE(health.value());
389 auto breaker = std::make_shared<circuit_breaker>();
390 registry.register_circuit_breaker(
"test", breaker);
392 auto retrieved = registry.get_circuit_breaker(
"test");
393 EXPECT_EQ(retrieved, breaker);
395 auto names = registry.get_all_names();
396 EXPECT_EQ(names.size(), 1);
397 EXPECT_EQ(names[0],
"test");
399 registry.remove_circuit_breaker(
"test");
400 retrieved = registry.get_circuit_breaker(
"test");
401 EXPECT_EQ(retrieved,
nullptr);
407 auto executor = std::make_shared<retry_executor<int>>(
"test_executor");
408 registry.register_executor<
int>(
"test", executor);
410 auto retrieved = registry.get_executor<
int>(
"test");
411 EXPECT_EQ(retrieved, executor);
413 auto names = registry.get_all_names();
414 EXPECT_EQ(names.size(), 1);
415 EXPECT_EQ(names[0],
"test");
417 registry.remove_executor(
"test");
418 retrieved = registry.get_executor<
int>(
"test");
419 EXPECT_EQ(retrieved,
nullptr);
425 auto manager = std::make_shared<fault_tolerance_manager<int>>(
"test_manager");
426 registry.register_manager<
int>(
"test", manager);
428 auto retrieved = registry.get_manager<
int>(
"test");
429 EXPECT_EQ(retrieved, manager);
431 auto names = registry.get_all_names();
432 EXPECT_EQ(names.size(), 1);
433 EXPECT_EQ(names[0],
"test");
435 registry.remove_manager(
"test");
436 retrieved = registry.get_manager<
int>(
"test");
437 EXPECT_EQ(retrieved,
nullptr);
479 config.failure_threshold = 10;
483 constexpr int num_threads = 4;
484 constexpr int operations_per_thread = 100;
486 std::vector<std::thread> threads;
487 std::atomic<int> successful_operations{0};
489 for (
int i = 0; i < num_threads; ++i) {
490 threads.emplace_back([&breaker, &successful_operations, operations_per_thread]() {
491 for (
int j = 0; j < operations_per_thread; ++j) {
493 if (result.is_ok()) {
494 successful_operations++;
500 for (
auto& thread : threads) {
504 EXPECT_EQ(successful_operations.load(), num_threads * operations_per_thread);
510 config.failure_threshold = 2;
512 auto breaker = std::make_unique<circuit_breaker>(config);
515 for (
int i = 0; i < 2; ++i) {
518 EXPECT_EQ(breaker->get_state(), circuit_state::OPEN);
521 breaker = std::make_unique<circuit_breaker>(config);
522 EXPECT_EQ(breaker->get_state(), circuit_state::CLOSED);
526 EXPECT_TRUE(result.is_ok());
534 executor.
execute([
this]() {
return always_succeeding_operation(); });
535 executor.
execute([
this]() {
return always_failing_operation(); });
538 EXPECT_GT(metrics_before.total_executions, 0);
544 EXPECT_EQ(metrics_after.total_executions, 0);
545 EXPECT_EQ(metrics_after.successful_executions, 0);
546 EXPECT_EQ(metrics_after.failed_executions, 0);
Circuit breaker integration for monitoring_system.
kcenon::common::Result< int > always_succeeding_operation()
kcenon::common::Result< int > always_failing_operation()
kcenon::common::Result< int > slow_operation(std::chrono::milliseconds delay)
kcenon::common::Result< int > failing_operation()
std::atomic< int > success_after_attempts
std::atomic< int > call_count
Fault tolerance manager template class.
common::Result< T > execute_with_timeout(Func &&func, std::chrono::milliseconds timeout)
Execute a function with timeout.
common::Result< bool > is_healthy()
Check if fault tolerance manager is healthy.
fault_tolerance_metrics get_metrics() const
Get fault tolerance metrics.
common::Result< T > execute(Func &&func)
Execute a function with fault tolerance.
Retry executor template class.
void reset_metrics()
Reset metrics.
retry_metrics get_metrics() const
Get retry metrics.
common::Result< T > execute(Func &&func)
Execute a function with retry logic.
Fault tolerance manager coordinating circuit breakers and retries.
@ delay
Delay requests until resources are available.
common::Result< T > execute_with_circuit_breaker(circuit_breaker &cb, const std::string &name, Func &&func)
Execute an operation through a circuit breaker.
retry_config create_fixed_delay_config(size_t max_attempts=3, std::chrono::milliseconds delay=std::chrono::milliseconds(1000))
Factory function for fixed delay config.
retry_config create_fibonacci_backoff_config(size_t max_attempts=3, std::chrono::milliseconds initial_delay=std::chrono::milliseconds(1000))
Factory function for Fibonacci backoff config.
retry_config create_exponential_backoff_config(size_t max_attempts=3, std::chrono::milliseconds initial_delay=std::chrono::milliseconds(1000))
Factory function for exponential backoff config.
common::resilience::circuit_breaker circuit_breaker
circuit_breaker_registry & global_circuit_breaker_registry()
Get global circuit breaker registry.
fault_tolerance_registry & global_fault_tolerance_registry()
Get global fault tolerance manager registry.
common::resilience::circuit_breaker_config circuit_breaker_config
retry_executor_registry & global_retry_executor_registry()
Get global retry executor registry.
Retry strategies with backoff for monitoring operations.
Extended error information with context.
Fault tolerance configuration.
bool enable_circuit_breaker
circuit_breaker_config circuit_config
bool circuit_breaker_first
double backoff_multiplier
std::function< bool(const error_info &)> should_retry
bool validate() const
Validate configuration.
TEST_F(FaultToleranceTest, CircuitBreakerClosedState)