361 lines
10 KiB
C#
361 lines
10 KiB
C#
using FluentAssertions;
|
|
using StellaOps.TestKit.Interop;
|
|
using Xunit;
|
|
|
|
namespace StellaOps.TestKit.Tests;
|
|
|
|
/// <summary>
|
|
/// Unit tests for cross-version interoperability testing infrastructure.
|
|
/// </summary>
|
|
[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
|
|
}
|