예제 #1
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, out _, 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, DestinationConfig>()),
        };

        clusters.Should().BeEquivalentTo(expectedClusters);
        _healthReports.Should().HaveCount(1);
    }
예제 #2
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, out var partition, 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.BuildDestinationFromReplicaAndPartition(replica, partition, "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);
    }
예제 #3
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, out var partition));

        Mock_ServiceLabels(application, service, labels);

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

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

        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);
    }
예제 #4
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, out _, serviceKind: ServiceKind.Stateful));

        Mock_ServiceLabels(application, service, labels);

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

        var expectedClusters = new[]
        {
            LabelsParser.BuildCluster(_testServiceName, labels, new Dictionary <string, DestinationConfig>()),
        };
        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);
    }
예제 #5
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, out var partition1),
            application2 = CreateApp_1Service_SingletonPartition_1Replica("MyApp2", "MyService2", out var service2, out var replica2, out var partition2));

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

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

        var expectedClusters = new[]
        {
            ClusterWithDestinations(_testServiceName, gatewayEnabledLabels,
                                    SFTestHelpers.BuildDestinationFromReplicaAndPartition(replica1, partition1)),
        };
        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);
    }
예제 #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, out var partitions));
        Mock_ServiceLabels(application, service, labels);

        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]),
                                    SFTestHelpers.BuildDestinationFromReplicaAndPartition(replicas[3], partitions[1])),
        };
        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_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, out var partition));
        Mock_ServiceLabels(application, service, labels);

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

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

        clusters.Should().BeEquivalentTo(expectedClusters);
        routes.Should().BeEquivalentTo(expectedRoutes);
        AssertServiceHealthReported(service, HealthState.Ok);
        _healthReports.Should().HaveCount(1);
    }
예제 #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, out _, 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, DestinationConfig>()),
        };
        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,
     out List <PartitionWrapper> partitions)
 {
     service = CreateService(appTypeName, serviceTypeName, 2, 2, out replicas, out partitions);
     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,
     out PartitionWrapper partition,
     ServiceKind serviceKind = ServiceKind.Stateless)
 {
     service   = CreateService(appTypeName, serviceTypeName, 1, 1, out var replicas, out var partitions, serviceKind);
     replica   = replicas[0];
     partition = partitions[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, out var partition1),
            application2 = CreateApp_2StatelessService_SingletonPartition_1Replica("MyApp2", "MyService2", "MyService3", out var service2, out var service3, out var replica2, out var replica3, out var partition2, out var partition3));

        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.BuildDestinationFromReplicaAndPartition(replica1, partition1)),
            ClusterWithDestinations(_testServiceName, labels2,
                                    SFTestHelpers.BuildDestinationFromReplicaAndPartition(replica2, partition2)),
            ClusterWithDestinations(_testServiceName, labels3,
                                    SFTestHelpers.BuildDestinationFromReplicaAndPartition(replica3, partition3)),
        };
        var expectedRoutes = new List <RouteConfig>();

        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
    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));
    }
예제 #14
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));
    }
예제 #15
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);
    }
예제 #16
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,
     out PartitionWrapper service1partition,
     out PartitionWrapper service2partition)
 {
     service1          = CreateService(appTypeName, serviceTypeName1, 1, 1, out var replicas1, out var partitions1);
     service2          = CreateService(appTypeName, serviceTypeName2, 1, 1, out var replicas2, out var partitions2);
     service1replica   = replicas1[0];
     service2replica   = replicas2[0];
     service1partition = partitions1[0];
     service2partition = partitions2[0];
     Mock_ServicesResponse(new Uri($"fabric:/{appTypeName}"), service1, service2);
     return(SFTestHelpers.FakeApp(appTypeName, appTypeName));
 }
예제 #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, out _));

        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, out var partitions),
            anotherApplication = CreateApp_1StatelessService_2Partition_2ReplicasEach("AnotherApp", "AnotherService", out var anotherService, out var otherReplicas, out var otherPartitions));
        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.BuildDestinationFromReplicaAndPartition(replicas[0], partitions[0]),
                                    SFTestHelpers.BuildDestinationFromReplicaAndPartition(replicas[1], partitions[0]),
                                    SFTestHelpers.BuildDestinationFromReplicaAndPartition(replicas[2], partitions[1]),
                                    SFTestHelpers.BuildDestinationFromReplicaAndPartition(replicas[3], partitions[1])),
        };
        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);
    }