Example #1
0
        public void BuildEndpoints_JustHostWithWildcard_Works()
        {
            // Arrange
            var builder     = Create <RuntimeRouteBuilder>();
            var parsedRoute = new ParsedRoute
            {
                RouteId  = "route1",
                Host     = "*.example.com",
                Priority = 12,
            };
            var backend   = new BackendInfo("backend1", new DestinationManager(), new Mock <IProxyHttpClientFactory>().Object);
            var routeInfo = new RouteInfo("route1");

            // Act
            var config = builder.Build(parsedRoute, backend, routeInfo);

            // Assert
            Assert.Same(backend, config.BackendOrNull);
            Assert.Equal(12, config.Priority);
            Assert.Equal(parsedRoute.GetConfigHash(), config.ConfigHash);
            Assert.Single(config.Endpoints);
            var routeEndpoint = config.Endpoints[0] as AspNetCore.Routing.RouteEndpoint;

            Assert.Equal("route1", routeEndpoint.DisplayName);
            Assert.Same(config, routeEndpoint.Metadata.GetMetadata <RouteConfig>());
            Assert.Equal("/{**catchall}", routeEndpoint.RoutePattern.RawText);

            var hostMetadata = routeEndpoint.Metadata.GetMetadata <AspNetCore.Routing.HostAttribute>();

            Assert.NotNull(hostMetadata);
            Assert.Single(hostMetadata.Hosts);
            Assert.Equal("*.example.com", hostMetadata.Hosts[0]);
        }
Example #2
0
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseRouting();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapGet("/", async context =>
                {
                    var connection  = context.Features.Get <IHttpConnectionFeature>();
                    var backendInfo = new BackendInfo()
                    {
                        IP       = connection.LocalIpAddress.ToString(),
                        Hostname = Dns.GetHostName(),
                    };

                    context.Response.ContentType = "application/json; charset=utf-8";
                    await JsonSerializer.SerializeAsync(context.Response.Body, backendInfo);
                });

                endpoints.MapGet("/crash", context =>
                {
                    System.Environment.Exit(1);
                    return(Task.CompletedTask);
                });

                endpoints.MapHealthChecks("/healthz");
            });
        }
Example #3
0
        public void BuildEndpoints_NullMatchers_Works()
        {
            // Arrange
            var builder     = Create <RuntimeRouteBuilder>();
            var parsedRoute = new ParsedRoute
            {
                RouteId  = "route1",
                Priority = 12,
            };
            var backend   = new BackendInfo("backend1", new EndpointManager(), new Mock <IProxyHttpClientFactory>().Object);
            var routeInfo = new RouteInfo("route1");

            // Act
            var config = builder.Build(parsedRoute, backend, routeInfo);

            // Assert
            Assert.Same(backend, config.BackendOrNull);
            Assert.Equal(12, config.Priority);
            Assert.Empty(config.MatcherSummary);
            Assert.Single(config.AspNetCoreEndpoints);
            var routeEndpoint = config.AspNetCoreEndpoints[0] as AspNetCore.Routing.RouteEndpoint;

            Assert.Equal("route1", routeEndpoint.DisplayName);
            Assert.Same(config, routeEndpoint.Metadata.GetMetadata <RouteConfig>());
            Assert.Equal("/{**catchall}", routeEndpoint.RoutePattern.RawText);

            var hostMetadata = routeEndpoint.Metadata.GetMetadata <AspNetCore.Routing.HostAttribute>();

            Assert.Null(hostMetadata);
        }
Example #4
0
        public void BuildEndpoints_JustHostWithWildcard_Works()
        {
            // Arrange
            var builder     = Create <RuntimeRouteBuilder>();
            var parsedRoute = new ParsedRoute
            {
                RouteId  = "route1",
                Host     = "*.example.com",
                Priority = 12,
            };
            var backend   = new BackendInfo("backend1", new EndpointManager(), new Mock <IProxyHttpClientFactory>().Object);
            var routeInfo = new RouteInfo("route1");

            // Act
            var config = builder.Build(parsedRoute, backend, routeInfo);

            // Assert
            config.BackendOrNull.Should().BeSameAs(backend);
            config.Priority.Should().Be(12);
            config.MatcherSummary.Should().Be(parsedRoute.GetMatcherSummary());
            config.AspNetCoreEndpoints.Should().HaveCount(1);
            var routeEndpoint = config.AspNetCoreEndpoints[0] as AspNetCore.Routing.RouteEndpoint;

            routeEndpoint.DisplayName.Should().Be("route1");
            routeEndpoint.Metadata.GetMetadata <RouteConfig>().Should().BeSameAs(config);
            routeEndpoint.RoutePattern.RawText.Should().Be("/{**catchall}");

            var hostMetadata = routeEndpoint.Metadata.GetMetadata <AspNetCore.Routing.HostAttribute>();

            hostMetadata.Should().NotBeNull();
            hostMetadata.Hosts.Should().BeEquivalentTo("*.example.com");
        }
Example #5
0
        public async Task Invoke_Works()
        {
            var proxyHttpClientFactoryMock = new Mock <IProxyHttpClientFactory>();
            var backend1 = new BackendInfo(
                backendId: "backend1",
                destinationManager: new DestinationManager(),
                proxyHttpClientFactory: proxyHttpClientFactoryMock.Object);

            backend1.Config.Value = new BackendConfig(default, new BackendConfig.BackendLoadBalancingOptions(LoadBalancingMode.RoundRobin), default);
Example #6
0
        /// <inheritdoc/>
        public RouteConfig Build(ParsedRoute source, BackendInfo backendOrNull, RouteInfo runtimeRoute)
        {
            Contracts.CheckValue(source, nameof(source));
            Contracts.CheckValue(runtimeRoute, nameof(runtimeRoute));

            var transforms = _transformBuilder.Build(source.Transforms);

            // NOTE: `new RouteConfig(...)` needs a reference to the list of ASP .NET Core endpoints,
            // but the ASP .NET Core endpoints cannot be created without a `RouteConfig` metadata item.
            // We solve this chicken-egg problem by creating an (empty) list first
            // and passing a read-only wrapper of it to `RouteConfig.ctor`.
            // Recall that `List<T>.AsReadOnly()` creates a wrapper over the original list,
            // and changes to the underlying list *are* reflected on the read-only view.
            var aspNetCoreEndpoints = new List <Endpoint>(1);
            var newRouteConfig      = new RouteConfig(
                runtimeRoute,
                source.GetConfigHash(),
                source.Priority,
                backendOrNull,
                aspNetCoreEndpoints.AsReadOnly(),
                transforms);

            // TODO: Handle arbitrary AST's properly
            // Catch-all pattern when no path was specified
            var pathPattern = string.IsNullOrEmpty(source.Path) ? "/{**catchall}" : source.Path;

            // TODO: Propagate route priority
            var endpointBuilder = new AspNetCore.Routing.RouteEndpointBuilder(
                requestDelegate: _pipeline ?? Invoke,
                routePattern: AspNetCore.Routing.Patterns.RoutePatternFactory.Parse(pathPattern),
                order: 0);

            endpointBuilder.DisplayName = source.RouteId;
            endpointBuilder.Metadata.Add(newRouteConfig);

            if (!string.IsNullOrEmpty(source.Host))
            {
                endpointBuilder.Metadata.Add(new AspNetCore.Routing.HostAttribute(source.Host));
            }

            if (source.Methods != null && source.Methods.Count > 0)
            {
                endpointBuilder.Metadata.Add(new AspNetCore.Routing.HttpMethodMetadata(source.Methods));
            }

            var endpoint = endpointBuilder.Build();

            aspNetCoreEndpoints.Add(endpoint);

            return(newRouteConfig);
        }
Example #7
0
        public static async Task <IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "get", Route = null)] HttpRequest req,
            ILogger log)
        {
            log.LogInformation("C# HTTP trigger function processed a request.");

            var backendInfo = new BackendInfo()
            {
                IP       = req.HttpContext.Connection.LocalIpAddress.ToString(),
                Hostname = System.Net.Dns.GetHostName(),
            };

            return(new OkObjectResult(backendInfo));
        }
Example #8
0
        public async Task Invoke_NoHealthyEndpoints_503()
        {
            var proxyHttpClientFactoryMock = new Mock <IProxyHttpClientFactory>();
            var backend1 = new BackendInfo(
                backendId: "backend1",
                destinationManager: new DestinationManager(),
                proxyHttpClientFactory: proxyHttpClientFactoryMock.Object);

            backend1.Config.Value = new BackendConfig(
                new BackendConfig.BackendHealthCheckOptions(enabled: true, Timeout.InfiniteTimeSpan, Timeout.InfiniteTimeSpan, 0, ""),
                new BackendConfig.BackendLoadBalancingOptions(),
                new BackendConfig.BackendSessionAffinityOptions());
            var destination1 = backend1.DestinationManager.GetOrCreateItem(
                "destination1",
                destination =>
            {
                destination.Config.Value       = new DestinationConfig("https://localhost:123/a/b/");
                destination.DynamicState.Value = new DestinationDynamicState(DestinationHealth.Unhealthy);
            });

            var aspNetCoreEndpoints = new List <Endpoint>();
            var routeConfig         = new RouteConfig(
                route: new RouteInfo("route1"),
                configHash: 0,
                priority: null,
                backendOrNull: backend1,
                aspNetCoreEndpoints: aspNetCoreEndpoints.AsReadOnly(),
                transforms: null);
            var aspNetCoreEndpoint = CreateAspNetCoreEndpoint(routeConfig);

            aspNetCoreEndpoints.Add(aspNetCoreEndpoint);
            var httpContext = new DefaultHttpContext();

            httpContext.SetEndpoint(aspNetCoreEndpoint);

            var sut = Create <DestinationInitializerMiddleware>();

            await sut.Invoke(httpContext);

            var feature = httpContext.Features.Get <IAvailableDestinationsFeature>();

            Assert.Null(feature);

            var backend = httpContext.Features.Get <BackendInfo>();

            Assert.Null(backend);

            Assert.Equal(503, httpContext.Response.StatusCode);
        }
Example #9
0
        public async Task Invoke_SetsFeatures()
        {
            var proxyHttpClientFactoryMock = new Mock <IProxyHttpClientFactory>();
            var backend1 = new BackendInfo(
                backendId: "backend1",
                destinationManager: new DestinationManager(),
                proxyHttpClientFactory: proxyHttpClientFactoryMock.Object);
            var destination1 = backend1.DestinationManager.GetOrCreateItem(
                "destination1",
                destination =>
            {
                destination.Config.Value       = new DestinationConfig("https://localhost:123/a/b/");
                destination.DynamicState.Value = new DestinationDynamicState(DestinationHealth.Healthy);
            });

            var aspNetCoreEndpoints = new List <Endpoint>();
            var routeConfig         = new RouteConfig(
                new RouteInfo("route1"),
                configHash: 0,
                priority: null,
                backend1,
                aspNetCoreEndpoints.AsReadOnly(),
                transforms: null);
            var aspNetCoreEndpoint = CreateAspNetCoreEndpoint(routeConfig);

            aspNetCoreEndpoints.Add(aspNetCoreEndpoint);
            var httpContext = new DefaultHttpContext();

            httpContext.SetEndpoint(aspNetCoreEndpoint);

            var sut = Create <DestinationInitializerMiddleware>();

            await sut.Invoke(httpContext);

            var feature = httpContext.Features.Get <IAvailableDestinationsFeature>();

            Assert.NotNull(feature);
            Assert.NotNull(feature.Destinations);
            Assert.Equal(1, feature.Destinations.Count);
            Assert.Same(destination1, feature.Destinations[0]);

            var backend = httpContext.Features.Get <BackendInfo>();

            Assert.Same(backend1, backend);

            Assert.Equal(200, httpContext.Response.StatusCode);
        }
        public async Task Invoke_SetsFeatures()
        {
            var proxyHttpClientFactoryMock = new Mock <IProxyHttpClientFactory>();
            var backend1 = new BackendInfo(
                backendId: "backend1",
                endpointManager: new EndpointManager(),
                proxyHttpClientFactory: proxyHttpClientFactoryMock.Object);
            var endpoint1 = backend1.EndpointManager.GetOrCreateItem(
                "endpoint1",
                endpoint =>
            {
                endpoint.Config.Value       = new EndpointConfig("https://localhost:123/a/b/");
                endpoint.DynamicState.Value = new EndpointDynamicState(EndpointHealth.Healthy);
            });

            var aspNetCoreEndpoints = new List <Endpoint>();
            var routeConfig         = new RouteConfig(
                route: new RouteInfo("route1"),
                matcherSummary: null,
                priority: null,
                backendOrNull: backend1,
                aspNetCoreEndpoints: aspNetCoreEndpoints.AsReadOnly());
            var aspNetCoreEndpoint = CreateAspNetCoreEndpoint(routeConfig);

            aspNetCoreEndpoints.Add(aspNetCoreEndpoint);
            var httpContext = new DefaultHttpContext();

            httpContext.SetEndpoint(aspNetCoreEndpoint);

            var sut = Create <EndpointInitializerMiddleware>();

            await sut.Invoke(httpContext);

            var feature = httpContext.Features.Get <IAvailableBackendEndpointsFeature>();

            Assert.NotNull(feature);
            Assert.NotNull(feature.Endpoints);
            Assert.Equal(1, feature.Endpoints.Count);
            Assert.Same(endpoint1, feature.Endpoints[0]);

            var backend = httpContext.Features.Get <BackendInfo>();

            Assert.Same(backend1, backend);

            Assert.Equal(200, httpContext.Response.StatusCode);
        }
Example #11
0
        public void BuildEndpoints_InvalidPath_BubblesOutException()
        {
            // Arrange
            var builder     = Create <RuntimeRouteBuilder>();
            var parsedRoute = new ParsedRoute
            {
                RouteId  = "route1",
                Path     = "/{invalid",
                Priority = 12,
            };
            var backend   = new BackendInfo("backend1", new DestinationManager(), new Mock <IProxyHttpClientFactory>().Object);
            var routeInfo = new RouteInfo("route1");

            // Act
            Action action = () => builder.Build(parsedRoute, backend, routeInfo);

            // Assert
            Assert.Throws <AspNetCore.Routing.Patterns.RoutePatternException>(action);
        }
Example #12
0
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseRouting();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapGet("/", async context =>
                {
                    var backendInfo = new BackendInfo()
                    {
                        IP       = context.Connection.LocalIpAddress.ToString(),
                        Hostname = Dns.GetHostName(),
                    };

                    context.Response.ContentType = "application/json; charset=utf-8";
                    await JsonSerializer.SerializeAsync(context.Response.Body, backendInfo);
                });
            });
        }
Example #13
0
        public Game(string path, EventHandler <string> statusCallback)
        {
            List <string> files    = Directory.GetFiles(path).ToList();
            List <string> dirs     = Directory.GetDirectories(path).ToList();
            string        gameName = files.Where(f => Path.GetExtension(f) == ".exe" && dirs.Select(d => Path.GetFileName(d)).Contains($"{Path.GetFileNameWithoutExtension(f)}_Data")).FirstOrDefault();

            if (string.IsNullOrEmpty(gameName))
            {
                throw new ArgumentException("Could not find game executable and Data folder pair.");
            }

            Name = Path.GetFileNameWithoutExtension(gameName);

            var appInfo = File.ReadLines($@"{path}\{Name}_Data\app.info").ToList();

            if (appInfo.Count != 2)
            {
                throw new ArgumentException("Malformed app.info file found in Data folder.");
            }

            Developer  = appInfo[0].Length > 14 ? appInfo[0].Substring(0, 11) + "..." : appInfo[0];
            VisualName = appInfo[1].Length > 14 ? appInfo[1].Substring(0, 11) + "..." : appInfo[1];

            Version          = Helpers.FromAssetFile($@"{path}\{Name}_Data\globalgamemanagers.assets").ToString();
            ScriptingBackend = BackendInfo.FromPath(path, Name, statusCallback);

            var binarypath = "";

            if (ScriptingBackend.Def == BackendDef.Il2Cpp)
            {
                binarypath = files.First(f => Path.GetFileName(f) == "GameAssembly.dll");
            }
            else
            {
                binarypath = @$ "{path}\{Name}_Data\Managed\Assembly-CSharp.dll";
            }
Example #14
0
        public async Task Invoke_Works()
        {
            // Arrange
            var httpContext = new DefaultHttpContext();

            httpContext.Request.Method      = "GET";
            httpContext.Request.Scheme      = "https";
            httpContext.Request.Host        = new HostString("example.com");
            httpContext.Request.Path        = "/api/test";
            httpContext.Request.QueryString = new QueryString("?a=b&c=d");

            var proxyHttpClientFactoryMock = new Mock <IProxyHttpClientFactory>();
            var backend1 = new BackendInfo(
                backendId: "backend1",
                destinationManager: new DestinationManager(),
                proxyHttpClientFactory: proxyHttpClientFactoryMock.Object);
            var destination1 = backend1.DestinationManager.GetOrCreateItem(
                "destination1",
                destination =>
            {
                destination.Config.Value       = new DestinationConfig("https://localhost:123/a/b/");
                destination.DynamicState.Value = new DestinationDynamicState(DestinationHealth.Healthy);
            });

            httpContext.Features.Set <IAvailableDestinationsFeature>(
                new AvailableDestinationsFeature()
            {
                Destinations = new List <DestinationInfo>()
                {
                    destination1
                }.AsReadOnly()
            });
            httpContext.Features.Set(backend1);

            var aspNetCoreEndpoints = new List <Endpoint>();
            var routeConfig         = new RouteConfig(
                route: new RouteInfo("route1"),
                matcherSummary: null,
                priority: null,
                backendOrNull: backend1,
                aspNetCoreEndpoints: aspNetCoreEndpoints.AsReadOnly());
            var aspNetCoreEndpoint = CreateAspNetCoreEndpoint(routeConfig);

            aspNetCoreEndpoints.Add(aspNetCoreEndpoint);
            httpContext.SetEndpoint(aspNetCoreEndpoint);

            var tcs1 = new TaskCompletionSource <bool>();
            var tcs2 = new TaskCompletionSource <bool>();

            Mock <IHttpProxy>()
            .Setup(h => h.ProxyAsync(
                       httpContext,
                       It.Is <Uri>(uri => uri == new Uri("https://localhost:123/a/b/api/test?a=b&c=d")),
                       proxyHttpClientFactoryMock.Object,
                       It.Is <ProxyTelemetryContext>(ctx => ctx.BackendId == "backend1" && ctx.RouteId == "route1" && ctx.DestinationId == "destination1"),
                       It.IsAny <CancellationToken>(),
                       It.IsAny <CancellationToken>()))
            .Returns(
                async() =>
            {
                tcs1.TrySetResult(true);
                await tcs2.Task;
            })
            .Verifiable();

            var sut = Create <ProxyInvokerMiddleware>();

            // Act
            Assert.Equal(0, backend1.ConcurrencyCounter.Value);
            Assert.Equal(0, destination1.ConcurrencyCounter.Value);

            var task = sut.Invoke(httpContext);

            if (task.IsFaulted)
            {
                // Something went wrong, don't hang the test.
                await task;
            }
            await tcs1.Task; // Wait until we get to the proxying step.

            Assert.Equal(1, backend1.ConcurrencyCounter.Value);
            Assert.Equal(1, destination1.ConcurrencyCounter.Value);

            tcs2.TrySetResult(true);
            await task;

            Assert.Equal(0, backend1.ConcurrencyCounter.Value);
            Assert.Equal(0, destination1.ConcurrencyCounter.Value);

            // Assert
            Mock <IHttpProxy>().Verify();
        }
Example #15
0
        private async Task InvokeInternal(HttpContext context, BackendConfig.BackendSessionAffinityOptions options, BackendInfo backend)
        {
            var destinationsFeature = context.GetRequiredDestinationFeature();
            var destinations        = destinationsFeature.Destinations;

            var affinityResult = _operationLogger.Execute(
                "ReverseProxy.FindAffinitizedDestinations",
                () =>
            {
                var currentProvider = _sessionAffinityProviders.GetRequiredServiceById(options.Mode);
                return(currentProvider.FindAffinitizedDestinations(context, destinations, backend.BackendId, options));
            });

            switch (affinityResult.Status)
            {
            case AffinityStatus.OK:
                destinationsFeature.Destinations = affinityResult.Destinations;
                break;

            case AffinityStatus.AffinityKeyNotSet:
                // Nothing to do so just continue processing
                break;

            case AffinityStatus.AffinityKeyExtractionFailed:
            case AffinityStatus.DestinationNotFound:
                var keepProcessing = await _operationLogger.ExecuteAsync("ReverseProxy.HandleAffinityFailure", () =>
                {
                    var failurePolicy = _affinityFailurePolicies.GetRequiredServiceById(options.AffinityFailurePolicy);
                    return(failurePolicy.Handle(context, options, affinityResult.Status));
                });

                if (!keepProcessing)
                {
                    // Policy reported the failure is unrecoverable and took the full responsibility for its handling,
                    // so we simply stop processing.
                    Log.AffinityResolutionFailedForBackend(_logger, backend.BackendId);
                    return;
                }

                Log.AffinityResolutionFailureWasHandledProcessingWillBeContinued(_logger, backend.BackendId, options.AffinityFailurePolicy);

                break;

            default:
                throw new NotSupportedException($"Affinity status '{affinityResult.Status}' is not supported.");
            }

            await _next(context);
        }
Example #16
0
        public async Task InvokeAsync_Works()
        {
            // Arrange
            var httpContext = new DefaultHttpContext();

            httpContext.Request.Method      = "GET";
            httpContext.Request.Scheme      = "https";
            httpContext.Request.Host        = new HostString("example.com");
            httpContext.Request.Path        = "/api/test";
            httpContext.Request.QueryString = new QueryString("?a=b&c=d");

            var proxyHttpClientFactoryMock = new Mock <IProxyHttpClientFactory>();
            var backend1 = new BackendInfo(
                backendId: "backend1",
                endpointManager: new EndpointManager(),
                proxyHttpClientFactory: proxyHttpClientFactoryMock.Object);
            var endpoint1 = backend1.EndpointManager.GetOrCreateItem(
                "endpoint1",
                endpoint =>
            {
                endpoint.Config.Value       = new EndpointConfig("https://localhost:123/a/b/");
                endpoint.DynamicState.Value = new EndpointDynamicState(EndpointHealth.Healthy);
            });

            var aspNetCoreEndpoints = new List <Endpoint>();
            var routeConfig         = new RouteConfig(
                route: new RouteInfo("route1"),
                matcherSummary: null,
                priority: null,
                backendOrNull: backend1,
                aspNetCoreEndpoints: aspNetCoreEndpoints.AsReadOnly());
            var aspNetCoreEndpoint = CreateAspNetCoreEndpoint(routeConfig);

            aspNetCoreEndpoints.Add(aspNetCoreEndpoint);
            httpContext.SetEndpoint(aspNetCoreEndpoint);

            Mock <ILoadBalancer>()
            .Setup(l => l.PickEndpoint(It.IsAny <IReadOnlyList <EndpointInfo> >(), It.IsAny <IReadOnlyList <EndpointInfo> >(), It.IsAny <BackendConfig.BackendLoadBalancingOptions>()))
            .Returns(endpoint1);

            var tcs1 = new TaskCompletionSource <bool>();
            var tcs2 = new TaskCompletionSource <bool>();

            Mock <IHttpProxy>()
            .Setup(h => h.ProxyAsync(
                       httpContext,
                       It.Is <Uri>(uri => uri == new Uri("https://localhost:123/a/b/api/test?a=b&c=d")),
                       proxyHttpClientFactoryMock.Object,
                       It.Is <ProxyTelemetryContext>(ctx => ctx.BackendId == "backend1" && ctx.RouteId == "route1" && ctx.EndpointId == "endpoint1"),
                       It.IsAny <CancellationToken>(),
                       It.IsAny <CancellationToken>()))
            .Returns(
                async() =>
            {
                tcs1.TrySetResult(true);
                await tcs2.Task;
            })
            .Verifiable();

            var sut = Create <ProxyInvoker>();

            // Act
            backend1.ConcurrencyCounter.Value.Should().Be(0);
            endpoint1.ConcurrencyCounter.Value.Should().Be(0);

            var task = sut.InvokeAsync(httpContext);
            await tcs1.Task; // Wait until we get to the proxying step.

            backend1.ConcurrencyCounter.Value.Should().Be(1);
            endpoint1.ConcurrencyCounter.Value.Should().Be(1);

            tcs2.TrySetResult(true);
            await task;

            backend1.ConcurrencyCounter.Value.Should().Be(0);
            endpoint1.ConcurrencyCounter.Value.Should().Be(0);

            // Assert
            Mock <IHttpProxy>().Verify();
        }
        public async Task Invoke_Works()
        {
            var proxyHttpClientFactoryMock = new Mock <IProxyHttpClientFactory>();
            var backend1 = new BackendInfo(
                backendId: "backend1",
                endpointManager: new EndpointManager(),
                proxyHttpClientFactory: proxyHttpClientFactoryMock.Object);
            var endpoint1 = backend1.EndpointManager.GetOrCreateItem(
                "endpoint1",
                endpoint =>
            {
                endpoint.Config.Value       = new EndpointConfig("https://localhost:123/a/b/");
                endpoint.DynamicState.Value = new EndpointDynamicState(EndpointHealth.Healthy);
            });
            var endpoint2 = backend1.EndpointManager.GetOrCreateItem(
                "endpoint2",
                endpoint =>
            {
                endpoint.Config.Value       = new EndpointConfig("https://localhost:123/a/b/");
                endpoint.DynamicState.Value = new EndpointDynamicState(EndpointHealth.Healthy);
            });

            var aspNetCoreEndpoints = new List <Endpoint>();
            var routeConfig         = new RouteConfig(
                route: new RouteInfo("route1"),
                matcherSummary: null,
                priority: null,
                backendOrNull: backend1,
                aspNetCoreEndpoints: aspNetCoreEndpoints.AsReadOnly());
            var aspNetCoreEndpoint = CreateAspNetCoreEndpoint(routeConfig);

            aspNetCoreEndpoints.Add(aspNetCoreEndpoint);
            var httpContext = new DefaultHttpContext();

            httpContext.SetEndpoint(aspNetCoreEndpoint);

            Mock <ILoadBalancer>()
            .Setup(l => l.PickEndpoint(It.IsAny <IReadOnlyList <EndpointInfo> >(), It.IsAny <BackendConfig.BackendLoadBalancingOptions>()))
            .Returns(endpoint1);

            httpContext.Features.Set <IAvailableBackendEndpointsFeature>(
                new AvailableBackendEndpointsFeature()
            {
                Endpoints = new List <EndpointInfo>()
                {
                    endpoint1, endpoint2
                }.AsReadOnly()
            });
            httpContext.Features.Set(backend1);

            var sut = Create <LoadBalancingMiddleware>();

            await sut.Invoke(httpContext);

            var feature = httpContext.Features.Get <IAvailableBackendEndpointsFeature>();

            Assert.NotNull(feature);
            Assert.NotNull(feature.Endpoints);
            Assert.Equal(1, feature.Endpoints.Count);
            Assert.Same(endpoint1, feature.Endpoints[0]);

            Assert.Equal(200, httpContext.Response.StatusCode);
        }
Example #18
0
 public BackendInfoController(ILogger <BackendInfoController> logger)
 {
     _logger = logger;
     Info    = new BackendInfo();
 }