- Fix pull consumer fetch: send original stream subject in HMSG (not inbox) so NATS client distinguishes data messages from control messages - Fix MaxAge expiry: add background timer in StreamManager for periodic pruning - Fix JetStream wire format: Go-compatible anonymous objects with string enums, proper offset-based pagination for stream/consumer list APIs - Add 42 E2E black-box tests (core messaging, auth, TLS, accounts, JetStream) - Add ~1000 parity tests across all subsystems (gaps closure) - Update gap inventory docs to reflect implementation status
84 lines
2.8 KiB
C#
84 lines
2.8 KiB
C#
using NATS.Server.Subscriptions;
|
|
|
|
namespace NATS.Server.Tests.Subscriptions;
|
|
|
|
public class SubjectTransformParityBatch3Tests
|
|
{
|
|
[Fact]
|
|
public void ValidateMapping_accepts_supported_templates_and_rejects_invalid_templates()
|
|
{
|
|
SubjectTransform.ValidateMapping("dest.$1").ShouldBeTrue();
|
|
SubjectTransform.ValidateMapping("dest.{{partition(10)}}").ShouldBeTrue();
|
|
SubjectTransform.ValidateMapping("dest.{{random(5)}}").ShouldBeTrue();
|
|
|
|
SubjectTransform.ValidateMapping("dest.*").ShouldBeFalse();
|
|
SubjectTransform.ValidateMapping("dest.{{wildcard()}}").ShouldBeFalse();
|
|
}
|
|
|
|
[Fact]
|
|
public void NewSubjectTransformStrict_requires_all_source_wildcards_to_be_used()
|
|
{
|
|
SubjectTransform.NewSubjectTransformWithStrict("foo.*.*", "bar.$1", strict: true).ShouldBeNull();
|
|
SubjectTransform.NewSubjectTransformWithStrict("foo.*.*", "bar.$1", strict: false).ShouldNotBeNull();
|
|
}
|
|
|
|
[Fact]
|
|
public void NewSubjectTransformStrict_accepts_when_all_source_wildcards_are_used()
|
|
{
|
|
var transform = SubjectTransform.NewSubjectTransformStrict("foo.*.*", "bar.$2.$1");
|
|
transform.ShouldNotBeNull();
|
|
transform.Apply("foo.A.B").ShouldBe("bar.B.A");
|
|
}
|
|
|
|
[Fact]
|
|
public void Random_transform_function_returns_bucket_in_range()
|
|
{
|
|
var transform = SubjectTransform.Create("*", "rand.{{random(3)}}");
|
|
transform.ShouldNotBeNull();
|
|
|
|
for (var i = 0; i < 20; i++)
|
|
{
|
|
var output = transform.Apply("foo");
|
|
output.ShouldNotBeNull();
|
|
var parts = output!.Split('.');
|
|
parts.Length.ShouldBe(2);
|
|
int.TryParse(parts[1], out var bucket).ShouldBeTrue();
|
|
bucket.ShouldBeGreaterThanOrEqualTo(0);
|
|
bucket.ShouldBeLessThan(3);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void TransformTokenize_and_transformUntokenize_round_trip_wildcards()
|
|
{
|
|
var tokenized = SubjectTransform.TransformTokenize("foo.*.*");
|
|
tokenized.ShouldBe("foo.$1.$2");
|
|
|
|
var untokenized = SubjectTransform.TransformUntokenize(tokenized);
|
|
untokenized.ShouldBe("foo.*.*");
|
|
}
|
|
|
|
[Fact]
|
|
public void Reverse_produces_inverse_transform_for_reordered_wildcards()
|
|
{
|
|
var forward = SubjectTransform.Create("foo.*.*", "bar.$2.$1");
|
|
forward.ShouldNotBeNull();
|
|
|
|
var reverse = forward.Reverse();
|
|
reverse.ShouldNotBeNull();
|
|
|
|
var mapped = forward.Apply("foo.A.B");
|
|
mapped.ShouldBe("bar.B.A");
|
|
reverse.Apply(mapped!).ShouldBe("foo.A.B");
|
|
}
|
|
|
|
[Fact]
|
|
public void TransformSubject_applies_transform_without_source_match_guard()
|
|
{
|
|
var transform = SubjectTransform.Create("foo.*", "bar.$1");
|
|
transform.ShouldNotBeNull();
|
|
|
|
transform.TransformSubject("baz.qux").ShouldBe("bar.qux");
|
|
}
|
|
}
|