Server-side scenario execution: effects client replaces local engine

- client.Effects: typed effects + completion methods posting scenario callbacks
- client.Scenario reduced to TriggerAsync
- pending polling via Update() pump: 30s heartbeat + wait-deadline checks
- local engine, plan persistence (IPlanStateStore) and resume removed
- RealtimeService and realtime transports removed (relay never deployed)
- dead IPlanScheduler leftover removed
- models regenerated from openapi (ExecutionPlan/BoundaryNode gone, PendingEffect added)
This commit is contained in:
edmand46
2026-09-04 14:03:41 +03:00
parent 05dd30f31d
commit 6c590ca520
52 changed files with 1304 additions and 2040 deletions
+3 -65
View File
@@ -23,7 +23,7 @@ public sealed class RudderClientTests
Assert.NotNull(client.BattlePass);
Assert.NotNull(client.Quests);
Assert.NotNull(client.Scenario);
Assert.NotNull(client.Realtime);
Assert.NotNull(client.Effects);
}
[Fact]
@@ -85,37 +85,17 @@ public sealed class RudderClientTests
Assert.Equal(new[] { RudderAuthState.SignedOut }, states);
}
[Fact]
public async Task Realtime_Connect_Returns_Session_From_Injected_Transport()
{
var realtimeTransport = new FakeRealtimeTransport();
var tokenStore = new FakeTokenStore { AccessToken = "access-token" };
var client = CreateClient(
tokenStore: tokenStore,
realtimeTransportFactory: new FakeRealtimeTransportFactory(realtimeTransport));
var session = await client.Realtime.ConnectAsync();
Assert.NotNull(session);
Assert.True(session.IsConnected);
Assert.Equal("access-token", session.AccessToken);
Assert.Equal(new Uri("ws://localhost:8090/api/realtime/ws"), realtimeTransport.Uri);
}
private static RudderClient CreateClient(
FakeTransport? transport = null,
FakeTokenStore? tokenStore = null,
IRealtimeTransportFactory? realtimeTransportFactory = null)
FakeTokenStore? tokenStore = null)
{
return new RudderClient(new RudderClientOptions
{
BaseUrl = "http://localhost:8082",
RealtimeUrl = "ws://localhost:8090/api/realtime/ws",
ProjectKey = "project-key",
Transport = transport ?? new FakeTransport(),
TokenStore = tokenStore ?? new FakeTokenStore(),
DeviceIdProvider = new FakeDeviceIdProvider(),
RealtimeTransportFactory = realtimeTransportFactory ?? new FakeRealtimeTransportFactory(new FakeRealtimeTransport())
DeviceIdProvider = new FakeDeviceIdProvider()
});
}
@@ -169,46 +149,4 @@ public sealed class RudderClientTests
{
public string DeviceId => "device-id";
}
private sealed class FakeRealtimeTransportFactory : IRealtimeTransportFactory
{
private readonly IRealtimeTransport _transport;
public FakeRealtimeTransportFactory(IRealtimeTransport transport) => _transport = transport;
public IRealtimeTransport Create() => _transport;
}
private sealed class FakeRealtimeTransport : IRealtimeTransport
{
public Uri? Uri { get; private set; }
public bool IsConnected { get; private set; }
public event Action? Closed;
public event Action<Exception>? Error;
public event Action<ArraySegment<byte>>? Received;
public Task ConnectAsync(Uri uri, TimeSpan timeout, CancellationToken cancellationToken = default)
{
Uri = uri;
IsConnected = true;
return Task.CompletedTask;
}
public Task SendAsync(ArraySegment<byte> payload, CancellationToken cancellationToken = default)
=> Task.CompletedTask;
public Task CloseAsync(CancellationToken cancellationToken = default)
{
IsConnected = false;
Closed?.Invoke();
return Task.CompletedTask;
}
public void Update(float deltaTime)
{
}
public void EmitError(Exception ex) => Error?.Invoke(ex);
public void EmitReceived(ArraySegment<byte> data) => Received?.Invoke(data);
}
}