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."); }); }