refactor: rename remaining tests to NATS.Server.Core.Tests

- Rename tests/NATS.Server.Tests -> tests/NATS.Server.Core.Tests
- Update solution file, InternalsVisibleTo, and csproj references
- Remove JETSTREAM_INTEGRATION_MATRIX and NATS.NKeys from csproj (moved to JetStream.Tests and Auth.Tests)
- Update all namespaces from NATS.Server.Tests.* to NATS.Server.Core.Tests.*
- Replace private GetFreePort/ReadUntilAsync helpers with TestUtilities calls
- Fix stale namespace in Transport.Tests/NetworkingGoParityTests.cs
This commit is contained in:
Joseph Doherty
2026-03-12 16:14:02 -04:00
parent 78b4bc2486
commit 7fbffffd05
114 changed files with 576 additions and 1121 deletions

View File

@@ -0,0 +1,396 @@
using NATS.Server.Subscriptions;
namespace NATS.Server.Core.Tests;
public class SubjectTransformTests
{
[Fact]
public void WildcardReplacement_SingleToken()
{
// foo.* -> bar.{{wildcard(1)}}
var transform = SubjectTransform.Create("foo.*", "bar.{{wildcard(1)}}");
transform.ShouldNotBeNull();
transform.Apply("foo.baz").ShouldBe("bar.baz");
}
[Fact]
public void DollarSyntax_ReversesOrder()
{
// foo.*.* -> bar.$2.$1 reverses captured tokens
var transform = SubjectTransform.Create("foo.*.*", "bar.$2.$1");
transform.ShouldNotBeNull();
transform.Apply("foo.A.B").ShouldBe("bar.B.A");
}
[Fact]
public void DollarSyntax_MultipleWildcardPositions()
{
// foo.*.bar.*.baz -> req.$2.$1
var transform = SubjectTransform.Create("foo.*.bar.*.baz", "req.$2.$1");
transform.ShouldNotBeNull();
transform.Apply("foo.A.bar.B.baz").ShouldBe("req.B.A");
}
[Fact]
public void WildcardFunction_MultiplePositions()
{
// foo.*.bar.*.baz -> req.{{wildcard(2)}}.{{wildcard(1)}}
var transform = SubjectTransform.Create("foo.*.bar.*.baz", "req.{{wildcard(2)}}.{{wildcard(1)}}");
transform.ShouldNotBeNull();
transform.Apply("foo.A.bar.B.baz").ShouldBe("req.B.A");
}
[Fact]
public void FullWildcardCapture_MultiToken()
{
// baz.> -> my.pre.> captures multi-token remainder
var transform = SubjectTransform.Create("baz.>", "my.pre.>");
transform.ShouldNotBeNull();
transform.Apply("baz.1.2.3").ShouldBe("my.pre.1.2.3");
}
[Fact]
public void FullWildcardCapture_FooBar()
{
// baz.> -> foo.bar.>
var transform = SubjectTransform.Create("baz.>", "foo.bar.>");
transform.ShouldNotBeNull();
transform.Apply("baz.1.2.3").ShouldBe("foo.bar.1.2.3");
}
[Fact]
public void NoMatch_ReturnsNull()
{
var transform = SubjectTransform.Create("foo.*", "bar.$1");
transform.ShouldNotBeNull();
transform.Apply("baz.qux").ShouldBeNull();
}
[Fact]
public void NoMatch_WrongTokenCount()
{
var transform = SubjectTransform.Create("foo.*", "bar.$1");
transform.ShouldNotBeNull();
transform.Apply("foo.a.b").ShouldBeNull();
}
[Fact]
public void PartitionFunction_DeterministicResult()
{
// Partition should produce deterministic 0..N-1 results
var transform = SubjectTransform.Create("*", "bar.{{partition(10)}}");
transform.ShouldNotBeNull();
// FNV-1a of "foo" mod 10 = 3
transform.Apply("foo").ShouldBe("bar.3");
// FNV-1a of "baz" mod 10 = 0
transform.Apply("baz").ShouldBe("bar.0");
// FNV-1a of "qux" mod 10 = 9
transform.Apply("qux").ShouldBe("bar.9");
}
[Fact]
public void PartitionFunction_ZeroBuckets()
{
var transform = SubjectTransform.Create("*", "bar.{{partition(0)}}");
transform.ShouldNotBeNull();
transform.Apply("baz").ShouldBe("bar.0");
}
[Fact]
public void PartitionFunction_WithTokenIndexes()
{
// partition(10, 1, 2) hashes concatenation of wildcard 1 and wildcard 2
// For source *.*: wildcard 1 -> pos 0 ("foo"), wildcard 2 -> pos 1 ("bar")
// Key = "foobar" (no separator), FNV-1a("foobar") % 10 = 0
var transform = SubjectTransform.Create("*.*", "bar.{{partition(10,1,2)}}");
transform.ShouldNotBeNull();
transform.Apply("foo.bar").ShouldBe("bar.0");
}
[Fact]
public void PartitionFunction_WithSpecificToken()
{
// partition(10, 0) with wildcard source: in Go, wildcard index 0 silently
// maps to source position 0 (Go map zero-value behavior). We match this.
var transform = SubjectTransform.Create("*", "bar.{{partition(10, 0)}}");
transform.ShouldNotBeNull();
transform.Apply("foo").ShouldBe("bar.3");
}
[Fact]
public void PartitionFunction_ShorthandNoWildcardsInSource()
{
// When source has no wildcards, partition(n) hashes the full subject
var transform = SubjectTransform.Create("foo.bar", "baz.{{partition(10)}}");
transform.ShouldNotBeNull();
transform.Apply("foo.bar").ShouldBe("baz.6");
}
[Fact]
public void PartitionFunction_ShorthandWithWildcards()
{
// partition(10) with wildcards hashes all subject tokens joined
var transform = SubjectTransform.Create("*.*", "bar.{{partition(10)}}");
transform.ShouldNotBeNull();
transform.Apply("foo.bar").ShouldBe("bar.6");
}
[Fact]
public void SplitFunction_BasicDelimiter()
{
// events.a-b-c with split(1,-) -> split.a.b.c
var transform = SubjectTransform.Create("*", "{{split(1,-)}}");
transform.ShouldNotBeNull();
transform.Apply("abc-def--ghi-").ShouldBe("abc.def.ghi");
}
[Fact]
public void SplitFunction_LeadingDelimiter()
{
var transform = SubjectTransform.Create("*", "{{split(1,-)}}");
transform.ShouldNotBeNull();
transform.Apply("-abc-def--ghi-").ShouldBe("abc.def.ghi");
}
[Fact]
public void LeftFunction_BasicTrim()
{
// data.abcdef with left(1,3) -> prefix.abc
var transform = SubjectTransform.Create("*", "prefix.{{left(1,3)}}");
transform.ShouldNotBeNull();
transform.Apply("abcdef").ShouldBe("prefix.abc");
}
[Fact]
public void LeftFunction_LenExceedsToken()
{
var transform = SubjectTransform.Create("*", "{{left(1,6)}}");
transform.ShouldNotBeNull();
// When len exceeds token length, return full token
transform.Apply("1234").ShouldBe("1234");
}
[Fact]
public void LeftFunction_SingleChar()
{
var transform = SubjectTransform.Create("*", "{{left(1,1)}}");
transform.ShouldNotBeNull();
transform.Apply("1234").ShouldBe("1");
}
[Fact]
public void RightFunction_BasicTrim()
{
// data.abcdef with right(1,3) -> suffix.def
var transform = SubjectTransform.Create("*", "suffix.{{right(1,3)}}");
transform.ShouldNotBeNull();
transform.Apply("abcdef").ShouldBe("suffix.def");
}
[Fact]
public void RightFunction_LenExceedsToken()
{
var transform = SubjectTransform.Create("*", "{{right(1,6)}}");
transform.ShouldNotBeNull();
transform.Apply("1234").ShouldBe("1234");
}
[Fact]
public void RightFunction_SingleChar()
{
var transform = SubjectTransform.Create("*", "{{right(1,1)}}");
transform.ShouldNotBeNull();
transform.Apply("1234").ShouldBe("4");
}
[Fact]
public void RightFunction_ThreeChars()
{
var transform = SubjectTransform.Create("*", "{{right(1,3)}}");
transform.ShouldNotBeNull();
transform.Apply("1234").ShouldBe("234");
}
[Fact]
public void SplitFromLeft_BasicSplit()
{
// data.abcdef with splitFromLeft(1,3) -> parts.abc.def
var transform = SubjectTransform.Create("*", "{{splitFromLeft(1,3)}}");
transform.ShouldNotBeNull();
transform.Apply("12345").ShouldBe("123.45");
}
[Fact]
public void SplitFromRight_BasicSplit()
{
// data.abcdef with splitFromRight(1,3) -> parts.abc.def
var transform = SubjectTransform.Create("*", "{{SplitFromRight(1,3)}}");
transform.ShouldNotBeNull();
transform.Apply("12345").ShouldBe("12.345");
}
[Fact]
public void SliceFromLeft_BasicSlice()
{
// data.abcdef with sliceFromLeft(1,2) -> chunks.ab.cd.ef
var transform = SubjectTransform.Create("*", "{{SliceFromLeft(1,3)}}");
transform.ShouldNotBeNull();
transform.Apply("1234567890").ShouldBe("123.456.789.0");
}
[Fact]
public void SliceFromRight_BasicSlice()
{
// data.abcdef with sliceFromRight(1,2) -> chunks.ab.cd.ef
var transform = SubjectTransform.Create("*", "{{SliceFromRight(1,3)}}");
transform.ShouldNotBeNull();
transform.Apply("1234567890").ShouldBe("1.234.567.890");
}
[Fact]
public void LiteralPassthrough_NoWildcards()
{
// Literal source with no wildcards: exact match, returns dest
var transform = SubjectTransform.Create("foo", "bar");
transform.ShouldNotBeNull();
transform.Apply("foo").ShouldBe("bar");
}
[Fact]
public void LiteralPassthrough_NoMatchOnDifferentSubject()
{
var transform = SubjectTransform.Create("foo", "bar");
transform.ShouldNotBeNull();
transform.Apply("baz").ShouldBeNull();
}
[Fact]
public void InvalidSource_ReturnsNull()
{
// foo.. is not a valid subject
SubjectTransform.Create("foo..", "bar").ShouldBeNull();
}
[Fact]
public void InvalidSource_EmptyToken()
{
SubjectTransform.Create(".foo", "bar").ShouldBeNull();
}
[Fact]
public void WildcardIndexOutOfRange_ReturnsNull()
{
// Source has 1 wildcard but dest references $2
SubjectTransform.Create("foo.*", "bar.$2").ShouldBeNull();
}
[Fact]
public void DestinationWithWildcard_ReturnsNull()
{
// Wildcards not allowed in destination (pwc)
SubjectTransform.Create("foo.*", "bar.*").ShouldBeNull();
}
[Fact]
public void FwcMismatch_ReturnsNull()
{
// If source has >, dest must also have >
SubjectTransform.Create("foo.*", "bar.$1.>").ShouldBeNull();
SubjectTransform.Create("foo.>", "bar.baz").ShouldBeNull();
}
[Fact]
public void UnknownFunction_ReturnsNull()
{
SubjectTransform.Create("foo.*", "foo.{{unimplemented(1)}}").ShouldBeNull();
}
[Fact]
public void SingleWildcardCapture_ExpandedToBarPrefix()
{
var transform = SubjectTransform.Create("*", "foo.bar.$1");
transform.ShouldNotBeNull();
transform.Apply("foo").ShouldBe("foo.bar.foo");
}
[Fact]
public void ComboTransform_SplitAndSplitFromLeft()
{
// Combo: split + splitFromLeft
var transform = SubjectTransform.Create("*.*", "{{split(2,-)}}.{{splitfromleft(1,2)}}");
transform.ShouldNotBeNull();
transform.Apply("foo.-abc-def--ghij-").ShouldBe("abc.def.ghij.fo.o");
}
[Fact]
public void PartitionFunction_NoWildcardSource_FullSubjectHash()
{
// foo.baz -> qux.{{partition(10)}}
var transform = SubjectTransform.Create("foo.baz", "qux.{{partition(10)}}");
transform.ShouldNotBeNull();
transform.Apply("foo.baz").ShouldBe("qux.4");
}
[Fact]
public void PartitionFunction_NoWildcardSource_TestSubject()
{
var transform = SubjectTransform.Create("test.subject", "result.{{partition(5)}}");
transform.ShouldNotBeNull();
transform.Apply("test.subject").ShouldBe("result.0");
}
[Fact]
public void WildcardFunction_CaseInsensitive()
{
// Function names are case-insensitive (e.g. Wildcard, wildcard, WILDCARD)
var transform = SubjectTransform.Create("foo.*", "bar.{{Wildcard(1)}}");
transform.ShouldNotBeNull();
transform.Apply("foo.test").ShouldBe("bar.test");
}
[Fact]
public void SplitFromLeft_CaseInsensitive()
{
var transform = SubjectTransform.Create("*", "{{splitfromleft(1,1)}}");
transform.ShouldNotBeNull();
// Single char split from left pos 1: "ab" -> "a.b"
}
[Fact]
public void NotEnoughTokensInDest_PartitionWithMissingArgs()
{
SubjectTransform.Create("foo.*", "foo.{{partition()}}").ShouldBeNull();
}
[Fact]
public void WildcardFunctionBadArg_ReturnsNull()
{
SubjectTransform.Create("foo.*", "foo.{{wildcard(foo)}}").ShouldBeNull();
}
[Fact]
public void WildcardFunctionNoArgs_ReturnsNull()
{
SubjectTransform.Create("foo.*", "foo.{{wildcard()}}").ShouldBeNull();
}
[Fact]
public void WildcardFunctionTooManyArgs_ReturnsNull()
{
SubjectTransform.Create("foo.*", "foo.{{wildcard(1,2)}}").ShouldBeNull();
}
[Fact]
public void BadMustacheFormat_ReturnsNull()
{
SubjectTransform.Create("foo.*", "foo.{{ wildcard5) }}").ShouldBeNull();
}
[Fact]
public void NoWildcardSource_TransformFunctionNotAllowed()
{
// When source has no wildcards, only partition and random functions are allowed
SubjectTransform.Create("foo", "bla.{{wildcard(1)}}").ShouldBeNull();
}
}