72 lines
2.2 KiB
C#
72 lines
2.2 KiB
C#
using System.Text;
|
|
using NATS.Server.JetStream;
|
|
using NATS.Server.JetStream.Models;
|
|
using NATS.Server.JetStream.Publish;
|
|
|
|
namespace NATS.Server.Tests;
|
|
|
|
public class JetStreamStreamReplicaGroupTests
|
|
{
|
|
[Fact]
|
|
public async Task Leader_stepdown_preserves_stream_write_availability_after_new_election()
|
|
{
|
|
await using var fixture = await JetStreamReplicaFixture.StartAsync(nodes: 3);
|
|
await fixture.CreateStreamAsync("ORDERS", replicas: 3);
|
|
|
|
await fixture.StepDownStreamLeaderAsync("ORDERS");
|
|
var ack = await fixture.PublishAndGetAckAsync("orders.created", "1");
|
|
|
|
ack.Stream.ShouldBe("ORDERS");
|
|
ack.Seq.ShouldBeGreaterThan((ulong)0);
|
|
}
|
|
}
|
|
|
|
internal sealed class JetStreamReplicaFixture : IAsyncDisposable
|
|
{
|
|
private readonly StreamManager _streamManager;
|
|
private readonly JetStreamPublisher _publisher;
|
|
|
|
private JetStreamReplicaFixture(StreamManager streamManager)
|
|
{
|
|
_streamManager = streamManager;
|
|
_publisher = new JetStreamPublisher(_streamManager);
|
|
}
|
|
|
|
public static Task<JetStreamReplicaFixture> StartAsync(int nodes)
|
|
{
|
|
_ = nodes;
|
|
var streamManager = new StreamManager();
|
|
return Task.FromResult(new JetStreamReplicaFixture(streamManager));
|
|
}
|
|
|
|
public Task CreateStreamAsync(string name, int replicas)
|
|
{
|
|
var response = _streamManager.CreateOrUpdate(new StreamConfig
|
|
{
|
|
Name = name,
|
|
Subjects = ["orders.*"],
|
|
Replicas = replicas,
|
|
});
|
|
|
|
if (response.Error is not null)
|
|
throw new InvalidOperationException(response.Error.Description);
|
|
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
public Task StepDownStreamLeaderAsync(string stream)
|
|
{
|
|
return _streamManager.StepDownStreamLeaderAsync(stream, default);
|
|
}
|
|
|
|
public Task<PubAck> PublishAndGetAckAsync(string subject, string payload)
|
|
{
|
|
if (_publisher.TryCapture(subject, Encoding.UTF8.GetBytes(payload), null, out var ack))
|
|
return Task.FromResult(ack);
|
|
|
|
throw new InvalidOperationException("Publish did not match a stream.");
|
|
}
|
|
|
|
public ValueTask DisposeAsync() => ValueTask.CompletedTask;
|
|
}
|