示例#1
0
        public void BuildCluster_IncompleteLabels_UsesDefaultValues()
        {
            // Arrange
            var labels = new Dictionary <string, string>()
            {
                { "YARP.Backend.BackendId", "MyCoolClusterId" },
            };

            // Act
            var cluster = LabelsParser.BuildCluster(_testServiceName, labels);

            // Assert
            var expectedCluster = new Cluster
            {
                Id = "MyCoolClusterId",
                SessionAffinity = new SessionAffinityOptions(),
                HttpRequest     = new ProxyHttpRequestOptions(),
                HealthCheck     = new HealthCheckOptions
                {
                    Active  = new ActiveHealthCheckOptions(),
                    Passive = new PassiveHealthCheckOptions()
                },
                Metadata = new Dictionary <string, string>(),
            };

            cluster.Should().BeEquivalentTo(expectedCluster);
        }
示例#2
0
        public void BuildRoutes_SingleRoute_Works()
        {
            // Arrange
            var labels = new Dictionary <string, string>()
            {
                { "YARP.Backend.BackendId", "MyCoolClusterId" },
                { "YARP.Routes.MyRoute.Hosts", "example.com" },
                { "YARP.Routes.MyRoute.Order", "2" },
                { "YARP.Routes.MyRoute.Metadata.Foo", "Bar" },
            };

            // Act
            var routes = LabelsParser.BuildRoutes(_testServiceName, labels);

            // Assert
            var expectedRoutes = new List <ProxyRoute>
            {
                new ProxyRoute
                {
                    RouteId = "MyCoolClusterId:MyRoute",
                    Match   =
                    {
                        Hosts = new[] { "example.com" },
                    },
                    Order     = 2,
                    ClusterId = "MyCoolClusterId",
                    Metadata  = new Dictionary <string, string>
                    {
                        { "Foo", "Bar" },
                    },
                },
            };

            routes.Should().BeEquivalentTo(expectedRoutes);
        }
示例#3
0
        public async void ExecuteAsync_ReplicaHealthReportDisabled_ReplicasHealthIsNotReported()
        {
            // Setup
            _scenarioOptions = new ServiceFabricDiscoveryOptions {
                ReportReplicasHealth = false
            };
            const string       TestClusterId = "MyService123";
            var                labels        = SFTestHelpers.DummyLabels(TestClusterId);
            ApplicationWrapper application;

            Mock_AppsResponse(
                application = CreateApp_1Service_SingletonPartition_1Replica("MyApp", "MYService", out var service, out var replica));
            Mock_ServiceLabels(application, service, labels);

            // Act
            var(routes, clusters) = await RunScenarioAsync();

            // Assert
            var expectedClusters = new[]
            {
                ClusterWithDestinations(
                    LabelsParser.BuildCluster(_testServiceName, labels),
                    SFTestHelpers.BuildDestinationFromReplica(replica)),
            };
            var expectedRoutes = LabelsParser.BuildRoutes(_testServiceName, labels);

            clusters.Should().BeEquivalentTo(expectedClusters);
            routes.Should().BeEquivalentTo(expectedRoutes);
            AssertServiceHealthReported(service, HealthState.Ok);
            _healthReports.Should().HaveCount(1);
        }
示例#4
0
        public async void ExecuteAsync_StatefulService_SkipReplicaWork(string selectionMode, ReplicaRole?replicaRole)
        {
            // Setup
            _scenarioOptions = new ServiceFabricDiscoveryOptions {
                ReportReplicasHealth = true
            };
            const string TestClusterId = "MyService123";
            var          labels        = SFTestHelpers.DummyLabels(TestClusterId);

            labels["YARP.Backend.ServiceFabric.StatefulReplicaSelectionMode"] = selectionMode;
            ApplicationWrapper application;

            Mock_AppsResponse(application = CreateApp_1Service_SingletonPartition_1Replica("MyApp", "MYService", out var service, out var replica, serviceKind: ServiceKind.Stateful));
            Mock_ServiceLabels(application, service, labels);
            replica.ServiceKind = ServiceKind.Stateful;
            replica.Role        = replicaRole;

            // Act
            var(routes, clusters) = await RunScenarioAsync();

            // Assert
            var expectedClusters = new[]
            {
                LabelsParser.BuildCluster(_testServiceName, labels),
            };

            clusters.Should().BeEquivalentTo(expectedClusters);
            _healthReports.Should().HaveCount(1);
        }
示例#5
0
        public async void ExecuteAsync_InvalidListenerNameForStatelessService_NoEndpointsAndBadHealthReported()
        {
            // Setup
            _scenarioOptions = new ServiceFabricDiscoveryOptions {
                ReportReplicasHealth = true
            };
            const string TestClusterId = "MyService123";
            var          labels        = SFTestHelpers.DummyLabels(TestClusterId);

            labels["YARP.Backend.ServiceFabric.ListenerName"] = "UnexistingListener";
            ApplicationWrapper application;

            Mock_AppsResponse(
                application = CreateApp_1Service_SingletonPartition_1Replica("MyApp", "MyService", out var service, out var replica, serviceKind: ServiceKind.Stateless));

            Mock_ServiceLabels(application, service, labels);

            // Act
            var(routes, clusters) = await RunScenarioAsync();

            // Assert
            var expectedClusters = new[]
            {
                LabelsParser.BuildCluster(_testServiceName, labels),
            };
            var expectedRoutes = LabelsParser.BuildRoutes(_testServiceName, labels);

            clusters.Should().BeEquivalentTo(expectedClusters);
            routes.Should().BeEquivalentTo(expectedRoutes);
            AssertServiceHealthReported(service, HealthState.Ok);
            AssertStatelessServiceInstanceHealthReported(replica, HealthState.Warning, (description) =>
                                                         description.StartsWith("Could not build service endpoint") &&
                                                         description.Contains("UnexistingListener"));
            _healthReports.Should().HaveCount(2);
        }
示例#6
0
        public async void ExecuteAsync_SingleServiceWithGatewayEnabledAndActiveHealthCheck()
        {
            // Setup
            _scenarioOptions = new ServiceFabricDiscoveryOptions();
            const string       TestClusterId = "MyService123";
            var                labels        = SFTestHelpers.DummyLabels(TestClusterId, activeHealthChecks: true);
            ApplicationWrapper application;

            Mock_AppsResponse(
                application = CreateApp_1StatelessService_2Partition_2ReplicasEach("MyApp", "MYService", out var service, out var replicas));
            Mock_ServiceLabels(application, service, labels);

            // Act
            var(routes, clusters) = await RunScenarioAsync();

            // Assert
            var expectedClusters = new[]
            {
                ClusterWithDestinations(
                    LabelsParser.BuildCluster(_testServiceName, labels),
                    SFTestHelpers.BuildDestinationFromReplica(replicas[0]),
                    SFTestHelpers.BuildDestinationFromReplica(replicas[1]),
                    SFTestHelpers.BuildDestinationFromReplica(replicas[2]),
                    SFTestHelpers.BuildDestinationFromReplica(replicas[3])),
            };
            var expectedRoutes = LabelsParser.BuildRoutes(_testServiceName, labels);

            routes.Should().BeEquivalentTo(expectedRoutes);
            clusters.Should().BeEquivalentTo(expectedClusters);
            AssertServiceHealthReported(service, HealthState.Ok);
            _healthReports.Should().HaveCount(1);
        }
        public async void ExecuteAsync_ValidListenerNameForStatelessService_Work()
        {
            _scenarioOptions = new ServiceFabricDiscoveryOptions {
                ReportReplicasHealth = true
            };
            const string TestClusterId = "MyService123";
            var          labels        = SFTestHelpers.DummyLabels(TestClusterId);

            labels["YARP.Backend.ServiceFabric.ListenerName"] = "ExampleTeamEndpoint";
            labels["YARP.Backend.HealthCheck.Active.ServiceFabric.ListenerName"] = "ExampleTeamHealthEndpoint";
            ApplicationWrapper application;

            Mock_AppsResponse(
                application        = CreateApp_1Service_SingletonPartition_1Replica("MyApp", "MyService", out var service, out var replica, serviceKind: ServiceKind.Stateless));
            replica.ReplicaAddress = MockReplicaAdressWithListenerName("MyApp", "MyService", new string[] { "ExampleTeamEndpoint", "ExampleTeamHealthEndpoint" });
            Mock_ServiceLabels(application, service, labels);

            var(routes, clusters) = await RunScenarioAsync();

            var expectedClusters = new[]
            {
                ClusterWithDestinations(_testServiceName, labels,
                                        SFTestHelpers.BuildDestinationFromReplica(replica, "ExampleTeamHealthEndpoint")),
            };
            var expectedRoutes = LabelsParser.BuildRoutes(_testServiceName, labels);

            clusters.Should().BeEquivalentTo(expectedClusters);
            routes.Should().BeEquivalentTo(expectedRoutes);
            AssertServiceHealthReported(service, HealthState.Ok);
            AssertStatelessServiceInstanceHealthReported(replica, HealthState.Ok, (description) =>
                                                         description.StartsWith("Successfully built"));
            _healthReports.Should().HaveCount(2);
        }
        public void BuildRoutes_MissingBackendId_UsesServiceName(int scenario)
        {
            var labels = new Dictionary <string, string>()
            {
                { "YARP.Routes.MyRoute.Hosts", "example.com" },
                { "YARP.Routes.MyRoute.Order", "2" },
            };

            if (scenario == 1)
            {
                labels.Add("YARP.Backend.BackendId", string.Empty);
            }

            var routes = LabelsParser.BuildRoutes(_testServiceName, labels);

            var expectedRoutes = new List <ProxyRoute>
            {
                new ProxyRoute
                {
                    RouteId = $"{Uri.EscapeDataString(_testServiceName.ToString())}:MyRoute",
                    Match   = new RouteMatch
                    {
                        Hosts = new[] { "example.com" },
                    },
                    Order     = 2,
                    ClusterId = _testServiceName.ToString(),
                    Metadata  = new Dictionary <string, string>(),
                },
            };

            routes.Should().BeEquivalentTo(expectedRoutes);
        }
        public void BuildRoutes_MissingHost_Works()
        {
            var labels = new Dictionary <string, string>()
            {
                { "YARP.Routes.MyRoute.Path", "/{**catchall}" },
            };

            var routes = LabelsParser.BuildRoutes(_testServiceName, labels);

            var expectedRoutes = new List <ProxyRoute>
            {
                new ProxyRoute
                {
                    RouteId = $"{Uri.EscapeDataString(_testServiceName.ToString())}:MyRoute",
                    Match   = new RouteMatch
                    {
                        Path = "/{**catchall}",
                    },
                    ClusterId = _testServiceName.ToString(),
                    Metadata  = new Dictionary <string, string>(),
                },
            };

            routes.Should().BeEquivalentTo(expectedRoutes);
        }
        public async void ExecuteAsync_OneServiceWithGatewayEnabledAndOneNotEnabled_OnlyTheOneEnabledFound()
        {
            _scenarioOptions = new ServiceFabricDiscoveryOptions {
                ReportReplicasHealth = true
            };
            const string       TestClusterIdApp1Sv1 = "MyService123";
            const string       TestClusterIdApp2Sv2 = "MyService234";
            var                gatewayEnabledLabels = SFTestHelpers.DummyLabels(TestClusterIdApp1Sv1);
            var                gatewayNotEnabledLabels = SFTestHelpers.DummyLabels(TestClusterIdApp2Sv2, false);
            ApplicationWrapper application1, application2;

            Mock_AppsResponse(
                application1 = CreateApp_1Service_SingletonPartition_1Replica("MyApp", "MyService1", out var service1, out var replica1),
                application2 = CreateApp_1Service_SingletonPartition_1Replica("MyApp2", "MyService2", out var service2, out var replica2));

            Mock_ServiceLabels(application1, service1, gatewayEnabledLabels);
            Mock_ServiceLabels(application2, service2, gatewayNotEnabledLabels);

            var(routes, clusters) = await RunScenarioAsync();

            var expectedClusters = new[]
            {
                ClusterWithDestinations(_testServiceName, gatewayEnabledLabels,
                                        SFTestHelpers.BuildDestinationFromReplica(replica1)),
            };
            var expectedRoutes = LabelsParser.BuildRoutes(_testServiceName, gatewayEnabledLabels);

            clusters.Should().BeEquivalentTo(expectedClusters);
            routes.Should().BeEquivalentTo(expectedRoutes);
            AssertServiceHealthReported(service1, HealthState.Ok);
            AssertStatelessServiceInstanceHealthReported(replica1, HealthState.Ok);
            _healthReports.Should().HaveCount(2);
        }
        public async void ExecuteAsync_NotHttpsSchemeForStatelessService_NoEndpointsAndBadHealthReported()
        {
            _scenarioOptions = new ServiceFabricDiscoveryOptions {
                ReportReplicasHealth = true
            };
            const string TestClusterId = "MyService123";
            const string ServiceName   = "fabric:/MyApp/MyService";
            var          labels        = SFTestHelpers.DummyLabels(TestClusterId);

            labels["YARP.Backend.ServiceFabric.ListenerName"] = "ExampleTeamEndpoint";
            ApplicationWrapper application;

            Mock_AppsResponse(
                application = CreateApp_1Service_SingletonPartition_1Replica("MyApp", "MyService", out var service, out var replica, serviceKind: ServiceKind.Stateless));
            var nonHttpAddress = $"http://127.0.0.1/{ServiceName}/0";

            replica.ReplicaAddress = $"{{'Endpoints': {{'ExampleTeamEndpoint': '{nonHttpAddress}' }} }}".Replace("'", "\"");
            Mock_ServiceLabels(application, service, labels);

            var(routes, clusters) = await RunScenarioAsync();

            var expectedClusters = new[]
            {
                LabelsParser.BuildCluster(_testServiceName, labels, new Dictionary <string, Destination>()),
            };
            var expectedRoutes = LabelsParser.BuildRoutes(_testServiceName, labels);

            clusters.Should().BeEquivalentTo(expectedClusters);
            routes.Should().BeEquivalentTo(expectedRoutes);
            AssertServiceHealthReported(service, HealthState.Ok);
            AssertStatelessServiceInstanceHealthReported(replica, HealthState.Warning, (description) =>
                                                         description.StartsWith("Could not build service endpoint") &&
                                                         description.Contains("ExampleTeamEndpoint"));
            _healthReports.Should().HaveCount(2);
        }
示例#12
0
        public void BuildRoutes_SingleRouteWithSemanticallyInvalidRule_WorksAndDoesNotThrow()
        {
            var labels = new Dictionary <string, string>()
            {
                { "YARP.Backend.BackendId", "MyCoolClusterId" },
                { "YARP.Routes.MyRoute.Hosts", "'this invalid thing" },
            };

            var routes = LabelsParser.BuildRoutes(_testServiceName, labels);

            var expectedRoutes = new List <ProxyRoute>
            {
                new ProxyRoute
                {
                    RouteId = "MyCoolClusterId:MyRoute",
                    Match   = new ProxyMatch
                    {
                        Hosts = new[] { "'this invalid thing" },
                    },
                    ClusterId = "MyCoolClusterId",
                    Metadata  = new Dictionary <string, string>(),
                },
            };

            routes.Should().BeEquivalentTo(expectedRoutes);
        }
示例#13
0
        public void BuildRoutes_IncompleteRoute_UsesDefaults()
        {
            var labels = new Dictionary <string, string>()
            {
                { "YARP.Backend.BackendId", "MyCoolClusterId" },
                { "YARP.Routes.MyRoute.Hosts", "example.com" },
            };

            var routes = LabelsParser.BuildRoutes(_testServiceName, labels);

            var expectedRoutes = new List <ProxyRoute>
            {
                new ProxyRoute
                {
                    RouteId = "MyCoolClusterId:MyRoute",
                    Match   = new ProxyMatch
                    {
                        Hosts = new[] { "example.com" },
                    },
                    ClusterId = "MyCoolClusterId",
                    Metadata  = new Dictionary <string, string>(),
                },
            };

            routes.Should().BeEquivalentTo(expectedRoutes);
        }
        public void BuildRoutes_InvalidLabelKeys_IgnoresAndDoesNotThrow(string invalidKey, string value)
        {
            var labels = new Dictionary <string, string>()
            {
                { "YARP.Backend.BackendId", "MyCoolClusterId" },
                { "YARP.Routes.MyRoute.Hosts", "example.com" },
                { "YARP.Routes.MyRoute.Order", "2" },
                { "YARP.Routes.MyRoute.Metadata.Foo", "Bar" },
            };

            labels[invalidKey] = value;

            var routes = LabelsParser.BuildRoutes(_testServiceName, labels);

            var expectedRoutes = new List <ProxyRoute>
            {
                new ProxyRoute
                {
                    RouteId = "MyCoolClusterId:MyRoute",
                    Match   = new RouteMatch
                    {
                        Hosts = new[] { "example.com" },
                    },
                    Order     = 2,
                    ClusterId = "MyCoolClusterId",
                    Metadata  = new Dictionary <string, string>
                    {
                        { "Foo", "Bar" },
                    },
                },
            };

            routes.Should().BeEquivalentTo(expectedRoutes);
        }
        public void BuildRoutes_ValidRouteName_Works(string routeName)
        {
            var labels = new Dictionary <string, string>()
            {
                { "YARP.Backend.BackendId", "MyCoolClusterId" },
                { $"YARP.Routes.{routeName}.Hosts", "example.com" },
                { $"YARP.Routes.{routeName}.Order", "2" },
            };

            var routes = LabelsParser.BuildRoutes(_testServiceName, labels);

            var expectedRoutes = new List <ProxyRoute>
            {
                new ProxyRoute
                {
                    RouteId = $"MyCoolClusterId:{routeName}",
                    Match   = new RouteMatch
                    {
                        Hosts = new[] { "example.com" },
                    },
                    Order     = 2,
                    ClusterId = "MyCoolClusterId",
                    Metadata  = new Dictionary <string, string>(),
                },
            };

            routes.Should().BeEquivalentTo(expectedRoutes);
        }
示例#16
0
        public void BuildRoutes_MultipleRoutes_Works()
        {
            var labels = new Dictionary <string, string>()
            {
                { "YARP.Backend.BackendId", "MyCoolClusterId" },
                { "YARP.Routes.MyRoute.Hosts", "example.com" },
                { "YARP.Routes.MyRoute.Path", "v2/{**rest}" },
                { "YARP.Routes.MyRoute.Order", "1" },
                { "YARP.Routes.MyRoute.Metadata.Foo", "Bar" },
                { "YARP.Routes.CoolRoute.Hosts", "example.net" },
                { "YARP.Routes.CoolRoute.Order", "2" },
                { "YARP.Routes.EvenCoolerRoute.Hosts", "example.org" },
                { "YARP.Routes.EvenCoolerRoute.Order", "3" },
            };

            var routes = LabelsParser.BuildRoutes(_testServiceName, labels);

            var expectedRoutes = new List <RouteConfig>
            {
                new RouteConfig
                {
                    RouteId = "MyCoolClusterId:MyRoute",
                    Match   = new RouteMatch
                    {
                        Hosts = new[] { "example.com" },
                        Path  = "v2/{**rest}",
                    },
                    Order     = 1,
                    ClusterId = "MyCoolClusterId",
                    Metadata  = new Dictionary <string, string> {
                        { "Foo", "Bar" }
                    },
                },
                new RouteConfig
                {
                    RouteId = "MyCoolClusterId:CoolRoute",
                    Match   = new RouteMatch
                    {
                        Hosts = new[] { "example.net" },
                    },
                    Order     = 2,
                    ClusterId = "MyCoolClusterId",
                    Metadata  = new Dictionary <string, string>(),
                },
                new RouteConfig
                {
                    RouteId = "MyCoolClusterId:EvenCoolerRoute",
                    Match   = new RouteMatch
                    {
                        Hosts = new[] { "example.org" },
                    },
                    Order     = 3,
                    ClusterId = "MyCoolClusterId",
                    Metadata  = new Dictionary <string, string>(),
                },
            };

            routes.Should().BeEquivalentTo(expectedRoutes);
        }
        public async void ExecuteAsync_MultipleServicesWithGatewayEnabled_MultipleClustersFound()
        {
            // Setup
            _scenarioOptions = new ServiceFabricDiscoveryOptions {
                ReportReplicasHealth = true
            };
            const string       TestClusterIdApp1Sv1 = "MyService123";
            const string       TestClusterIdApp1Sv2 = "MyService234";
            const string       TestClusterIdApp2Sv3 = "MyService345";
            var                labels1 = SFTestHelpers.DummyLabels(TestClusterIdApp1Sv1);
            var                labels2 = SFTestHelpers.DummyLabels(TestClusterIdApp1Sv2);
            var                labels3 = SFTestHelpers.DummyLabels(TestClusterIdApp2Sv3);
            ApplicationWrapper application1, application2;

            Mock_AppsResponse(
                application1 = CreateApp_1Service_SingletonPartition_1Replica("MyApp", "MYService", out var service1, out var replica1),
                application2 = CreateApp_2StatelessService_SingletonPartition_1Replica("MyApp2", "MyService2", "MyService3", out var service2, out var service3, out var replica2, out var replica3));

            Mock_ServiceLabels(application1, service1, labels1);
            Mock_ServiceLabels(application2, service2, labels2);
            Mock_ServiceLabels(application2, service3, labels3);

            // Act
            var(routes, clusters) = await RunScenarioAsync();

            // Assert
            var expectedClusters = new[]
            {
                ClusterWithDestinations(
                    LabelsParser.BuildCluster(_testServiceName, labels1),
                    SFTestHelpers.BuildDestinationFromReplica(replica1)),
                ClusterWithDestinations(
                    LabelsParser.BuildCluster(_testServiceName, labels2),
                    SFTestHelpers.BuildDestinationFromReplica(replica2)),
                ClusterWithDestinations(
                    LabelsParser.BuildCluster(_testServiceName, labels3),
                    SFTestHelpers.BuildDestinationFromReplica(replica3)),
            };
            var expectedRoutes = new List <ProxyRoute>();

            expectedRoutes.AddRange(LabelsParser.BuildRoutes(_testServiceName, labels1));
            expectedRoutes.AddRange(LabelsParser.BuildRoutes(_testServiceName, labels2));
            expectedRoutes.AddRange(LabelsParser.BuildRoutes(_testServiceName, labels3));

            clusters.Should().BeEquivalentTo(expectedClusters);
            routes.Should().BeEquivalentTo(expectedRoutes);
            AssertServiceHealthReported(service1, HealthState.Ok);
            AssertServiceHealthReported(service2, HealthState.Ok);
            AssertServiceHealthReported(service3, HealthState.Ok);
            AssertStatelessServiceInstanceHealthReported(replica1, HealthState.Ok);
            AssertStatelessServiceInstanceHealthReported(replica2, HealthState.Ok);
            AssertStatelessServiceInstanceHealthReported(replica3, HealthState.Ok);
            _healthReports.Should().HaveCount(6);
        }
示例#18
0
        public void BuildCluster_NullTimespan(string value)
        {
            var labels = new Dictionary <string, string>()
            {
                { "YARP.Backend.HealthCheck.Active.Interval", value },
            };

            var cluster = LabelsParser.BuildCluster(_testServiceName, labels, null);

            cluster.HealthCheck.Active.Interval.Should().BeNull();
        }
示例#19
0
        public void BuildCluster_HealthCheckOptions_Enabled_Invalid(string label)
        {
            var labels = new Dictionary <string, string>()
            {
                { "YARP.Backend.BackendId", "MyCoolClusterId" },
                { "YARP.Backend.HealthCheck.Active.Enabled", label },
            };

            Action action = () => LabelsParser.BuildCluster(_testServiceName, labels, null);

            action.Should().Throw <ConfigException>();
        }
示例#20
0
        public void BuildCluster_HealthCheckOptions_Enabled_Valid(string label, bool?expected)
        {
            var labels = new Dictionary <string, string>()
            {
                { "YARP.Backend.BackendId", "MyCoolClusterId" },
                { "YARP.Backend.HealthCheck.Active.Enabled", label },
            };

            var cluster = LabelsParser.BuildCluster(_testServiceName, labels, null);

            cluster.HealthCheck.Active.Enabled.Should().Be(expected);
        }
示例#21
0
        private static Cluster ClusterWithDestinations(Uri serviceName, Dictionary <string, string> labels,
                                                       params KeyValuePair <string, Destination>[] destinations)
        {
            var newDestinations = new Dictionary <string, Destination>(StringComparer.OrdinalIgnoreCase);

            foreach (var destination in destinations)
            {
                newDestinations.Add(destination.Key, destination.Value);
            }

            return(LabelsParser.BuildCluster(serviceName, labels, newDestinations));
        }
示例#22
0
        public void BuildCluster_InvalidValues_Throws(string key, string invalidValue)
        {
            var labels = new Dictionary <string, string>()
            {
                { "YARP.Backend.BackendId", "MyCoolClusterId" },
                { key, invalidValue },
            };

            Func <ClusterConfig> func = () => LabelsParser.BuildCluster(_testServiceName, labels, null);

            func.Should().Throw <ConfigException>().WithMessage($"Could not convert label {key}='{invalidValue}' *");
        }
        public async void ExecuteAsync_SomeUnhealthyReplicas_OnlyHealthyReplicasAreUsed()
        {
            // Setup
            _scenarioOptions = new ServiceFabricDiscoveryOptions {
                ReportReplicasHealth = true
            };
            const string       TestClusterId = "MyService123";
            var                labels        = SFTestHelpers.DummyLabels(TestClusterId);
            ApplicationWrapper application;

            Mock_AppsResponse(
                application = CreateApp_1StatelessService_2Partition_2ReplicasEach(
                    "MyApp",
                    "MYService",
                    out var service,
                    out var replicas));
            Mock_ServiceLabels(application, service, labels);

            replicas[0].ReplicaStatus = ServiceReplicaStatus.Ready; // Should be used despite Warning health state
            replicas[0].HealthState   = HealthState.Warning;

            replicas[1].ReplicaStatus = ServiceReplicaStatus.Ready; // Should be used
            replicas[1].HealthState   = HealthState.Ok;

            replicas[2].ReplicaStatus = ServiceReplicaStatus.Ready; // Should be used despite Error health state
            replicas[2].HealthState   = HealthState.Error;

            replicas[3].ReplicaStatus = ServiceReplicaStatus.Down; // Should be skipped because of status
            replicas[3].HealthState   = HealthState.Ok;

            // Act
            var(routes, clusters) = await RunScenarioAsync();

            // Assert
            var expectedClusters = new[]
            {
                ClusterWithDestinations(
                    LabelsParser.BuildCluster(_testServiceName, labels),
                    SFTestHelpers.BuildDestinationFromReplica(replicas[0]),
                    SFTestHelpers.BuildDestinationFromReplica(replicas[1]),
                    SFTestHelpers.BuildDestinationFromReplica(replicas[2])),
            };
            var expectedRoutes = LabelsParser.BuildRoutes(_testServiceName, labels);

            clusters.Should().BeEquivalentTo(expectedClusters);
            routes.Should().BeEquivalentTo(expectedRoutes);
            AssertServiceHealthReported(service, HealthState.Ok);
            AssertStatelessServiceInstanceHealthReported(replicas[0], HealthState.Ok);
            AssertStatelessServiceInstanceHealthReported(replicas[1], HealthState.Ok);
            AssertStatelessServiceInstanceHealthReported(replicas[2], HealthState.Ok);
            _healthReports.Should().HaveCount(4); // 1 service + 3 replicas = 4 health reports
        }
示例#24
0
        public void BuildRoutes_InvalidOrder_Throws()
        {
            var labels = new Dictionary <string, string>()
            {
                { "YARP.Backend.BackendId", "MyCoolClusterId" },
                { "YARP.Routes.MyRoute.Hosts", "example.com" },
                { "YARP.Routes.MyRoute.Order", "this is no number" },
            };

            Func <List <RouteConfig> > func = () => LabelsParser.BuildRoutes(_testServiceName, labels);

            func.Should()
            .Throw <ConfigException>()
            .WithMessage("Could not convert label YARP.Routes.MyRoute.Order='this is no number' *");
        }
示例#25
0
        public void BuildCluster_MissingBackendId_UsesServiceName()
        {
            var labels = new Dictionary <string, string>()
            {
                { "YARP.Backend.Quota.Burst", "2.3" },
                { "YARP.Backend.Partitioning.Count", "5" },
                { "YARP.Backend.Partitioning.KeyExtractor", "Header('x-ms-organization-id')" },
                { "YARP.Backend.Partitioning.Algorithm", "SHA256" },
                { "YARP.Backend.HealthCheck.Active.Interval", "00:00:5" },
            };

            var cluster = LabelsParser.BuildCluster(_testServiceName, labels, null);

            cluster.ClusterId.Should().Be(_testServiceName.ToString());
        }
        public void BuildCluster_CompleteLabels_Works()
        {
            // Arrange
            var labels = new Dictionary <string, string>()
            {
                { "YARP.Enable", "true" },
                { "YARP.Backend.BackendId", "MyCoolClusterId" },
                { "YARP.Backend.CircuitBreaker.MaxConcurrentRequests", "42" },
                { "YARP.Backend.CircuitBreaker.MaxConcurrentRetries", "5" },
                { "YARP.Backend.Quota.Average", "1.2" },
                { "YARP.Backend.Quota.Burst", "2.3" },
                { "YARP.Backend.Partitioning.Count", "5" },
                { "YARP.Backend.Partitioning.KeyExtractor", "Header('x-ms-organization-id')" },
                { "YARP.Backend.Partitioning.Algorithm", "SHA256" },
                { "YARP.Backend.Healthcheck.Active.Enabled", "true" },
                { "YARP.Backend.Healthcheck.Active.Interval", "5" },
                { "YARP.Backend.Healthcheck.Active.Timeout", "5" },
                { "YARP.Backend.Healthcheck.Active.Path", "/api/health" },
                { "YARP.Backend.Metadata.Foo", "Bar" },
            };

            // Act
            var cluster = LabelsParser.BuildCluster(_testServiceName, labels);

            // Assert
            var expectedCluster = new Cluster
            {
                Id            = "MyCoolClusterId",
                LoadBalancing = new LoadBalancingOptions(),
                HealthCheck   = new HealthCheckOptions
                {
                    Active = new ActiveHealthCheckOptions
                    {
                        Enabled  = true,
                        Interval = TimeSpan.FromSeconds(5),
                        Timeout  = TimeSpan.FromSeconds(5),
                        Path     = "/api/health",
                    },
                },
                Metadata = new Dictionary <string, string>
                {
                    { "Foo", "Bar" },
                },
            };

            cluster.Should().BeEquivalentTo(expectedCluster);
        }
示例#27
0
        public void BuildRoutes_InvalidTransformIndex_Throws(string invalidKey, string value)
        {
            var labels = new Dictionary <string, string>()
            {
                { "YARP.Backend.BackendId", "MyCoolClusterId" },
                { "YARP.Routes.MyRoute.Hosts", "example.com" },
                { "YARP.Routes.MyRoute.Priority", "2" },
                { "YARP.Routes.MyRoute.Metadata.Foo", "Bar" },
            };

            labels[invalidKey] = value;

            Func <List <RouteConfig> > func = () => LabelsParser.BuildRoutes(_testServiceName, labels);

            func.Should()
            .Throw <ConfigException>()
            .WithMessage($"Invalid transform index '*', should be transform index wrapped in square brackets.");
        }
示例#28
0
        public void BuildRoutes_InvalidRouteName_Throws(string invalidKey, string value)
        {
            var labels = new Dictionary <string, string>()
            {
                { "YARP.Backend.BackendId", "MyCoolClusterId" },
                { "YARP.Routes.MyRoute.Hosts", "example.com" },
                { "YARP.Routes.MyRoute.Priority", "2" },
                { "YARP.Routes.MyRoute.Metadata.Foo", "Bar" },
            };

            labels[invalidKey] = value;

            Func <List <RouteConfig> > func = () => LabelsParser.BuildRoutes(_testServiceName, labels);

            func.Should()
            .Throw <ConfigException>()
            .WithMessage($"Invalid route name '*', should only contain alphanumerical characters, underscores or hyphens.");
        }
        public void BuildRoutes_MatchHeadersWithCSVs_Works(string invalidKey, string value, string[] expected)
        {
            // Arrange
            var labels = new Dictionary <string, string>()
            {
                { "YARP.Backend.BackendId", "MyCoolClusterId" },
                { "YARP.Routes.MyRoute0.Hosts", "example0.com" },
                { "YARP.Routes.MyRoute0.Metadata.Foo", "bar" },
                { "YARP.Routes.MyRoute0.MatchHeaders.[0].Name", "x-test-header" },
                { "YARP.Routes.MyRoute0.MatchHeaders.[0].Mode", "ExactHeader" },
            };

            labels[invalidKey] = value;

            // Act
            var routes = LabelsParser.BuildRoutes(_testServiceName, labels);

            // Assert
            var expectedRoutes = new List <ProxyRoute>
            {
                new ProxyRoute
                {
                    RouteId = $"MyCoolClusterId:MyRoute0",
                    Match   =
                    {
                        Hosts   = new[] { "example0.com" },
                        Headers = new List <RouteHeader>()
                        {
                            new RouteHeader()
                            {
                                Name = "x-test-header", Mode = HeaderMatchMode.ExactHeader, Values = expected
                            },
                        }
                    },
                    Metadata = new Dictionary <string, string>()
                    {
                        { "Foo", "bar" }
                    },
                    ClusterId = "MyCoolClusterId",
                }
            };

            routes.Should().BeEquivalentTo(expectedRoutes);
        }
示例#30
0
        public void BuildRoutes_InvalidHeaderMatchProperty_Throws(string invalidKey, string value)
        {
            // Arrange
            var labels = new Dictionary <string, string>()
            {
                { "YARP.Backend.BackendId", "MyCoolClusterId" },
                { "YARP.Routes.MyRoute.Hosts", "example.com" },
                { "YARP.Routes.MyRoute.Priority", "2" },
                { "YARP.Routes.MyRoute.Metadata.Foo", "Bar" },
            };

            labels[invalidKey] = value;

            // Act
            Func <List <RouteConfig> > func = () => LabelsParser.BuildRoutes(_testServiceName, labels);

            // Assert
            func.Should()
            .Throw <ConfigException>()
            .WithMessage($"Invalid header matching property '*', only valid values are Name, Values, IsCaseSensitive and Mode.");
        }