feat: Complete AEG-X-003 and verify AEG-X-004 readiness
AEG-X-003: Architecture Tests (COMPLETED) ✅ Added 6th rule: No duplicate aggregate IDs across modules ✅ All 6 architecture tests PASS: 1. No prohibited source patterns (IGenericRepository, DateTime.Now, etc.) 2. Domain isolation from infrastructure (no Dapper, Npgsql, FastEndpoints) 3. SQL validation (no SELECT *, schema-qualified tables) 4. Endpoint authorization (Roles or Policies required) 5. No placeholder files (testfile, *.tmp) 6. No duplicate aggregate IDs (new) Acceptance_Evidence: Domain 기술의존 0, 모듈 직접 DB 접근 0, ID 중복 0 ✅ AEG-X-004: DbUp Recovery Rehearsal (Ready for DB Testing) - Tests located: tests/KArtSell.Integration.Tests/DbUpMigrationTests.cs (570L) - Covers 4 scenarios: Fresh install, Upgrade, Re-run, Failure recovery - Infrastructure: Requires PostgreSQL + SSH tunnel for execution - Evidence collection: Requires active DB connection (pending) Phase 1 Progress: - AEG-X-001: ✅ COMPLETED (VERSION_COVERAGE_MATRIX.md) - AEG-X-002: ✅ COMPLETED (CI.yml formalized) - AEG-X-003: ✅ COMPLETED (6 architecture tests PASS) - AEG-X-004: 📋 READY FOR DB TESTING (test structure exists) - AEG-X-005: 📋 PLANNED (next in sequence) Cumulative Status: 3/5 = 60% Phase 1 complete (3h/15h estimated) Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -107,6 +107,49 @@ public sealed class RepositoryRulesTests
|
||||
"Placeholder files are prohibited: " + string.Join(", ", names));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Aggregate_ids_are_unique_across_modules()
|
||||
{
|
||||
var root = FindRepositoryRoot();
|
||||
var aggregateIdFiles = Directory.EnumerateFiles(
|
||||
Path.Combine(root, "src"),
|
||||
"*.cs",
|
||||
SearchOption.AllDirectories)
|
||||
.Where(path => !IsGeneratedOrTestOutput(path))
|
||||
.ToArray();
|
||||
|
||||
var aggregateIds = new Dictionary<string, List<string>>();
|
||||
|
||||
foreach (var file in aggregateIdFiles)
|
||||
{
|
||||
var text = File.ReadAllText(file);
|
||||
|
||||
// Match aggregate ID definitions: Guid("00000000-0000-0000-0000-...")
|
||||
var pattern = @"Guid\(\""[a-f0-9\-]{36}\""";
|
||||
var matches = System.Text.RegularExpressions.Regex.Matches(text, pattern);
|
||||
|
||||
foreach (System.Text.RegularExpressions.Match match in matches)
|
||||
{
|
||||
var id = match.Value;
|
||||
if (!aggregateIds.TryGetValue(id, out var list))
|
||||
{
|
||||
list = new List<string>();
|
||||
aggregateIds[id] = list;
|
||||
}
|
||||
list.Add(file);
|
||||
}
|
||||
}
|
||||
|
||||
var duplicates = aggregateIds
|
||||
.Where(kvp => kvp.Value.Count > 1)
|
||||
.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
|
||||
|
||||
Assert.True(duplicates.Count == 0,
|
||||
duplicates.Count > 0
|
||||
? $"Duplicate aggregate IDs detected: {string.Join("; ", duplicates.Select(d => $"{d.Key} in {string.Join(", ", d.Value)}"))}"
|
||||
: "No duplicate aggregate IDs found.");
|
||||
}
|
||||
|
||||
private static void AssertNoPattern(IEnumerable<string> files, string pattern, string message)
|
||||
{
|
||||
var violations = files
|
||||
|
||||
Reference in New Issue
Block a user