Skip to content

Commit 7ee79b3

Browse files
committed
TASK-039-007: Split TurboHttp.Tests/Security/
1 parent ca5e3d3 commit 7ee79b3

23 files changed

Lines changed: 1611 additions & 1468 deletions

.maggus/COMMIT.md

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,23 @@
1-
# TASK-038-001: Fix RedirectBidiStageTransaction Guard + _inFlightCount Decrement
1+
# TASK-039-007: Split TurboHttp.Tests/Security/All Files ≤500 Lines
22

3-
Added `_redirectTransactionActive` guard to `RedirectBidiStage` and corrected `_inFlightCount`
4-
decrement ordering across redirect hops so that `TryCompleteIfDone` Case 2 fires reliably.
3+
Split 5 oversized Security test files into companion files so every file in
4+
`src/TurboHttp.Tests/Security/` is ≤500 lines. No `NN_` prefix added (Security/
5+
folder convention unchanged).
56

6-
- Added `_redirectTransactionActive` bool field to `Logic` (mirrors `RetryBidiStage` pattern)
7-
- Redirect path in `onPush(InResponse)` now uses atomic transaction:
8-
enqueue → TryEmitRedirect → `_inFlightCount--` → TryPullResponse → guard off → TryCompleteIfDone
9-
- `TryCompleteIfDone()` returns early when `_redirectTransactionActive == true`, preventing
10-
premature Out1 completion mid-redirect transaction
11-
- Catch blocks for `ProtocolDowngrade` and `MaxRedirects` do NOT set the guard (non-redirect paths)
12-
- Added `BidiFlowFeedbackRaceTests.cs` with 4 regression tests (BidiLoop-001 through BidiLoop-004)
7+
**Trimmed originals:**
8+
- `HpackBombTests.cs` 852 → 500 lines (QPACK + cross-cutting section extracted)
9+
- `Http11FuzzTests.cs` 669 → 410 lines (Categories 6–9 extracted)
10+
- `Http2FrameFuzzTests.cs` 593 → 378 lines (Categories 7–10 extracted)
11+
- `TlsSecurityTests.cs` 526 → 275 lines (sensitive header + TLS options section extracted)
12+
- `UriSecurityTests.cs` 514 → 359 lines (Sections 7–11 extracted)
13+
14+
**New companion files:**
15+
- `QpackSecurityTests.cs` (374 lines) — SEC-QPACK-001..013 + SEC-HPACK-019..022
16+
- `Http11FuzzBodyTests.cs` (369 lines) — RFC9112-FUZZ-MIX-001, LCL-001, CCL-001, FRG-001
17+
- `Http2FrameFuzzTests2.cs` (280 lines) — RFC9113-FUZZ-OVS-001, ALT-001, SET-001, WUZ-001
18+
- `TlsOptionsTests.cs` (273 lines) — SEC-TLS-018..032
19+
- `UriRedirectTests.cs` (195 lines) — SEC-URI-019..026
1320

1421
Verified:
1522
- Build: 0 errors, 0 warnings
16-
- Stream tests: 835/835 pass (BidiLoop-001..004 all green)
17-
- Roslyn get_diagnostics on RedirectBidiStage.cs: 0 errors
23+
- Security tests: 325/325 pass

.maggus/features/feature_039.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -347,11 +347,11 @@ rmdir src/TurboHttp.Tests/Configuration
347347
Note: Security/ has NO `NN_` prefix convention. New file names use descriptive names only.
348348

349349
**Acceptance Criteria:**
350-
- [ ] All files in `src/TurboHttp.Tests/Security/` are ≤ 500 lines
351-
- [ ] No `NN_` prefix added (Security/ folder convention unchanged)
352-
- [ ] `dotnet build --configuration Release ./src/TurboHttp.sln` succeeds
353-
- [ ] `dotnet test --project src/TurboHttp.Tests/TurboHttp.Tests.csproj -- --filter-namespace "TurboHttp.Tests.Security"` passes
354-
- [ ] Unit tests are written and successful
350+
- [x] All files in `src/TurboHttp.Tests/Security/` are ≤ 500 lines
351+
- [x] No `NN_` prefix added (Security/ folder convention unchanged)
352+
- [x] `dotnet build --configuration Release ./src/TurboHttp.sln` succeeds
353+
- [x] `dotnet test --project src/TurboHttp.Tests/TurboHttp.Tests.csproj -- --filter-namespace "TurboHttp.Tests.Security"` passes
354+
- [x] Unit tests are written and successful
355355

356356
---
357357

src/TurboHttp.Benchmarks/HttpClientComparativeBenchmarks.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using BenchmarkDotNet.Attributes;
2+
using TurboHttp.Benchmarks.Internal;
23

34
namespace TurboHttp.Benchmarks;
45

src/TurboHttp.Benchmarks/BenchmarkBaseClass.cs renamed to src/TurboHttp.Benchmarks/Internal/BenchmarkBaseClass.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
using BenchmarkDotNet.Attributes;
22

3-
namespace TurboHttp.Benchmarks;
3+
namespace TurboHttp.Benchmarks.Internal;
44

55
/// <summary>
66
/// Shared base class for all comparative benchmarks. Provides common
@@ -13,7 +13,7 @@ public abstract class BenchmarkBaseClass
1313
{
1414
/// <summary>Static shared Kestrel server instance, initialized once per test run.</summary>
1515
private static BenchmarkServer? _sharedServer;
16-
private static readonly object _serverLock = new();
16+
private static readonly Lock _serverLock = new();
1717
private static int _serverRefCount;
1818

1919
/// <summary>Number of concurrent requests to issue per benchmark iteration.</summary>

src/TurboHttp.Benchmarks/BenchmarkComparisonReport.cs renamed to src/TurboHttp.Benchmarks/Internal/BenchmarkComparisonReport.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
using System.Text;
22

3-
namespace TurboHttp.Benchmarks;
3+
namespace TurboHttp.Benchmarks.Internal;
44

55
/// <summary>
66
/// Represents the measured result of a single benchmark scenario.

src/TurboHttp.Benchmarks/BenchmarkServer.cs renamed to src/TurboHttp.Benchmarks/Internal/BenchmarkServer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
using Microsoft.Extensions.DependencyInjection;
88
using Microsoft.Extensions.Logging;
99

10-
namespace TurboHttp.Benchmarks;
10+
namespace TurboHttp.Benchmarks.Internal;
1111

1212
/// <summary>
1313
/// Minimal Kestrel test server for benchmarking both HttpClient and TurboHttp.

src/TurboHttp.Benchmarks/Config.cs renamed to src/TurboHttp.Benchmarks/Internal/Config.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
using BenchmarkDotNet.Reports;
66
using BenchmarkDotNet.Running;
77

8-
namespace TurboHttp.Benchmarks;
8+
namespace TurboHttp.Benchmarks.Internal;
99

1010
public class RequestsPerSecondColumn : IColumn
1111
{
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
using BenchmarkDotNet.Reports;
2+
using BenchmarkDotNet.Running;
3+
4+
namespace TurboHttp.Benchmarks.Internal;
5+
6+
/// <summary>
7+
/// Extracts <see cref="BenchmarkResult"/> instances directly from a BenchmarkDotNet
8+
/// <see cref="Summary"/>, bypassing the CSV artifact round-trip.
9+
/// </summary>
10+
public static class SummaryExtractor
11+
{
12+
/// <summary>
13+
/// Converts all completed reports in <paramref name="summary"/> to
14+
/// <see cref="BenchmarkResult"/> instances. Reports with missing statistics
15+
/// (cancelled or errored runs) are silently skipped.
16+
/// </summary>
17+
public static IReadOnlyList<BenchmarkResult> Extract(Summary summary)
18+
{
19+
var results = new List<BenchmarkResult>(summary.Reports.Length);
20+
21+
foreach (var report in summary.Reports)
22+
{
23+
var statistics = report.ResultStatistics;
24+
if (statistics is null)
25+
{
26+
continue;
27+
}
28+
29+
var name = BuildName(report.BenchmarkCase);
30+
var allocBytes = report.GcStats.GetBytesAllocatedPerOperation(report.BenchmarkCase) ?? 0L;
31+
32+
results.Add(new BenchmarkResult(
33+
name,
34+
statistics.Mean,
35+
statistics.Percentiles.P50,
36+
statistics.Percentiles.P95,
37+
statistics.Percentiles.Percentile(99),
38+
allocBytes));
39+
}
40+
41+
return results;
42+
}
43+
44+
/// <summary>
45+
/// Builds a scenario name matching the format used by the CSV-based pipeline:
46+
/// <c>{Method} / CL={ConcurrencyLevel} / {PayloadType} / HTTP {HttpVersion}</c>.
47+
/// </summary>
48+
private static string BuildName(BenchmarkCase benchmarkCase)
49+
{
50+
var method = benchmarkCase.Descriptor.WorkloadMethod.Name;
51+
var concurrency = GetParam(benchmarkCase, "ConcurrencyLevel") ?? "1";
52+
var payload = GetParam(benchmarkCase, "PayloadType") ?? "light";
53+
var version = GetParam(benchmarkCase, "HttpVersion") ?? "1.1";
54+
55+
return $"{method} / CL={concurrency} / {payload} / HTTP {version}";
56+
}
57+
58+
private static string? GetParam(BenchmarkCase benchmarkCase, string paramName)
59+
=> benchmarkCase.Parameters.Items
60+
.FirstOrDefault(p => p.Name == paramName)
61+
?.Value?.ToString();
62+
}
63+
64+
/// <summary>
65+
/// Extension helpers for <see cref="Summary"/>.
66+
/// </summary>
67+
public static class SummaryExtensions
68+
{
69+
/// <summary>
70+
/// Returns <see langword="true"/> when <paramref name="summary"/> contains at least
71+
/// one benchmark case belonging to <typeparamref name="T"/>.
72+
/// </summary>
73+
public static bool HasBenchmarksOf<T>(this Summary summary)
74+
=> summary.BenchmarksCases.Any(c => c.Descriptor.Type == typeof(T));
75+
}

0 commit comments

Comments
 (0)