File: CachedResponseBodyTests.cs
Web Access
Project: src\src\Middleware\OutputCaching\test\Microsoft.AspNetCore.OutputCaching.Tests.csproj (Microsoft.AspNetCore.OutputCaching.Tests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Buffers;
using System.Diagnostics;
using System.IO.Pipelines;
 
namespace Microsoft.AspNetCore.OutputCaching.Tests;
 
public class CachedResponseBodyTests
{
    private readonly int _timeout = Debugger.IsAttached ? -1 : 5000;
 
    [Fact]
    public void GetSegments()
    {
        var segments = new List<byte[]>();
        var body = RecyclableReadOnlySequenceSegment.CreateSequence(segments);
 
        Assert.True(body.IsEmpty);
        RecyclableReadOnlySequenceSegment.RecycleChain(body);
    }
 
    [Fact]
    public async Task Copy_DoNothingWhenNoSegments()
    {
        var segments = new List<byte[]>();
        var receivedSegments = new List<byte[]>();
        var body = RecyclableReadOnlySequenceSegment.CreateSequence(segments);
 
        var pipe = new Pipe();
        using var cts = new CancellationTokenSource(_timeout);
 
        var receiverTask = ReceiveDataAsync(pipe.Reader, receivedSegments, cts.Token);
        var copyTask = RecyclableReadOnlySequenceSegment.CopyToAsync(body, pipe.Writer, cts.Token).AsTask().ContinueWith(t => pipe.Writer.CompleteAsync(t.Exception));
 
        await Task.WhenAll(receiverTask, copyTask);
 
        Assert.Empty(receivedSegments);
        RecyclableReadOnlySequenceSegment.RecycleChain(body);
    }
 
    [Fact]
    public async Task Copy_SingleSegment()
    {
        var segments = new List<byte[]>
            {
                new byte[] { 1 }
            };
        var receivedSegments = new List<byte[]>();
        var body = RecyclableReadOnlySequenceSegment.CreateSequence(segments);
 
        var pipe = new Pipe();
 
        using var cts = new CancellationTokenSource(_timeout);
 
        var receiverTask = ReceiveDataAsync(pipe.Reader, receivedSegments, cts.Token);
        var copyTask = CopyDataAsync(body, pipe.Writer, cts.Token);
 
        await Task.WhenAll(receiverTask, copyTask);
 
        Assert.Equal(segments, receivedSegments);
        RecyclableReadOnlySequenceSegment.RecycleChain(body);
    }
 
    [Fact]
    public async Task Copy_MultipleSegments()
    {
        var segments = new List<byte[]>
            {
                new byte[] { 1 },
                new byte[] { 2, 3 }
            };
        var receivedSegments = new List<byte[]>();
        var body = RecyclableReadOnlySequenceSegment.CreateSequence(segments);
 
        var pipe = new Pipe();
 
        using var cts = new CancellationTokenSource(_timeout);
 
        var receiverTask = ReceiveDataAsync(pipe.Reader, receivedSegments, cts.Token);
        var copyTask = CopyDataAsync(body, pipe.Writer, cts.Token);
 
        await Task.WhenAll(receiverTask, copyTask);
 
        Assert.Equal(new byte[] { 1, 2, 3 }, receivedSegments.SelectMany(x => x).ToArray());
        RecyclableReadOnlySequenceSegment.RecycleChain(body);
    }
 
    static async Task CopyDataAsync(ReadOnlySequence<byte> body, PipeWriter writer, CancellationToken cancellationToken)
    {
        await RecyclableReadOnlySequenceSegment.CopyToAsync(body, writer, cancellationToken);
        await writer.CompleteAsync();
    }
 
    static async Task ReceiveDataAsync(PipeReader reader, List<byte[]> receivedSegments, CancellationToken cancellationToken)
    {
        while (true)
        {
            var result = await reader.ReadAsync(cancellationToken);
            var buffer = result.Buffer;
 
            foreach (var memory in buffer)
            {
                receivedSegments.Add(memory.ToArray());
            }
 
            reader.AdvanceTo(buffer.End, buffer.End);
 
            if (result.IsCompleted)
            {
                break;
            }
        }
        await reader.CompleteAsync();
    }
}