consolidation of some of the modules, localization fixes, product advisories work, qa work
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
# Excititor Plugin Tests Charter
|
||||
|
||||
## Mission
|
||||
Validate plugin catalog behavior and VEX connector registration with deterministic tests.
|
||||
|
||||
## Responsibilities
|
||||
- Maintain `StellaOps.Excititor.Plugin.Tests`.
|
||||
- Keep tests deterministic and offline-friendly.
|
||||
- Surface open work on `TASKS.md`; update statuses (TODO/DOING/DONE/BLOCKED/REVIEW).
|
||||
|
||||
## Key Paths
|
||||
- `PluginCatalogTests.cs`
|
||||
- `VexConnectorRegistrationTests.cs`
|
||||
|
||||
## Coordination
|
||||
- Excititor connector owners.
|
||||
|
||||
## Required Reading
|
||||
- `docs/modules/excititor/architecture.md`
|
||||
- `docs/modules/excititor/attestation-plan.md`
|
||||
- `docs/modules/platform/architecture-overview.md`
|
||||
- `docs-archived/implplan/2025-12-29-csproj-audit/SPRINT_20251229_049_BE_csproj_audit_maint_tests.md`
|
||||
|
||||
## Working Agreement
|
||||
- 1. Update task status to `DOING`/`DONE` in both corresponding sprint file and local `TASKS.md`.
|
||||
- 2. Keep tests deterministic (stable ordering, timestamps, IDs).
|
||||
- 3. Avoid network in tests; use in-memory or fixtures.
|
||||
- 4. Log any cross-module edits in the sprint Execution Log.
|
||||
@@ -0,0 +1,276 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using StellaOps.Excititor.Core;
|
||||
using StellaOps.Excititor.Connectors.RedHat.CSAF;
|
||||
using StellaOps.Plugin;
|
||||
using StellaOps.TestKit;
|
||||
using System.Reflection;
|
||||
|
||||
namespace StellaOps.Excititor.Plugin.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// Integration tests for PluginCatalog with VEX connectors.
|
||||
/// Validates plugin discovery, loading, and availability filtering.
|
||||
/// </summary>
|
||||
public sealed class PluginCatalogTests
|
||||
{
|
||||
#region Assembly Loading Tests
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void AddAssembly_RedHatConnector_AddsToAssemblies()
|
||||
{
|
||||
// Arrange
|
||||
var catalog = new PluginCatalog();
|
||||
var assembly = typeof(RedHatCsafConnector).Assembly;
|
||||
|
||||
// Act
|
||||
catalog.AddAssembly(assembly);
|
||||
|
||||
// Assert - Should not throw and should be able to get plugins
|
||||
var plugins = catalog.GetConnectorPlugins();
|
||||
// RedHatCsafConnector is not an IConnectorPlugin, it's an IVexConnector
|
||||
// but the catalog should still accept the assembly
|
||||
plugins.Should().NotBeNull();
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void AddAssembly_DuplicateAssembly_IsIdempotent()
|
||||
{
|
||||
// Arrange
|
||||
var catalog = new PluginCatalog();
|
||||
var assembly = typeof(RedHatCsafConnector).Assembly;
|
||||
|
||||
// Act
|
||||
catalog.AddAssembly(assembly);
|
||||
catalog.AddAssembly(assembly);
|
||||
catalog.AddAssembly(assembly);
|
||||
|
||||
// Assert - Should not duplicate
|
||||
var plugins = catalog.GetConnectorPlugins();
|
||||
// Verify no exception is thrown
|
||||
plugins.Should().NotBeNull();
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void AddAssembly_NullAssembly_ThrowsException()
|
||||
{
|
||||
// Arrange
|
||||
var catalog = new PluginCatalog();
|
||||
|
||||
// Act
|
||||
var act = () => catalog.AddAssembly(null!);
|
||||
|
||||
// Assert
|
||||
act.Should().Throw<ArgumentNullException>();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region AddFromDirectory Tests
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void AddFromDirectory_NonExistentDirectory_HandlesGracefully()
|
||||
{
|
||||
// Arrange
|
||||
var catalog = new PluginCatalog();
|
||||
var nonExistentDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString(), "plugins");
|
||||
|
||||
// Act - Should not throw
|
||||
catalog.AddFromDirectory(nonExistentDir);
|
||||
|
||||
// Assert
|
||||
var plugins = catalog.GetConnectorPlugins();
|
||||
plugins.Should().BeEmpty();
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void AddFromDirectory_EmptyDirectory_LoadsNoPlugins()
|
||||
{
|
||||
// Arrange
|
||||
var catalog = new PluginCatalog();
|
||||
var emptyDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
||||
Directory.CreateDirectory(emptyDir);
|
||||
|
||||
try
|
||||
{
|
||||
// Act
|
||||
catalog.AddFromDirectory(emptyDir);
|
||||
|
||||
// Assert
|
||||
var plugins = catalog.GetConnectorPlugins();
|
||||
plugins.Should().BeEmpty();
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(emptyDir);
|
||||
}
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void AddFromDirectory_NullDirectory_ThrowsException()
|
||||
{
|
||||
// Arrange
|
||||
var catalog = new PluginCatalog();
|
||||
|
||||
// Act
|
||||
var act = () => catalog.AddFromDirectory(null!);
|
||||
|
||||
// Assert
|
||||
act.Should().Throw<ArgumentException>();
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void AddFromDirectory_EmptyStringDirectory_ThrowsException()
|
||||
{
|
||||
// Arrange
|
||||
var catalog = new PluginCatalog();
|
||||
|
||||
// Act
|
||||
var act = () => catalog.AddFromDirectory("");
|
||||
|
||||
// Assert
|
||||
act.Should().Throw<ArgumentException>();
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void AddFromDirectory_WhitespaceDirectory_ThrowsException()
|
||||
{
|
||||
// Arrange
|
||||
var catalog = new PluginCatalog();
|
||||
|
||||
// Act
|
||||
var act = () => catalog.AddFromDirectory(" ");
|
||||
|
||||
// Assert
|
||||
act.Should().Throw<ArgumentException>();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region PluginLoader Tests
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void LoadPlugins_WithValidAssemblies_DiscoverTypes()
|
||||
{
|
||||
// Arrange
|
||||
var assemblies = new List<Assembly> { typeof(RedHatCsafConnector).Assembly };
|
||||
|
||||
// Act - Discover types that implement IVexConnector
|
||||
var vexConnectorTypes = assemblies
|
||||
.SelectMany(a => a.GetTypes())
|
||||
.Where(t => typeof(IVexConnector).IsAssignableFrom(t) && !t.IsInterface && !t.IsAbstract)
|
||||
.ToList();
|
||||
|
||||
// Assert - RedHatCsafConnector should be discovered
|
||||
vexConnectorTypes.Should().Contain(typeof(RedHatCsafConnector));
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void LoadPlugins_NullAssemblies_ThrowsException()
|
||||
{
|
||||
// Act
|
||||
var act = () => PluginLoader.LoadPlugins<IVexConnector>(null!);
|
||||
|
||||
// Assert
|
||||
act.Should().Throw<ArgumentNullException>();
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void LoadPlugins_EmptyAssemblies_ReturnsEmpty()
|
||||
{
|
||||
// Arrange
|
||||
var assemblies = new List<Assembly>();
|
||||
|
||||
// Act
|
||||
var plugins = PluginLoader.LoadPlugins<IConnectorPlugin>(assemblies);
|
||||
|
||||
// Assert
|
||||
plugins.Should().BeEmpty();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Availability Filter Tests
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void GetAvailableConnectorPlugins_WithMockProvider_FiltersCorrectly()
|
||||
{
|
||||
// Arrange
|
||||
var catalog = new PluginCatalog();
|
||||
// Note: The test assembly doesn't have IConnectorPlugin implementations
|
||||
// This tests the filtering mechanism
|
||||
|
||||
var services = new ServiceCollection()
|
||||
.AddLogging()
|
||||
.BuildServiceProvider();
|
||||
|
||||
// Act
|
||||
var availablePlugins = catalog.GetAvailableConnectorPlugins(services);
|
||||
|
||||
// Assert
|
||||
availablePlugins.Should().NotBeNull();
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void GetAvailableExporterPlugins_WithMockProvider_FiltersCorrectly()
|
||||
{
|
||||
// Arrange
|
||||
var catalog = new PluginCatalog();
|
||||
|
||||
var services = new ServiceCollection()
|
||||
.AddLogging()
|
||||
.BuildServiceProvider();
|
||||
|
||||
// Act
|
||||
var availablePlugins = catalog.GetAvailableExporterPlugins(services);
|
||||
|
||||
// Assert
|
||||
availablePlugins.Should().NotBeNull();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Method Chaining Tests
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void PluginCatalog_MethodChaining_Works()
|
||||
{
|
||||
// Arrange
|
||||
var tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
||||
Directory.CreateDirectory(tempDir);
|
||||
|
||||
try
|
||||
{
|
||||
var assembly = typeof(RedHatCsafConnector).Assembly;
|
||||
|
||||
// Act
|
||||
var catalog = new PluginCatalog()
|
||||
.AddAssembly(assembly)
|
||||
.AddFromDirectory(tempDir);
|
||||
|
||||
// Assert
|
||||
catalog.Should().NotBeNull();
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(tempDir);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<LangVersion>preview</LangVersion>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
|
||||
<NoWarn>$(NoWarn);CA2255</NoWarn>
|
||||
<IsPackable>false</IsPackable>
|
||||
<IsTestProject>true</IsTestProject>
|
||||
<RootNamespace>StellaOps.Excititor.Plugin.Tests</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Using Include="FluentAssertions" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FluentAssertions" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" />
|
||||
<PackageReference Include="Moq" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\__Libraries\StellaOps.Excititor.Core\StellaOps.Excititor.Core.csproj" />
|
||||
<ProjectReference Include="..\..\__Libraries\StellaOps.Excititor.Connectors.Abstractions\StellaOps.Excititor.Connectors.Abstractions.csproj" />
|
||||
<ProjectReference Include="..\..\__Libraries\StellaOps.Excititor.Connectors.RedHat.CSAF\StellaOps.Excititor.Connectors.RedHat.CSAF.csproj" />
|
||||
<ProjectReference Include="..\..\__Libraries\StellaOps.Excititor.Connectors.Cisco.CSAF\StellaOps.Excititor.Connectors.Cisco.CSAF.csproj" />
|
||||
<ProjectReference Include="..\..\__Libraries\StellaOps.Excititor.Connectors.Ubuntu.CSAF\StellaOps.Excititor.Connectors.Ubuntu.CSAF.csproj" />
|
||||
<ProjectReference Include="..\..\..\__Libraries\StellaOps.Plugin\StellaOps.Plugin.csproj" />
|
||||
<ProjectReference Include="..\..\..\__Libraries\StellaOps.TestKit\StellaOps.TestKit.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,10 @@
|
||||
# Excititor Plugin Tests Task Board
|
||||
|
||||
This board mirrors active sprint tasks for this module.
|
||||
Source of truth: `docs-archived/implplan/2025-12-29-csproj-audit/SPRINT_20251229_049_BE_csproj_audit_maint_tests.md`.
|
||||
|
||||
| Task ID | Status | Notes |
|
||||
| --- | --- | --- |
|
||||
| AUDIT-0752-M | DONE | Revalidated 2026-01-07 (test project). |
|
||||
| AUDIT-0752-T | DONE | Revalidated 2026-01-07. |
|
||||
| AUDIT-0752-A | DONE | Waived (test project; revalidated 2026-01-07). |
|
||||
@@ -0,0 +1,249 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using StellaOps.Excititor.Core;
|
||||
using StellaOps.Excititor.Core.Storage;
|
||||
using StellaOps.Excititor.Connectors.Abstractions;
|
||||
using StellaOps.Excititor.Connectors.RedHat.CSAF;
|
||||
using StellaOps.Excititor.Connectors.RedHat.CSAF.DependencyInjection;
|
||||
using StellaOps.TestKit;
|
||||
|
||||
namespace StellaOps.Excititor.Plugin.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// Integration tests for VEX connector service registration.
|
||||
/// Validates that connector DI extensions correctly register services.
|
||||
/// </summary>
|
||||
public sealed class VexConnectorRegistrationTests
|
||||
{
|
||||
#region RedHat Connector Registration Tests
|
||||
|
||||
[Trait("Category", TestCategories.Integration)]
|
||||
[Fact]
|
||||
public void AddRedHatCsafConnector_RegistersIVexConnector()
|
||||
{
|
||||
// Arrange
|
||||
var services = new ServiceCollection();
|
||||
services.AddLogging();
|
||||
|
||||
// Add required dependencies
|
||||
services.AddSingleton(TimeProvider.System);
|
||||
services.AddSingleton<IVexConnectorStateRepository, InMemoryVexConnectorStateRepository>();
|
||||
|
||||
// Add connector-specific descriptor
|
||||
services.AddSingleton(new VexConnectorDescriptor(
|
||||
"excititor:redhat",
|
||||
VexProviderKind.Vendor,
|
||||
"Red Hat CSAF"));
|
||||
|
||||
// Act
|
||||
services.AddRedHatCsafConnector();
|
||||
|
||||
// Assert
|
||||
var provider = services.BuildServiceProvider();
|
||||
var connector = provider.GetService<IVexConnector>();
|
||||
connector.Should().NotBeNull();
|
||||
connector.Should().BeOfType<RedHatCsafConnector>();
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Integration)]
|
||||
[Fact]
|
||||
public void AddRedHatCsafConnector_WithConfiguration_AppliesOptions()
|
||||
{
|
||||
// Arrange
|
||||
var services = new ServiceCollection();
|
||||
services.AddLogging();
|
||||
services.AddSingleton(TimeProvider.System);
|
||||
services.AddSingleton<IVexConnectorStateRepository, InMemoryVexConnectorStateRepository>();
|
||||
services.AddSingleton(new VexConnectorDescriptor(
|
||||
"excititor:redhat",
|
||||
VexProviderKind.Vendor,
|
||||
"Red Hat CSAF"));
|
||||
|
||||
// Act
|
||||
services.AddRedHatCsafConnector(options =>
|
||||
{
|
||||
options.MetadataUri = new Uri("https://custom.redhat.com/csaf/provider-metadata.json");
|
||||
});
|
||||
|
||||
// Assert
|
||||
var provider = services.BuildServiceProvider();
|
||||
var options = provider.GetService<Microsoft.Extensions.Options.IOptions<
|
||||
StellaOps.Excititor.Connectors.RedHat.CSAF.Configuration.RedHatConnectorOptions>>();
|
||||
options.Should().NotBeNull();
|
||||
options!.Value.MetadataUri.Should().Be(new Uri("https://custom.redhat.com/csaf/provider-metadata.json"));
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Integration)]
|
||||
[Fact]
|
||||
public void AddRedHatCsafConnector_RegistersHttpClient()
|
||||
{
|
||||
// Arrange
|
||||
var services = new ServiceCollection();
|
||||
services.AddLogging();
|
||||
services.AddSingleton(TimeProvider.System);
|
||||
services.AddSingleton<IVexConnectorStateRepository, InMemoryVexConnectorStateRepository>();
|
||||
services.AddSingleton(new VexConnectorDescriptor(
|
||||
"excititor:redhat",
|
||||
VexProviderKind.Vendor,
|
||||
"Red Hat CSAF"));
|
||||
|
||||
// Act
|
||||
services.AddRedHatCsafConnector();
|
||||
|
||||
// Assert
|
||||
var provider = services.BuildServiceProvider();
|
||||
var httpClientFactory = provider.GetService<IHttpClientFactory>();
|
||||
httpClientFactory.Should().NotBeNull();
|
||||
|
||||
var client = httpClientFactory!.CreateClient(
|
||||
StellaOps.Excititor.Connectors.RedHat.CSAF.Configuration.RedHatConnectorOptions.HttpClientName);
|
||||
client.Should().NotBeNull();
|
||||
client.DefaultRequestHeaders.UserAgent.Should().NotBeEmpty();
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void AddRedHatCsafConnector_NullServices_ThrowsException()
|
||||
{
|
||||
// Arrange
|
||||
IServiceCollection services = null!;
|
||||
|
||||
// Act
|
||||
var act = () => services.AddRedHatCsafConnector();
|
||||
|
||||
// Assert
|
||||
act.Should().Throw<ArgumentNullException>();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Connector Descriptor Tests
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void VexConnectorDescriptor_RequiresId()
|
||||
{
|
||||
// Act
|
||||
var act = () => new VexConnectorDescriptor(null!, VexProviderKind.Vendor, "Display Name");
|
||||
|
||||
// Assert
|
||||
act.Should().Throw<ArgumentException>();
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void VexConnectorDescriptor_EmptyId_ThrowsException()
|
||||
{
|
||||
// Act
|
||||
var act = () => new VexConnectorDescriptor("", VexProviderKind.Vendor, "Display Name");
|
||||
|
||||
// Assert
|
||||
act.Should().Throw<ArgumentException>();
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void VexConnectorDescriptor_WhitespaceId_ThrowsException()
|
||||
{
|
||||
// Act
|
||||
var act = () => new VexConnectorDescriptor(" ", VexProviderKind.Vendor, "Display Name");
|
||||
|
||||
// Assert
|
||||
act.Should().Throw<ArgumentException>();
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void VexConnectorDescriptor_NullDisplayName_UsesId()
|
||||
{
|
||||
// Act
|
||||
var descriptor = new VexConnectorDescriptor("test:connector", VexProviderKind.Vendor, null!);
|
||||
|
||||
// Assert
|
||||
descriptor.DisplayName.Should().Be("test:connector");
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void VexConnectorDescriptor_ValidParameters_StoresValues()
|
||||
{
|
||||
// Act
|
||||
var descriptor = new VexConnectorDescriptor("test:connector", VexProviderKind.Hub, "Test Connector");
|
||||
|
||||
// Assert
|
||||
descriptor.Id.Should().Be("test:connector");
|
||||
descriptor.Kind.Should().Be(VexProviderKind.Hub);
|
||||
descriptor.DisplayName.Should().Be("Test Connector");
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void VexConnectorDescriptor_ToString_FormatsCorrectly()
|
||||
{
|
||||
// Arrange
|
||||
var descriptor = new VexConnectorDescriptor("test:connector", VexProviderKind.Vendor, "Test");
|
||||
|
||||
// Act
|
||||
var result = descriptor.ToString();
|
||||
|
||||
// Assert
|
||||
result.Should().Be("test:connector (Vendor)");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Multiple Connector Registration Tests
|
||||
|
||||
[Trait("Category", TestCategories.Integration)]
|
||||
[Fact]
|
||||
public void MultipleConnectors_RegisteredCorrectly()
|
||||
{
|
||||
// Arrange
|
||||
var services = new ServiceCollection();
|
||||
services.AddLogging();
|
||||
services.AddSingleton(TimeProvider.System);
|
||||
services.AddSingleton<IVexConnectorStateRepository, InMemoryVexConnectorStateRepository>();
|
||||
|
||||
// Add descriptor for RedHat
|
||||
services.AddSingleton(new VexConnectorDescriptor(
|
||||
"excititor:redhat",
|
||||
VexProviderKind.Vendor,
|
||||
"Red Hat CSAF"));
|
||||
|
||||
// Act - Register RedHat connector
|
||||
services.AddRedHatCsafConnector();
|
||||
|
||||
// Assert - Verify services are registered
|
||||
var descriptors = services.Where(d => d.ServiceType == typeof(IVexConnector)).ToList();
|
||||
descriptors.Should().HaveCountGreaterThanOrEqualTo(1);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// In-memory implementation of IVexConnectorStateRepository for testing.
|
||||
/// </summary>
|
||||
file sealed class InMemoryVexConnectorStateRepository : IVexConnectorStateRepository
|
||||
{
|
||||
private readonly Dictionary<string, VexConnectorState> _states = new(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
public ValueTask<VexConnectorState?> GetAsync(string connectorId, CancellationToken cancellationToken)
|
||||
{
|
||||
_states.TryGetValue(connectorId, out var state);
|
||||
return ValueTask.FromResult(state);
|
||||
}
|
||||
|
||||
public ValueTask SaveAsync(VexConnectorState state, CancellationToken cancellationToken)
|
||||
{
|
||||
_states[state.ConnectorId] = state;
|
||||
return ValueTask.CompletedTask;
|
||||
}
|
||||
|
||||
public ValueTask<IReadOnlyCollection<VexConnectorState>> ListAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
return ValueTask.FromResult<IReadOnlyCollection<VexConnectorState>>(_states.Values.ToList());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user