- WP-1-3: Central/site failover + dual-node recovery tests (17 tests) - WP-4: Performance testing framework for target scale (7 tests) - WP-5: Security hardening (LDAPS, JWT key length, no secrets in logs) (11 tests) - WP-6: Script sandboxing adversarial tests (28 tests, all forbidden APIs) - WP-7: Recovery drill test scaffolds (5 tests) - WP-8: Observability validation (structured logs, correlation IDs, metrics) (6 tests) - WP-9: Message contract compatibility (forward/backward compat) (18 tests) - WP-10: Deployment packaging (installation guide, production checklist, topology) - WP-11: Operational runbooks (failover, troubleshooting, maintenance) 92 new tests, all passing. Zero warnings.
138 lines
4.4 KiB
C#
138 lines
4.4 KiB
C#
using System.Text.Json;
|
|
|
|
namespace ScadaLink.InboundAPI.Tests;
|
|
|
|
/// <summary>
|
|
/// WP-2: Tests for parameter validation — type checking, required fields, extended type system.
|
|
/// </summary>
|
|
public class ParameterValidatorTests
|
|
{
|
|
[Fact]
|
|
public void NoDefinitions_NoBody_ReturnsValid()
|
|
{
|
|
var result = ParameterValidator.Validate(null, null);
|
|
Assert.True(result.IsValid);
|
|
Assert.Empty(result.Parameters);
|
|
}
|
|
|
|
[Fact]
|
|
public void EmptyDefinitions_ReturnsValid()
|
|
{
|
|
var result = ParameterValidator.Validate(null, "[]");
|
|
Assert.True(result.IsValid);
|
|
}
|
|
|
|
[Fact]
|
|
public void RequiredParameterMissing_ReturnsInvalid()
|
|
{
|
|
var definitions = JsonSerializer.Serialize(new[]
|
|
{
|
|
new { Name = "value", Type = "Integer", Required = true }
|
|
});
|
|
|
|
var result = ParameterValidator.Validate(null, definitions);
|
|
Assert.False(result.IsValid);
|
|
Assert.Contains("Missing required parameter", result.ErrorMessage);
|
|
}
|
|
|
|
[Fact]
|
|
public void BodyNotObject_ReturnsInvalid()
|
|
{
|
|
var definitions = JsonSerializer.Serialize(new[]
|
|
{
|
|
new { Name = "value", Type = "String", Required = true }
|
|
});
|
|
|
|
using var doc = JsonDocument.Parse("\"just a string\"");
|
|
var result = ParameterValidator.Validate(doc.RootElement.Clone(), definitions);
|
|
Assert.False(result.IsValid);
|
|
Assert.Contains("must be a JSON object", result.ErrorMessage);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData("Boolean", "true", true)]
|
|
[InlineData("Integer", "42", (long)42)]
|
|
[InlineData("Float", "3.14", 3.14)]
|
|
[InlineData("String", "\"hello\"", "hello")]
|
|
public void ValidTypeCoercion_Succeeds(string type, string jsonValue, object expected)
|
|
{
|
|
var definitions = JsonSerializer.Serialize(new[]
|
|
{
|
|
new { Name = "val", Type = type, Required = true }
|
|
});
|
|
|
|
using var doc = JsonDocument.Parse($"{{\"val\": {jsonValue}}}");
|
|
var result = ParameterValidator.Validate(doc.RootElement.Clone(), definitions);
|
|
Assert.True(result.IsValid);
|
|
Assert.Equal(expected, result.Parameters["val"]);
|
|
}
|
|
|
|
[Fact]
|
|
public void WrongType_ReturnsInvalid()
|
|
{
|
|
var definitions = JsonSerializer.Serialize(new[]
|
|
{
|
|
new { Name = "count", Type = "Integer", Required = true }
|
|
});
|
|
|
|
using var doc = JsonDocument.Parse("{\"count\": \"not a number\"}");
|
|
var result = ParameterValidator.Validate(doc.RootElement.Clone(), definitions);
|
|
Assert.False(result.IsValid);
|
|
Assert.Contains("must be an Integer", result.ErrorMessage);
|
|
}
|
|
|
|
[Fact]
|
|
public void ObjectType_Parsed()
|
|
{
|
|
var definitions = JsonSerializer.Serialize(new[]
|
|
{
|
|
new { Name = "data", Type = "Object", Required = true }
|
|
});
|
|
|
|
using var doc = JsonDocument.Parse("{\"data\": {\"key\": \"value\"}}");
|
|
var result = ParameterValidator.Validate(doc.RootElement.Clone(), definitions);
|
|
Assert.True(result.IsValid);
|
|
Assert.IsType<Dictionary<string, object?>>(result.Parameters["data"]);
|
|
}
|
|
|
|
[Fact]
|
|
public void ListType_Parsed()
|
|
{
|
|
var definitions = JsonSerializer.Serialize(new[]
|
|
{
|
|
new { Name = "items", Type = "List", Required = true }
|
|
});
|
|
|
|
using var doc = JsonDocument.Parse("{\"items\": [1, 2, 3]}");
|
|
var result = ParameterValidator.Validate(doc.RootElement.Clone(), definitions);
|
|
Assert.True(result.IsValid);
|
|
Assert.IsType<List<object?>>(result.Parameters["items"]);
|
|
}
|
|
|
|
[Fact]
|
|
public void OptionalParameter_MissingBody_ReturnsValid()
|
|
{
|
|
var definitions = JsonSerializer.Serialize(new[]
|
|
{
|
|
new { Name = "optional", Type = "String", Required = false }
|
|
});
|
|
|
|
var result = ParameterValidator.Validate(null, definitions);
|
|
Assert.True(result.IsValid);
|
|
}
|
|
|
|
[Fact]
|
|
public void UnknownType_ReturnsInvalid()
|
|
{
|
|
var definitions = JsonSerializer.Serialize(new[]
|
|
{
|
|
new { Name = "val", Type = "CustomType", Required = true }
|
|
});
|
|
|
|
using var doc = JsonDocument.Parse("{\"val\": \"test\"}");
|
|
var result = ParameterValidator.Validate(doc.RootElement.Clone(), definitions);
|
|
Assert.False(result.IsValid);
|
|
Assert.Contains("Unknown parameter type", result.ErrorMessage);
|
|
}
|
|
}
|