forked from xiongyuxing/tiku-backend.net
154 lines
6.2 KiB
C#
154 lines
6.2 KiB
C#
namespace Tiku.IntegrationTests;
|
|
|
|
public sealed class ArchitectureBoundaryTests
|
|
{
|
|
[Fact]
|
|
public void Business_code_does_not_bypass_tenant_query_boundaries()
|
|
{
|
|
var root = FindRepositoryRoot();
|
|
var sourceRoots = new[] { "Tiku.Api", "Tiku.Application", "Tiku.Infrastructure" };
|
|
var forbidden = new[]
|
|
{
|
|
"IgnoreQueryFilters(",
|
|
"FromSql(",
|
|
"FromSqlRaw(",
|
|
"FromSqlInterpolated(",
|
|
"ExecuteSql(",
|
|
"ExecuteSqlRaw(",
|
|
"ExecuteSqlInterpolated(",
|
|
"new NpgsqlCommand("
|
|
};
|
|
|
|
var violations = sourceRoots
|
|
.SelectMany(directory => Directory.EnumerateFiles(
|
|
Path.Combine(root, directory),
|
|
"*.cs",
|
|
SearchOption.AllDirectories))
|
|
.Where(path => !path.Contains(
|
|
$"{Path.DirectorySeparatorChar}Persistence{Path.DirectorySeparatorChar}Migrations{Path.DirectorySeparatorChar}",
|
|
StringComparison.Ordinal))
|
|
.SelectMany(path => File.ReadLines(path)
|
|
.Select((line, index) => new { path, line, lineNumber = index + 1 }))
|
|
.Where(candidate => forbidden.Any(symbol =>
|
|
candidate.line.Contains(symbol, StringComparison.Ordinal)))
|
|
.Select(candidate => $"{Path.GetRelativePath(root, candidate.path)}:{candidate.lineNumber}")
|
|
.ToArray();
|
|
|
|
Assert.True(
|
|
violations.Length == 0,
|
|
$"Forbidden tenant-boundary bypasses were found:{Environment.NewLine}{string.Join(Environment.NewLine, violations)}");
|
|
}
|
|
|
|
[Fact]
|
|
public void Business_code_does_not_depend_on_supabase_or_removed_provider_models()
|
|
{
|
|
var root = FindRepositoryRoot();
|
|
var sourceRoots = new[] { "Tiku.Api", "Tiku.Application", "Tiku.Domain", "Tiku.Infrastructure" };
|
|
var forbidden = new[]
|
|
{
|
|
"Supabase",
|
|
"supabase_storage",
|
|
"SUPABASE_",
|
|
"TenantAuthProvider",
|
|
"TenantPaymentAccount",
|
|
"TenantPaymentMode",
|
|
"TenantPaymentAccountStatus",
|
|
"TenantAuthProviderStatus"
|
|
};
|
|
|
|
var allowedPathFragments = new[]
|
|
{
|
|
$"{Path.DirectorySeparatorChar}Persistence{Path.DirectorySeparatorChar}Migrations{Path.DirectorySeparatorChar}"
|
|
};
|
|
|
|
var violations = sourceRoots
|
|
.SelectMany(directory => Directory.EnumerateFiles(
|
|
Path.Combine(root, directory),
|
|
"*.cs",
|
|
SearchOption.AllDirectories))
|
|
.Where(path => !allowedPathFragments.Any(fragment => path.Contains(fragment, StringComparison.Ordinal)))
|
|
.SelectMany(path => File.ReadLines(path)
|
|
.Select((line, index) => new { path, line, lineNumber = index + 1 }))
|
|
.Where(candidate => forbidden.Any(symbol =>
|
|
candidate.line.Contains(symbol, StringComparison.Ordinal)))
|
|
.Select(candidate => $"{Path.GetRelativePath(root, candidate.path)}:{candidate.lineNumber}")
|
|
.ToArray();
|
|
|
|
Assert.True(
|
|
violations.Length == 0,
|
|
$"Forbidden external-provider coupling was found:{Environment.NewLine}{string.Join(Environment.NewLine, violations)}");
|
|
}
|
|
|
|
[Fact]
|
|
public void Production_code_does_not_reference_removed_wechat_payment_sdk()
|
|
{
|
|
var root = FindRepositoryRoot();
|
|
var sourceRoots = new[] { "Tiku.Api", "Tiku.Application", "Tiku.Domain", "Tiku.Infrastructure", "Tiku.Worker" };
|
|
var forbidden = new[]
|
|
{
|
|
"SKIT.FlurlHttpClient.Wechat"
|
|
};
|
|
|
|
var violations = sourceRoots
|
|
.SelectMany(directory => Directory.EnumerateFiles(
|
|
Path.Combine(root, directory),
|
|
"*.cs",
|
|
SearchOption.AllDirectories))
|
|
.Where(path => !path.Contains(
|
|
$"{Path.DirectorySeparatorChar}Persistence{Path.DirectorySeparatorChar}Migrations{Path.DirectorySeparatorChar}",
|
|
StringComparison.Ordinal))
|
|
.SelectMany(path => File.ReadLines(path)
|
|
.Select((line, index) => new { path, line, lineNumber = index + 1 }))
|
|
.Where(candidate => forbidden.Any(symbol =>
|
|
candidate.line.Contains(symbol, StringComparison.Ordinal)))
|
|
.Select(candidate => $"{Path.GetRelativePath(root, candidate.path)}:{candidate.lineNumber}")
|
|
.ToArray();
|
|
|
|
Assert.True(
|
|
violations.Length == 0,
|
|
$"Removed WeChat payment SDK references were found:{Environment.NewLine}{string.Join(Environment.NewLine, violations)}");
|
|
}
|
|
|
|
[Fact]
|
|
public void Business_layers_do_not_reference_third_party_provider_sdks()
|
|
{
|
|
var root = FindRepositoryRoot();
|
|
var sourceRoots = new[] { "Tiku.Api", "Tiku.Application", "Tiku.Domain" };
|
|
var forbidden = new[]
|
|
{
|
|
"AlibabaCloud.",
|
|
"Aliyun.OSS",
|
|
"Senparc.Weixin",
|
|
"AlipaySDKNet",
|
|
"Aop.Api"
|
|
};
|
|
|
|
var violations = sourceRoots
|
|
.SelectMany(directory => Directory.EnumerateFiles(
|
|
Path.Combine(root, directory),
|
|
"*.cs",
|
|
SearchOption.AllDirectories))
|
|
.SelectMany(path => File.ReadLines(path)
|
|
.Select((line, index) => new { path, line, lineNumber = index + 1 }))
|
|
.Where(candidate => forbidden.Any(symbol =>
|
|
candidate.line.Contains(symbol, StringComparison.Ordinal)))
|
|
.Select(candidate => $"{Path.GetRelativePath(root, candidate.path)}:{candidate.lineNumber}")
|
|
.ToArray();
|
|
|
|
Assert.True(
|
|
violations.Length == 0,
|
|
$"Business-layer third-party provider SDK references were found:{Environment.NewLine}{string.Join(Environment.NewLine, violations)}");
|
|
}
|
|
|
|
private static string FindRepositoryRoot()
|
|
{
|
|
var directory = new DirectoryInfo(AppContext.BaseDirectory);
|
|
while (directory is not null && !File.Exists(Path.Combine(directory.FullName, "TIKU-BACKEND.slnx")))
|
|
{
|
|
directory = directory.Parent;
|
|
}
|
|
|
|
return directory?.FullName ?? throw new DirectoryNotFoundException("Repository root was not found.");
|
|
}
|
|
}
|