@Test(groups = "unit", dataProvider = "readStrong_SecondaryReadBarrierExhausted_ReadBarrierOnPrimary_SuccessArgProvider")
public void readStrong_SecondaryReadBarrierExhausted_ReadBarrierOnPrimary_Success(int numberOfHeadBarriersWithPrimaryIncludedTillQuorumMet) {

    // scenario: we exhaust all barrier request retries on secondaries
    // after that we start barrier requests including the primary
    int numberOfBarrierRequestTillCatchUp = configs.getMaxNumberOfReadBarrierReadRetries() + numberOfHeadBarriersWithPrimaryIncludedTillQuorumMet;
    ReadMode readMode = ReadMode.Strong;
    int replicaCountToRead = 2;
    ISessionContainer sessionContainer = Mockito.mock(ISessionContainer.class);
    Uri primaryReplicaURI = Uri.create("primary");
    ImmutableList<Uri> secondaryReplicaURIs = ImmutableList.of(Uri.create("secondary1"), Uri.create("secondary2"));
    AddressSelectorWrapper addressSelectorWrapper = AddressSelectorWrapper.Builder.Simple.create()
            .withPrimary(primaryReplicaURI)
            .withSecondary(secondaryReplicaURIs)
            .build();
    RxDocumentServiceRequest request = RxDocumentServiceRequest.createFromName(
            OperationType.Read, "/dbs/db/colls/col/docs/docId", ResourceType.Document);
    request.requestContext = new DocumentServiceRequestContext();
    request.requestContext.timeoutHelper = Mockito.mock(TimeoutHelper.class);
    request.requestContext.resolvedPartitionKeyRange = Mockito.mock(PartitionKeyRange.class);
    request.requestContext.requestChargeTracker = new RequestChargeTracker();
    BigDecimal requestChargePerRead = new BigDecimal(1.1);
    BigDecimal requestChargePerHead = BigDecimal.ZERO;
    TransportClientWrapper.Builder.UriToResultBuilder builder = TransportClientWrapper.Builder.uriToResultBuilder();
    long expectedQuorumLsn = 53;
    long expectedQuorumLocalLSN = 20;
    for(int i = 0; i < numberOfHeadBarriersWithPrimaryIncludedTillQuorumMet; i++) {
        int lsnIncrement = (i == numberOfHeadBarriersWithPrimaryIncludedTillQuorumMet - 1) ? 1 : 0;
        StoreResponse headResponse = StoreResponseBuilder.create()
                .withLSN(expectedQuorumLsn - 1 + lsnIncrement)
                .withLocalLSN(expectedQuorumLocalLSN - 1 + lsnIncrement)
                .withRequestCharge(requestChargePerHead)
                .build();
        builder.storeResponseOn(primaryReplicaURI, OperationType.Head, ResourceType.DocumentCollection, headResponse, false);
    }
    // slow replica
    StoreResponse readResponse = StoreResponseBuilder.create()
            .withLSN(expectedQuorumLsn - 1)
            .withLocalLSN(expectedQuorumLocalLSN - 1)
            .withRequestCharge(requestChargePerRead)
            .build();
    builder.storeResponseOn(secondaryReplicaURIs.get(0), OperationType.Read, ResourceType.Document, readResponse, false);
    for(int i = 0; i < numberOfBarrierRequestTillCatchUp; i++) {
        int lsnIncrement = (i == numberOfBarrierRequestTillCatchUp - 1) ? 1 : 0;
        readResponse = StoreResponseBuilder.create()
                .withLSN(expectedQuorumLsn - 1 + lsnIncrement)
                .withLocalLSN(expectedQuorumLocalLSN - 1 + lsnIncrement)
                .withRequestCharge(requestChargePerRead)
                .build();
        builder.storeResponseOn(secondaryReplicaURIs.get(0), OperationType.Read, ResourceType.Document, readResponse, false);
        StoreResponse headResponse = StoreResponseBuilder.create()
                .withLSN(expectedQuorumLsn - 1  + lsnIncrement)
                .withLocalLSN(expectedQuorumLocalLSN - 1 + lsnIncrement)
                .withRequestCharge(requestChargePerHead)
                .build();
        builder.storeResponseOn(secondaryReplicaURIs.get(0), OperationType.Head, ResourceType.DocumentCollection, headResponse, false);
    }
    // faster replica
    readResponse = StoreResponseBuilder.create()
            .withLSN(expectedQuorumLsn)
            .withLocalLSN(expectedQuorumLocalLSN)
            .withRequestCharge(requestChargePerRead)
            .build();
    builder.storeResponseOn(secondaryReplicaURIs.get(1), OperationType.Read, ResourceType.Document, readResponse, false);
    for(int i = 0; i < numberOfBarrierRequestTillCatchUp; i++) {
        StoreResponse headResponse = StoreResponseBuilder.create()
                .withLSN(expectedQuorumLsn + 10 * (i + 1))
                .withLocalLSN(expectedQuorumLocalLSN + 10 * (i + 1))
                .withRequestCharge(requestChargePerHead)
                .build();
        builder.storeResponseOn(secondaryReplicaURIs.get(1), OperationType.Head, ResourceType.DocumentCollection, headResponse, false);
    }
    TransportClientWrapper transportClientWrapper = builder.build();
    StoreReader storeReader = new StoreReader(transportClientWrapper.transportClient, addressSelectorWrapper.addressSelector, sessionContainer);
    GatewayServiceConfigurationReader serviceConfigurator = Mockito.mock(GatewayServiceConfigurationReader.class);
    IAuthorizationTokenProvider authTokenProvider = Mockito.mock(IAuthorizationTokenProvider.class);
    QuorumReader quorumReader = new QuorumReader(configs, transportClientWrapper.transportClient, addressSelectorWrapper.addressSelector, storeReader, serviceConfigurator, authTokenProvider);
    int beforeSecondariesRetriesExhausted_expectedNumberOfReads = 2;
    int beforeSecondariesRetriesExhausted_expectedNumberOfHeads = 2 * configs.getMaxNumberOfReadBarrierReadRetries();
    int numberOfHeadRetriesRequestWhenPrimaryIncluded = 3 * numberOfHeadBarriersWithPrimaryIncludedTillQuorumMet;
    double expectedRequestCharge = requestChargePerRead.multiply(BigDecimal.valueOf(beforeSecondariesRetriesExhausted_expectedNumberOfReads))
            .add(requestChargePerHead.multiply(BigDecimal.valueOf(beforeSecondariesRetriesExhausted_expectedNumberOfHeads)))
            .setScale(4, RoundingMode.FLOOR).doubleValue();
    Stopwatch stopwatch = Stopwatch.createStarted();
    Single<StoreResponse> storeResponseSingle = quorumReader.readStrongAsync(request, replicaCountToRead, readMode);
    StoreResponseValidator validator = StoreResponseValidator.create()
            .withBELSN(expectedQuorumLsn)
            .withRequestCharge(expectedRequestCharge)
            .build();
    validateSuccess(storeResponseSingle, validator);
    assertThat(stopwatch.elapsed().plus(timeResolution)).isGreaterThanOrEqualTo(Duration.ofMillis(
            numberOfBarrierRequestTillCatchUp * configs.getDelayBetweenReadBarrierCallsInMs()));
    transportClientWrapper.validate()
            .verifyNumberOfInvocations(beforeSecondariesRetriesExhausted_expectedNumberOfReads
                                               + beforeSecondariesRetriesExhausted_expectedNumberOfHeads
                                               + numberOfHeadRetriesRequestWhenPrimaryIncluded);
    addressSelectorWrapper.validate()
            .verifyNumberOfForceCachRefresh(0)
            .verifyVesolvePrimaryUriAsyncCount(0)
            .verifyTotalInvocations(1 + numberOfBarrierRequestTillCatchUp);
    AddressSelectorWrapper.InOrderVerification.Verifier primaryNotIncludedVerifier = AddressSelectorWrapper
            .InOrderVerification.Verifier.builder()
            .resolveAllUriAsync_IncludePrimary(false)
            .resolveAllUriAsync_ForceRefresh(false)
            .build();
    AddressSelectorWrapper.InOrderVerification.Verifier primaryIncludedVerifier = AddressSelectorWrapper
            .InOrderVerification.Verifier.builder()
            .resolveAllUriAsync_IncludePrimary(true)
            .resolveAllUriAsync_ForceRefresh(false)
            .build();
    int numberOfAddressResolutionWithoutPrimary = configs.getMaxNumberOfReadBarrierReadRetries()+ 1;
    int numberOfAddressResolutionWithPrimary = 1;
    AddressSelectorWrapper.InOrderVerification ov = addressSelectorWrapper.getInOrderVerification();
    for(int i = 0; i < numberOfAddressResolutionWithoutPrimary; i++) {
        ov.verifyNext(primaryNotIncludedVerifier);
    }
    for(int i = 0; i < numberOfAddressResolutionWithPrimary; i++) {
        ov.verifyNext(primaryIncludedVerifier);
    }
    DocumentServiceRequestValidator requestValidator = DocumentServiceRequestValidator.builder()
            .add(DocumentServiceRequestContextValidator.builder()
                         .qurorumSelectedLSN(0l)
                         .globalCommittedSelectedLSN(0l)
                         .storeResponses(null)
                         .build())
            .build();
    requestValidator.validate(request);
}