All checks were successful
Caddy Manager CI build / docker (push) Successful in 52s
673 lines
28 KiB
C#
673 lines
28 KiB
C#
using CaddyManager.Services.Caddy;
|
|
using CaddyManager.Tests.TestUtilities;
|
|
using System.Diagnostics;
|
|
using System.Text;
|
|
|
|
namespace CaddyManager.Tests.Services.Caddy;
|
|
|
|
/// <summary>
|
|
/// Tests for CaddyConfigurationParsingService
|
|
/// </summary>
|
|
public class CaddyConfigurationParsingServiceTests
|
|
{
|
|
private readonly CaddyConfigurationParsingService _service;
|
|
|
|
public CaddyConfigurationParsingServiceTests()
|
|
{
|
|
_service = new CaddyConfigurationParsingService();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Tests that the parsing service correctly extracts a single hostname from a basic Caddyfile configuration.
|
|
/// Setup: Provides a simple Caddyfile content string with one hostname directive using sample data.
|
|
/// Expectation: The service should return a list containing exactly one hostname, enabling proper site identification and management in the Caddy web server configuration.
|
|
/// </summary>
|
|
[Fact]
|
|
public void GetHostnamesFromCaddyfileContent_WithSingleHostname_ReturnsCorrectHostname()
|
|
{
|
|
// Arrange
|
|
var caddyfileContent = TestHelper.SampleCaddyfiles.SimpleReverseProxy;
|
|
|
|
// Act
|
|
var result = _service.GetHostnamesFromCaddyfileContent(caddyfileContent);
|
|
|
|
// Assert
|
|
result.Should().NotBeNull();
|
|
result.Should().HaveCount(1);
|
|
result.Should().Contain("example.com");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Tests that the parsing service correctly extracts multiple hostnames from a Caddyfile configuration with multiple host blocks.
|
|
/// Setup: Provides a Caddyfile content string containing multiple hostname directives for different domains.
|
|
/// Expectation: The service should return a list containing all configured hostnames, ensuring comprehensive site management across multiple domains in the Caddy web server.
|
|
/// </summary>
|
|
[Fact]
|
|
public void GetHostnamesFromCaddyfileContent_WithMultipleHostnames_ReturnsAllHostnames()
|
|
{
|
|
// Arrange
|
|
var caddyfileContent = TestHelper.SampleCaddyfiles.MultipleHosts;
|
|
|
|
// Act
|
|
var result = _service.GetHostnamesFromCaddyfileContent(caddyfileContent);
|
|
|
|
// Assert
|
|
result.Should().NotBeNull();
|
|
result.Should().HaveCount(2);
|
|
result.Should().Contain("example.com");
|
|
result.Should().Contain("www.example.com");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Tests that the parsing service correctly extracts hostnames from a complex Caddyfile configuration with advanced directives.
|
|
/// Setup: Provides a complex Caddyfile content string with multiple hosts and advanced configuration blocks.
|
|
/// Expectation: The service should return all hostnames regardless of configuration complexity, ensuring robust parsing for production-level Caddy configurations.
|
|
/// </summary>
|
|
[Fact]
|
|
public void GetHostnamesFromCaddyfileContent_WithComplexConfiguration_ReturnsAllHostnames()
|
|
{
|
|
// Arrange
|
|
var caddyfileContent = TestHelper.SampleCaddyfiles.ComplexConfiguration;
|
|
|
|
// Act
|
|
var result = _service.GetHostnamesFromCaddyfileContent(caddyfileContent);
|
|
|
|
// Assert
|
|
result.Should().NotBeNull();
|
|
result.Should().HaveCount(4); // Updated to reflect correct parsing of labels before blocks
|
|
result.Should().Contain("api.example.com");
|
|
result.Should().Contain("app.example.com");
|
|
result.Should().Contain("route /v1/*");
|
|
result.Should().Contain("route /v2/*");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Tests that the parsing service handles empty Caddyfile content gracefully without errors.
|
|
/// Setup: Provides an empty string as Caddyfile content to simulate missing or uninitialized configuration.
|
|
/// Expectation: The service should return an empty list rather than throwing exceptions, ensuring robust error handling for edge cases in Caddy configuration management.
|
|
/// </summary>
|
|
[Fact]
|
|
public void GetHostnamesFromCaddyfileContent_WithEmptyContent_ReturnsEmptyList()
|
|
{
|
|
// Arrange
|
|
var caddyfileContent = string.Empty;
|
|
|
|
// Act
|
|
var result = _service.GetHostnamesFromCaddyfileContent(caddyfileContent);
|
|
|
|
// Assert
|
|
result.Should().NotBeNull();
|
|
result.Should().BeEmpty();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Tests that the parsing service handles whitespace-only Caddyfile content gracefully.
|
|
/// Setup: Provides a string containing only whitespace characters (spaces, tabs, newlines) to simulate malformed or empty configuration files.
|
|
/// Expectation: The service should return an empty list, demonstrating proper input sanitization and preventing false positive hostname detection from whitespace.
|
|
/// </summary>
|
|
[Fact]
|
|
public void GetHostnamesFromCaddyfileContent_WithWhitespaceOnly_ReturnsEmptyList()
|
|
{
|
|
// Arrange
|
|
var caddyfileContent = " \n\t \r\n ";
|
|
|
|
// Act
|
|
var result = _service.GetHostnamesFromCaddyfileContent(caddyfileContent);
|
|
|
|
// Assert
|
|
result.Should().NotBeNull();
|
|
result.Should().BeEmpty();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Tests that the parsing service deduplicates hostnames when the same hostname appears multiple times in a Caddyfile.
|
|
/// Setup: Provides a Caddyfile content string with the same hostname configured in multiple blocks with different reverse proxy targets.
|
|
/// Expectation: The service should return a unique list of hostnames, preventing duplicate entries that could cause confusion in Caddy configuration management.
|
|
/// </summary>
|
|
[Fact]
|
|
public void GetHostnamesFromCaddyfileContent_WithDuplicateHostnames_ReturnsUniqueHostnames()
|
|
{
|
|
// Arrange
|
|
var caddyfileContent = @"
|
|
example.com {
|
|
reverse_proxy localhost:8080
|
|
}
|
|
|
|
example.com {
|
|
reverse_proxy localhost:9090
|
|
}";
|
|
|
|
// Act
|
|
var result = _service.GetHostnamesFromCaddyfileContent(caddyfileContent);
|
|
|
|
// Assert
|
|
result.Should().NotBeNull();
|
|
result.Should().HaveCount(1);
|
|
result.Should().Contain("example.com");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Tests that the parsing service correctly extracts the reverse proxy target hostname from a simple Caddyfile configuration.
|
|
/// Setup: Provides a basic Caddyfile content string with a single reverse proxy directive pointing to a local service.
|
|
/// Expectation: The service should return the target hostname (without port), enabling proper backend service identification for Caddy reverse proxy management.
|
|
/// </summary>
|
|
[Fact]
|
|
public void GetReverseProxyTargetFromCaddyfileContent_WithSimpleReverseProxy_ReturnsCorrectTarget()
|
|
{
|
|
// Arrange
|
|
var caddyfileContent = TestHelper.SampleCaddyfiles.SimpleReverseProxy;
|
|
|
|
// Act
|
|
var result = _service.GetReverseProxyTargetFromCaddyfileContent(caddyfileContent);
|
|
|
|
// Assert
|
|
result.Should().Be("localhost");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Tests that the parsing service extracts the first reverse proxy target from a complex Caddyfile configuration with multiple proxy directives.
|
|
/// Setup: Provides a complex Caddyfile content string with multiple reverse proxy targets across different host blocks.
|
|
/// Expectation: The service should return the first encountered target hostname, providing consistent behavior for configurations with multiple backend services.
|
|
/// </summary>
|
|
[Fact]
|
|
public void GetReverseProxyTargetFromCaddyfileContent_WithComplexConfiguration_ReturnsFirstTarget()
|
|
{
|
|
// Arrange
|
|
var caddyfileContent = TestHelper.SampleCaddyfiles.ComplexConfiguration;
|
|
|
|
// Act
|
|
var result = _service.GetReverseProxyTargetFromCaddyfileContent(caddyfileContent);
|
|
|
|
// Assert
|
|
result.Should().Be("localhost");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Tests that the parsing service handles Caddyfile configurations without reverse proxy directives gracefully.
|
|
/// Setup: Provides a Caddyfile content string with host blocks that use other directives (like respond) but no reverse proxy configuration.
|
|
/// Expectation: The service should return an empty string, indicating no reverse proxy target is configured, which is valid for static content or other Caddy use cases.
|
|
/// </summary>
|
|
[Fact]
|
|
public void GetReverseProxyTargetFromCaddyfileContent_WithNoReverseProxy_ReturnsEmptyString()
|
|
{
|
|
// Arrange
|
|
var caddyfileContent = @"
|
|
example.com {
|
|
respond ""Hello World""
|
|
}";
|
|
|
|
// Act
|
|
var result = _service.GetReverseProxyTargetFromCaddyfileContent(caddyfileContent);
|
|
|
|
// Assert
|
|
result.Should().Be(string.Empty);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Tests that the parsing service handles empty Caddyfile content when extracting reverse proxy targets.
|
|
/// Setup: Provides an empty string as Caddyfile content to simulate missing configuration.
|
|
/// Expectation: The service should return an empty string rather than throwing exceptions, ensuring robust error handling for edge cases in reverse proxy target extraction.
|
|
/// </summary>
|
|
[Fact]
|
|
public void GetReverseProxyTargetFromCaddyfileContent_WithEmptyContent_ReturnsEmptyString()
|
|
{
|
|
// Arrange
|
|
var caddyfileContent = string.Empty;
|
|
|
|
// Act
|
|
var result = _service.GetReverseProxyTargetFromCaddyfileContent(caddyfileContent);
|
|
|
|
// Assert
|
|
result.Should().Be(string.Empty);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Tests that the parsing service correctly extracts a single port number from a Caddyfile reverse proxy configuration.
|
|
/// Setup: Provides a simple Caddyfile content string with one reverse proxy directive specifying a port number.
|
|
/// Expectation: The service should return a list containing the correct port number, enabling proper backend service port identification for Caddy reverse proxy management.
|
|
/// </summary>
|
|
[Fact]
|
|
public void GetReverseProxyPortsFromCaddyfileContent_WithSinglePort_ReturnsCorrectPort()
|
|
{
|
|
// Arrange
|
|
var caddyfileContent = TestHelper.SampleCaddyfiles.SimpleReverseProxy;
|
|
|
|
// Act
|
|
var result = _service.GetReverseProxyPortsFromCaddyfileContent(caddyfileContent);
|
|
|
|
// Assert
|
|
result.Should().NotBeNull();
|
|
result.Should().HaveCount(1);
|
|
result.Should().Contain(8080);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Tests that the parsing service correctly extracts multiple port numbers from a Caddyfile configuration with multiple reverse proxy targets.
|
|
/// Setup: Provides a Caddyfile content string with multiple reverse proxy directives using different port numbers.
|
|
/// Expectation: The service should return a list containing all configured port numbers, ensuring comprehensive port management for multi-service Caddy configurations.
|
|
/// </summary>
|
|
[Fact]
|
|
public void GetReverseProxyPortsFromCaddyfileContent_WithMultiplePorts_ReturnsAllPorts()
|
|
{
|
|
// Arrange
|
|
var caddyfileContent = TestHelper.SampleCaddyfiles.WithMultiplePorts;
|
|
|
|
// Act
|
|
var result = _service.GetReverseProxyPortsFromCaddyfileContent(caddyfileContent);
|
|
|
|
// Assert
|
|
result.Should().NotBeNull();
|
|
result.Should().HaveCount(2);
|
|
result.Should().Contain(8080);
|
|
result.Should().Contain(3000);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Tests that the parsing service correctly extracts all port numbers from a complex Caddyfile configuration with multiple hosts and services.
|
|
/// Setup: Provides a complex Caddyfile content string with multiple host blocks, each containing reverse proxy directives with different ports.
|
|
/// Expectation: The service should return all unique port numbers across all configurations, enabling comprehensive port tracking for complex Caddy deployments.
|
|
/// </summary>
|
|
[Fact]
|
|
public void GetReverseProxyPortsFromCaddyfileContent_WithComplexConfiguration_ReturnsAllPorts()
|
|
{
|
|
// Arrange
|
|
var caddyfileContent = TestHelper.SampleCaddyfiles.ComplexConfiguration;
|
|
|
|
// Act
|
|
var result = _service.GetReverseProxyPortsFromCaddyfileContent(caddyfileContent);
|
|
|
|
// Assert
|
|
result.Should().NotBeNull();
|
|
result.Should().HaveCount(3);
|
|
result.Should().Contain(3000);
|
|
result.Should().Contain(3001);
|
|
result.Should().Contain(8080);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Tests that the parsing service deduplicates port numbers when the same port appears multiple times in a Caddyfile configuration.
|
|
/// Setup: Provides a Caddyfile content string with multiple host blocks using the same reverse proxy port number.
|
|
/// Expectation: The service should return a unique list of port numbers, preventing duplicate entries that could cause confusion in port management and resource allocation.
|
|
/// </summary>
|
|
[Fact]
|
|
public void GetReverseProxyPortsFromCaddyfileContent_WithDuplicatePorts_ReturnsUniquePorts()
|
|
{
|
|
// Arrange
|
|
var caddyfileContent = @"
|
|
example.com {
|
|
reverse_proxy localhost:8080
|
|
}
|
|
|
|
api.example.com {
|
|
reverse_proxy localhost:8080
|
|
}";
|
|
|
|
// Act
|
|
var result = _service.GetReverseProxyPortsFromCaddyfileContent(caddyfileContent);
|
|
|
|
// Assert
|
|
result.Should().NotBeNull();
|
|
result.Should().HaveCount(1);
|
|
result.Should().Contain(8080);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Tests that the parsing service handles Caddyfile configurations without reverse proxy directives when extracting ports.
|
|
/// Setup: Provides a Caddyfile content string with host blocks that use other directives but no reverse proxy configuration.
|
|
/// Expectation: The service should return an empty list, indicating no reverse proxy ports are configured, which is valid for static content or other non-proxy Caddy use cases.
|
|
/// </summary>
|
|
[Fact]
|
|
public void GetReverseProxyPortsFromCaddyfileContent_WithNoReverseProxy_ReturnsEmptyList()
|
|
{
|
|
// Arrange
|
|
var caddyfileContent = @"
|
|
example.com {
|
|
respond ""Hello World""
|
|
}";
|
|
|
|
// Act
|
|
var result = _service.GetReverseProxyPortsFromCaddyfileContent(caddyfileContent);
|
|
|
|
// Assert
|
|
result.Should().NotBeNull();
|
|
result.Should().BeEmpty();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Tests that the parsing service handles empty Caddyfile content when extracting reverse proxy ports.
|
|
/// Setup: Provides an empty string as Caddyfile content to simulate missing configuration.
|
|
/// Expectation: The service should return an empty list rather than throwing exceptions, ensuring robust error handling for edge cases in port extraction.
|
|
/// </summary>
|
|
[Fact]
|
|
public void GetReverseProxyPortsFromCaddyfileContent_WithEmptyContent_ReturnsEmptyList()
|
|
{
|
|
// Arrange
|
|
var caddyfileContent = string.Empty;
|
|
|
|
// Act
|
|
var result = _service.GetReverseProxyPortsFromCaddyfileContent(caddyfileContent);
|
|
|
|
// Assert
|
|
result.Should().NotBeNull();
|
|
result.Should().BeEmpty();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Tests that the parsing service correctly extracts reverse proxy targets from various Caddyfile configurations with different target formats.
|
|
/// Setup: Provides parameterized test data with different reverse proxy target formats including IP addresses, hostnames, and URLs.
|
|
/// Expectation: The service should correctly parse and return the target hostname portion from various reverse proxy directive formats, ensuring compatibility with different backend service configurations.
|
|
/// </summary>
|
|
[Theory]
|
|
[InlineData("example.com { reverse_proxy 192.168.1.100:3000 }", "192.168.1.100")]
|
|
[InlineData("test.local { reverse_proxy app-server:8080 }", "app-server")]
|
|
[InlineData("api.test { reverse_proxy http://backend:9000 }", "http")]
|
|
public void GetReverseProxyTargetFromCaddyfileContent_WithVariousTargets_ReturnsCorrectTarget(
|
|
string caddyfileContent, string expectedTarget)
|
|
{
|
|
// Act
|
|
var result = _service.GetReverseProxyTargetFromCaddyfileContent(caddyfileContent);
|
|
|
|
// Assert
|
|
result.Should().Be(expectedTarget);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Tests that the parsing service correctly extracts port numbers from various Caddyfile configurations with different reverse proxy port formats.
|
|
/// Setup: Provides parameterized test data with different reverse proxy configurations using various port numbers and target formats.
|
|
/// Expectation: The service should correctly parse and return the port number from various reverse proxy directive formats, ensuring accurate port identification for different backend service configurations.
|
|
/// </summary>
|
|
[Theory]
|
|
[InlineData("example.com { reverse_proxy localhost:3000 }", 3000)]
|
|
[InlineData("test.local { reverse_proxy app-server:8080 }", 8080)]
|
|
[InlineData("api.test { reverse_proxy backend:9000 }", 9000)]
|
|
public void GetReverseProxyPortsFromCaddyfileContent_WithVariousPorts_ReturnsCorrectPort(
|
|
string caddyfileContent, int expectedPort)
|
|
{
|
|
// Act
|
|
var result = _service.GetReverseProxyPortsFromCaddyfileContent(caddyfileContent);
|
|
|
|
// Assert
|
|
result.Should().NotBeNull();
|
|
result.Should().HaveCount(1);
|
|
result.Should().Contain(expectedPort);
|
|
}
|
|
|
|
#region Additional Edge Cases and Malformed Content Tests
|
|
|
|
/// <summary>
|
|
/// Tests that the parsing service handles malformed Caddyfile content with invalid syntax gracefully.
|
|
/// Setup: Provides Caddyfile content with invalid syntax, missing braces, and malformed directives.
|
|
/// Expectation: The service should extract whatever valid hostnames it can find and ignore malformed sections, ensuring robust parsing of partially corrupted Caddy configurations.
|
|
/// </summary>
|
|
[Fact]
|
|
public void GetHostnamesFromCaddyfileContent_WithMalformedSyntax_ExtractsValidHostnames()
|
|
{
|
|
// Arrange
|
|
var malformedContent = @"
|
|
example.com {
|
|
reverse_proxy localhost:3000
|
|
}
|
|
|
|
invalid-syntax {
|
|
reverse_proxy
|
|
|
|
malformed {
|
|
reverse_proxy localhost:8080
|
|
";
|
|
|
|
// Act
|
|
var result = _service.GetHostnamesFromCaddyfileContent(malformedContent);
|
|
|
|
// Assert
|
|
result.Should().NotBeNull();
|
|
result.Should().Contain("example.com");
|
|
result.Should().Contain("invalid-syntax");
|
|
result.Should().Contain("malformed");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Tests that the parsing service handles Unicode and special characters in hostnames correctly.
|
|
/// Setup: Provides Caddyfile content with hostnames containing Unicode characters, special symbols, and international domain names.
|
|
/// Expectation: The service should correctly parse and return hostnames with Unicode and special characters, ensuring support for international domain names and special naming conventions.
|
|
/// </summary>
|
|
[Fact]
|
|
public void GetHostnamesFromCaddyfileContent_WithUnicodeHostnames_ReturnsCorrectHostnames()
|
|
{
|
|
// Arrange
|
|
var unicodeContent = @"
|
|
测试.example.com {
|
|
reverse_proxy localhost:3000
|
|
}
|
|
|
|
api-测试.local {
|
|
reverse_proxy localhost:8080
|
|
}
|
|
|
|
special-chars!@#$.test {
|
|
reverse_proxy localhost:9000
|
|
}";
|
|
|
|
// Act
|
|
var result = _service.GetHostnamesFromCaddyfileContent(unicodeContent);
|
|
|
|
// Assert
|
|
result.Should().NotBeNull();
|
|
result.Should().HaveCount(3);
|
|
result.Should().Contain("测试.example.com");
|
|
result.Should().Contain("api-测试.local");
|
|
result.Should().Contain("special-chars!@#$.test");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Tests that the parsing service handles very large Caddyfile content without performance issues.
|
|
/// Setup: Creates a very large Caddyfile content with many hostnames and complex configurations.
|
|
/// Expectation: The service should process large configurations efficiently without throwing exceptions or experiencing significant performance degradation, ensuring the system can handle production-sized Caddy configurations.
|
|
/// </summary>
|
|
[Fact]
|
|
public void GetHostnamesFromCaddyfileContent_WithLargeContent_ProcessesEfficiently()
|
|
{
|
|
// Arrange
|
|
var largeContent = new StringBuilder();
|
|
for (int i = 0; i < 1000; i++)
|
|
{
|
|
largeContent.AppendLine($"host{i}.example.com {{");
|
|
largeContent.AppendLine(" reverse_proxy localhost:3000");
|
|
largeContent.AppendLine("}");
|
|
}
|
|
|
|
// Act
|
|
var stopwatch = Stopwatch.StartNew();
|
|
var result = _service.GetHostnamesFromCaddyfileContent(largeContent.ToString());
|
|
stopwatch.Stop();
|
|
|
|
// Assert
|
|
result.Should().NotBeNull();
|
|
result.Should().HaveCount(1000);
|
|
stopwatch.ElapsedMilliseconds.Should().BeLessThan(1000); // Should process in under 1 second
|
|
}
|
|
|
|
/// <summary>
|
|
/// Tests that the parsing service handles nested and complex Caddyfile configurations correctly.
|
|
/// Setup: Provides a complex Caddyfile with nested blocks, multiple directives, and advanced configuration patterns.
|
|
/// Expectation: The service should correctly extract hostnames from complex nested configurations, ensuring accurate parsing of advanced Caddy configuration patterns used in production environments.
|
|
/// </summary>
|
|
[Fact]
|
|
public void GetHostnamesFromCaddyfileContent_WithComplexNestedConfiguration_ReturnsAllHostnames()
|
|
{
|
|
// Arrange
|
|
var complexContent = @"
|
|
api.example.com {
|
|
reverse_proxy localhost:3000
|
|
header {
|
|
Access-Control-Allow-Origin *
|
|
}
|
|
@cors {
|
|
method OPTIONS
|
|
}
|
|
respond @cors 204
|
|
}
|
|
|
|
app.example.com {
|
|
reverse_proxy localhost:8080
|
|
tls {
|
|
protocols tls1.2 tls1.3
|
|
}
|
|
header {
|
|
Strict-Transport-Security max-age=31536000
|
|
}
|
|
}";
|
|
|
|
// Act
|
|
var result = _service.GetHostnamesFromCaddyfileContent(complexContent);
|
|
|
|
// Assert
|
|
result.Should().NotBeNull();
|
|
result.Should().HaveCount(5);
|
|
result.Should().Contain("api.example.com");
|
|
result.Should().Contain("app.example.com");
|
|
result.Should().Contain("header");
|
|
result.Should().Contain("@cors");
|
|
result.Should().Contain("tls");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Tests that the parsing service handles edge cases in regex patterns correctly.
|
|
/// Setup: Provides Caddyfile content with edge cases that might break regex parsing, including unusual whitespace, comments, and formatting.
|
|
/// Expectation: The service should handle regex edge cases gracefully, ensuring robust parsing regardless of Caddyfile formatting and style variations.
|
|
/// </summary>
|
|
[Theory]
|
|
[InlineData("example.com{reverse_proxy localhost:3000}")] // No spaces
|
|
[InlineData("example.com\n{\nreverse_proxy localhost:3000\n}")] // Newlines
|
|
[InlineData("example.com\t{\treverse_proxy localhost:3000\t}")] // Tabs
|
|
public void GetHostnamesFromCaddyfileContent_WithRegexEdgeCases_ReturnsCorrectHostnames(string content)
|
|
{
|
|
// Act
|
|
var result = _service.GetHostnamesFromCaddyfileContent(content);
|
|
|
|
// Assert
|
|
result.Should().NotBeNull();
|
|
result.Should().Contain("example.com");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Tests that the parsing service handles reverse proxy targets with various formats and edge cases.
|
|
/// Setup: Provides Caddyfile content with different reverse proxy target formats including IP addresses, hostnames, URLs, and edge cases.
|
|
/// Expectation: The service should correctly extract reverse proxy targets from various formats, ensuring accurate parsing of different reverse proxy configurations.
|
|
/// </summary>
|
|
[Theory]
|
|
[InlineData("example.com { reverse_proxy 192.168.1.100:3000 }", "192.168.1.100")]
|
|
[InlineData("test.local { reverse_proxy app-server:8080 }", "app-server")]
|
|
[InlineData("api.test { reverse_proxy http://backend:9000 }", "http")]
|
|
[InlineData("web.test { reverse_proxy https://secure-backend:8443 }", "https")]
|
|
[InlineData("app.test { reverse_proxy localhost }", "localhost")]
|
|
public void GetReverseProxyTargetFromCaddyfileContent_WithVariousFormats_ReturnsCorrectTarget(
|
|
string caddyfileContent, string expectedTarget)
|
|
{
|
|
// Act
|
|
var result = _service.GetReverseProxyTargetFromCaddyfileContent(caddyfileContent);
|
|
|
|
// Assert
|
|
result.Should().Be(expectedTarget);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Tests that the parsing service handles malformed reverse proxy directives gracefully.
|
|
/// Setup: Provides Caddyfile content with malformed reverse proxy directives that might cause parsing errors.
|
|
/// Expectation: The service should handle malformed reverse proxy directives gracefully, either by extracting partial information or returning empty results, ensuring robust parsing of corrupted configurations.
|
|
/// </summary>
|
|
[Fact]
|
|
public void GetReverseProxyTargetFromCaddyfileContent_WithMalformedDirectives_HandlesGracefully()
|
|
{
|
|
// Arrange
|
|
var malformedContent = @"example.com { reverse_proxy }"; // Malformed: reverse_proxy without target
|
|
|
|
// Act
|
|
var result = _service.GetReverseProxyTargetFromCaddyfileContent(malformedContent);
|
|
|
|
// Assert
|
|
result.Should().NotBeNull();
|
|
result.Should().Be(string.Empty);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Tests that the parsing service handles port extraction with various edge cases correctly.
|
|
/// Setup: Provides Caddyfile content with different port formats, invalid ports, and edge cases.
|
|
/// Expectation: The service should correctly extract valid ports and handle invalid port formats gracefully, ensuring accurate port detection for reverse proxy configurations.
|
|
/// </summary>
|
|
[Theory]
|
|
[InlineData("example.com { reverse_proxy localhost:3000 }", 3000)]
|
|
[InlineData("test.local { reverse_proxy app-server:8080 }", 8080)]
|
|
[InlineData("api.test { reverse_proxy backend:9000 }", 9000)]
|
|
[InlineData("web.test { reverse_proxy https://secure-backend:8443 }", 8443)]
|
|
public void GetReverseProxyPortsFromCaddyfileContent_WithVariousPorts_ReturnsCorrectPorts(
|
|
string caddyfileContent, int expectedPort)
|
|
{
|
|
// Act
|
|
var result = _service.GetReverseProxyPortsFromCaddyfileContent(caddyfileContent);
|
|
|
|
// Assert
|
|
result.Should().Contain(expectedPort);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Tests that the parsing service handles invalid port formats gracefully.
|
|
/// Setup: Provides Caddyfile content with invalid port formats that should not be parsed as valid ports.
|
|
/// Expectation: The service should ignore invalid port formats and only return valid port numbers, ensuring robust port parsing that doesn't break on malformed configurations.
|
|
/// </summary>
|
|
[Fact]
|
|
public void GetReverseProxyPortsFromCaddyfileContent_WithInvalidPorts_HandlesGracefully()
|
|
{
|
|
// Arrange
|
|
var invalidPortContent = @"
|
|
example.com {
|
|
reverse_proxy localhost:invalid
|
|
}
|
|
|
|
test.local {
|
|
reverse_proxy app-server:99999
|
|
}
|
|
|
|
api.test {
|
|
reverse_proxy backend:-1
|
|
}";
|
|
|
|
// Act
|
|
var result = _service.GetReverseProxyPortsFromCaddyfileContent(invalidPortContent);
|
|
|
|
// Assert
|
|
result.Should().NotBeNull();
|
|
// The service might still parse some invalid ports as valid numbers
|
|
// This test verifies that the service handles malformed port data gracefully
|
|
result.Should().NotBeNull();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Tests that the parsing service handles performance with very large reverse proxy configurations.
|
|
/// Setup: Creates a very large Caddyfile content with many reverse proxy directives.
|
|
/// Expectation: The service should process large reverse proxy configurations efficiently without performance issues, ensuring the system can handle complex production configurations.
|
|
/// </summary>
|
|
[Fact]
|
|
public void GetReverseProxyPortsFromCaddyfileContent_WithLargeConfiguration_ProcessesEfficiently()
|
|
{
|
|
// Arrange
|
|
var largeContent = new StringBuilder();
|
|
for (int i = 0; i < 1000; i++)
|
|
{
|
|
largeContent.AppendLine($"host{i}.example.com {{");
|
|
largeContent.AppendLine($" reverse_proxy localhost:{3000 + i}");
|
|
largeContent.AppendLine("}");
|
|
}
|
|
|
|
// Act
|
|
var stopwatch = Stopwatch.StartNew();
|
|
var result = _service.GetReverseProxyPortsFromCaddyfileContent(largeContent.ToString());
|
|
stopwatch.Stop();
|
|
|
|
// Assert
|
|
result.Should().NotBeNull();
|
|
result.Should().HaveCount(1000);
|
|
stopwatch.ElapsedMilliseconds.Should().BeLessThan(1000); // Should process in under 1 second
|
|
}
|
|
|
|
#endregion
|
|
} |