using System.Security.Cryptography; using System.Text; using System.Text.Json; using XFEExtension.NetCore.XUnit.Attributes; using XFEEDToolBox.Core.Execution; namespace XFEEDToolBox.Test; [TestFixture] public class NativeCommunityGoalClientTests { private sealed class Channel:IOriginalCommerceChannel { public string Identity=>"test-session"; public int Reads,Polls,Refusals=2; public string? Failure; public bool CancelAfterRefusal; public CancellationTokenSource? Stop; public Task CallAsync(object request,CancellationToken token) { token.ThrowIfCancellationRequested();var command=JsonSerializer.SerializeToElement(request); var op=command.GetProperty("op").GetString(); if(op=="cg.read.mine") { Reads++; if(Failure is not null)throw new InvalidOperationException(Failure); if(Reads<=Refusals){if(CancelAfterRefusal)Stop!.Cancel();throw new InvalidOperationException("Fresh healthy docking at the requested CG market required");} return Task.FromResult(JsonSerializer.SerializeToElement(new{generation=17UL})); } if(op!="cg.status")throw new InvalidOperationException("Unexpected mutation or replay"); Check.Equal(17UL,command.GetProperty("generation").GetUInt64());Polls++; if(Polls==1)throw new IOException("Transient status transport failure"); const string body="{\"initiatives\":[]}"; return Task.FromResult(JsonSerializer.SerializeToElement(new{state=3,kind=2,mutationsSent=0,fresh=true,responseBody=body, proof=Convert.ToHexStringLower(SHA256.HashData(Encoding.UTF8.GetBytes(body)))})); } } [Test] public async Task DockingTransitionWaitsThenPollsOnlyTheAcceptedRead() { var channel=new Channel();var result=await new NativeCommunityGoalClient(channel).ReadAsync(true); Check.Equal(3,channel.Reads);Check.Equal(2,channel.Polls);Check.Equal(17UL,result.Generation);Check.Equal(0,result.Goals.Count); } [Test] public async Task UnrelatedRefusalRemainsTerminal() { var channel=new Channel{Failure="Wrong game identity"};var rejected=false; try{await new NativeCommunityGoalClient(channel).ReadAsync(true);}catch(InvalidOperationException error){rejected=error.Message==channel.Failure;} Check.That(rejected);Check.Equal(1,channel.Reads);Check.Equal(0,channel.Polls); } [Test] public async Task CancellationDuringDockingWaitDoesNotQueueAnotherRequest() { using var stop=new CancellationTokenSource();var channel=new Channel{Stop=stop,CancelAfterRefusal=true};var cancelled=false; try{await new NativeCommunityGoalClient(channel).ReadAsync(true,stop.Token);}catch(OperationCanceledException){cancelled=true;} Check.That(cancelled);Check.Equal(1,channel.Reads);Check.Equal(0,channel.Polls); } }