예제 #1
0
        public async void ExecuteAsync_ReplicaHealthReportDisabled_ReplicasHealthIsNotReported()
        {
            _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);

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

            var expectedClusters = new[]
            {
                ClusterWithDestinations(_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);
        }
예제 #2
0
        public async void ExecuteAsync_InvalidRouteOrder_NoRoutesAndBadHealthReported()
        {
            _scenarioOptions = new ServiceFabricDiscoveryOptions {
                ReportReplicasHealth = true
            };
            var labels = new Dictionary <string, string>()
            {
                { "YARP.Enable", "true" },
                { "YARP.Backend.BackendId", "SomeClusterId" },
                { "YARP.Routes.MyRoute.Hosts", "example.com" },
                { "YARP.Routes.MyRoute.Order", "not a number" },
            };
            ApplicationWrapper application;

            Mock_AppsResponse(
                application = CreateApp_1Service_SingletonPartition_1Replica("MyApp", "MyService", out var service, out var replica));

            Mock_ServiceLabels(application, service, labels);

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

            var expectedClusters = new[]
            {
                ClusterWithDestinations(_testServiceName, labels,
                                        SFTestHelpers.BuildDestinationFromReplica(replica)),
            };
            var expectedRoutes = new List <ProxyRoute>();

            clusters.Should().BeEquivalentTo(expectedClusters);
            routes.Should().BeEmpty();
            AssertServiceHealthReported(service, HealthState.Warning, (description) =>
                                        description.Contains("Order")); // Check that the invalid key is mentioned in the description
            _healthReports.Should().HaveCount(2);
        }
예제 #3
0
        public async void ExecuteAsync_InvalidListenerNameForStatefulService_NoEndpointsAndBadHealthReported()
        {
            _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.Stateful));

            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);
            AssertStatefulServiceReplicaHealthReported(replica, HealthState.Warning, (description) =>
                                                       description.StartsWith("Could not build service endpoint") &&
                                                       description.Contains("UnexistingListener"));
            _healthReports.Should().HaveCount(2);
        }
예제 #4
0
        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);
        }
예제 #5
0
        public async void ExecuteAsync_StatefulService_SkipReplicaWork(string selectionMode, ReplicaRole?replicaRole)
        {
            _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;

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

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

            clusters.Should().BeEquivalentTo(expectedClusters);
            _healthReports.Should().HaveCount(1);
        }
예제 #6
0
        public async void ExecuteAsync_SingleServiceWithGatewayEnabledAndActiveHealthCheck()
        {
            _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);

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

            var expectedClusters = new[]
            {
                ClusterWithDestinations(_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);
        }
예제 #7
0
        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);
        }
예제 #8
0
        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);
        }
예제 #9
0
 private ApplicationWrapper CreateApp_1StatelessService_2Partition_2ReplicasEach(
     string appTypeName,
     string serviceTypeName,
     out ServiceWrapper service,
     out List <ReplicaWrapper> replicas)
 {
     service = CreateService(appTypeName, serviceTypeName, 2, 2, out replicas);
     Mock_ServicesResponse(new Uri($"fabric:/{appTypeName}"), service);
     return(SFTestHelpers.FakeApp(appTypeName, appTypeName));
 }
예제 #10
0
 // Mocking helpers
 private ApplicationWrapper CreateApp_1Service_SingletonPartition_1Replica(
     string appTypeName,
     string serviceTypeName,
     out ServiceWrapper service,
     out ReplicaWrapper replica,
     ServiceKind serviceKind = ServiceKind.Stateless)
 {
     service = CreateService(appTypeName, serviceTypeName, 1, 1, out var replicas, serviceKind);
     replica = replicas[0];
     Mock_ServicesResponse(new Uri($"fabric:/{appTypeName}"), service);
     return(SFTestHelpers.FakeApp(appTypeName, appTypeName));
 }
예제 #11
0
        public async void ExecuteAsync_SomeUnhealthyReplicas_OnlyHealthyReplicasAreUsed()
        {
            _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,
                    out var partitions));
            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;

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

            var expectedClusters = new[]
            {
                ClusterWithDestinations(_testServiceName, labels,
                                        SFTestHelpers.BuildDestinationFromReplicaAndPartition(replicas[0], partitions[0]),
                                        SFTestHelpers.BuildDestinationFromReplicaAndPartition(replicas[1], partitions[0]),
                                        SFTestHelpers.BuildDestinationFromReplicaAndPartition(replicas[2], partitions[1])),
            };
            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
        }
예제 #12
0
        public async void ExecuteAsync_MultipleServicesWithGatewayEnabled_MultipleClustersFound()
        {
            _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);

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

            var expectedClusters = new[]
            {
                ClusterWithDestinations(_testServiceName, labels1,
                                        SFTestHelpers.BuildDestinationFromReplica(replica1)),
                ClusterWithDestinations(_testServiceName, labels2,
                                        SFTestHelpers.BuildDestinationFromReplica(replica2)),
                ClusterWithDestinations(_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);
        }
예제 #13
0
 private ApplicationWrapper CreateApp_2StatelessService_SingletonPartition_1Replica(
     string appTypeName,
     string serviceTypeName1,
     string serviceTypeName2,
     out ServiceWrapper service1,
     out ServiceWrapper service2,
     out ReplicaWrapper service1replica,
     out ReplicaWrapper service2replica)
 {
     service1        = CreateService(appTypeName, serviceTypeName1, 1, 1, out var replicas1);
     service2        = CreateService(appTypeName, serviceTypeName2, 1, 1, out var replicas2);
     service1replica = replicas1[0];
     service2replica = replicas2[0];
     Mock_ServicesResponse(new Uri($"fabric:/{appTypeName}"), service1, service2);
     return(SFTestHelpers.FakeApp(appTypeName, appTypeName));
 }
예제 #14
0
        public async void GetApplicationListAsync_ServiceFabricFails_ResultIsCached()
        {
            var caller       = Create <CachedServiceFabricCaller>();
            var originalApps = new List <ApplicationWrapper> {
                SFTestHelpers.FakeApp("MyApp")
            };

            Mock <IQueryClientWrapper>()
            .SetupSequence(m => m.GetApplicationListAsync(
                               It.IsAny <TimeSpan>(),
                               It.IsAny <CancellationToken>()))
            .ReturnsAsync(originalApps)
            .ThrowsAsync(new Exception("the cake is a lie"))
            .ThrowsAsync(new Exception("the cake is still a lie"));

            await CallThreeTimesAndAssertAsync(() => caller.GetApplicationListAsync(CancellationToken.None));
        }
예제 #15
0
        public async void GetPartitionListAsync_ServiceFabricFails_ResultIsCached()
        {
            var caller = Create <CachedServiceFabricCaller>();
            var originalPartitionInfoList = new List <PartitionWrapper> {
                SFTestHelpers.FakePartition()
            };

            Mock <IQueryClientWrapper>()
            .SetupSequence(m => m.GetPartitionListAsync(
                               new Uri("http://localhost/app1/sv1"),
                               It.IsAny <TimeSpan>(),
                               It.IsAny <CancellationToken>()))
            .ReturnsAsync(originalPartitionInfoList)
            .ThrowsAsync(new Exception("the cake is a lie"))
            .ThrowsAsync(new Exception("the cake is still a lie"));

            await CallThreeTimesAndAssertAsync(() => caller.GetPartitionListAsync(new Uri("http://localhost/app1/sv1"), CancellationToken.None));
        }
예제 #16
0
        private ServiceWrapper CreateService(string appName, string serviceName, int numPartitions, int numReplicasPerPartition, out List <ReplicaWrapper> replicas, out List <PartitionWrapper> partitions, ServiceKind serviceKind = ServiceKind.Stateless)
        {
            var svcName = new Uri($"fabric:/{appName}/{serviceName}");
            var service = SFTestHelpers.FakeService(svcName, $"{appName}_{serviceName}_Type", serviceKind: serviceKind);

            replicas   = new List <ReplicaWrapper>();
            partitions = new List <PartitionWrapper>();

            for (var i = 0; i < numPartitions; i++)
            {
                var partitionReplicas = Enumerable.Range(i * numReplicasPerPartition, numReplicasPerPartition).Select(replicaId => SFTestHelpers.FakeReplica(svcName, replicaId)).ToList();
                replicas.AddRange(partitionReplicas);
                var partition = SFTestHelpers.FakePartition();
                partitions.Add(partition);
                Mock_ReplicasResponse(partition.Id, partitionReplicas.ToArray());
            }
            Mock_PartitionsResponse(svcName, partitions.ToArray());
            return(service);
        }
예제 #17
0
        public async void ExecuteAsync_InvalidLabelsForCluster_NoClustersAndBadHealthReported(string keyToOverride, string value)
        {
            _scenarioOptions = new ServiceFabricDiscoveryOptions {
                ReportReplicasHealth = true
            };
            var labels = SFTestHelpers.DummyLabels("SomeClusterId");

            labels[keyToOverride] = value;
            ApplicationWrapper application;

            Mock_AppsResponse(
                application = CreateApp_1Service_SingletonPartition_1Replica("MyApp", "MyService", out var service, out var replica));

            Mock_ServiceLabels(application, service, labels);

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

            clusters.Should().BeEmpty();
            routes.Should().BeEmpty();
            AssertServiceHealthReported(service, HealthState.Warning, (description) =>
                                        description.Contains(keyToOverride)); // Check that the invalid key is mentioned in the description
            _healthReports.Where(report => report.HealthInformation.HealthState == HealthState.Warning).Should().HaveCount(1);
        }
예제 #18
0
        public async void ExecuteAsync_SingleServiceWithGatewayEnabled_OneClusterFound()
        {
            _scenarioOptions = new ServiceFabricDiscoveryOptions {
                ReportReplicasHealth = true
            };
            const string       TestClusterId = "MyService123";
            var                labels = SFTestHelpers.DummyLabels(TestClusterId);
            ApplicationWrapper application, anotherApplication;

            Mock_AppsResponse(
                application        = CreateApp_1StatelessService_2Partition_2ReplicasEach("MyApp", "MYService", out var service, out var replicas),
                anotherApplication = CreateApp_1StatelessService_2Partition_2ReplicasEach("AnotherApp", "AnotherService", out var anotherService, out var otherReplicas));
            Mock_ServiceLabels(application, service, labels);
            Mock_ServiceLabels(anotherApplication, anotherService, new Dictionary <string, string>());

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

            var expectedClusters = new[]
            {
                ClusterWithDestinations(_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);
            foreach (var replica in replicas)
            {
                AssertStatelessServiceInstanceHealthReported(replica, HealthState.Ok);
            }
            _healthReports.Should().HaveCount(5);
        }