From 24f76f8572b0217367adb45023b846de0d89d375 Mon Sep 17 00:00:00 2001 From: Duy Dao Date: Wed, 23 Jul 2025 15:29:00 +0700 Subject: [PATCH] refactor: update Blazor testing guidelines and improve regex for hostname parsing in Caddy configuration --- .cursor/rules/blazor-development.mdc | 2 +- .../Caddy/CaddyConfigurationParsingService.cs | 8 ++-- .../CaddyConfigurationParsingServiceTests.cs | 40 +++++++++++++++---- 3 files changed, 39 insertions(+), 11 deletions(-) diff --git a/.cursor/rules/blazor-development.mdc b/.cursor/rules/blazor-development.mdc index 9868785..7cbcc29 100644 --- a/.cursor/rules/blazor-development.mdc +++ b/.cursor/rules/blazor-development.mdc @@ -32,7 +32,7 @@ alwaysApply: true ## Testing and Debugging - All unit testing and integration testing should be done in Cursor ide -- Test Blazor components and services using xUnit +- Test services, unit and integration, using xUnit - Use Moq for mocking dependencies during tests - Debug Blazor UI issues using browser developer tools and Cursor ide's debugging tools for backend and server-side issues - For performance profiling and optimization, rely on Cursor ide's diagnostics tools \ No newline at end of file diff --git a/CaddyManager.Services/Caddy/CaddyConfigurationParsingService.cs b/CaddyManager.Services/Caddy/CaddyConfigurationParsingService.cs index 542eb0b..a4cf8fc 100644 --- a/CaddyManager.Services/Caddy/CaddyConfigurationParsingService.cs +++ b/CaddyManager.Services/Caddy/CaddyConfigurationParsingService.cs @@ -8,9 +8,11 @@ public partial class CaddyConfigurationParsingService: ICaddyConfigurationParsin { /// /// Regex to help parse hostnames from a Caddyfile. + /// This regex only matches hostname declarations at the beginning of lines (column 1 after optional whitespace) + /// and excludes nested directives like "reverse_proxy target {". /// /// - [GeneratedRegex(@"(?m)^\s*([^\{\r\n]+?)\s*\{", RegexOptions.Multiline)] + [GeneratedRegex(@"(?m)^([^\s\{\r\n][^\{\r\n]*?)\s*\{", RegexOptions.Multiline)] private static partial Regex HostnamesRegex(); /// @@ -67,8 +69,8 @@ public partial class CaddyConfigurationParsingService: ICaddyConfigurationParsin foreach (Match match in matches) { - var parts = match.Value.TrimEnd('}').Trim().Split(' '); - var targetPart = parts.LastOrDefault(string.Empty); + // Use the captured group which contains the target (e.g., pikachu:3011) + var targetPart = match.Groups[1].Value.Trim(); if (string.IsNullOrEmpty(targetPart)) continue; var targetComponents = targetPart.Split(':'); diff --git a/CaddyManager.Tests/Services/Caddy/CaddyConfigurationParsingServiceTests.cs b/CaddyManager.Tests/Services/Caddy/CaddyConfigurationParsingServiceTests.cs index b7c2938..f997a8d 100644 --- a/CaddyManager.Tests/Services/Caddy/CaddyConfigurationParsingServiceTests.cs +++ b/CaddyManager.Tests/Services/Caddy/CaddyConfigurationParsingServiceTests.cs @@ -74,11 +74,9 @@ public class CaddyConfigurationParsingServiceTests // Assert result.Should().NotBeNull(); - result.Should().HaveCount(4); // Updated to reflect correct parsing of labels before blocks + result.Should().HaveCount(2); // Should only return outermost hostname declarations result.Should().Contain("api.example.com"); result.Should().Contain("app.example.com"); - result.Should().Contain("route /v1/*"); - result.Should().Contain("route /v2/*"); } /// @@ -522,12 +520,9 @@ app.example.com { // Assert result.Should().NotBeNull(); - result.Should().HaveCount(5); + result.Should().HaveCount(2); // Should only return outermost hostname declarations result.Should().Contain("api.example.com"); result.Should().Contain("app.example.com"); - result.Should().Contain("header"); - result.Should().Contain("@cors"); - result.Should().Contain("tls"); } /// @@ -669,5 +664,36 @@ api.test { stopwatch.ElapsedMilliseconds.Should().BeLessThan(1000); // Should process in under 1 second } + /// + /// Tests the parsing issue where the provided configuration is incorrectly parsed as 2 sites and 0 ports + /// instead of 1 site and 1 port. + /// + [Fact] + public void GetHostnamesAndPortsFromCaddyfileContent_WithProvidedConfiguration_ReturnsCorrectSiteAndPort() + { + // Arrange + var caddyfileContent = @"pika-auth.duydao.org { + reverse_proxy pikachu:3011 { + header_down X-Frame-Options """" + } + encode zstd gzip +}"; + + // Act + var hostnames = _service.GetHostnamesFromCaddyfileContent(caddyfileContent); + var ports = _service.GetReverseProxyPortsFromCaddyfileContent(caddyfileContent); + + // Assert - Should have 1 site and 1 port + hostnames.Should().NotBeNull(); + hostnames.Should().HaveCount(1); + hostnames.Should().Contain("pika-auth.duydao.org"); + + ports.Should().NotBeNull(); + ports.Should().HaveCount(1); + ports.Should().Contain(3011); + } + + + #endregion } \ No newline at end of file