using Xunit; using Moq; using OpenHarbor.MCP.Gateway.Core.Interfaces; namespace OpenHarbor.MCP.Gateway.Core.Tests.Interfaces; /// /// Unit tests for ICircuitBreaker interface following TDD approach. /// Tests circuit breaker pattern implementation. /// public class ICircuitBreakerTests { [Fact] public async Task ExecuteAsync_WithClosedCircuit_ExecutesOperation() { // Arrange var mockCircuitBreaker = new Mock(); var expectedResult = "success"; mockCircuitBreaker .Setup(cb => cb.ExecuteAsync( It.IsAny>>(), It.IsAny())) .Returns>, CancellationToken>((operation, ct) => operation()); // Act var result = await mockCircuitBreaker.Object.ExecuteAsync( async () => await Task.FromResult(expectedResult), CancellationToken.None); // Assert Assert.Equal(expectedResult, result); } [Fact] public async Task ExecuteAsync_WithOpenCircuit_ThrowsException() { // Arrange var mockCircuitBreaker = new Mock(); mockCircuitBreaker .Setup(cb => cb.ExecuteAsync( It.IsAny>>(), It.IsAny())) .ThrowsAsync(new InvalidOperationException("Circuit is open")); // Act & Assert await Assert.ThrowsAsync(() => mockCircuitBreaker.Object.ExecuteAsync( async () => await Task.FromResult("result"), CancellationToken.None)); } [Fact] public void GetState_ReturnsCircuitState() { // Arrange var mockCircuitBreaker = new Mock(); mockCircuitBreaker.Setup(cb => cb.GetState()).Returns("Closed"); // Act var state = mockCircuitBreaker.Object.GetState(); // Assert Assert.Equal("Closed", state); mockCircuitBreaker.Verify(cb => cb.GetState(), Times.Once); } [Fact] public void Reset_ResetsCircuitBreaker() { // Arrange var mockCircuitBreaker = new Mock(); mockCircuitBreaker.Setup(cb => cb.Reset()).Verifiable(); // Act mockCircuitBreaker.Object.Reset(); // Assert mockCircuitBreaker.Verify(cb => cb.Reset(), Times.Once); } [Fact] public async Task ExecuteAsync_WithMultipleFailures_OpensCircuit() { // Arrange var mockCircuitBreaker = new Mock(); var callCount = 0; mockCircuitBreaker .Setup(cb => cb.ExecuteAsync( It.IsAny>>(), It.IsAny())) .Returns>, CancellationToken>((operation, ct) => { callCount++; if (callCount >= 3) { throw new InvalidOperationException("Circuit is open"); } return operation(); }); // Act & Assert // First two calls should succeed await mockCircuitBreaker.Object.ExecuteAsync( async () => await Task.FromResult("result1"), CancellationToken.None); await mockCircuitBreaker.Object.ExecuteAsync( async () => await Task.FromResult("result2"), CancellationToken.None); // Third call should fail with open circuit await Assert.ThrowsAsync(() => mockCircuitBreaker.Object.ExecuteAsync( async () => await Task.FromResult("result3"), CancellationToken.None)); } }