File: Latency\Internal\HttpLatencyMediatorTests.cs
Web Access
Project: src\test\Libraries\Microsoft.Extensions.Http.Diagnostics.Tests\Microsoft.Extensions.Http.Diagnostics.Tests.csproj (Microsoft.Extensions.Http.Diagnostics.Tests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
#if NET
using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.AmbientMetadata;
using Microsoft.Extensions.Diagnostics.Latency;
using Microsoft.Extensions.Http.Latency.Internal;
using Microsoft.Extensions.Options;
using Moq;
using Moq.Protected;
using Xunit;
 
namespace Microsoft.Extensions.Http.Latency.Test.Internal;
 
public class HttpLatencyMediatorTests
{
    [Fact]
    public void RecordStart_RecordsGCPauseMeasure()
    {
        // Arrange
        var lcti = HttpMockProvider.GetTokenIssuer();
        var measureToken = new MeasureToken(HttpMeasures.GCPauseTime, 0);
        lcti.Setup(i => i.GetMeasureToken(HttpMeasures.GCPauseTime))
            .Returns(measureToken);
 
        var lc = HttpMockProvider.GetLatencyContext();
        var mediator = new HttpLatencyMediator(lcti.Object);
 
        // Act
        mediator.RecordStart(lc.Object);
 
        // Assert
        // Verify RecordMeasure was called with the correct token
        lc.Verify(c => c.RecordMeasure(
                measureToken,
                It.Is<long>(v => v <= 0)), // Value should be negative (start value)
            Times.Once);
    }
 
    [Fact]
    public async Task HttpLatencyTelemetryHandler_UsesMediator()
    {
        // Arrange
        var lc = HttpMockProvider.GetLatencyContext();
        var lcp = HttpMockProvider.GetContextProvider(lc);
        lcp.Setup(p => p.CreateContext()).Returns(lc.Object);
 
        var context = new HttpClientLatencyContext();
 
        var sop = new Mock<IOptions<ApplicationMetadata>>();
        sop.Setup(a => a.Value).Returns(new ApplicationMetadata());
        var hop = new Mock<IOptions<HttpClientLatencyTelemetryOptions>>();
        hop.Setup(a => a.Value).Returns(new HttpClientLatencyTelemetryOptions());
 
        var lcti = HttpMockProvider.GetTokenIssuer();
 
        // Create a mediator
        var mediator = new HttpLatencyMediator(lcti.Object);
 
        using var listener = HttpMockProvider.GetListener(context, lcti.Object);
        using var req = new HttpRequestMessage();
        req.Method = HttpMethod.Post;
        req.RequestUri = new Uri($"https://default-uri.com/foo");
 
        var resp = new HttpResponseMessage();
        var mockHandler = new Mock<DelegatingHandler>();
        mockHandler.Protected().Setup<Task<HttpResponseMessage>>(
                "SendAsync",
                ItExpr.IsAny<HttpRequestMessage>(),
                ItExpr.IsAny<CancellationToken>())
            .ReturnsAsync(resp);
 
        using var handler = new HttpLatencyTelemetryHandler(
            listener, lcti.Object, lcp.Object, hop.Object, sop.Object, mediator);
        handler.InnerHandler = mockHandler.Object;
 
        // Act
        using var client = new HttpClient(handler);
        await client.SendAsync(req, It.IsAny<CancellationToken>());
 
        // Verify that the latency context was created and properly used
        lcp.Verify(p => p.CreateContext(), Times.Once);
        resp.Dispose();
    }
 
    [Fact]
    public void RecordEnd_RecordsGCPauseMeasure()
    {
        // Arrange
        var lcti = HttpMockProvider.GetTokenIssuer();
        var measureToken = new MeasureToken(HttpMeasures.GCPauseTime, 0);
        lcti.Setup(i => i.GetMeasureToken(HttpMeasures.GCPauseTime))
            .Returns(measureToken);
 
        var lc = HttpMockProvider.GetLatencyContext();
        var mediator = new HttpLatencyMediator(lcti.Object);
 
        // Act
        mediator.RecordEnd(lc.Object);
 
        lc.Verify(c => c.AddMeasure(measureToken, It.IsAny<long>()), Times.Once);
    }
 
    [Fact]
    public void RecordEnd_WithResponse_SetsHttpVersionTag()
    {
        // Arrange
        var lcti = HttpMockProvider.GetTokenIssuer();
        var httpVersionToken = new TagToken(HttpTags.HttpVersion, 0);
        lcti.Setup(i => i.GetTagToken(HttpTags.HttpVersion))
            .Returns(httpVersionToken);
 
        var lc = HttpMockProvider.GetLatencyContext();
        var mediator = new HttpLatencyMediator(lcti.Object);
 
        using var response = new HttpResponseMessage();
        response.Version = new Version(2, 0);
 
        // Act
        mediator.RecordEnd(lc.Object, response);
 
        // Assert
        lc.Verify(c => c.SetTag(
                httpVersionToken,
                "2.0"),
            Times.Once);
    }
 
    [Fact]
    public void RecordEnd_WithNullResponse_DoesNotSetHttpVersionTag()
    {
        // Arrange
        var lcti = HttpMockProvider.GetTokenIssuer();
        var httpVersionToken = new TagToken("Http.Version", 0);
        lcti.Setup(i => i.GetTagToken(HttpTags.HttpVersion))
            .Returns(httpVersionToken);
 
        var lc = HttpMockProvider.GetLatencyContext();
        var mediator = new HttpLatencyMediator(lcti.Object);
 
        // Act
        mediator.RecordEnd(lc.Object);
 
        // Assert
        lc.Verify(c => c.SetTag(
                It.Is<TagToken>(t => t.Name == HttpTags.HttpVersion),
                It.IsAny<string>()),
            Times.Never);
    }
}
#endif