Files
natsdotnet/tests/NATS.Server.Tests/JetStream/Api/JetStreamApiLimitsParityBatch1Tests.cs
Joseph Doherty c30e67a69d Fix E2E test gaps and add comprehensive E2E + parity test suites
- 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
2026-03-12 14:09:23 -04:00

109 lines
3.4 KiB
C#

using NATS.Server.JetStream.Api;
using NATS.Server.JetStream.Models;
using NATS.Server.JetStream.Validation;
using NATS.Server.JetStream;
namespace NATS.Server.Tests.JetStream.Api;
public class JetStreamApiLimitsParityBatch1Tests
{
[Fact]
public void Constants_match_go_reference_values()
{
JetStreamApiLimits.JSMaxDescriptionLen.ShouldBe(4_096);
JetStreamApiLimits.JSMaxMetadataLen.ShouldBe(128 * 1024);
JetStreamApiLimits.JSMaxNameLen.ShouldBe(255);
JetStreamApiLimits.JSDefaultRequestQueueLimit.ShouldBe(10_000);
}
[Theory]
[InlineData(null, false)]
[InlineData("", false)]
[InlineData(" ", false)]
[InlineData("ORDERS", true)]
[InlineData("ORD ERS", false)]
[InlineData("ORDERS.*", false)]
[InlineData("ORDERS.>", false)]
public void IsValidName_enforces_expected_rules(string? name, bool expected)
{
JetStreamConfigValidator.IsValidName(name).ShouldBe(expected);
}
[Fact]
public void Stream_create_rejects_name_over_max_length()
{
var manager = new StreamManager();
var response = manager.CreateOrUpdate(new StreamConfig
{
Name = new string('S', JetStreamApiLimits.JSMaxNameLen + 1),
Subjects = ["a"],
});
response.Error.ShouldNotBeNull();
response.Error!.Description.ShouldBe("invalid stream name");
}
[Fact]
public void Stream_create_rejects_description_over_max_bytes()
{
var manager = new StreamManager();
var response = manager.CreateOrUpdate(new StreamConfig
{
Name = "LIMITDESC",
Subjects = ["a"],
Description = new string('d', JetStreamApiLimits.JSMaxDescriptionLen + 1),
});
response.Error.ShouldNotBeNull();
response.Error!.Description.ShouldBe("stream description is too long");
}
[Fact]
public void Stream_create_rejects_metadata_over_max_bytes()
{
var manager = new StreamManager();
var response = manager.CreateOrUpdate(new StreamConfig
{
Name = "LIMITMETA",
Subjects = ["a"],
Metadata = new Dictionary<string, string>
{
["k"] = new string('m', JetStreamApiLimits.JSMaxMetadataLen),
},
});
response.Error.ShouldNotBeNull();
response.Error!.Description.ShouldBe("stream metadata exceeds maximum size");
}
[Fact]
public void Consumer_create_rejects_durable_name_over_max_length()
{
var manager = new ConsumerManager();
var response = manager.CreateOrUpdate("S", new ConsumerConfig
{
DurableName = new string('C', JetStreamApiLimits.JSMaxNameLen + 1),
});
response.Error.ShouldNotBeNull();
response.Error!.Description.ShouldBe("invalid durable name");
}
[Fact]
public void Consumer_create_rejects_metadata_over_max_bytes()
{
var manager = new ConsumerManager();
var response = manager.CreateOrUpdate("S", new ConsumerConfig
{
DurableName = "C1",
Metadata = new Dictionary<string, string>
{
["k"] = new string('m', JetStreamApiLimits.JSMaxMetadataLen),
},
});
response.Error.ShouldNotBeNull();
response.Error!.Description.ShouldBe("consumer metadata exceeds maximum size");
}
}