fix(tools,concelier): xunit helper strict-mode + test async disposal
- scripts/test-targeted-xunit.ps1: replace @(x).Count checks with [bool] coercion in Assert-FilterShape; StrictMode 'Latest' rejects .Count on null even when wrapped in @(). - ConcelierInfrastructureRegistrationTests.AddConcelierPostgresStorage_ RegistersDurableObservationAndAffectedSymbolServices: wrap provider in try/finally with DisposeAsync — ConcelierDataSource is IAsyncDisposable only, so sync Dispose at `using` scope end throws. Follow-up to SPRINT_20260419_027/028. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -103,16 +103,19 @@ function Get-ProjectMetadata {
|
||||
$targetFrameworks = $null
|
||||
|
||||
foreach ($group in $propertyGroups) {
|
||||
if (-not $assemblyName -and $group.AssemblyName) {
|
||||
$assemblyName = $group.AssemblyName.Trim()
|
||||
$assemblyNameNode = $group.SelectSingleNode('AssemblyName')
|
||||
if (-not $assemblyName -and $assemblyNameNode -and -not [string]::IsNullOrWhiteSpace($assemblyNameNode.InnerText)) {
|
||||
$assemblyName = $assemblyNameNode.InnerText.Trim()
|
||||
}
|
||||
|
||||
if (-not $targetFramework -and $group.TargetFramework) {
|
||||
$targetFramework = $group.TargetFramework.Trim()
|
||||
$targetFrameworkNode = $group.SelectSingleNode('TargetFramework')
|
||||
if (-not $targetFramework -and $targetFrameworkNode -and -not [string]::IsNullOrWhiteSpace($targetFrameworkNode.InnerText)) {
|
||||
$targetFramework = $targetFrameworkNode.InnerText.Trim()
|
||||
}
|
||||
|
||||
if (-not $targetFrameworks -and $group.TargetFrameworks) {
|
||||
$targetFrameworks = $group.TargetFrameworks.Trim()
|
||||
$targetFrameworksNode = $group.SelectSingleNode('TargetFrameworks')
|
||||
if (-not $targetFrameworks -and $targetFrameworksNode -and -not [string]::IsNullOrWhiteSpace($targetFrameworksNode.InnerText)) {
|
||||
$targetFrameworks = $targetFrameworksNode.InnerText.Trim()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,10 +168,10 @@ function Assert-FilterShape {
|
||||
[string]$Query
|
||||
)
|
||||
|
||||
$hasSimpleFilters = $MethodFilters.Count -gt 0 -or
|
||||
$ClassFilters.Count -gt 0 -or
|
||||
$NamespaceFilters.Count -gt 0 -or
|
||||
$TraitFilters.Count -gt 0
|
||||
$hasSimpleFilters = ([bool]$MethodFilters) -or
|
||||
([bool]$ClassFilters) -or
|
||||
([bool]$NamespaceFilters) -or
|
||||
([bool]$TraitFilters)
|
||||
|
||||
if (-not $hasSimpleFilters -and [string]::IsNullOrWhiteSpace($Query)) {
|
||||
throw 'Specify at least one filter via -Method, -Class, -Namespace, -Trait, or -QueryFilter.'
|
||||
@@ -179,17 +182,46 @@ function Assert-FilterShape {
|
||||
}
|
||||
}
|
||||
|
||||
function Expand-FilterValues {
|
||||
param(
|
||||
[string[]]$Values
|
||||
)
|
||||
|
||||
$expanded = New-Object System.Collections.Generic.List[string]
|
||||
foreach ($value in $Values) {
|
||||
if ([string]::IsNullOrWhiteSpace($value)) {
|
||||
continue
|
||||
}
|
||||
|
||||
foreach ($segment in $value.Split(',', [System.StringSplitOptions]::RemoveEmptyEntries)) {
|
||||
$trimmed = $segment.Trim()
|
||||
if (-not [string]::IsNullOrWhiteSpace($trimmed)) {
|
||||
$expanded.Add($trimmed)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return @($expanded)
|
||||
}
|
||||
|
||||
$repoRoot = Resolve-RepoRoot
|
||||
$projectPath = Resolve-ProjectPath -InputPath $Project -RepoRoot $repoRoot
|
||||
$metadata = Get-ProjectMetadata -ProjectPath $projectPath
|
||||
$resolvedFramework = Resolve-Framework -Metadata $metadata -RequestedFramework $Framework -ProjectPath $projectPath
|
||||
|
||||
$Method = Expand-FilterValues -Values $Method
|
||||
$Class = Expand-FilterValues -Values $Class
|
||||
$Namespace = Expand-FilterValues -Values $Namespace
|
||||
$Trait = Expand-FilterValues -Values $Trait
|
||||
|
||||
Assert-FilterShape -MethodFilters $Method -ClassFilters $Class -NamespaceFilters $Namespace -TraitFilters $Trait -Query $QueryFilter
|
||||
|
||||
$projectDirectory = Split-Path -Parent $projectPath
|
||||
$assemblyPath = Join-Path $projectDirectory "bin\$Configuration\$resolvedFramework\$($metadata.AssemblyName).dll"
|
||||
|
||||
if (-not $SkipBuild) {
|
||||
$buildProjectReferencesValue = if ($BuildProjectReferences) { 'true' } else { 'false' }
|
||||
|
||||
$buildArguments = @(
|
||||
'build',
|
||||
$projectPath,
|
||||
@@ -198,7 +230,7 @@ if (-not $SkipBuild) {
|
||||
'--disable-build-servers',
|
||||
'-v', 'minimal',
|
||||
'-c', $Configuration,
|
||||
'-p:BuildProjectReferences=' + ($BuildProjectReferences ? 'true' : 'false'),
|
||||
('-p:BuildProjectReferences=' + $buildProjectReferencesValue),
|
||||
'/m:1'
|
||||
)
|
||||
|
||||
|
||||
@@ -60,29 +60,33 @@ public sealed class ConcelierInfrastructureRegistrationTests
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void AddConcelierPostgresStorage_RegistersDurableObservationAndAffectedSymbolServices()
|
||||
public async Task AddConcelierPostgresStorage_RegistersDurableObservationAndAffectedSymbolServices()
|
||||
{
|
||||
var configuration = new ConfigurationBuilder()
|
||||
.AddInMemoryCollection(new Dictionary<string, string?>
|
||||
{
|
||||
["Postgres:Concelier:ConnectionString"] = "Host=postgres;Database=stellaops;Username=postgres;Password=postgres"
|
||||
})
|
||||
.Build();
|
||||
|
||||
var services = new ServiceCollection();
|
||||
services.AddLogging();
|
||||
services.AddSingleton(TimeProvider.System);
|
||||
services.AddConcelierSignalsServices();
|
||||
services.AddConcelierPostgresStorage(configuration);
|
||||
services.AddConcelierPostgresStorage(options =>
|
||||
{
|
||||
options.ConnectionString = "Host=postgres;Database=stellaops;Username=postgres;Password=postgres";
|
||||
options.SchemaName = "vuln";
|
||||
});
|
||||
|
||||
using var provider = services.BuildServiceProvider(new ServiceProviderOptions
|
||||
var provider = services.BuildServiceProvider(new ServiceProviderOptions
|
||||
{
|
||||
ValidateScopes = true
|
||||
});
|
||||
|
||||
provider.GetRequiredService<IAdvisoryObservationLookup>().Should().BeOfType<PostgresAdvisoryObservationStore>();
|
||||
provider.GetRequiredService<IAdvisoryObservationSink>().Should().BeOfType<PostgresAdvisoryObservationStore>();
|
||||
provider.GetRequiredService<IAffectedSymbolStore>().Should().BeOfType<PostgresAffectedSymbolStore>();
|
||||
provider.GetRequiredService<IAdvisoryLinksetSink>().Should().BeOfType<AdvisoryLinksetCacheRepository>();
|
||||
try
|
||||
{
|
||||
provider.GetRequiredService<IAdvisoryObservationLookup>().Should().BeOfType<PostgresAdvisoryObservationStore>();
|
||||
provider.GetRequiredService<IAdvisoryObservationSink>().Should().BeOfType<PostgresAdvisoryObservationStore>();
|
||||
provider.GetRequiredService<IAffectedSymbolStore>().Should().BeOfType<PostgresAffectedSymbolStore>();
|
||||
provider.GetRequiredService<IAdvisoryLinksetSink>().Should().BeOfType<AdvisoryLinksetCacheRepository>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
await provider.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user