test: add E2E JetStream push consumers, ACK policies, retention modes, ordered, mirror, source

Adds 8 new E2E tests to JetStreamTests.cs (tests 11-18) covering push
consumer config, AckNone/AckAll policies, Interest/WorkQueue retention,
ordered consumers, mirror streams, and source streams.

Fixes three server gaps exposed by the new tests: mirror JSON parsing
(deliver_subject and mirror object fields were silently ignored in stream
and consumer API handlers), and deliver_subject omitted from consumer
info wire format. Also fixes ShutdownDrainTests to use TaskCompletionSource
on ConnectionDisconnected instead of a Task.Delay poll loop.
This commit is contained in:
Joseph Doherty
2026-03-12 19:36:29 -04:00
parent 76f8ccec2e
commit 5d9d1bebd5
5 changed files with 408 additions and 2 deletions

View File

@@ -308,6 +308,18 @@ public static class ConsumerApiHandlers
if (configEl.TryGetProperty("ephemeral", out var ephemeralEl) && ephemeralEl.ValueKind == JsonValueKind.True)
config.Ephemeral = true;
// Go: consumer.go — deliver_subject marks a consumer as push-based.
// Reference: server/consumer.go:deliverSubject field on ConsumerConfig
if (configEl.TryGetProperty("deliver_subject", out var deliverSubjectEl))
{
var ds = deliverSubjectEl.GetString();
if (!string.IsNullOrWhiteSpace(ds))
{
config.DeliverSubject = ds;
config.Push = true; // presence of deliver_subject implies push mode
}
}
if (configEl.TryGetProperty("push", out var pushEl) && pushEl.ValueKind == JsonValueKind.True)
config.Push = true;

View File

@@ -516,6 +516,16 @@ public static class StreamApiHandlers
config.Storage = StorageType.Memory;
}
// Go: stream.go — mirror field is a StreamSource object with at minimum a "name" key.
// Reference: server/stream.go:NormalizeConfig mirror handling
if (root.TryGetProperty("mirror", out var mirrorEl))
{
if (mirrorEl.ValueKind == JsonValueKind.Object && mirrorEl.TryGetProperty("name", out var mirrorNameEl))
config.Mirror = mirrorNameEl.GetString();
else if (mirrorEl.ValueKind == JsonValueKind.String)
config.Mirror = mirrorEl.GetString();
}
if (root.TryGetProperty("source", out var sourceEl))
config.Source = sourceEl.GetString();

View File

@@ -157,6 +157,8 @@ public sealed class JetStreamApiResponse
max_deliver = c.MaxDeliver,
max_ack_pending = c.MaxAckPending,
filter_subject = c.FilterSubject,
// Go: consumer.go — deliver_subject present for push consumers
deliver_subject = string.IsNullOrEmpty(c.DeliverSubject) ? null : c.DeliverSubject,
};
public static JetStreamApiResponse NotFound(string subject) => new()