public void UploadKeysInMultipleBatches_shouldSendOnlyDkKeys(int batchSize)
        {
            // .: Setup
            // key data must be unique for verification methods
            var denmarkKeys_ApiV1 = TestTemporaryExposureKeyBuilder.CreateDefault(_denmark)
                                    .SetVisitedCountries(new[] { _germany, _poland })
                                    .SetKeySource(KeySource.SmitteStopApiVersion2)
                                    .SetRollingStartNumber(DateTime.UtcNow.AddDays(-1))
                                    .Build(new[] { "Dk_V1_1", "Dk_V1_2", "Dk_V1_3", "Dk_V1_4" });

            var denmarkKeys_ApiV2 = TestTemporaryExposureKeyBuilder.CreateDefault(_denmark)
                                    .SetVisitedCountries(new[] { _germany, _poland })
                                    .SetKeySource(KeySource.SmitteStopApiVersion3)
                                    .SetRollingStartNumber(DateTime.UtcNow.AddDays(-1))
                                    .SetDaysSinceOnsetOfSymptoms(10)
                                    .Build(new[] { "Dk_V2_1", "Dk_V2_2", "Dk_V2_3", "Dk_V2_4" });

            var denmarkKeys_ApiV2_InvalidDaysSinceOnsetOfSymptoms = TestTemporaryExposureKeyBuilder.CreateDefault(_denmark)
                                                                    .SetVisitedCountries(new[] { _germany, _poland })
                                                                    .SetKeySource(KeySource.SmitteStopApiVersion3)
                                                                    .SetRollingStartNumber(DateTime.UtcNow.AddDays(-1))
                                                                    .SetDaysSinceOnsetOfSymptoms(100)
                                                                    .Build(new[] { "Dk_V2_5", "Dk_V2_6", "Dk_V2_7", "Dk_V2_8" });

            var denmarkKeys_ApiV2_Old = TestTemporaryExposureKeyBuilder.CreateDefault(_denmark)
                                        .SetVisitedCountries(new[] { _germany, _poland })
                                        .SetKeySource(KeySource.SmitteStopApiVersion3)
                                        .SetRollingStartNumber(DateTime.UtcNow.AddDays(-16))
                                        .Build(new[] { "Dk_V2_Old_1", "Dk_V2_Old_2", "Dk_V2_Old_3", "Dk_V2_Old_4" });

            var germanKeys_FromGateway = TestTemporaryExposureKeyBuilder.CreateDefault(_germany)
                                         .SetVisitedCountries(new[] { _poland })
                                         .SetKeySource(KeySource.Gateway)
                                         .Build(new[] { "De_Gate_1", "De_Gate_2", "De_Gate_3", "De_Gate_4", "De_Gate_5", "De_Gate_6" });

            var latviaKeys_FromGateway = TestTemporaryExposureKeyBuilder.CreateDefault(_latvia)
                                         .SetKeySource(KeySource.Gateway)
                                         .Build(new[] { "Lv_Gate_1", "Lv_Gate_2", "Lv_Gate_3", "Lv_Gate_4", "Lv_Gate_5", "Lv_Gate_6" });

            _dbContext.TemporaryExposureKey.AddRange(denmarkKeys_ApiV1);
            _dbContext.TemporaryExposureKey.AddRange(denmarkKeys_ApiV2);
            _dbContext.TemporaryExposureKey.AddRange(denmarkKeys_ApiV2_Old);
            _dbContext.TemporaryExposureKey.AddRange(germanKeys_FromGateway);
            _dbContext.TemporaryExposureKey.AddRange(latviaKeys_FromGateway);
            _dbContext.TemporaryExposureKey.AddRange(denmarkKeys_ApiV2_InvalidDaysSinceOnsetOfSymptoms);
            _dbContext.SaveChanges();

            // setup mock
            var gatewayHttpClientMock = new Mock <IGatewayHttpClient>();

            var expectedResponse = new HttpResponseMessage {
                StatusCode = HttpStatusCode.Created, Content = new StringContent("")
            };

            gatewayHttpClientMock.Setup(client => client.PostAsync(It.IsAny <string>(), It.IsAny <HttpContent>()))
            .ReturnsAsync(expectedResponse);

            var service = CreateGatewayServiceAndDependencies(gatewayHttpClientMock.Object);

            // .: Act
            service.UploadKeysToTheGateway(10, batchSize);

            // .: Verify
            var requestArgInterceptor = new ArgumentInterceptor <HttpContent>();

            gatewayHttpClientMock.Verify(c => c.PostAsync(It.IsAny <string>(), requestArgInterceptor.CreateCaptureAction()));

            var allBatchesPassedToHttpClient = ParseRequestBodiesBatches(requestArgInterceptor);
            var keysFromAllSentBatches       = allBatchesPassedToHttpClient.SelectMany(bath => bath.Keys).ToList();

            keysFromAllSentBatches.Should()
            .OnlyContain(key => key.Origin == _denmark.Code, because: "Only DK keys from APIV2 can be send to the UE Gateway.")
            .And.OnlyHaveUniqueItems(key => key.KeyData, because: "Service cannot send duplicates.")
            .And.OnlyContain(key => denmarkKeys_ApiV2.Any(keyApiv2 => EqualsKeyData(key.KeyData.ToByteArray(), keyApiv2.KeyData)));

            int expectedNumberOfBatches = (int)Math.Ceiling(denmarkKeys_ApiV2.Count / (decimal)batchSize);

            allBatchesPassedToHttpClient.Should()
            .NotBeNull()
            .And.HaveCount(expectedNumberOfBatches, because: "Keys needed to be send in batches");

            allBatchesPassedToHttpClient.ToList().ForEach(
                batch =>
            {
                batch.Keys.Should()
                .HaveCountGreaterThan(0, because: "Service cannot send empty requests.")
                .And.HaveCountLessOrEqualTo(batchSize, because: "Service cannot send batch with wrong size.")
                .And.OnlyHaveUniqueItems(key => key.KeyData, because: "Service cannot send duplicates.");
            });
        }
        public void UploadKeysInOneBatch_shouldSendDkKeysOnlyWithConsent(int batchSize)
        {
            int keysNotOlderThenDays = 14;
            // .: Setup - key data must be unique for verification methods
            var dkApiV2DefaultBuilder = TestTemporaryExposureKeyBuilder.CreateDefault(_denmark)
                                        .SetKeySource(KeySource.SmitteStopApiVersion3)
                                        .SetRollingStartNumber(DateTime.UtcNow.AddDays(-1));

            var otherKeysDefaultBuilder = TestTemporaryExposureKeyBuilder.CreateDefault(_poland)
                                          .SetKeySource(KeySource.Gateway)
                                          .SetRollingStartNumber(DateTime.UtcNow.AddDays(-3));

            // data for upload 1
            // it is not possible to have creation date exactly the same as before for data that appear in the db later
            dkApiV2DefaultBuilder.SetCreatedOn(DateTime.Now);
            var denmarkKeys_upload1 = dkApiV2DefaultBuilder.Copy()
                                      .SetVisitedCountries(new[] { _germany, _poland })
                                      .Build(new[] { "Dk_U1_1", "Dk_U1_2", "Dk_U1_3", "Dk_U1_4" });

            for (int i = 0; i < denmarkKeys_upload1.Count; i++)
            {
                denmarkKeys_upload1[i].SharingConsentGiven = i % 2 == 0;//Set evenkly placed keys to not shared
            }
            var otherKeys_upload1 = otherKeysDefaultBuilder.Copy()
                                    .SetOrigin(_poland)
                                    .Build(new[] { "Other_U1_1", "Other_U1_2", "Other_U1_2", "Other_U1_3" });
            // setup mock
            var gatewayHttpClientMock = new Mock <IGatewayHttpClient>();

            var expectedResponse = new HttpResponseMessage {
                StatusCode = HttpStatusCode.Created, Content = new StringContent("")
            };

            gatewayHttpClientMock.Setup(client => client.PostAsync(It.IsAny <string>(), It.IsAny <HttpContent>()))
            .ReturnsAsync(expectedResponse);

            var service = CreateGatewayServiceAndDependencies(gatewayHttpClientMock.Object);

            // .: Act
            _dbContext.TemporaryExposureKey.AddRange(denmarkKeys_upload1);
            _dbContext.TemporaryExposureKey.AddRange(otherKeys_upload1);
            _dbContext.SaveChanges();

            service.UploadKeysToTheGateway(keysNotOlderThenDays, batchSize);

            // .: Verify
            // get data
            var requestArgInterceptor = new ArgumentInterceptor <HttpContent>();

            gatewayHttpClientMock.Verify(c => c.PostAsync(It.IsAny <string>(), requestArgInterceptor.CreateCaptureAction()));

            var allBatchesPassedToHttpClient = ParseRequestBodiesBatches(requestArgInterceptor);
            var keysFromAllSentBatches       = allBatchesPassedToHttpClient.SelectMany(batch => batch.Keys).ToList();
            // assert
            var expected_AllSentKeys             = denmarkKeys_upload1.Where(key => key.SharingConsentGiven == true).ToList();
            int expectedNumberOfBatchesInUpload1 = (int)Math.Ceiling(denmarkKeys_upload1.Where(key => key.SharingConsentGiven).Count() / (decimal)batchSize);

            keysFromAllSentBatches.Should()
            .OnlyContain(key => key.Origin == _denmark.Code, because: "Only DK keys from APIV2 can be send to the UE Gateway.")
            .And.HaveCount(expected_AllSentKeys.Count(), "Service need to send all keys valid for the sending.")
            .And.HaveCountLessThan(denmarkKeys_upload1.Count, because: "Service should only send keys with consent.")
            .And.OnlyHaveUniqueItems(key => key.KeyData.ToBase64(), because: "Service cannot send duplicates.")
            .And.OnlyContain(key => expected_AllSentKeys.Any(keyApiv2 => EqualsKeyData(key.KeyData.ToByteArray(), keyApiv2.KeyData)));

            allBatchesPassedToHttpClient.Should()
            .NotBeNull()
            .And.HaveCount(expectedNumberOfBatchesInUpload1, because: "Keys needed to be send in batches");

            allBatchesPassedToHttpClient.ToList().ForEach(
                batch =>
            {
                batch.Keys.Should()
                .HaveCountGreaterThan(0, because: "Service cannot send empty requests.")
                .And.HaveCountLessOrEqualTo(batchSize, because: "Service cannot send batch with wrong size.")
                .And.OnlyHaveUniqueItems(key => key.KeyData, because: "Service cannot send duplicates.");
            });
        }
 private IList <TemporaryExposureKeyGatewayBatchProtoDto> ParseRequestBodiesBatches(ArgumentInterceptor <HttpContent> requestArgInterceptor)
 {
     return(requestArgInterceptor.Calls
            .Select(httpContentArg => httpContentArg.ReadAsByteArrayAsync().Result)
            .Select(requestBody => TemporaryExposureKeyGatewayBatchProtoDto.Parser.ParseFrom(requestBody))
            .ToList());
 }
        public void UploadKeysInMultipleBatches_connectionErrrorOccured_shouldSendAllDkKeys()
        {
            int batchSize            = 2;
            int keysNotOlderThenDays = 14;
            // .: Setup - key data must be unique for verification methods
            var keysThatShouldBeSent = TestTemporaryExposureKeyBuilder.CreateDefault(_denmark)
                                       .SetVisitedCountries(new[] { _germany, _poland })
                                       .SetKeySource(KeySource.SmitteStopApiVersion3)
                                       .SetRollingStartNumber(DateTime.UtcNow.AddDays(-1))
                                       .Build(new[] { "Dk_V2_1", "Dk_V2_2", "Dk_V2_3", "Dk_V2_4" });

            var denmarkKeys_ApiV2_Old = TestTemporaryExposureKeyBuilder.CreateDefault(_denmark)
                                        .SetVisitedCountries(new[] { _germany, _poland })
                                        .SetKeySource(KeySource.SmitteStopApiVersion3)
                                        .SetRollingStartNumber(DateTime.UtcNow.AddDays(-16))
                                        .Build(new[] { "Dk_V2_Old_1", "Dk_V2_Old_2", "Dk_V2_Old_3", "Dk_V2_Old_4" });

            var germanKeys_FromGateway = TestTemporaryExposureKeyBuilder.CreateDefault(_germany)
                                         .SetVisitedCountries(new[] { _poland })
                                         .SetKeySource(KeySource.Gateway)
                                         .Build(new[] { "De_Gate_1", "De_Gate_2", "De_Gate_3", "De_Gate_4", "De_Gate_5", "De_Gate_6" });

            _dbContext.TemporaryExposureKey.AddRange(keysThatShouldBeSent);
            _dbContext.TemporaryExposureKey.AddRange(denmarkKeys_ApiV2_Old);
            _dbContext.TemporaryExposureKey.AddRange(germanKeys_FromGateway);
            _dbContext.SaveChanges();

            // setup mock
            var gatewayHttpClientMock = new Mock <IGatewayHttpClient>();

            var successfulResponse = new HttpResponseMessage {
                StatusCode = HttpStatusCode.Created, Content = new StringContent("")
            };
            var errorResponse = new HttpResponseMessage {
                StatusCode = HttpStatusCode.BadRequest, Content = new StringContent("")
            };

            gatewayHttpClientMock.SetupSequence(client => client.PostAsync(It.IsAny <string>(), It.IsAny <HttpContent>()))
            .ReturnsAsync(successfulResponse)
            .ReturnsAsync(errorResponse)
            .ReturnsAsync(errorResponse)
            .ReturnsAsync(successfulResponse);

            var service = CreateGatewayServiceAndDependencies(gatewayHttpClientMock.Object);

            // .: Act
            try
            {
                service.UploadKeysToTheGateway(keysNotOlderThenDays, batchSize); // partial success - one batch sent, second fail
            }
            catch (Exception) { }

            // emulate Job retry
            try
            {
                service.UploadKeysToTheGateway(keysNotOlderThenDays, batchSize);  // first batch fails
            }
            catch (Exception) { }


            // emulate Job retry
            service.UploadKeysToTheGateway(keysNotOlderThenDays, batchSize); // success
            // .: Verify
            var requestArgInterceptor = new ArgumentInterceptor <HttpContent>();

            gatewayHttpClientMock.Verify(c => c.PostAsync(It.IsAny <string>(), requestArgInterceptor.CreateCaptureAction()));

            var allBatchesPassedToHttpClient = ParseRequestBodiesBatches(requestArgInterceptor);

            var firstSucessfulCall         = allBatchesPassedToHttpClient[0].Keys;
            var keysFromRetry1             = allBatchesPassedToHttpClient[1].Keys;
            var keysFromRetry2             = allBatchesPassedToHttpClient[2].Keys;
            var lastSuccessfulCall         = allBatchesPassedToHttpClient[3].Keys;
            var keysFromAllSuccessfulCalls = firstSucessfulCall.Concat(lastSuccessfulCall);

            // all  keys has been sent
            keysFromAllSuccessfulCalls.Should()
            .OnlyContain(key => key.Origin == _denmark.Code, because: "Only DK keys from APIV2 can be send to the UE Gateway.")
            .And.OnlyHaveUniqueItems(key => key.KeyData, because: "Service cannot send duplicates.")
            .And.OnlyContain(key => keysThatShouldBeSent.Any(keyApiv2 => EqualsKeyData(key.KeyData.ToByteArray(), keyApiv2.KeyData)))
            .And.HaveCount(keysThatShouldBeSent.Count);

            // Service was trying to send  keys again
            keysFromRetry1.Should()
            .OnlyHaveUniqueItems(key => key.KeyData, because: "Service cannot send duplicates.")
            .And.OnlyContain(key2Check => keysThatShouldBeSent.Any(keyFromCollection => EqualsKeyData(key2Check.KeyData.ToByteArray(), keyFromCollection.KeyData)))
            .And.NotContain(key2Check => firstSucessfulCall.Any(keyFromCollection => EqualsKeyData(key2Check.KeyData, keyFromCollection.KeyData)));

            keysFromRetry2.Should()
            .OnlyHaveUniqueItems(key => key.KeyData, because: "Service cannot send duplicates.")
            .And.OnlyContain(key2Check => keysFromRetry1.Any(denmarkKey => EqualsKeyData(key2Check.KeyData, denmarkKey.KeyData)))
            .And.HaveCount(keysFromRetry1.Count);

            lastSuccessfulCall.Should()
            .OnlyHaveUniqueItems(key => key.KeyData, because: "Service cannot send duplicates.")
            .And.OnlyContain(key => keysThatShouldBeSent.Any(keyApiv2 => EqualsKeyData(key.KeyData.ToByteArray(), keyApiv2.KeyData)), because: "Can contain only keys that should be sent.")
            .And.OnlyContain(key2Check => keysFromRetry1.Any(keyFromCollection => EqualsKeyData(key2Check.KeyData, keyFromCollection.KeyData)), because: "Service should try to sent the same keys again.")
            .And.OnlyContain(key2Check => keysFromRetry2.Any(keyFromCollection => EqualsKeyData(key2Check.KeyData, keyFromCollection.KeyData)), because: "Service should try to sent the same keys again.")
            .And.NotContain(key2Check => firstSucessfulCall.Any(keyFromCollection => EqualsKeyData(key2Check.KeyData, keyFromCollection.KeyData)), because: "Service cannot send duplicates.")
            .And.HaveCount(keysFromRetry1.Count)
            .And.HaveCount(keysFromRetry2.Count);

            allBatchesPassedToHttpClient.ToList().ForEach(
                batch =>
            {
                batch.Keys.Should()
                .HaveCountGreaterThan(0, because: "Service cannot send empty requests.")
                .And.HaveCountLessOrEqualTo(batchSize, because: "Service cannot send batch with wrong size.");
            });
        }