File: HeaderPropagationMessageHandlerTest.cs
Web Access
Project: src\src\Middleware\HeaderPropagation\test\Microsoft.AspNetCore.HeaderPropagation.Tests.csproj (Microsoft.AspNetCore.HeaderPropagation.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.Net.Http;
using System.Net.Http.Headers;
using Microsoft.Extensions.Primitives;
 
namespace Microsoft.AspNetCore.HeaderPropagation.Tests;
 
public class HeaderPropagationMessageHandlerTest
{
    public HeaderPropagationMessageHandlerTest()
    {
        Handler = new SimpleHandler();
 
        State = new HeaderPropagationValues();
        State.Headers = new Dictionary<string, StringValues>(StringComparer.OrdinalIgnoreCase);
 
        Configuration = new HeaderPropagationMessageHandlerOptions();
 
        var headerPropagationMessageHandler =
            new HeaderPropagationMessageHandler(Configuration, State)
            {
                InnerHandler = Handler
            };
 
        Client = new HttpClient(headerPropagationMessageHandler)
        {
            BaseAddress = new Uri("http://example.com")
        };
    }
 
    private SimpleHandler Handler { get; }
    public HeaderPropagationValues State { get; set; }
    public HeaderPropagationMessageHandlerOptions Configuration { get; set; }
    public HttpClient Client { get; set; }
 
    [Fact]
    public async Task HeaderInState_AddCorrectValue()
    {
        // Arrange
        Configuration.Headers.Add("out");
        State.Headers.Add("out", "test");
 
        // Act
        await Client.SendAsync(new HttpRequestMessage());
 
        // Assert
        Assert.True(Handler.Headers.Contains("out"));
        Assert.Equal(new[] { "test" }, Handler.Headers.GetValues("out"));
    }
 
    [Fact]
    public async Task HeaderInState_WithMultipleValues_AddAllValues()
    {
        // Arrange
        Configuration.Headers.Add("out");
        State.Headers.Add("out", new[] { "one", "two" });
 
        // Act
        await Client.SendAsync(new HttpRequestMessage());
 
        // Assert
        Assert.True(Handler.Headers.Contains("out"));
        Assert.Equal(new[] { "one", "two" }, Handler.Headers.GetValues("out"));
    }
 
    [Fact]
    public async Task HeaderInState_RequestWithContent_ContentHeaderPresent_DoesNotAddIt()
    {
        Configuration.Headers.Add("Content-Type");
        State.Headers.Add("Content-Type", "test");
 
        // Act
        await Client.SendAsync(new HttpRequestMessage() { Content = new StringContent("test") });
 
        // Assert
        Assert.True(Handler.Content.Headers.Contains("Content-Type"));
        Assert.Equal(new[] { "text/plain; charset=utf-8" }, Handler.Content.Headers.GetValues("Content-Type"));
    }
 
    [Fact]
    public async Task HeaderInState_RequestWithContent_ContentHeaderNotPresent_AddValue()
    {
        Configuration.Headers.Add("Content-Language");
        State.Headers.Add("Content-Language", "test");
 
        // Act
        await Client.SendAsync(new HttpRequestMessage() { Content = new StringContent("test") });
 
        // Assert
        Assert.True(Handler.Content.Headers.Contains("Content-Language"));
        Assert.Equal(new[] { "test" }, Handler.Content.Headers.GetValues("Content-Language"));
    }
 
    [Fact]
    public async Task HeaderInState_WithMultipleValues_RequestWithContent_ContentHeaderNotPresent_AddAllValues()
    {
        Configuration.Headers.Add("Content-Language");
        State.Headers.Add("Content-Language", new[] { "one", "two" });
 
        // Act
        await Client.SendAsync(new HttpRequestMessage() { Content = new StringContent("test") });
 
        // Assert
        Assert.True(Handler.Content.Headers.Contains("Content-Language"));
        Assert.Equal(new[] { "one", "two" }, Handler.Content.Headers.GetValues("Content-Language"));
    }
 
    [Fact]
    public async Task HeaderInState_WithOutboundName_UseOutboundName()
    {
        // Arrange
        Configuration.Headers.Add("state", "out");
        State.Headers.Add("state", "test");
 
        // Act
        await Client.SendAsync(new HttpRequestMessage());
 
        // Assert
        Assert.True(Handler.Headers.Contains("out"));
        Assert.Equal(new[] { "test" }, Handler.Headers.GetValues("out"));
    }
 
    [Fact]
    public async Task NoHeaderInState_DoesNotAddIt()
    {
        // Arrange
        Configuration.Headers.Add("inout");
 
        // Act
        await Client.SendAsync(new HttpRequestMessage());
 
        // Assert
        Assert.Empty(Handler.Headers);
    }
 
    [Fact]
    public async Task HeaderInState_NotInOptions_DoesNotAddIt()
    {
        // Arrange
        State.Headers.Add("inout", "test");
 
        // Act
        await Client.SendAsync(new HttpRequestMessage());
 
        // Assert
        Assert.Empty(Handler.Headers);
    }
 
    [Fact]
    public async Task MultipleHeadersInState_AddsAll()
    {
        // Arrange
        Configuration.Headers.Add("inout");
        Configuration.Headers.Add("another");
        State.Headers.Add("inout", "test");
        State.Headers.Add("another", "test2");
 
        // Act
        await Client.SendAsync(new HttpRequestMessage());
 
        // Assert
        Assert.True(Handler.Headers.Contains("inout"));
        Assert.True(Handler.Headers.Contains("another"));
        Assert.Equal(new[] { "test" }, Handler.Headers.GetValues("inout"));
        Assert.Equal(new[] { "test2" }, Handler.Headers.GetValues("another"));
    }
 
    [Theory]
    [InlineData(null)]
    [InlineData("")]
    public async Task HeaderEmptyInState_DoNotAddIt(string headerValue)
    {
        // Arrange
        Configuration.Headers.Add("inout");
        State.Headers.Add("inout", headerValue);
 
        // Act
        await Client.SendAsync(new HttpRequestMessage());
 
        // Assert
        Assert.False(Handler.Headers.Contains("inout"));
    }
 
    [Theory]
    [InlineData("", new[] { "" })]
    [InlineData(null, new[] { "" })]
    [InlineData("42", new[] { "42" })]
    public async Task HeaderInState_HeaderAlreadyInOutgoingRequest_DoesNotOverrideIt(string outgoingValue,
        string[] expectedValues)
    {
        // Arrange
        State.Headers.Add("inout", "test");
        Configuration.Headers.Add("inout");
 
        var request = new HttpRequestMessage();
        request.Headers.Add("inout", outgoingValue);
 
        // Act
        await Client.SendAsync(request);
 
        // Assert
        Assert.True(Handler.Headers.Contains("inout"));
        Assert.Equal(expectedValues, Handler.Headers.GetValues("inout"));
    }
 
    [Fact]
    public async Task HeaderInState_HeaderTwiceInOptions_DoesNotAddItTwice()
    {
        // Arrange
        State.Headers.Add("name", "value");
        Configuration.Headers.Add("name");
        Configuration.Headers.Add("name");
 
        // Act
        await Client.SendAsync(new HttpRequestMessage());
 
        // Assert
        Assert.True(Handler.Headers.Contains("name"));
        Assert.Equal(new[] { "value" }, Handler.Headers.GetValues("name"));
    }
 
    [Fact]
    public async Task HeaderInState_HeaderTwiceInOptionsWithDifferentNames_AddsBoth()
    {
        // Arrange
        State.Headers.Add("name", "value");
        Configuration.Headers.Add("name");
        Configuration.Headers.Add("name", "other");
 
        // Act
        await Client.SendAsync(new HttpRequestMessage());
 
        // Assert
        Assert.True(Handler.Headers.Contains("name"));
        Assert.Equal(new[] { "value" }, Handler.Headers.GetValues("name"));
        Assert.True(Handler.Headers.Contains("other"));
        Assert.Equal(new[] { "value" }, Handler.Headers.GetValues("name"));
    }
 
    [Fact]
    public async Task TwoHeadersInState_BothHeadersInOptionsWithSameName_AddsFirst()
    {
        // Arrange
        State.Headers.Add("name", "value");
        State.Headers.Add("other", "override");
        Configuration.Headers.Add("name");
        Configuration.Headers.Add("other", "name");
 
        // Act
        await Client.SendAsync(new HttpRequestMessage());
 
        // Assert
        Assert.True(Handler.Headers.Contains("name"));
        Assert.Equal(new[] { "value" }, Handler.Headers.GetValues("name"));
    }
 
    private class SimpleHandler : DelegatingHandler
    {
        public HttpHeaders Headers { get; private set; }
        public HttpContent Content { get; private set; }
 
        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
            CancellationToken cancellationToken)
        {
            Headers = request.Headers;
            Content = request.Content;
            return Task.FromResult(new HttpResponseMessage());
        }
    }
}