using FluentAssertions; using StellaOps.TestKit.Interop; using Xunit; namespace StellaOps.TestKit.Tests; /// /// Unit tests for cross-version interoperability testing infrastructure. /// [Trait("Category", TestCategories.Unit)] public sealed class InteropTests { #region SchemaVersionMatrix Tests [Fact] public void SchemaVersionMatrix_AddVersion_StoresSchema() { // Arrange var matrix = new SchemaVersionMatrix(); var schema = new SchemaDefinition { RequiredFields = ["id", "name"] }; // Act matrix.AddVersion("1.0", schema); // Assert matrix.Versions.Should().Contain("1.0"); matrix.GetVersion("1.0").Should().Be(schema); } [Fact] public void SchemaVersionMatrix_IsBackwardCompatible_ReturnsTrueWhenNoFieldsRemoved() { // Arrange var matrix = new SchemaVersionMatrix(); matrix.AddVersion("1.0", new SchemaDefinition { RequiredFields = ["id", "name"] }); matrix.AddVersion("2.0", new SchemaDefinition { RequiredFields = ["id", "name", "type"], // Added field, none removed OptionalFields = ["description"] }); // Act & Assert matrix.IsBackwardCompatible("1.0", "2.0").Should().BeTrue(); } [Fact] public void SchemaVersionMatrix_IsBackwardCompatible_ReturnsFalseWhenFieldsRemoved() { // Arrange var matrix = new SchemaVersionMatrix(); matrix.AddVersion("1.0", new SchemaDefinition { RequiredFields = ["id", "name", "oldField"] }); matrix.AddVersion("2.0", new SchemaDefinition { RequiredFields = ["id", "name"] // oldField removed }); // Act & Assert matrix.IsBackwardCompatible("1.0", "2.0").Should().BeFalse(); } [Fact] public void SchemaVersionMatrix_IsForwardCompatible_ReturnsTrueWhenNewFieldsHaveDefaults() { // Arrange var matrix = new SchemaVersionMatrix(); matrix.AddVersion("1.0", new SchemaDefinition { RequiredFields = ["id", "name"] }); matrix.AddVersion("2.0", new SchemaDefinition { RequiredFields = ["id", "name", "type"], FieldDefaults = new() { ["type"] = "default" } }); // Act & Assert matrix.IsForwardCompatible("1.0", "2.0").Should().BeTrue(); } [Fact] public void SchemaVersionMatrix_IsForwardCompatible_ReturnsFalseWhenNewRequiredFieldsHaveNoDefaults() { // Arrange var matrix = new SchemaVersionMatrix(); matrix.AddVersion("1.0", new SchemaDefinition { RequiredFields = ["id", "name"] }); matrix.AddVersion("2.0", new SchemaDefinition { RequiredFields = ["id", "name", "type"] // No default for "type" }); // Act & Assert matrix.IsForwardCompatible("1.0", "2.0").Should().BeFalse(); } [Fact] public void SchemaVersionMatrix_Analyze_GeneratesReport() { // Arrange var matrix = new SchemaVersionMatrix(); matrix.AddVersion("1.0", new SchemaDefinition { RequiredFields = ["id"] }); matrix.AddVersion("2.0", new SchemaDefinition { RequiredFields = ["id", "name"] }); // Act var report = matrix.Analyze(); // Assert report.Versions.Should().Contain(["1.0", "2.0"]); report.Pairs.Should().HaveCount(2); // 1.0->2.0 and 2.0->1.0 report.GeneratedAt.Should().BeCloseTo(DateTimeOffset.UtcNow, TimeSpan.FromSeconds(5)); } [Fact] public void SchemaVersionMatrix_Analyze_DetectsTypeChanges() { // Arrange var matrix = new SchemaVersionMatrix(); matrix.AddVersion("1.0", new SchemaDefinition { RequiredFields = ["id"], FieldTypes = new() { ["id"] = "int" } }); matrix.AddVersion("2.0", new SchemaDefinition { RequiredFields = ["id"], FieldTypes = new() { ["id"] = "string" } // Type changed }); // Act var report = matrix.Analyze(); // Assert var pair = report.Pairs.First(p => p.FromVersion == "1.0" && p.ToVersion == "2.0"); pair.IsBackwardCompatible.Should().BeFalse(); pair.BackwardIssues.Should().Contain(i => i.Contains("Type changed")); } [Fact] public void CompatibilityReport_ToMarkdown_ProducesValidMarkdown() { // Arrange var matrix = new SchemaVersionMatrix(); matrix.AddVersion("1.0", new SchemaDefinition { RequiredFields = ["id"] }); matrix.AddVersion("2.0", new SchemaDefinition { RequiredFields = ["id"] }); var report = matrix.Analyze(); // Act var markdown = report.ToMarkdown(); // Assert markdown.Should().Contain("# Schema Compatibility Report"); markdown.Should().Contain("| From | To |"); markdown.Should().Contain("1.0"); markdown.Should().Contain("2.0"); } [Fact] public void CompatibilityReport_ToJson_ProducesValidJson() { // Arrange var matrix = new SchemaVersionMatrix(); matrix.AddVersion("1.0", new SchemaDefinition { RequiredFields = ["id"] }); var report = matrix.Analyze(); // Act var json = report.ToJson(); // Assert json.Should().Contain("\"generatedAt\""); json.Should().Contain("\"versions\""); } #endregion #region VersionCompatibilityFixture Tests [Fact] public async Task VersionCompatibilityFixture_Initialize_CreatesCurrentEndpoint() { // Arrange var fixture = new VersionCompatibilityFixture { Config = new VersionCompatibilityConfig { CurrentVersion = "3.0" } }; // Act await fixture.InitializeAsync(); // Assert fixture.CurrentEndpoint.Should().NotBeNull(); fixture.CurrentEndpoint!.Version.Should().Be("3.0"); fixture.CurrentEndpoint.IsHealthy.Should().BeTrue(); // Cleanup await fixture.DisposeAsync(); } [Fact] public async Task VersionCompatibilityFixture_StartVersion_CreatesEndpoint() { // Arrange var fixture = new VersionCompatibilityFixture(); await fixture.InitializeAsync(); // Act var endpoint = await fixture.StartVersion("1.0", "EvidenceLocker"); // Assert endpoint.Should().NotBeNull(); endpoint.Version.Should().Be("1.0"); endpoint.ServiceName.Should().Be("EvidenceLocker"); // Cleanup await fixture.DisposeAsync(); } [Fact] public async Task VersionCompatibilityFixture_StartVersion_ReturnsSameEndpointForSameVersion() { // Arrange var fixture = new VersionCompatibilityFixture(); await fixture.InitializeAsync(); // Act var endpoint1 = await fixture.StartVersion("1.0", "Service"); var endpoint2 = await fixture.StartVersion("1.0", "Service"); // Assert endpoint1.Should().BeSameAs(endpoint2); // Cleanup await fixture.DisposeAsync(); } [Fact] public async Task VersionCompatibilityFixture_TestHandshake_ReturnsSuccess() { // Arrange var fixture = new VersionCompatibilityFixture(); await fixture.InitializeAsync(); var server = await fixture.StartVersion("1.0", "Service"); // Act var result = await fixture.TestHandshake(fixture.CurrentEndpoint!, server); // Assert result.IsSuccess.Should().BeTrue(); result.ClientVersion.Should().Be(fixture.CurrentEndpoint!.Version); result.ServerVersion.Should().Be("1.0"); // Cleanup await fixture.DisposeAsync(); } [Fact] public async Task VersionCompatibilityFixture_TestMessageFormat_ReturnsSuccess() { // Arrange var fixture = new VersionCompatibilityFixture(); await fixture.InitializeAsync(); var producer = await fixture.StartVersion("1.0", "Producer"); var consumer = await fixture.StartVersion("2.0", "Consumer"); // Act var result = await fixture.TestMessageFormat(producer, consumer, "EvidenceBundle"); // Assert result.IsSuccess.Should().BeTrue(); result.Message.Should().Contain("EvidenceBundle"); // Cleanup await fixture.DisposeAsync(); } [Fact] public async Task VersionCompatibilityFixture_TestSchemaMigration_ReturnsSuccess() { // Arrange var fixture = new VersionCompatibilityFixture(); await fixture.InitializeAsync(); // Act var result = await fixture.TestSchemaMigration("1.0", "2.0", new { id = 1 }); // Assert result.IsSuccess.Should().BeTrue(); result.FromVersion.Should().Be("1.0"); result.ToVersion.Should().Be("2.0"); result.DataPreserved.Should().BeTrue(); result.RollbackSupported.Should().BeTrue(); // Cleanup await fixture.DisposeAsync(); } [Fact] public async Task VersionCompatibilityFixture_StopVersion_RemovesEndpoint() { // Arrange var fixture = new VersionCompatibilityFixture(); await fixture.InitializeAsync(); await fixture.StartVersion("1.0", "Service"); // Act await fixture.StopVersion("1.0", "Service"); var newEndpoint = await fixture.StartVersion("1.0", "Service"); // Assert - new endpoint should be created (different base URL due to increment) newEndpoint.Should().NotBeNull(); // Cleanup await fixture.DisposeAsync(); } #endregion #region ServiceEndpoint Tests [Fact] public void ServiceEndpoint_DefaultValues_AreSet() { // Arrange & Act var endpoint = new ServiceEndpoint(); // Assert endpoint.ServiceName.Should().BeEmpty(); endpoint.Version.Should().BeEmpty(); endpoint.BaseUrl.Should().BeEmpty(); endpoint.IsHealthy.Should().BeFalse(); } #endregion #region CompatibilityResult Tests [Fact] public void CompatibilityResult_DefaultValues_AreSet() { // Arrange & Act var result = new CompatibilityResult(); // Assert result.IsSuccess.Should().BeFalse(); result.Errors.Should().BeEmpty(); result.Warnings.Should().BeEmpty(); } #endregion }