File: Latency\AddServerTimingHeaderMiddlewareTests.cs
Web Access
Project: src\test\Libraries\Microsoft.AspNetCore.Diagnostics.Middleware.Tests\Microsoft.AspNetCore.Diagnostics.Middleware.Tests.csproj (Microsoft.AspNetCore.Diagnostics.Middleware.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;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Diagnostics.Latency;
using Xunit;
 
namespace Microsoft.AspNetCore.Diagnostics.Latency.Test;
 
public class AddServerTimingHeaderMiddlewareTests
{
    private static readonly RequestDelegate _stubRequestDelegate =
        static _ => Task.CompletedTask;
 
    [Fact]
    public async Task Middleware_ReturnsTotalMillisecondsElapsed_InsteadOfFraction()
    {
        const long TimeAdvanceMs = 1500L; // We need to use any value greater than 1000 (1 second)
 
        using FakeLatencyContext fakeLatencyContextController = new();
        Checkpoint checkpoint = new(RequestCheckpointConstants.ElapsedTillHeaders, TimeAdvanceMs, 1000);
        ArraySegment<Checkpoint> checkpoints = new(new[] { checkpoint });
        fakeLatencyContextController.LatencyData = new LatencyData(default, checkpoints, default, default, default);
 
        using var serviceProvider = new ServiceCollection()
            .AddSingleton<ILatencyContext>(_ => fakeLatencyContextController)
            .BuildServiceProvider();
 
        var context = new DefaultHttpContext
        {
            RequestServices = serviceProvider
        };
 
        var fakeHttpResponseFeature = new FakeHttpResponseFeature();
        context.Features.Set<IHttpResponseFeature>(fakeHttpResponseFeature);
 
        var middleware = new AddServerTimingHeaderMiddleware(_stubRequestDelegate);
        await middleware.InvokeAsync(context);
        await fakeHttpResponseFeature.StartAsync();
 
        var header = context.Response.Headers[AddServerTimingHeaderMiddleware.ServerTimingHeaderName];
        Assert.True(header.Count > 0);
        Assert.Equal($"reqlatency;dur={TimeAdvanceMs}", header[0]);
    }
 
    private sealed class FakeHttpResponseFeature : HttpResponseFeature
    {
        private Func<Task> _responseStartingAsync =
            static () => Task.CompletedTask;
 
        public override void OnStarting(Func<object, Task> callback, object state)
        {
            var prior = _responseStartingAsync;
            _responseStartingAsync = async () =>
            {
                await callback(state);
                await prior();
            };
        }
 
        public async Task StartAsync() => await _responseStartingAsync();
    }
 
    private sealed class FakeLatencyContext : ILatencyContext
    {
        public LatencyData LatencyData { get; set; }
 
        public void AddCheckpoint(CheckpointToken token) => throw new NotSupportedException();
        public void AddMeasure(MeasureToken token, long value) => throw new NotSupportedException();
        public void Dispose()
        {
            // Method intentionally left empty.
        }
 
        public void Freeze() => throw new NotSupportedException();
        public void RecordMeasure(MeasureToken _0, long _1) => throw new NotSupportedException();
        public void SetTag(TagToken _0, string _1) => throw new NotSupportedException();
    }
}