File: Routing\WeightedRoutingStrategyTest.cs
Web Access
Project: src\test\Libraries\Microsoft.Extensions.Http.Resilience.Tests\Microsoft.Extensions.Http.Resilience.Tests.csproj (Microsoft.Extensions.Http.Resilience.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.Collections.Generic;
using System.Linq;
using FluentAssertions;
using Microsoft.Extensions.Http.Resilience.Internal;
using Microsoft.Extensions.Http.Resilience.Routing.Internal;
using Microsoft.Extensions.Http.Resilience.Routing.Internal.WeightedGroups;
using Microsoft.Extensions.ObjectPool;
using Moq;
using Xunit;
 
namespace Microsoft.Extensions.Http.Resilience.Test.Routing;
 
public class WeightedRoutingStrategyTest : RoutingStrategyTest
{
    private WeightedGroupSelectionMode _selectionMode;
 
    [Fact]
    public void GetRoutes_InitialAttempt_EnsureExpectedOutput()
    {
        _selectionMode = WeightedGroupSelectionMode.InitialAttempt;
 
        SetupRandomizer(0d);
        StrategyResultHelper("https://a/", "https://b/", "https://c/");
 
        SetupRandomizer(21d);
        StrategyResultHelper("https://b/", "https://a/", "https://c/");
 
        SetupRandomizer(51d);
        StrategyResultHelper("https://c/", "https://a/", "https://b/");
    }
 
    [Fact]
    public void GetRoutes_EveryAttempt_EnsureExpectedOutput()
    {
        _selectionMode = WeightedGroupSelectionMode.EveryAttempt;
 
        SetupRandomizer(0d);
        StrategyResultHelper("https://a/", "https://b/", "https://c/");
    }
 
    [Fact]
    public void Reload_Ok()
    {
        SetupRandomizer(1.0);
 
        ReloadHelper(
            (b, c) => b.ConfigureWeightedGroups(c.GetSection("section")),
            new()
            {
                { "section:groups:0:endpoints:0:uri", "https://a/" },
                { "section:groups:0:weight", "10" }
            },
            new()
            {
                { "section:groups:0:endpoints:0:uri", "https://b/" },
                { "section:groups:0:weight", "10" }
            },
            new[] { "https://a/" },
            new[] { "https://b/" });
    }
 
    protected override void Configure(IRoutingStrategyBuilder routingBuilder)
    {
        routingBuilder.ConfigureWeightedGroups(GetSection(new Dictionary<string, string>
        {
            { "groups:0:endpoints:0:uri", "https://a/" },
            { "groups:0:weight", "10" }
        }));
 
        routingBuilder.ConfigureWeightedGroups(options =>
        {
            options.SelectionMode = _selectionMode;
 
            var group = CreateGroup("https://b/");
            group.Weight = 20;
 
            var groups = new List<WeightedUriEndpointGroup>(options.Groups)
            {
                group
            };
            options.Groups = groups;
        });
 
        routingBuilder.ConfigureWeightedGroups((options, serviceProvider) =>
        {
            serviceProvider.Should().NotBeNull();
            var group = CreateGroup("https://c/");
            group.Weight = 30;
            options.Groups.Add(group);
        });
    }
 
    protected override IEnumerable<string> ConfigureMinRoutes(IRoutingStrategyBuilder routingBuilder)
    {
        routingBuilder.ConfigureWeightedGroups(options => options.Groups.Add(CreateGroup("https://dummy-route/")));
        yield return "https://dummy-route/";
    }
 
    protected override IEnumerable<Action<IRoutingStrategyBuilder>> ConfigureInvalidRoutes()
    {
        yield return builder => builder.ConfigureWeightedGroups(options => { });
 
        yield return builder => builder.ConfigureWeightedGroups(options =>
        {
            var group = CreateGroup("https://dummy");
            group.Weight = 0;
 
            var groups = new List<WeightedUriEndpointGroup>(options.Groups)
            {
                group
            };
            options.Groups = groups;
        });
 
        yield return builder => builder.ConfigureWeightedGroups(options =>
        {
            var group = CreateGroup("https://dummy");
            group.Weight = 99999;
 
            var groups = new List<WeightedUriEndpointGroup>(options.Groups)
            {
                group
            };
            options.Groups = groups;
        });
 
        yield return builder => builder.ConfigureWeightedGroups(options =>
        {
            var group = CreateGroup("https://dummy");
            group.Endpoints.Single().Weight = 0;
 
            var groups = new List<WeightedUriEndpointGroup>(options.Groups)
            {
                group
            };
            options.Groups = groups;
        });
 
        yield return builder => builder.ConfigureWeightedGroups(options =>
        {
            var group = CreateGroup("https://dummy");
            group.Endpoints.Single().Weight = 99999;
 
            var groups = new List<WeightedUriEndpointGroup>(options.Groups)
            {
                group
            };
            options.Groups = groups;
        });
 
        yield return builder => builder.ConfigureWeightedGroups(options =>
        {
            var groups = new List<WeightedUriEndpointGroup>(options.Groups)
            {
                null!
            };
            options.Groups = groups;
        });
    }
 
    internal override RequestRoutingStrategy CreateEmptyStrategy() => new WeightedGroupsRoutingStrategy(Mock.Of<Randomizer>(), Mock.Of<ObjectPool<WeightedGroupsRoutingStrategy>>());
 
    private static WeightedUriEndpointGroup CreateGroup(params string[] endpoints)
    {
        return CreateGroup(endpoints.Select(v => new WeightedUriEndpoint { Uri = new Uri(v) }).ToArray());
    }
 
    private static WeightedUriEndpointGroup CreateGroup(params WeightedUriEndpoint[] endpoint)
    {
        return new WeightedUriEndpointGroup
        {
            Endpoints = endpoint.ToList()
        };
    }
}