XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFEEDToolBox

【WinUI】XFE精英危险工具箱

公开
关注 0 Fork 0 Star 0
UTF-8
using XFEEDToolBox.Core.Galaxy;
using XFEEDToolBox.Core.Models;
using XFEExtension.NetCore.XUnit.Attributes;

namespace XFEEDToolBox.Test;

[TestFixture]
public class GalaxyCellStreamingTests
{
    private static GalaxyCellQueryPlan Plan(double z = 5, Coordinates? origin = null)
    {
        var centre = new Coordinates(5, 5, z);
        return new(GalaxyCamera.Create(centre, 1600, 900, 0, 0, 4),
            GalaxyOriginalCatalogueLod.Create(centre, 1, 500, .001, 1, 0), origin ?? new(0, 0, 0));
    }
    private static GalacticSystem Star(ulong cell, Coordinates? position = null) =>
        new("Fixture " + cell, position ?? new(9, 9, 9), (long)(cell | (1UL << (44 - 3 * (int)(cell & 7)))));
    private static GalaxyRegionResult Receipt(IReadOnlyList<ulong> cells, IReadOnlyList<GalacticSystem>? stars = null) =>
        new(stars ?? cells.Select(c => Star(c)).ToArray(), (int)cells.Min(c => c & 7), cells.Count, cells.Count, false, true)
        { Scope = "requested-cells", RequestedCells = cells.Count, Origin = new(0, 0, 0) };
    private static async Task<List<GalaxyCellStreamUpdate>> Collect(GalaxyCellStreamingSession session, GalaxyCellQueryPlan plan,
        Func<Coordinates, IReadOnlyList<double>, IReadOnlyList<ulong>, CancellationToken, Task<GalaxyRegionResult>> query)
    {
        var updates = new List<GalaxyCellStreamUpdate>();
        await foreach (var update in session.StreamAsync(plan, query)) updates.Add(update);
        return updates;
    }

    [Test] public void ReceiptProvesOnlyTheExactRequestedMassCells()
    {
        var actual = Receipt(new ulong[] { 7 });
        Check.That(GalaxyCellStreamingSession.CoversRequestedCells(actual, 1));
        Check.That(!actual.IsFullyCovered, "A requested mass-seven cell is not evidence of a whole all-mass region.");
        Check.That(!GalaxyCellStreamingSession.CoversRequestedCells(actual, 2));
        Check.That(!GalaxyCellStreamingSession.CoversRequestedCells(actual with { Scope = "region" }, 1));
        Check.That(!GalaxyCellStreamingSession.CoversRequestedCells(actual with { RequestedCells = -1 }, 1));
        Check.That(!GalaxyCellStreamingSession.CoversRequestedCells(actual with { FailedCells = 1 }, 1));
    }

    [Test] public async Task CappedBatchesSplitCellListsWithoutClippingOrDuplicatingEdgeStars()
    {
        using var session = new GalaxyCellStreamingSession(); var plan = Plan();
        Task<GalaxyRegionResult> Query(Coordinates centre, IReadOnlyList<double> radii, IReadOnlyList<ulong> cells, CancellationToken token)
        {
            var result = Receipt(cells);
            return Task.FromResult(cells.Count > 1 ? result with { Systems = [Star(cells[0])], Truncated = true, Complete = false } : result);
        }
        var updates = await Collect(session, plan, Query);
        var rows = updates.SelectMany(u => u.Systems).ToArray();
        Check.That(updates[^1].CoverageComplete && updates[^1].RefinedBatches > 0);
        Check.Equal(plan.Cells.Count, rows.Length);
        Check.Equal(rows.Length, rows.Select(s => s.SystemAddress).Distinct().Count());
        Check.That(rows.Any(s => s.Position.DistanceTo(plan.Descriptor.Centre) > plan.Descriptor.InnerRadius));
        var repeated = await Collect(session, plan, (_, _, _, _) => throw new Exception("Complete cell should be cached"));
        Check.That(repeated[^1].CoverageComplete && repeated.Any(u => u.FromCache));
    }

    [Test] public async Task UnknownAndFailedSingleCellsRemainRetryableInsteadOfBecomingEmptyCoverage()
    {
        using var session = new GalaxyCellStreamingSession(new() { BatchSize = 1 }); var plan = Plan();
        var first = await Collect(session, plan, (_, _, cells, _) => Task.FromResult(new GalaxyRegionResult([], (int)(cells[0] & 7), 1, 1){Origin=new(0,0,0)}));
        Check.That(!first[^1].CoverageComplete && first[^1].UnverifiedCells == plan.Cells.Count);
        var retried = 0;
        var second = await Collect(session, plan, (_, _, cells, _) => { retried++; return Task.FromResult(Receipt(cells, [])); });
        Check.That(second[^1].CoverageComplete && retried == plan.Cells.Count);
    }

    [Test] public async Task OffRequestAndConflictingRowsCannotPoisonTheCellCache()
    {
        using var session = new GalaxyCellStreamingSession(); var plan = Plan();
        var rejected = false;
        try { await Collect(session, plan, (_, _, cells, _) => Task.FromResult(Receipt(cells, [Star(GalaxyCellQueryPlan.Encode(0, 10, 10, 10))]))); }
        catch (InvalidDataException) { rejected = true; }
        Check.That(rejected && session.CachedCells == 0);
        rejected = false;
        try { await Collect(session, plan, (_, _, cells, _) => Task.FromResult(Receipt(cells) with { Origin = new(1, 2, 3) })); }
        catch (InvalidDataException) { rejected = true; }
        Check.That(rejected && session.CachedCells == 0);
        rejected = false;
        try { await Collect(session, plan, (_, _, cells, _) => Task.FromResult(Receipt(cells, [Star(cells[0]), Star(cells[0], new(2, 3, 4))]))); }
        catch (InvalidDataException) { rejected = true; }
        Check.That(rejected && session.CachedCells == 0);
    }

    [Test] public async Task LatestDisjointViewCancelsOldWorkAndNeverPublishesItsRows()
    {
        using var session = new GalaxyCellStreamingSession(); var started = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
        async Task<GalaxyRegionResult> Old(Coordinates centre, IReadOnlyList<double> radii, IReadOnlyList<ulong> cells, CancellationToken token)
        { started.SetResult(); await Task.Delay(Timeout.Infinite, token); return Receipt(cells); }
        await using var old = session.StreamAsync(Plan(), Old).GetAsyncEnumerator();
        var oldMove = old.MoveNextAsync().AsTask(); await started.Task.WaitAsync(TimeSpan.FromSeconds(3));
        var latest = await Collect(session, Plan(10005), (_, _, cells, _) => Task.FromResult(Receipt(cells, [])));
        var cancelled = false; try { await oldMove; } catch (OperationCanceledException) { cancelled = true; }
        Check.That(cancelled && latest[^1].CoverageComplete && latest.All(u => u.Systems.Count == 0));
    }

    [Test] public async Task UsefulInflightCellsCanFinishForTheNewViewWithoutStalePublication()
    {
        using var session = new GalaxyCellStreamingSession(); var plan = Plan();
        var started = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
        var release = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
        async Task<GalaxyRegionResult> Query(Coordinates centre, IReadOnlyList<double> radii, IReadOnlyList<ulong> cells, CancellationToken token)
        { started.SetResult(); await release.Task.WaitAsync(token); return Receipt(cells); }
        await using var old = session.StreamAsync(plan, Query).GetAsyncEnumerator();
        var oldMove = old.MoveNextAsync().AsTask(); await started.Task.WaitAsync(TimeSpan.FromSeconds(3));
        var latestTask = Collect(session, plan, (_, _, _, _) => throw new Exception("Useful accepted cells should be reused"));
        release.SetResult(); var latest = await latestTask;
        var cancelled = false; try { await oldMove; } catch (OperationCanceledException) { cancelled = true; }
        Check.That(cancelled && latest[^1].CoverageComplete && latest.Any(u => u.FromCache && u.Systems.Count > 0));
    }

    [Test] public async Task CoordinateOriginIsPartOfTheCacheIdentityAndEvictionRemainsBounded()
    {
        using var session = new GalaxyCellStreamingSession(new() { MaximumCachedCells = 2, MaximumCachedSystems = 2 });
        await Collect(session, Plan(), (_, _, cells, _) => Task.FromResult(Receipt(cells)));
        Check.That(session.CachedCells <= 2);
        var queried = 0;
        await Collect(session, Plan(origin: new(100, 100, 100)), (_, _, cells, _) => { queried++; return Task.FromResult(Receipt(cells) with {Origin=new(100,100,100)}); });
        Check.That(queried > 0 && session.CachedCells <= 2);
    }

    [Test] public async Task PartlyOverlappingPanKeepsUsefulAcceptedCellsAndQueriesOnlyTheNewOnes()
    {
        using var session = new GalaxyCellStreamingSession(); var first = Plan(); var next = Plan(15);
        var oldIds = first.Cells.Select(c => c.Address).ToHashSet();
        var newIds = next.Cells.Select(c => c.Address).ToHashSet();
        Check.That(oldIds.Overlaps(newIds) && !oldIds.SetEquals(newIds));
        var started = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
        var release = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
        async Task<GalaxyRegionResult> Original(Coordinates centre, IReadOnlyList<double> radii, IReadOnlyList<ulong> cells, CancellationToken token)
        { started.SetResult(); await release.Task.WaitAsync(token); return Receipt(cells); }
        await using var old = session.StreamAsync(first, Original).GetAsyncEnumerator();
        var oldMove = old.MoveNextAsync().AsTask(); await started.Task.WaitAsync(TimeSpan.FromSeconds(3));
        var queried = new List<ulong>();
        var latestTask = Collect(session, next, (_, _, cells, _) => { queried.AddRange(cells); return Task.FromResult(Receipt(cells)); });
        release.SetResult(); var latest = await latestTask;
        var cancelled = false; try { await oldMove; } catch (OperationCanceledException) { cancelled = true; }
        Check.That(cancelled && latest[^1].CoverageComplete && latest.Any(u => u.FromCache));
        Check.That(queried.ToHashSet().SetEquals(newIds.Except(oldIds)));
    }
}