diff --git a/Covid19Radar/Covid19Radar/App.xaml.cs b/Covid19Radar/Covid19Radar/App.xaml.cs index adfdac73d..c98b1921d 100644 --- a/Covid19Radar/Covid19Radar/App.xaml.cs +++ b/Covid19Radar/Covid19Radar/App.xaml.cs @@ -183,21 +183,25 @@ private static void RegisterCommonTypes(IContainer container) container.Register(Reuse.Singleton); container.Register(Reuse.Singleton); container.Register(Reuse.Singleton); - container.Register(Reuse.Singleton); container.Register(Reuse.Singleton); - container.Register(Reuse.Singleton); container.Register(Reuse.Singleton); container.Register(Reuse.Singleton); container.Register(Reuse.Singleton); #if USE_MOCK + container.Register(Reuse.Singleton); + container.Register(Reuse.Singleton); + container.Register(Reuse.Singleton); container.Register(Reuse.Singleton); - container.Register(Reuse.Singleton); container.Register(Reuse.Singleton); + container.Register(Reuse.Singleton); #else + container.Register(Reuse.Singleton); + container.Register(Reuse.Singleton); + container.Register(Reuse.Singleton); container.Register(Reuse.Singleton); - container.Register(Reuse.Singleton); container.Register(Reuse.Singleton); + container.Register(Reuse.Singleton); #endif #if DEBUG @@ -208,14 +212,12 @@ private static void RegisterCommonTypes(IContainer container) container.Register(Reuse.Singleton); #endif - container.Register(Reuse.Singleton); container.Register(Reuse.Singleton); container.Register(Reuse.Singleton); container.Register(Reuse.Singleton); container.Register(Reuse.Singleton); container.Register(Reuse.Singleton); container.Register(Reuse.Singleton); - container.Register(Reuse.Singleton); container.Register(Reuse.Singleton); #if EVENT_LOG_ENABLED diff --git a/Covid19Radar/Covid19Radar/Repository/DiagnosisKeyRepository.cs b/Covid19Radar/Covid19Radar/Repository/DiagnosisKeyRepository.cs index 4b10c575e..b14e6b16b 100644 --- a/Covid19Radar/Covid19Radar/Repository/DiagnosisKeyRepository.cs +++ b/Covid19Radar/Covid19Radar/Repository/DiagnosisKeyRepository.cs @@ -41,20 +41,20 @@ public class DiagnosisKeyRepository : IDiagnosisKeyRepository private readonly ILoggerService _loggerService; - private readonly HttpClient _httpClient; + private readonly IHttpClientService _httpClientService; public DiagnosisKeyRepository( IHttpClientService httpClientService, ILoggerService loggerService ) { - _httpClient = httpClientService.Create(); + _httpClientService = httpClientService; _loggerService = loggerService; } public async Task<(HttpStatusCode, IList)> GetDiagnosisKeysListAsync(string url, CancellationToken cancellationToken) { - HttpResponseMessage response = await _httpClient.GetAsync(url, cancellationToken); + HttpResponseMessage response = await _httpClientService.CdnClient.GetAsync(url, cancellationToken); if (response.IsSuccessStatusCode) { string content = await response.Content.ReadAsStringAsync(); @@ -74,7 +74,7 @@ public async Task DownloadDiagnosisKeysAsync(DiagnosisKeyEntry diagnosis { Uri uri = new Uri(diagnosisKeyEntry.Url); - HttpResponseMessage response = await _httpClient.GetAsync(uri, cancellationToken); + HttpResponseMessage response = await _httpClientService.CdnClient.GetAsync(uri, cancellationToken); if (response.IsSuccessStatusCode) { string fileName = uri.Segments[uri.Segments.Length - 1]; diff --git a/Covid19Radar/Covid19Radar/Repository/ExposureConfigurationRepository.cs b/Covid19Radar/Covid19Radar/Repository/ExposureConfigurationRepository.cs index 94b2f17ab..0daabc8c9 100644 --- a/Covid19Radar/Covid19Radar/Repository/ExposureConfigurationRepository.cs +++ b/Covid19Radar/Covid19Radar/Repository/ExposureConfigurationRepository.cs @@ -40,7 +40,7 @@ public class ExposureConfigurationRepository : IExposureConfigurationRepository private readonly IDateTimeUtility _dateTimeUtility; private readonly ILoggerService _loggerService; - private readonly HttpClient _httpClient; + private readonly IHttpClientService _httpClientService; private readonly string _configDir; @@ -63,8 +63,7 @@ ILoggerService loggerService _dateTimeUtility = dateTimeUtility; _loggerService = loggerService; - _httpClient = httpClientService.Create(); - _httpClient.Timeout = TimeSpan.FromSeconds(TIMEOUT_SECONDS); + _httpClientService = httpClientService; _configDir = PrepareConfigDir(); _currentExposureConfigurationPath = localPathService.CurrentExposureConfigurationPath; @@ -147,7 +146,7 @@ private async Task GetExposureConfigurationInternalAsync( ExposureConfiguration newExposureConfiguration = null; - var response = await _httpClient.GetAsync(url); + var response = await _httpClientService.StaticJsonContentClient.GetAsync(url); if (response.IsSuccessStatusCode) { string exposureConfigurationAsJson = await response.Content.ReadAsStringAsync(); diff --git a/Covid19Radar/Covid19Radar/Repository/ExposureRiskCalculationConfigurationRepository.cs b/Covid19Radar/Covid19Radar/Repository/ExposureRiskCalculationConfigurationRepository.cs index ea6f24e0f..007243d41 100644 --- a/Covid19Radar/Covid19Radar/Repository/ExposureRiskCalculationConfigurationRepository.cs +++ b/Covid19Radar/Covid19Radar/Repository/ExposureRiskCalculationConfigurationRepository.cs @@ -21,13 +21,11 @@ public interface IExposureRiskCalculationConfigurationRepository public class ExposureRiskCalculationConfigurationRepository : IExposureRiskCalculationConfigurationRepository { - private const double TIMEOUT_SECONDS = 10.0; - private readonly ILocalPathService _localPathService; private readonly IServerConfigurationRepository _serverConfigurationRepository; private readonly ILoggerService _loggerService; - private readonly HttpClient _httpClient; + private readonly IHttpClientService _httpClientService; private readonly string _configDir; @@ -46,8 +44,7 @@ ILoggerService loggerService _serverConfigurationRepository = serverConfigurationRepository; _loggerService = loggerService; - _httpClient = httpClientService.Create(); - _httpClient.Timeout = TimeSpan.FromSeconds(TIMEOUT_SECONDS); + _httpClientService = httpClientService; _configDir = PrepareConfigDir(); _currentPath = localPathService.CurrentExposureRiskCalculationConfigurationPath; @@ -126,7 +123,7 @@ private async Task GetExposureRiskCalcul try { - var response = await _httpClient.GetAsync(url); + var response = await _httpClientService.StaticJsonContentClient.GetAsync(url); if (response.IsSuccessStatusCode) { string exposureRiskCalculationConfigurationAsJson = await response.Content.ReadAsStringAsync(); @@ -227,7 +224,7 @@ private void Swap(string sourcePath, string destPath) { File.Move(sourcePath, destPath); } - catch(IOException exception) + catch (IOException exception) { _loggerService.Exception("IOException", exception); @@ -252,4 +249,10 @@ private async Task LoadAsync(string path) private async Task SaveAsync(string exposureConfigurationAsJson, string outPath) => await File.WriteAllTextAsync(outPath, exposureConfigurationAsJson); } + + public class ExposureRiskCalculationConfigurationRepositoryMock : IExposureRiskCalculationConfigurationRepository + { + public Task GetExposureRiskCalculationConfigurationAsync(bool preferCache) + => Task.FromResult(new V1ExposureRiskCalculationConfiguration()); + } } diff --git a/Covid19Radar/Covid19Radar/Services/CheckVersionService.cs b/Covid19Radar/Covid19Radar/Services/CheckVersionService.cs index 0e97ffcdb..d994db80e 100644 --- a/Covid19Radar/Covid19Radar/Services/CheckVersionService.cs +++ b/Covid19Radar/Covid19Radar/Services/CheckVersionService.cs @@ -3,7 +3,6 @@ // file, You can obtain one at https://mozilla.org/MPL/2.0/. using System; -using System.Net.Http; using System.Threading.Tasks; using Covid19Radar.Resources; using Covid19Radar.Services.Logs; @@ -24,7 +23,7 @@ public Task IsUpdateVersionExistAsync() public class CheckVersionService : ICheckVersionService { - private readonly HttpClient _httpClient; + private readonly IHttpClientService _httpClientService; private readonly IEssentialsService _essentialsService; private readonly ILoggerService _loggerService; @@ -34,7 +33,7 @@ public CheckVersionService( ILoggerService loggerService ) { - _httpClient = httpClientService.Create(); + _httpClientService = httpClientService; _essentialsService = essentialsService; _loggerService = loggerService; } @@ -46,7 +45,7 @@ public async Task IsUpdateVersionExistAsync() var uri = AppResources.UrlVersion; try { - var json = await _httpClient.GetStringAsync(uri); + var json = await _httpClientService.StaticJsonContentClient.GetStringAsync(uri); var key = _essentialsService.IsIos ? "ios" : "android"; var versionString = JObject.Parse(json).Value(key); diff --git a/Covid19Radar/Covid19Radar/Services/DebugExposureDataCollectServer.cs b/Covid19Radar/Covid19Radar/Services/DebugExposureDataCollectServer.cs index 7b9846a37..f01683bd4 100644 --- a/Covid19Radar/Covid19Radar/Services/DebugExposureDataCollectServer.cs +++ b/Covid19Radar/Covid19Radar/Services/DebugExposureDataCollectServer.cs @@ -75,7 +75,7 @@ public class DebugExposureDataCollectServer : IDebugExposureDataCollectServer { private readonly ILoggerService _loggerService; private readonly IServerConfigurationRepository _serverConfigurationRepository; - private readonly HttpClient _httpClient; + private readonly IHttpClientService _httpClientService; public DebugExposureDataCollectServer( ILoggerService loggerService, @@ -85,7 +85,7 @@ IHttpClientService httpClientService { _loggerService = loggerService; _serverConfigurationRepository = serverConfigurationRepository; - _httpClient = httpClientService.Create(); + _httpClientService = httpClientService; } public async Task UploadExposureDataAsync( @@ -173,7 +173,7 @@ string exposureDataCollectServerEndpoint Uri uri = new Uri(exposureDataCollectServerEndpoint); - HttpResponseMessage response = await _httpClient.PutAsync(uri, httpContent); + HttpResponseMessage response = await _httpClientService.ApiClient.PutAsync(uri, httpContent); if (response.IsSuccessStatusCode) { var responseJson = await response.Content.ReadAsStringAsync(); diff --git a/Covid19Radar/Covid19Radar/Services/DiagnosisKeyRegisterServer.cs b/Covid19Radar/Covid19Radar/Services/DiagnosisKeyRegisterServer.cs index d350f6a4b..3cff86afa 100644 --- a/Covid19Radar/Covid19Radar/Services/DiagnosisKeyRegisterServer.cs +++ b/Covid19Radar/Covid19Radar/Services/DiagnosisKeyRegisterServer.cs @@ -6,11 +6,15 @@ using System.Collections.Generic; using System.Linq; using System.Net; +using System.Net.Http; +using System.Text; using System.Threading.Tasks; using Chino; using Covid19Radar.Common; using Covid19Radar.Model; +using Covid19Radar.Repository; using Covid19Radar.Services.Logs; +using Newtonsoft.Json; using Xamarin.Essentials; namespace Covid19Radar.Services @@ -18,18 +22,21 @@ namespace Covid19Radar.Services public class DiagnosisKeyRegisterServer : IDiagnosisKeyRegisterServer { private readonly ILoggerService _loggerService; - private readonly IHttpDataService _httpDataService; + private readonly IHttpClientService _httpClientService; private readonly IDeviceVerifier _deviceVerifier; + private readonly IServerConfigurationRepository _serverConfigurationRepository; public DiagnosisKeyRegisterServer( ILoggerService loggerService, - IHttpDataService httpDataService, - IDeviceVerifier deviceVerifier + IHttpClientService httpClientService, + IDeviceVerifier deviceVerifier, + IServerConfigurationRepository serverConfigurationRepository ) { _loggerService = loggerService; - _httpDataService = httpDataService; + _httpClientService = httpClientService; _deviceVerifier = deviceVerifier; + _serverConfigurationRepository = serverConfigurationRepository; } public async Task SubmitDiagnosisKeysAsync( @@ -68,7 +75,7 @@ string idempotencyKey processNumber, idempotencyKey ); - return await _httpDataService.PutSelfExposureKeysAsync(diagnosisInfo); + return await PutSelfExposureKeysAsync(diagnosisInfo); } finally { @@ -76,6 +83,43 @@ string idempotencyKey } } + public async Task PutSelfExposureKeysAsync(DiagnosisSubmissionParameter request) + { + _loggerService.StartMethod(); + + try + { + await _serverConfigurationRepository.LoadAsync(); + + var diagnosisKeyRegisterApiUrls = _serverConfigurationRepository.DiagnosisKeyRegisterApiUrls; + if (diagnosisKeyRegisterApiUrls.Count() == 0) + { + _loggerService.Error("DiagnosisKeyRegisterApiUrls count 0"); + throw new InvalidOperationException("DiagnosisKeyRegisterApiUrls count 0"); + } + else if (diagnosisKeyRegisterApiUrls.Count() > 1) + { + _loggerService.Warning("Multi DiagnosisKeyRegisterApiUrl are detected."); + } + + var url = diagnosisKeyRegisterApiUrls.First(); + var content = new StringContent(JsonConvert.SerializeObject(request), Encoding.UTF8, "application/json"); + + return await PutAsync(url, content); + } + finally + { + _loggerService.EndMethod(); + } + } + + private async Task PutAsync(string url, HttpContent body) + { + var result = await _httpClientService.ApiClient.PutAsync(url, body); + await result.Content.ReadAsStringAsync(); + return result.StatusCode; + } + private async Task CreateSubmissionAsync( bool hasSymptom, DateTime symptomOnsetDate, @@ -164,6 +208,21 @@ private static string GetPadding(Random random = null) } } + public class DiagnosisKeyRegisterServerMock : IDiagnosisKeyRegisterServer + { + public Task SubmitDiagnosisKeysAsync( + bool hasSymptom, + DateTime symptomOnsetDate, + IList temporaryExposureKeys, + string processNumber, + string idempotencyKey + ) + => Task.FromResult(HttpStatusCode.NoContent); + + public Task PutSelfExposureKeysAsync(DiagnosisSubmissionParameter request) + => Task.FromResult(HttpStatusCode.NoContent); + } + public class DiagnosisKeyRegisterException : Exception { private const string DataKeyCode = "code"; diff --git a/Covid19Radar/Covid19Radar/Services/HttpClientService.cs b/Covid19Radar/Covid19Radar/Services/HttpClientService.cs index b4b58d953..a3cd2b889 100644 --- a/Covid19Radar/Covid19Radar/Services/HttpClientService.cs +++ b/Covid19Radar/Covid19Radar/Services/HttpClientService.cs @@ -4,21 +4,70 @@ using System; using System.Net.Http; +using System.Net.Http.Headers; namespace Covid19Radar.Services { public interface IHttpClientService { - HttpClient Create(); + public HttpClient ApiClient + { + get; + } + + public HttpClient StaticJsonContentClient + { + get; + } + + public HttpClient CdnClient + { + get; + } } + public class HttpClientService : IHttpClientService { + private const double TimeoutSeconds = 10.0; + + private readonly HttpClient _apiClient; + private readonly HttpClient _staticJsonContentClient; + private readonly HttpClient _cdnClient; + + public HttpClient ApiClient => _apiClient; + public HttpClient StaticJsonContentClient => _staticJsonContentClient; + public HttpClient CdnClient => _cdnClient; + public HttpClientService() { + _apiClient = CreateApiClient(); + _staticJsonContentClient = CreateStaticJsonContentClient(); + _cdnClient = CreateCdnClient(); + } + + private HttpClient CreateApiClient() + { + var apiClient = new HttpClient(); + apiClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); + apiClient.DefaultRequestHeaders.Add("x-functions-key", AppSettings.Instance.ApiSecret); + apiClient.DefaultRequestHeaders.Add("x-api-key", AppSettings.Instance.ApiKey); + + return apiClient; + } + + private HttpClient CreateStaticJsonContentClient() + { + var httpClient = new HttpClient(); + httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); + httpClient.Timeout = TimeSpan.FromSeconds(TimeoutSeconds); + + return httpClient; } - public HttpClient Create() + + private HttpClient CreateCdnClient() { - return new HttpClient(); + var cdnClient = new HttpClient(); + return cdnClient; } } } diff --git a/Covid19Radar/Covid19Radar/Services/HttpDataService.cs b/Covid19Radar/Covid19Radar/Services/HttpDataService.cs deleted file mode 100644 index ce5308f1c..000000000 --- a/Covid19Radar/Covid19Radar/Services/HttpDataService.cs +++ /dev/null @@ -1,155 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ - -using Covid19Radar.Model; -using Covid19Radar.Services.Logs; -using System; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Text; -using System.Threading.Tasks; -using System.Net; -using Newtonsoft.Json; -using Covid19Radar.Repository; -using System.Linq; - -namespace Covid19Radar.Services -{ - public class HttpDataService : IHttpDataService - { - private readonly ILoggerService loggerService; - private readonly IHttpClientService httpClientService; - private readonly IServerConfigurationRepository serverConfigurationRepository; - - private readonly HttpClient apiClient; - private readonly HttpClient httpClient; - - public HttpDataService( - ILoggerService loggerService, - IHttpClientService httpClientService, - IServerConfigurationRepository serverConfigurationRepository - ) - { - this.loggerService = loggerService; - this.httpClientService = httpClientService; - this.serverConfigurationRepository = serverConfigurationRepository; - - apiClient = CreateApiClient(); - httpClient = CreateHttpClient(); - } - - private HttpClient CreateApiClient() - { - var apiClient = httpClientService.Create(); - apiClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); - apiClient.DefaultRequestHeaders.Add("x-functions-key", AppSettings.Instance.ApiSecret); - apiClient.DefaultRequestHeaders.Add("x-api-key", AppSettings.Instance.ApiKey); - - return apiClient; - } - - private HttpClient CreateHttpClient() - { - var httpClient = httpClientService.Create(); - httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); - httpClient.DefaultRequestHeaders.Add("x-functions-key", AppSettings.Instance.ApiSecret); - - return httpClient; - } - - // POST /api/Register - Register User - public async Task PostRegisterUserAsync() - { - loggerService.StartMethod(); - try - { - await serverConfigurationRepository.LoadAsync(); - - string url = serverConfigurationRepository.UserRegisterApiEndpoint; - var content = new StringContent(string.Empty, Encoding.UTF8, "application/json"); - - HttpResponseMessage result = await httpClient.PostAsync(url, content); - loggerService.EndMethod(); - return result.StatusCode; - } - catch (Exception ex) - { - loggerService.Exception("Failed to register user.", ex); - loggerService.EndMethod(); - throw; - } - } - - public async Task PutSelfExposureKeysAsync(DiagnosisSubmissionParameter request) - { - loggerService.StartMethod(); - - try - { - await serverConfigurationRepository.LoadAsync(); - - var diagnosisKeyRegisterApiUrls = serverConfigurationRepository.DiagnosisKeyRegisterApiUrls; - if (diagnosisKeyRegisterApiUrls.Count() == 0) - { - loggerService.Error("DiagnosisKeyRegisterApiUrls count 0"); - throw new InvalidOperationException("DiagnosisKeyRegisterApiUrls count 0"); - } - else if (diagnosisKeyRegisterApiUrls.Count() > 1) - { - loggerService.Warning("Multi DiagnosisKeyRegisterApiUrl are detected."); - } - - var url = diagnosisKeyRegisterApiUrls.First(); - var content = new StringContent(JsonConvert.SerializeObject(request), Encoding.UTF8, "application/json"); - - return await PutAsync(url, content); - } - finally - { - loggerService.EndMethod(); - } - } - - public async Task> GetLogStorageSas() - { - loggerService.StartMethod(); - - int statusCode; - LogStorageSas logStorageSas = default; - - try - { - await serverConfigurationRepository.LoadAsync(); - - var url = serverConfigurationRepository.InquiryLogApiUrl; - - var response = await apiClient.GetAsync(url); - - statusCode = (int)response.StatusCode; - loggerService.Info($"Response status: {statusCode}"); - - if (statusCode == (int)HttpStatusCode.OK) - { - var content = await response.Content.ReadAsStringAsync(); - logStorageSas = JsonConvert.DeserializeObject(content); - } - } - catch (Exception ex) - { - loggerService.Exception("Failed get log storage SAS.", ex); - statusCode = 0; - logStorageSas = default; - } - loggerService.EndMethod(); - return new ApiResponse(statusCode, logStorageSas); - } - - private async Task PutAsync(string url, HttpContent body) - { - var result = await httpClient.PutAsync(url, body); - await result.Content.ReadAsStringAsync(); - return result.StatusCode; - } - } -} diff --git a/Covid19Radar/Covid19Radar/Services/HttpDataServiceMock.cs b/Covid19Radar/Covid19Radar/Services/HttpDataServiceMock.cs deleted file mode 100644 index cacb6abfc..000000000 --- a/Covid19Radar/Covid19Radar/Services/HttpDataServiceMock.cs +++ /dev/null @@ -1,202 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ - -using Covid19Radar.Model; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Net; -using System.Threading; -using System.Threading.Tasks; -using System.Linq; -using System.Net.Http; -using System.Text.RegularExpressions; - -namespace Covid19Radar.Services -{ - class HttpDataServiceMock : IHttpDataService - { - private readonly HttpClient downloadClient; - private readonly MockCommonUtils mockCommonUtils = new MockCommonUtils(); - - public HttpDataServiceMock(IHttpClientService httpClientService) - { - downloadClient = httpClientService.Create(); - } - - // copy from ./HttpDataService.cs - private async Task GetCdnAsync(string url, CancellationToken cancellationToken) - { - HttpResponseMessage result = await downloadClient.GetAsync(url, cancellationToken); - await result.Content.ReadAsStringAsync(); - - if (result.StatusCode == System.Net.HttpStatusCode.OK) - { - return await result.Content.ReadAsStringAsync(); - } - return null; - } - - public Task MigrateFromUserData(UserDataModel userData) - { - return Task.CompletedTask; - } - - public (string, string) GetCredentials() - { - return ("user-uuid", "secret"); - } - - public void RemoveCredentials() - { - } - - private TemporaryExposureKeyExportFileModel CreateTestData(long created) - { - return new TemporaryExposureKeyExportFileModel() - { - Region = "440", - Url = "testUrl", - Created = created - }; - } - - private long CalcTimeAddDays(int day) - => new DateTimeOffset(DateTime.UtcNow.AddDays(day)).ToUnixTimeMilliseconds(); - - private long CalcMidnightTimeAddDays(int day) - { - DateTime d = DateTime.UtcNow.AddDays(day); - // set 0 hour,1 min,2 sec,3 millisecond for debug - return new DateTimeOffset(new DateTime(d.Year, d.Month, d.Day, 0, 1, 2, 3)).ToUnixTimeMilliseconds(); - } - - enum PresetTekListType // PresetTekListData for Tek List - { - Nothing = 0, //nothing (default for v1.2.3) - RealTime = 1, // real time - MidnightTime = 2, // last night - // please add "YourDataType = " - } - - private List PresetTekListData(int dataVersion) - { - switch ((PresetTekListType)dataVersion) - { - case PresetTekListType.MidnightTime: - return new List { CreateTestData(CalcMidnightTimeAddDays(-1)), CreateTestData(CalcMidnightTimeAddDays(0)) }; - case PresetTekListType.RealTime: - return new List { CreateTestData(CalcTimeAddDays(-1)), CreateTestData(CalcTimeAddDays(0)) }; - case PresetTekListType.Nothing: - default: - return new List(); - } - } - - async Task IHttpDataService.PostRegisterUserAsync() - { - Debug.WriteLine("HttpDataServiceMock::PostRegisterUserAsync called"); - var code = HttpStatusCode.OK; - var result = mockCommonUtils.GetRegisterDataType(); - if (result >= 100) - { - code = (HttpStatusCode)result; - } - else - { - if (result.Equals(1)) - { - code = HttpStatusCode.NoContent; - } - } - - return await Task.FromResult(code); - } - - Task IHttpDataService.PutSelfExposureKeysAsync(DiagnosisSubmissionParameter request) - { - var code = HttpStatusCode.OK; // default. for PutSelfExposureKeys NG - var dataType = mockCommonUtils.GetDiagnosisDataType(); - if (dataType >= 100) // HttpStatusCode >=100 by RFC2616#section-10 - { - code = (HttpStatusCode)dataType; - } - else - { - switch (dataType) - { - case 1: - code = HttpStatusCode.NoContent; // for Successful PutSelfExposureKeys - break; - } - } - - Debug.WriteLine("HttpDataServiceMock::PutSelfExposureKeysAsync called"); - return Task.FromResult(code); - } - - public Task> GetLogStorageSas() - { - return Task.Factory.StartNew(() => - { - Debug.WriteLine("HttpDataServiceMock::GetStorageKey called"); - return new ApiResponse((int)HttpStatusCode.OK, new LogStorageSas { SasToken = "sv=2012-02-12&se=2015-07-08T00%3A12%3A08Z&sr=c&sp=wl&sig=t%2BbzU9%2B7ry4okULN9S0wst%2F8MCUhTjrHyV9rDNLSe8g%3Dsss" }); - }); - } - } - - public class MockCommonUtils - { - public string CdnUrlBase => AppSettings.Instance.CdnUrlBase; - public string ApiUrlBase => AppSettings.Instance.ApiUrlBase; - - public bool IsDownloadRequired() - => Regex.IsMatch(CdnUrlBase, @"^https://.*\..*\..*/$"); - - public bool IsDirectInput() - => Regex.IsMatch(CdnUrlBase, @"^(\d+,)+\d+,*$"); - - - private ushort NumberEndofSentence(string url) - { - Match match = Regex.Match(url, @"(?\d+)$"); - ushort number = 0; - if (match.Success) - { - number = Convert.ToUInt16(match.Groups["d"].Value); - } - return number; - } - public List GetCreatedTimes() - => CdnUrlBase.Split(",").ToList(); - public ushort GetTekListDataType() - => NumberEndofSentence(CdnUrlBase); - public string[] GetApiUrlSegment() - { - // "url/api" -> { "url/api", "", "" } - // "url/base/api/register1/diagnosis2" -> { "url/base/api", "/register1", "/diagnosis2" } - // "url/api1/r1/d2" -> { "url/api1", "/r1", "/d2" } - // "url/api1/d2/r1" -> { "url/api1", "/r1", "/d2" } - var url = ApiUrlBase; - var r = new Regex("/r(egister)?[0-9]+"); - var d = new Regex("/d(iagnosis)?[0-9]+"); - var urlRegister = r.Match(url).Value; - url = r.Replace(url, ""); - var urlDiagnosis = d.Match(url).Value; - url = d.Replace(url, ""); - var urlApi = url; - return new string[] { urlApi, urlRegister, urlDiagnosis }; - } - public ushort GetDiagnosisDataType() - => NumberEndofSentence(GetApiUrlSegment()[2]); - public ushort GetRegisterDataType() - => NumberEndofSentence(GetApiUrlSegment()[1]); - public ushort GetApiDataType() - => NumberEndofSentence(GetApiUrlSegment()[0]); - public bool IsDirectInputApi() - => Regex.IsMatch(GetApiUrlSegment()[0], @"^(\d+,)+\d+,?$"); - public List GetApiStrings() - => GetApiUrlSegment()[0].Split(",").ToList(); - } -} diff --git a/Covid19Radar/Covid19Radar/Services/IDiagnosisKeyRegisterServer.cs b/Covid19Radar/Covid19Radar/Services/IDiagnosisKeyRegisterServer.cs index 1a4d01764..8df635ad4 100644 --- a/Covid19Radar/Covid19Radar/Services/IDiagnosisKeyRegisterServer.cs +++ b/Covid19Radar/Covid19Radar/Services/IDiagnosisKeyRegisterServer.cs @@ -7,6 +7,7 @@ using System.Net; using System.Threading.Tasks; using Chino; +using Covid19Radar.Model; namespace Covid19Radar.Services { @@ -19,5 +20,7 @@ public Task SubmitDiagnosisKeysAsync( string processNumber, string idempotencyKey ); + + public Task PutSelfExposureKeysAsync(DiagnosisSubmissionParameter request); } } diff --git a/Covid19Radar/Covid19Radar/Services/IHttpDataService.cs b/Covid19Radar/Covid19Radar/Services/IHttpDataService.cs deleted file mode 100644 index 4a6d72205..000000000 --- a/Covid19Radar/Covid19Radar/Services/IHttpDataService.cs +++ /dev/null @@ -1,19 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ - -using Covid19Radar.Model; -using System.Net; -using System.Threading.Tasks; - -namespace Covid19Radar.Services -{ - public interface IHttpDataService - { - Task PostRegisterUserAsync(); - - Task PutSelfExposureKeysAsync(DiagnosisSubmissionParameter request); - - Task> GetLogStorageSas(); - } -} diff --git a/Covid19Radar/Covid19Radar/Services/Logs/ILogUploadService.cs b/Covid19Radar/Covid19Radar/Services/Logs/ILogUploadService.cs index 18361487f..0c7921bce 100644 --- a/Covid19Radar/Covid19Radar/Services/Logs/ILogUploadService.cs +++ b/Covid19Radar/Covid19Radar/Services/Logs/ILogUploadService.cs @@ -2,12 +2,16 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +using System.Net; using System.Threading.Tasks; +using Covid19Radar.Model; namespace Covid19Radar.Services.Logs { public interface ILogUploadService { - Task UploadAsync(string zipFilePath, string sasToken); + Task> GetLogStorageSas(); + + Task UploadAsync(string zipFilePath, string sasToken); } } diff --git a/Covid19Radar/Covid19Radar/Services/Logs/LogUploadService.cs b/Covid19Radar/Covid19Radar/Services/Logs/LogUploadService.cs index 15f9cad46..05c2dc59c 100644 --- a/Covid19Radar/Covid19Radar/Services/Logs/LogUploadService.cs +++ b/Covid19Radar/Covid19Radar/Services/Logs/LogUploadService.cs @@ -2,8 +2,11 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -using System; +using System.Net; using System.Threading.Tasks; +using Covid19Radar.Model; +using Covid19Radar.Repository; +using Newtonsoft.Json; namespace Covid19Radar.Services.Logs { @@ -12,22 +15,59 @@ public class LogUploadService : ILogUploadService private readonly ILoggerService loggerService; private readonly ILogPathService logPathService; private readonly IStorageService storageService; + private readonly IHttpClientService httpClientService; + private readonly IServerConfigurationRepository serverConfigurationRepository; public LogUploadService( ILoggerService loggerService, ILogPathService logPathService, - IStorageService storageService) + IStorageService storageService, + IHttpClientService httpClientService, + IServerConfigurationRepository serverConfigurationRepository + ) { this.loggerService = loggerService; this.logPathService = logPathService; this.storageService = storageService; + this.httpClientService = httpClientService; + this.serverConfigurationRepository = serverConfigurationRepository; } - public async Task UploadAsync(string zipFilePath, string sasToken) + public async Task> GetLogStorageSas() { loggerService.StartMethod(); - var result = false; + int statusCode; + LogStorageSas logStorageSas = default; + + try + { + await serverConfigurationRepository.LoadAsync(); + + var url = serverConfigurationRepository.InquiryLogApiUrl; + + var response = await httpClientService.ApiClient.GetAsync(url); + + statusCode = (int)response.StatusCode; + loggerService.Info($"Response status: {statusCode}"); + + if (statusCode == (int)HttpStatusCode.OK) + { + var content = await response.Content.ReadAsStringAsync(); + logStorageSas = JsonConvert.DeserializeObject(content); + } + + return new ApiResponse(statusCode, logStorageSas); + } + finally + { + loggerService.EndMethod(); + } + } + + public async Task UploadAsync(string zipFilePath, string sasToken) + { + loggerService.StartMethod(); try { @@ -39,21 +79,12 @@ public async Task UploadAsync(string zipFilePath, string sasToken) var uploadPath = setting.LogStorageContainerName; var accountName = setting.LogStorageAccountName; - var uploadResult = await storageService.UploadAsync(endpoint, uploadPath, accountName, sasToken, zipFilePath); - if (!uploadResult) - { - throw new Exception("Failed to upload to storage."); - } - - result = true; + return await storageService.UploadAsync(endpoint, uploadPath, accountName, sasToken, zipFilePath); } - catch (Exception ex) + finally { - loggerService.Exception("Failed upload.", ex); + loggerService.EndMethod(); } - - loggerService.EndMethod(); - return result; } } } diff --git a/Covid19Radar/Covid19Radar/Services/Logs/LogUploadServiceMock.cs b/Covid19Radar/Covid19Radar/Services/Logs/LogUploadServiceMock.cs new file mode 100644 index 000000000..4eb2730c8 --- /dev/null +++ b/Covid19Radar/Covid19Radar/Services/Logs/LogUploadServiceMock.cs @@ -0,0 +1,25 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +using System.Net; +using System.Threading.Tasks; +using Covid19Radar.Model; + +namespace Covid19Radar.Services.Logs +{ + public class LogUploadServiceMock : ILogUploadService + { + public Task> GetLogStorageSas() + => Task.FromResult(new ApiResponse( + (int)HttpStatusCode.OK, + new LogStorageSas() + { + SasToken = "Dummy Token" + } + )); + + public Task UploadAsync(string zipFilePath, string sasToken) + => Task.FromResult(HttpStatusCode.Created); + } +} diff --git a/Covid19Radar/Covid19Radar/Services/StorageService.cs b/Covid19Radar/Covid19Radar/Services/StorageService.cs index afe99eade..80fcc93f4 100644 --- a/Covid19Radar/Covid19Radar/Services/StorageService.cs +++ b/Covid19Radar/Covid19Radar/Services/StorageService.cs @@ -13,7 +13,7 @@ namespace Covid19Radar.Services { public interface IStorageService { - Task UploadAsync(string endpoint, string uploadPath, string accountName, string sasToken, string sourceFilePath); + Task UploadAsync(string endpoint, string uploadPath, string accountName, string sasToken, string sourceFilePath); } public class StorageService : IStorageService @@ -25,11 +25,10 @@ public StorageService(ILoggerService loggerService) this.loggerService = loggerService; } - public async Task UploadAsync(string endpoint, string uploadPath, string accountName, string sasToken, string sourceFilePath) + public async Task UploadAsync(string endpoint, string uploadPath, string accountName, string sasToken, string sourceFilePath) { loggerService.StartMethod(); - var result = false; try { var fileName = Path.GetFileName(sourceFilePath); @@ -44,20 +43,13 @@ public async Task UploadAsync(string endpoint, string uploadPath, string a { var response = await client.UploadAsync(fileStream); var rawResponse = response.GetRawResponse(); - if (rawResponse.Status == (int)HttpStatusCode.Created) - { - result = true; - } + return (HttpStatusCode)rawResponse.Status; } } - catch (Exception ex) + finally { - loggerService.Error("Failed upload to storage"); - System.Diagnostics.Debug.WriteLine($"Exception: {ex}"); + loggerService.EndMethod(); } - - loggerService.EndMethod(); - return result; } } } diff --git a/Covid19Radar/Covid19Radar/Services/StorageServiceMock.cs b/Covid19Radar/Covid19Radar/Services/StorageServiceMock.cs index b0428bdab..853cc34d6 100644 --- a/Covid19Radar/Covid19Radar/Services/StorageServiceMock.cs +++ b/Covid19Radar/Covid19Radar/Services/StorageServiceMock.cs @@ -2,16 +2,17 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +using System.Net; using System.Threading.Tasks; namespace Covid19Radar.Services { public class StorageServiceMock : IStorageService { - public async Task UploadAsync(string endpoint, string uploadPath, string accountName, string sasToken, string sourceFilePath) + public async Task UploadAsync(string endpoint, string uploadPath, string accountName, string sasToken, string sourceFilePath) { await Task.Delay(500); - return true; + return HttpStatusCode.Created; } } } diff --git a/Covid19Radar/Covid19Radar/Services/TermsUpdateService.cs b/Covid19Radar/Covid19Radar/Services/TermsUpdateService.cs index 5b0908033..c408fc14a 100644 --- a/Covid19Radar/Covid19Radar/Services/TermsUpdateService.cs +++ b/Covid19Radar/Covid19Radar/Services/TermsUpdateService.cs @@ -3,7 +3,6 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ using System; -using System.Net.Http; using System.Threading.Tasks; using Covid19Radar.Model; using Covid19Radar.Repository; @@ -21,12 +20,10 @@ public interface ITermsUpdateService public class TermsUpdateService : ITermsUpdateService { - private const double TimeoutSeconds = 5.0; - private readonly ILoggerService loggerService; private readonly IUserDataRepository userDataRepository; - private readonly HttpClient _httpClient; + private readonly IHttpClientService _httpClientService; public TermsUpdateService( ILoggerService loggerService, @@ -37,8 +34,7 @@ IUserDataRepository userDataRepository this.loggerService = loggerService; this.userDataRepository = userDataRepository; - _httpClient = httpClientService.Create(); - _httpClient.Timeout = TimeSpan.FromSeconds(TimeoutSeconds); + _httpClientService = httpClientService; } public async Task GetTermsUpdateInfo() @@ -48,7 +44,7 @@ public async Task GetTermsUpdateInfo() var uri = AppResources.UrlTermsUpdate; try { - var json = await _httpClient.GetStringAsync(uri); + var json = await _httpClientService.StaticJsonContentClient.GetStringAsync(uri); loggerService.Info($"uri: {uri}"); loggerService.Info($"TermsUpdateInfo: {json}"); diff --git a/Covid19Radar/Covid19Radar/Services/UserDataService.cs b/Covid19Radar/Covid19Radar/Services/UserDataService.cs index d0e4a8e8c..6a575175c 100644 --- a/Covid19Radar/Covid19Radar/Services/UserDataService.cs +++ b/Covid19Radar/Covid19Radar/Services/UserDataService.cs @@ -6,6 +6,8 @@ using Covid19Radar.Services.Logs; using System; using System.Net; +using System.Net.Http; +using System.Text; using System.Threading.Tasks; namespace Covid19Radar.Services @@ -21,18 +23,21 @@ public interface IUserDataService public class UserDataService : IUserDataService { private readonly ILoggerService loggerService; - private readonly IHttpDataService httpDataService; + private readonly IHttpClientService httpClientService; private readonly IUserDataRepository userDataRepository; + private readonly IServerConfigurationRepository serverConfigurationRepository; public UserDataService( - IHttpDataService httpDataService, + IHttpClientService httpClientService, ILoggerService loggerService, - IUserDataRepository userDataRepository + IUserDataRepository userDataRepository, + IServerConfigurationRepository serverConfigurationRepository ) { - this.httpDataService = httpDataService; + this.httpClientService = httpClientService; this.loggerService = loggerService; this.userDataRepository = userDataRepository; + this.serverConfigurationRepository = serverConfigurationRepository; } public async Task RegisterUserAsync() @@ -40,7 +45,13 @@ public async Task RegisterUserAsync() loggerService.StartMethod(); try { - var resultStatusCode = await httpDataService.PostRegisterUserAsync(); + await serverConfigurationRepository.LoadAsync(); + + string url = serverConfigurationRepository.UserRegisterApiEndpoint; + var content = new StringContent(string.Empty, Encoding.UTF8, "application/json"); + + HttpResponseMessage result = await httpClientService.ApiClient.PostAsync(url, content); + HttpStatusCode resultStatusCode = result.StatusCode; if (resultStatusCode == HttpStatusCode.OK) { @@ -52,16 +63,24 @@ public async Task RegisterUserAsync() loggerService.Info("Failed register"); } - loggerService.EndMethod(); return resultStatusCode; } catch(Exception ex) { loggerService.Exception("Failed to register user.", ex); - loggerService.EndMethod(); throw; } + finally + { + loggerService.EndMethod(); + } } } + + public class UserDataServiceMock : IUserDataService + { + public Task RegisterUserAsync() + => Task.FromResult(HttpStatusCode.OK); + } } diff --git a/Covid19Radar/Covid19Radar/ViewModels/HelpPage/SendLogConfirmationPageViewModel.cs b/Covid19Radar/Covid19Radar/ViewModels/HelpPage/SendLogConfirmationPageViewModel.cs index dc07c35df..713754d67 100644 --- a/Covid19Radar/Covid19Radar/ViewModels/HelpPage/SendLogConfirmationPageViewModel.cs +++ b/Covid19Radar/Covid19Radar/ViewModels/HelpPage/SendLogConfirmationPageViewModel.cs @@ -7,7 +7,6 @@ using System.Threading.Tasks; using Acr.UserDialogs; using Covid19Radar.Resources; -using Covid19Radar.Services; using Covid19Radar.Services.Logs; using Covid19Radar.Views; using Prism.Navigation; @@ -24,7 +23,6 @@ public class SendLogConfirmationPageViewModel : ViewModelBase private readonly ILogFileService logFileService; private readonly ILogUploadService logUploadService; private readonly ILogPathService logPathService; - private readonly IHttpDataService httpDataService; public Action BeginInvokeOnMainThread { get; set; } = MainThread.BeginInvokeOnMainThread; public Func TaskRun { get; set; } = Task.Run; @@ -36,13 +34,12 @@ public SendLogConfirmationPageViewModel( INavigationService navigationService, ILoggerService loggerService, ILogFileService logFileService, - ILogUploadService logUploadService, - IHttpDataService httpDataService) : base(navigationService) + ILogUploadService logUploadService + ) : base(navigationService) { this.loggerService = loggerService; this.logFileService = logFileService; this.logUploadService = logUploadService; - this.httpDataService = httpDataService; } public Command OnClickConfirmLogCommand => new Command(async () => @@ -83,11 +80,10 @@ await Share.RequestAsync(new ShareFileRequest // Upload log file. UserDialogs.Instance.ShowLoading(AppResources.Sending); - var response = await httpDataService.GetLogStorageSas(); + var response = await logUploadService.GetLogStorageSas(); if (response.StatusCode == (int)HttpStatusCode.Forbidden) { - UserDialogs.Instance.HideLoading(); // Access from overseas await UserDialogs.Instance.AlertAsync( AppResources.DialogNetworkConnectionErrorFromOverseasMessage, @@ -96,15 +92,13 @@ await UserDialogs.Instance.AlertAsync( return; } - var uploadResult = false; + HttpStatusCode uploadResultStatusCode = HttpStatusCode.Forbidden; if (response.StatusCode == (int)HttpStatusCode.OK && !string.IsNullOrEmpty(response.Result.SasToken)) { - uploadResult = await logUploadService.UploadAsync(ZipFilePath, response.Result.SasToken); + uploadResultStatusCode = await logUploadService.UploadAsync(ZipFilePath, response.Result.SasToken); } - UserDialogs.Instance.HideLoading(); - - if (!uploadResult) + if (uploadResultStatusCode != HttpStatusCode.Created) { // Failed to create ZIP file await UserDialogs.Instance.AlertAsync( @@ -138,6 +132,8 @@ await UserDialogs.Instance.AlertAsync( } finally { + UserDialogs.Instance.HideLoading(); + loggerService.EndMethod(); } }); diff --git a/Covid19Radar/Tests/Covid19Radar.UnitTests/Repository/DiagnosisKeyRepositoryTests.cs b/Covid19Radar/Tests/Covid19Radar.UnitTests/Repository/DiagnosisKeyRepositoryTests.cs index 408a01d7b..e54d4728e 100644 --- a/Covid19Radar/Tests/Covid19Radar.UnitTests/Repository/DiagnosisKeyRepositoryTests.cs +++ b/Covid19Radar/Tests/Covid19Radar.UnitTests/Repository/DiagnosisKeyRepositoryTests.cs @@ -46,7 +46,7 @@ public async void GetDiagnosisKeysListAsyncTests_Success() "application/json" ) ); - mockClientService.Setup(x => x.Create()).Returns(client); + mockClientService.Setup(x => x.CdnClient).Returns(client); var unitUnderTest = CreateRepository(); var (_, result) = await unitUnderTest.GetDiagnosisKeysListAsync("https://example.com", default); @@ -71,7 +71,7 @@ public async void GetDiagnosisKeysListAsyncTests_HttpError(System.Net.HttpStatus statusCode, new StringContent("", Encoding.UTF8, "application/json") ); - mockClientService.Setup(x => x.Create()).Returns(client); + mockClientService.Setup(x => x.CdnClient).Returns(client); var unitUnderTest = CreateRepository(); var (_, result) = await unitUnderTest.GetDiagnosisKeysListAsync("https://example.com", default); @@ -89,7 +89,7 @@ public async void DownloadDiagnosisKeysAsyncTests_Success() HttpStatusCode.OK, content ); - mockClientService.Setup(x => x.Create()).Returns(client); + mockClientService.Setup(x => x.CdnClient).Returns(client); var entry = new DiagnosisKeyEntry() { @@ -122,7 +122,7 @@ public async void DownloadDiagnosisKeysAsyncTests_HttpError(System.Net.HttpStatu statusCode, content ); - mockClientService.Setup(x => x.Create()).Returns(client); + mockClientService.Setup(x => x.CdnClient).Returns(client); var entry = new DiagnosisKeyEntry() { diff --git a/Covid19Radar/Tests/Covid19Radar.UnitTests/Repository/ExposureConfigurationRepositoryTests.cs b/Covid19Radar/Tests/Covid19Radar.UnitTests/Repository/ExposureConfigurationRepositoryTests.cs index d067993f1..756cdaf72 100644 --- a/Covid19Radar/Tests/Covid19Radar.UnitTests/Repository/ExposureConfigurationRepositoryTests.cs +++ b/Covid19Radar/Tests/Covid19Radar.UnitTests/Repository/ExposureConfigurationRepositoryTests.cs @@ -89,7 +89,7 @@ public async Task GetExposureConfigurationTest_firsttime() "application/json" ); var client = HttpClientUtils.CreateHttpClient(HttpStatusCode.OK, jsonContent); - mockClientService.Setup(x => x.Create()).Returns(client); + mockClientService.Setup(x => x.StaticJsonContentClient).Returns(client); mockLocalPathService.Setup(x => x.ExposureConfigurationDirPath).Returns("./"); mockLocalPathService.Setup(x => x.CurrentExposureConfigurationPath).Returns(CURRENT_EXPOSURE_CONFIGURATION_FILE_PATH); @@ -135,7 +135,7 @@ public async Task GetExposureConfigurationTest_updated_but_not_cache_expired() "application/json" ); var client = HttpClientUtils.CreateHttpClient(HttpStatusCode.OK, jsonContent); - mockClientService.Setup(x => x.Create()).Returns(client); + mockClientService.Setup(x => x.StaticJsonContentClient).Returns(client); mockLocalPathService.Setup(x => x.ExposureConfigurationDirPath).Returns("./"); mockLocalPathService.Setup(x => x.CurrentExposureConfigurationPath).Returns(CURRENT_EXPOSURE_CONFIGURATION_FILE_PATH); @@ -177,7 +177,7 @@ public async Task GetExposureConfigurationTest_updated_DataMappingNotUpdated_and "application/json" ); var client = HttpClientUtils.CreateHttpClient(HttpStatusCode.OK, jsonContent); - mockClientService.Setup(x => x.Create()).Returns(client); + mockClientService.Setup(x => x.StaticJsonContentClient).Returns(client); mockLocalPathService.Setup(x => x.ExposureConfigurationDirPath).Returns("./"); mockLocalPathService.Setup(x => x.CurrentExposureConfigurationPath).Returns(CURRENT_EXPOSURE_CONFIGURATION_FILE_PATH); @@ -220,7 +220,7 @@ public async Task GetExposureConfigurationTest_updated_DataMappingUpdated_and_ca "application/json" ); var client = HttpClientUtils.CreateHttpClient(HttpStatusCode.OK, jsonContent); - mockClientService.Setup(x => x.Create()).Returns(client); + mockClientService.Setup(x => x.StaticJsonContentClient).Returns(client); mockLocalPathService.Setup(x => x.ExposureConfigurationDirPath).Returns("./"); mockLocalPathService.Setup(x => x.CurrentExposureConfigurationPath).Returns(CURRENT_EXPOSURE_CONFIGURATION_FILE_PATH); @@ -261,7 +261,7 @@ public async Task GetExposureConfigurationTest_updated_mapping_but_not_cache_exp "application/json" ); var client = HttpClientUtils.CreateHttpClient(HttpStatusCode.OK, jsonContent); - mockClientService.Setup(x => x.Create()).Returns(client); + mockClientService.Setup(x => x.StaticJsonContentClient).Returns(client); mockLocalPathService.Setup(x => x.ExposureConfigurationDirPath).Returns("./"); mockLocalPathService.Setup(x => x.CurrentExposureConfigurationPath).Returns(CURRENT_EXPOSURE_CONFIGURATION_FILE_PATH); @@ -304,7 +304,7 @@ public async Task GetExposureConfigurationTest_updated_mapping_and_cache_expired "application/json" ); var client = HttpClientUtils.CreateHttpClient(HttpStatusCode.OK, jsonContent); - mockClientService.Setup(x => x.Create()).Returns(client); + mockClientService.Setup(x => x.StaticJsonContentClient).Returns(client); mockLocalPathService.Setup(x => x.ExposureConfigurationDirPath).Returns("./"); mockLocalPathService.Setup(x => x.CurrentExposureConfigurationPath).Returns(CURRENT_EXPOSURE_CONFIGURATION_FILE_PATH); @@ -348,7 +348,7 @@ public async Task GetExposureConfigurationTest_not_updated_mapping_and_cache_exp "application/json" ); var client = HttpClientUtils.CreateHttpClient(HttpStatusCode.OK, jsonContent); - mockClientService.Setup(x => x.Create()).Returns(client); + mockClientService.Setup(x => x.StaticJsonContentClient).Returns(client); mockLocalPathService.Setup(x => x.ExposureConfigurationDirPath).Returns("./"); mockLocalPathService.Setup(x => x.CurrentExposureConfigurationPath).Returns(CURRENT_EXPOSURE_CONFIGURATION_FILE_PATH); diff --git a/Covid19Radar/Tests/Covid19Radar.UnitTests/Repository/ExposureRiskCalculationConfigurationRepositoryTests.cs b/Covid19Radar/Tests/Covid19Radar.UnitTests/Repository/ExposureRiskCalculationConfigurationRepositoryTests.cs index a7d1d2e98..d673104ac 100644 --- a/Covid19Radar/Tests/Covid19Radar.UnitTests/Repository/ExposureRiskCalculationConfigurationRepositoryTests.cs +++ b/Covid19Radar/Tests/Covid19Radar.UnitTests/Repository/ExposureRiskCalculationConfigurationRepositoryTests.cs @@ -71,7 +71,7 @@ V1ExposureRiskCalculationConfiguration expect "application/json" ); var client = HttpClientUtils.CreateHttpClient(HttpStatusCode.OK, jsonContent); - mockClientService.Setup(x => x.Create()).Returns(client); + mockClientService.Setup(x => x.StaticJsonContentClient).Returns(client); mockLocalPathService.Setup(x => x.ExposureConfigurationDirPath).Returns("./"); mockLocalPathService.Setup(x => x.CurrentExposureRiskCalculationConfigurationPath).Returns(CURRENT_EXPOSURE_RISK_CONFIGURATION_FILE_PATH); @@ -104,7 +104,7 @@ V1ExposureRiskCalculationConfiguration expect "application/json" ); var client = HttpClientUtils.CreateHttpClient(HttpStatusCode.OK, jsonContent); - mockClientService.Setup(x => x.Create()).Returns(client); + mockClientService.Setup(x => x.StaticJsonContentClient).Returns(client); mockLocalPathService.Setup(x => x.ExposureConfigurationDirPath).Returns("./"); mockLocalPathService.Setup(x => x.CurrentExposureRiskCalculationConfigurationPath).Returns(CURRENT_EXPOSURE_RISK_CONFIGURATION_FILE_PATH); @@ -138,7 +138,7 @@ V1ExposureRiskCalculationConfiguration newConfiguration "application/json" ); var client = HttpClientUtils.CreateHttpClient(HttpStatusCode.OK, jsonContent); - mockClientService.Setup(x => x.Create()).Returns(client); + mockClientService.Setup(x => x.StaticJsonContentClient).Returns(client); mockLocalPathService.Setup(x => x.ExposureConfigurationDirPath).Returns("./"); mockLocalPathService.Setup(x => x.CurrentExposureRiskCalculationConfigurationPath).Returns(CURRENT_EXPOSURE_RISK_CONFIGURATION_FILE_PATH); @@ -173,7 +173,7 @@ V1ExposureRiskCalculationConfiguration newConfiguration "application/json" ); var client = HttpClientUtils.CreateHttpClient(HttpStatusCode.OK, jsonContent); - mockClientService.Setup(x => x.Create()).Returns(client); + mockClientService.Setup(x => x.StaticJsonContentClient).Returns(client); mockLocalPathService.Setup(x => x.ExposureConfigurationDirPath).Returns("./"); mockLocalPathService.Setup(x => x.CurrentExposureRiskCalculationConfigurationPath).Returns(CURRENT_EXPOSURE_RISK_CONFIGURATION_FILE_PATH); diff --git a/Covid19Radar/Tests/Covid19Radar.UnitTests/Services/CheckVersionServiceTests.cs b/Covid19Radar/Tests/Covid19Radar.UnitTests/Services/CheckVersionServiceTests.cs index 4a14a5a3c..5ee5bd0c5 100644 --- a/Covid19Radar/Tests/Covid19Radar.UnitTests/Services/CheckVersionServiceTests.cs +++ b/Covid19Radar/Tests/Covid19Radar.UnitTests/Services/CheckVersionServiceTests.cs @@ -76,7 +76,7 @@ private async void IsUpdate(bool isIos, string version, bool expected) "application/json" ); var client = HttpClientUtils.CreateHttpClient(HttpStatusCode.OK, jsonContent); - _mockClientService.Setup(x => x.Create()).Returns(client); + _mockClientService.Setup(x => x.StaticJsonContentClient).Returns(client); _mockEssentialsService.Setup(x => x.IsIos).Returns(isIos); _mockEssentialsService.Setup(x => x.AppVersion).Returns(version); diff --git a/Covid19Radar/Tests/Covid19Radar.UnitTests/Services/DiagnosisKeyRegisterServerTests.cs b/Covid19Radar/Tests/Covid19Radar.UnitTests/Services/DiagnosisKeyRegisterServerTests.cs new file mode 100644 index 000000000..911c70bbe --- /dev/null +++ b/Covid19Radar/Tests/Covid19Radar.UnitTests/Services/DiagnosisKeyRegisterServerTests.cs @@ -0,0 +1,130 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +using System; +using System.Collections.Generic; +using System.Net; +using System.Net.Http; +using System.Threading.Tasks; +using Covid19Radar.Model; +using Covid19Radar.Repository; +using Covid19Radar.Services; +using Covid19Radar.Services.Logs; +using Covid19Radar.UnitTests.Mocks; +using Moq; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Xunit; + +namespace Covid19Radar.UnitTests.Services +{ + public class DiagnosisKeyRegisterServerTests + { + private readonly MockRepository mockRepository; + private readonly Mock mockLoggerService; + private readonly Mock mockHttpClientService; + private readonly Mock mockDeviceVerifier; + private readonly Mock mockServerConfigurationRepository; + + public DiagnosisKeyRegisterServerTests() + { + mockRepository = new MockRepository(MockBehavior.Default); + mockLoggerService = mockRepository.Create(); + mockHttpClientService = mockRepository.Create(); + mockDeviceVerifier = mockRepository.Create(); + mockServerConfigurationRepository = mockRepository.Create(); + } + + private IDiagnosisKeyRegisterServer CreateService() + { + return new DiagnosisKeyRegisterServer( + mockLoggerService.Object, + mockHttpClientService.Object, + mockDeviceVerifier.Object, + mockServerConfigurationRepository.Object + ); + } + + #region PutSelfExposureKeysAsync() + + [Fact] + public async Task PutSelfExposureKeysAsync_Success() + { + HttpContent requestContent = null; + var mockHttpClient = new HttpClient(new MockHttpHandler((r, c) => + { + var absoluteUri = r.RequestUri.AbsoluteUri; + if (absoluteUri.EndsWith("/api/v3/diagnosis")) + { + requestContent = r.Content; + var response = new HttpResponseMessage(HttpStatusCode.NoContent); + response.Content = new StringContent(""); + return response; + } + return new HttpResponseMessage(HttpStatusCode.NotFound); + })); + + mockHttpClientService.Setup(x => x.ApiClient).Returns(mockHttpClient); + mockServerConfigurationRepository.Setup(x => x.DiagnosisKeyRegisterApiUrls) + .Returns(new List() { IServerConfigurationRepository.CombineAsUrl(AppSettings.Instance.ApiUrlBase, "api/v3/diagnosis") }); + + var unitUnderTest = CreateService(); + + var temporaryExposureKeys = new DiagnosisSubmissionParameter.Key[] { + new DiagnosisSubmissionParameter.Key(){ + KeyData = "key-data", + RollingStartNumber = 1, + RollingPeriod = 2 + } + }; + + var result = await unitUnderTest.PutSelfExposureKeysAsync( + new DiagnosisSubmissionParameter() + { + Regions = new string[] { "440" }, + Keys = temporaryExposureKeys, + Platform = "platform", + DeviceVerificationPayload = "device-verification-payload", + AppPackageName = "app-package-name", + VerificationPayload = "verification-payload", + Padding = "padding" + + } + ); + + mockLoggerService.Verify(x => x.StartMethod("PutSelfExposureKeysAsync", It.IsAny(), It.IsAny()), Times.Once()); + mockLoggerService.Verify(x => x.EndMethod("PutSelfExposureKeysAsync", It.IsAny(), It.IsAny()), Times.Once()); + mockLoggerService.Verify(x => x.Exception(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Never()); + + Assert.Equal(HttpStatusCode.NoContent, result); + Assert.NotNull(requestContent); + + var stringContent = await requestContent.ReadAsStringAsync(); + Assert.NotEmpty(stringContent); + + var jsonContent = JsonConvert.DeserializeObject(stringContent) as JObject; + Assert.NotNull(jsonContent); + + var keys = jsonContent["keys"] as JArray; + Assert.Single(keys); + Assert.Equal("key-data", keys[0]["keyData"].Value()); + Assert.Equal(1, keys[0]["rollingStartNumber"].Value()); + Assert.Equal(2, keys[0]["rollingPeriod"].Value()); + + var rgions = jsonContent["regions"] as JArray; + Assert.Equal("440", rgions[0].Value()); + + Assert.Equal("platform", jsonContent["platform"].Value()); + Assert.Equal("device-verification-payload", jsonContent["deviceVerificationPayload"].Value()); + Assert.Equal("app-package-name", jsonContent["appPackageName"].Value()); + Assert.Equal("verification-payload", jsonContent["verificationPayload"].Value()); + Assert.Equal("padding", jsonContent["padding"].Value()); + + Assert.Null(jsonContent["userUuid"]); + Assert.Null(mockHttpClient.DefaultRequestHeaders.Authorization); + } + + #endregion + } +} diff --git a/Covid19Radar/Tests/Covid19Radar.UnitTests/Services/ExposureDetectionServiceTests.cs b/Covid19Radar/Tests/Covid19Radar.UnitTests/Services/ExposureDetectionServiceTests.cs index 72323761d..6a68bdd29 100644 --- a/Covid19Radar/Tests/Covid19Radar.UnitTests/Services/ExposureDetectionServiceTests.cs +++ b/Covid19Radar/Tests/Covid19Radar.UnitTests/Services/ExposureDetectionServiceTests.cs @@ -75,7 +75,7 @@ public void Dispose() private ExposureDetectionService CreateService() { - clientService.Setup(x => x.Create()) + clientService.Setup(x => x.StaticJsonContentClient) .Returns(new HttpClient()); var exposureConfigurationRepository = new ExposureConfigurationRepository( diff --git a/Covid19Radar/Tests/Covid19Radar.UnitTests/Services/HttpClientServiceTests.cs b/Covid19Radar/Tests/Covid19Radar.UnitTests/Services/HttpClientServiceTests.cs index 0d0879d97..33111c59c 100644 --- a/Covid19Radar/Tests/Covid19Radar.UnitTests/Services/HttpClientServiceTests.cs +++ b/Covid19Radar/Tests/Covid19Radar.UnitTests/Services/HttpClientServiceTests.cs @@ -20,10 +20,26 @@ public HttpClientService CreateService() } [Fact] - public void CreateTest() + public void CreateApiClientTest() { var unitUnderTest = CreateService(); - var httpClient = unitUnderTest.Create(); + var httpClient = unitUnderTest.ApiClient; + Assert.IsType(httpClient); + } + + [Fact] + public void CreateHttpClientTest() + { + var unitUnderTest = CreateService(); + var httpClient = unitUnderTest.StaticJsonContentClient; + Assert.IsType(httpClient); + } + + [Fact] + public void CreateCdnClientTest() + { + var unitUnderTest = CreateService(); + var httpClient = unitUnderTest.CdnClient; Assert.IsType(httpClient); } } diff --git a/Covid19Radar/Tests/Covid19Radar.UnitTests/Services/HttpDataServiceTests.cs b/Covid19Radar/Tests/Covid19Radar.UnitTests/Services/HttpDataServiceTests.cs deleted file mode 100644 index 03ac6a495..000000000 --- a/Covid19Radar/Tests/Covid19Radar.UnitTests/Services/HttpDataServiceTests.cs +++ /dev/null @@ -1,236 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ - -using System; -using System.Collections.Generic; -using System.Net; -using System.Net.Http; -using System.Threading.Tasks; -using Covid19Radar.Model; -using Covid19Radar.Repository; -using Covid19Radar.Services; -using Covid19Radar.Services.Logs; -using Covid19Radar.UnitTests.Mocks; -using Moq; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using Xunit; - -namespace Covid19Radar.UnitTests.Services -{ - public class HttpDataServiceTests - { - #region Instance Properties - - private readonly MockRepository mockRepository; - private readonly Mock mockLoggerService; - private readonly Mock mockHttpClientService; - private readonly Mock mockServerConfigurationRepository; - - #endregion - - #region Constructors - - public HttpDataServiceTests() - { - mockRepository = new MockRepository(MockBehavior.Default); - mockLoggerService = mockRepository.Create(); - mockHttpClientService = mockRepository.Create(); - mockServerConfigurationRepository = mockRepository.Create(); - } - - #endregion - - #region Other Private Methods - - private IHttpDataService CreateService() - { - return new HttpDataService( - mockLoggerService.Object, - mockHttpClientService.Object, - mockServerConfigurationRepository.Object - ); - } - - #endregion - - #region Test Methods - - #region PostRegisterUserAsync() - - [Fact] - public async Task PostRegisterUserAsyncTestsAsync_Success() - { - var mockHttpClient = new HttpClient(new MockHttpHandler((r, c) => - { - var absoluteUri = r.RequestUri.AbsoluteUri; - if (absoluteUri.EndsWith("/api/register")) - { - var response = new HttpResponseMessage(HttpStatusCode.OK); - response.Content = new StringContent("{}"); - response.Content.Headers.Remove("Content-Type"); - response.Content.Headers.Add("Content-Type", "application/json"); - return response; - } - return new HttpResponseMessage(HttpStatusCode.NotFound); - })); - - mockHttpClientService.Setup(x => x.Create()).Returns(mockHttpClient); - mockServerConfigurationRepository.Setup(x => x.UserRegisterApiEndpoint) - .Returns(IServerConfigurationRepository.CombineAsUrl(AppSettings.Instance.ApiUrlBase, "api/register")); - - var unitUnderTest = CreateService(); - - var result = await unitUnderTest.PostRegisterUserAsync(); - - mockLoggerService.Verify(x => x.StartMethod("PostRegisterUserAsync", It.IsAny(), It.IsAny()), Times.Once()); - mockLoggerService.Verify(x => x.EndMethod("PostRegisterUserAsync", It.IsAny(), It.IsAny()), Times.Once()); - mockLoggerService.Verify(x => x.Exception(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Never()); - - Assert.Null(mockHttpClient.DefaultRequestHeaders.Authorization); - } - - [Fact] - public async Task PostRegisterUserAsyncTestsAsync_Failure() - { - var mockHttpClient = new HttpClient(new MockHttpHandler((r, c) => - { - var absoluteUri = r.RequestUri.AbsoluteUri; - if (absoluteUri.EndsWith("/api/register")) - { - var response = new HttpResponseMessage(HttpStatusCode.ServiceUnavailable); - return response; - } - return new HttpResponseMessage(HttpStatusCode.NotFound); - })); - - mockHttpClientService.Setup(x => x.Create()).Returns(mockHttpClient); - mockServerConfigurationRepository.Setup(x => x.UserRegisterApiEndpoint) - .Returns(IServerConfigurationRepository.CombineAsUrl(AppSettings.Instance.ApiUrlBase, "api/register")); - - var unitUnderTest = CreateService(); - - var result = await unitUnderTest.PostRegisterUserAsync(); - - mockLoggerService.Verify(x => x.StartMethod("PostRegisterUserAsync", It.IsAny(), It.IsAny()), Times.Once()); - mockLoggerService.Verify(x => x.EndMethod("PostRegisterUserAsync", It.IsAny(), It.IsAny()), Times.Once()); - mockLoggerService.Verify(x => x.Exception(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Never()); - - Assert.Equal(HttpStatusCode.ServiceUnavailable, result); - } - - [Fact] - public void PostRegisterUserAsyncTestsAsync_Exception() - { - var exception = new HttpRequestException("unit-test"); - var mockHttpClient = new HttpClient(new MockHttpHandler((r, c) => - { - var absoluteUri = r.RequestUri.AbsoluteUri; - if (absoluteUri.EndsWith("/api/register")) - { - throw exception; - } - return new HttpResponseMessage(HttpStatusCode.NotFound); - })); - - mockHttpClientService.Setup(x => x.Create()).Returns(mockHttpClient); - mockServerConfigurationRepository.Setup(x => x.UserRegisterApiEndpoint) - .Returns(IServerConfigurationRepository.CombineAsUrl(AppSettings.Instance.ApiUrlBase, "api/register")); - - var unitUnderTest = CreateService(); - - - Assert.ThrowsAsync(async () => - { - await unitUnderTest.PostRegisterUserAsync(); - }); - - mockLoggerService.Verify(x => x.StartMethod("PostRegisterUserAsync", It.IsAny(), It.IsAny()), Times.Once()); - mockLoggerService.Verify(x => x.EndMethod("PostRegisterUserAsync", It.IsAny(), It.IsAny()), Times.Once()); - mockLoggerService.Verify(x => x.Exception(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Once()); - } - - #endregion - - #region PutSelfExposureKeysAsync() - - [Fact] - public async Task PutSelfExposureKeysAsync_Success() - { - HttpContent requestContent = null; - var mockHttpClient = new HttpClient(new MockHttpHandler((r, c) => - { - var absoluteUri = r.RequestUri.AbsoluteUri; - if (absoluteUri.EndsWith("/api/v3/diagnosis")) - { - requestContent = r.Content; - var response = new HttpResponseMessage(HttpStatusCode.NoContent); - response.Content = new StringContent(""); - return response; - } - return new HttpResponseMessage(HttpStatusCode.NotFound); - })); - - mockHttpClientService.Setup(x => x.Create()).Returns(mockHttpClient); - mockServerConfigurationRepository.Setup(x => x.DiagnosisKeyRegisterApiUrls) - .Returns(new List() { IServerConfigurationRepository.CombineAsUrl(AppSettings.Instance.ApiUrlBase, "api/v3/diagnosis") }); - - var unitUnderTest = CreateService(); - - var request = new DiagnosisSubmissionParameter() - { - Keys = new DiagnosisSubmissionParameter.Key[] { - new DiagnosisSubmissionParameter.Key(){ - KeyData = "key-data", - RollingStartNumber = 1, - RollingPeriod = 2 - } - }, - Regions = new string[] { "440" }, - Platform = "platform", - DeviceVerificationPayload = "device-verification-payload", - AppPackageName = "app-package-name", - VerificationPayload = "verification-payload", - Padding = "padding" - }; - - var result = await unitUnderTest.PutSelfExposureKeysAsync(request); - - mockLoggerService.Verify(x => x.StartMethod("PutSelfExposureKeysAsync", It.IsAny(), It.IsAny()), Times.Once()); - mockLoggerService.Verify(x => x.EndMethod("PutSelfExposureKeysAsync", It.IsAny(), It.IsAny()), Times.Once()); - mockLoggerService.Verify(x => x.Exception(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Never()); - - Assert.Equal(HttpStatusCode.NoContent, result); - Assert.NotNull(requestContent); - - var stringContent = await requestContent.ReadAsStringAsync(); - Assert.NotEmpty(stringContent); - - var jsonContent = JsonConvert.DeserializeObject(stringContent) as JObject; - Assert.NotNull(jsonContent); - - var keys = jsonContent["keys"] as JArray; - Assert.Single(keys); - Assert.Equal("key-data", keys[0]["keyData"].Value()); - Assert.Equal(1, keys[0]["rollingStartNumber"].Value()); - Assert.Equal(2, keys[0]["rollingPeriod"].Value()); - - var rgions = jsonContent["regions"] as JArray; - Assert.Equal("440", rgions[0].Value()); - - Assert.Equal("platform", jsonContent["platform"].Value()); - Assert.Equal("device-verification-payload", jsonContent["deviceVerificationPayload"].Value()); - Assert.Equal("app-package-name", jsonContent["appPackageName"].Value()); - Assert.Equal("verification-payload", jsonContent["verificationPayload"].Value()); - Assert.Equal("padding", jsonContent["padding"].Value()); - - Assert.Null(jsonContent["userUuid"]); - Assert.Null(mockHttpClient.DefaultRequestHeaders.Authorization); - } - - #endregion - - #endregion - } -} diff --git a/Covid19Radar/Tests/Covid19Radar.UnitTests/Services/Logs/LogUploadServiceTests.cs b/Covid19Radar/Tests/Covid19Radar.UnitTests/Services/Logs/LogUploadServiceTests.cs index 218444cfd..7d71c1fe4 100644 --- a/Covid19Radar/Tests/Covid19Radar.UnitTests/Services/Logs/LogUploadServiceTests.cs +++ b/Covid19Radar/Tests/Covid19Radar.UnitTests/Services/Logs/LogUploadServiceTests.cs @@ -3,6 +3,8 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ using System.IO; +using System.Net; +using Covid19Radar.Repository; using Covid19Radar.Services; using Covid19Radar.Services.Logs; using Moq; @@ -16,6 +18,8 @@ public class LogUploadServiceTests private readonly Mock mockLoggerService; private readonly Mock mockLogPathService; private readonly Mock mockStorageService; + private readonly Mock mockHttpClientService; + private readonly Mock mockServerConfigurationRepository; public LogUploadServiceTests() { @@ -23,6 +27,8 @@ public LogUploadServiceTests() mockLoggerService = mockRepository.Create(); mockLogPathService = mockRepository.Create(); mockStorageService = mockRepository.Create(); + mockHttpClientService = mockRepository.Create(); + mockServerConfigurationRepository = mockRepository.Create(); } private LogUploadService CreateService() @@ -30,7 +36,10 @@ private LogUploadService CreateService() var s = new LogUploadService( mockLoggerService.Object, mockLogPathService.Object, - mockStorageService.Object); + mockStorageService.Object, + mockHttpClientService.Object, + mockServerConfigurationRepository.Object + ); return s; } @@ -45,12 +54,13 @@ public async void UploadAsyncTests_Success() var testZipFilePath = Path.Combine(testTmpPath, testZipFileName); mockLogPathService.Setup(x => x.LogUploadingTmpPath).Returns(testTmpPath); - mockStorageService.Setup(x => x.UploadAsync("https://LOG_STORAGE_URL_BASE/", "LOG_STORAGE_CONTAINER_NAME", "LOG_STORAGE_ACCOUNT_NAME", testSasToken, testZipFilePath)).ReturnsAsync(true); + mockStorageService.Setup(x => x.UploadAsync(It.IsAny(), It.IsAny(), It.IsAny(), testSasToken, testZipFilePath)) + .ReturnsAsync(HttpStatusCode.Created); var result = await unitUnderTest.UploadAsync(testZipFilePath, testSasToken); - Assert.True(result); - mockStorageService.Verify(x => x.UploadAsync("https://LOG_STORAGE_URL_BASE/", "LOG_STORAGE_CONTAINER_NAME", "LOG_STORAGE_ACCOUNT_NAME", testSasToken, testZipFilePath), Times.Once()); + Assert.Equal(HttpStatusCode.Created, result); + mockStorageService.Verify(x => x.UploadAsync(It.IsAny(), It.IsAny(), It.IsAny(), testSasToken, testZipFilePath), Times.Once()); } [Fact] @@ -64,11 +74,12 @@ public async void UploadAsyncTests_UploadAsyncFailure() var testZipFilePath = Path.Combine(testTmpPath, testZipFileName); mockLogPathService.Setup(x => x.LogUploadingTmpPath).Returns(testTmpPath); - mockStorageService.Setup(x => x.UploadAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(false); + mockStorageService.Setup(x => x.UploadAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(HttpStatusCode.Forbidden); var result = await unitUnderTest.UploadAsync(testZipFilePath, testSasToken); - Assert.False(result); + Assert.NotEqual(HttpStatusCode.Created, result); mockStorageService.Verify(x => x.UploadAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Once()); } @@ -82,11 +93,12 @@ public async void UploadAsyncTests_UnexpectedError() var testSasToken = "test-sas-token"; var testZipFilePath = Path.Combine(testTmpPath, testZipFileName); - mockStorageService.Setup(x => x.UploadAsync("https://LOG_STORAGE_URL_BASE/", "LOG_STORAGE_CONTAINER_NAME", "LOG_STORAGE_ACCOUNT_NAME", testSasToken, testZipFilePath)).ReturnsAsync(false); + mockStorageService.Setup(x => x.UploadAsync(It.IsAny(), It.IsAny(), It.IsAny(), testSasToken, testZipFilePath)) + .ReturnsAsync(HttpStatusCode.Forbidden); var result = await unitUnderTest.UploadAsync(testZipFilePath, testSasToken); - Assert.False(result); + Assert.NotEqual(HttpStatusCode.Created, result); } } } diff --git a/Covid19Radar/Tests/Covid19Radar.UnitTests/Services/TermsUpdateServiceTests.cs b/Covid19Radar/Tests/Covid19Radar.UnitTests/Services/TermsUpdateServiceTests.cs index 5d866df1c..eb461bcbd 100644 --- a/Covid19Radar/Tests/Covid19Radar.UnitTests/Services/TermsUpdateServiceTests.cs +++ b/Covid19Radar/Tests/Covid19Radar.UnitTests/Services/TermsUpdateServiceTests.cs @@ -32,7 +32,7 @@ public TermsUpdateServiceTests() private TermsUpdateService CreateService() { - mockHttpClientService.Setup(x => x.Create()) + mockHttpClientService.Setup(x => x.StaticJsonContentClient) .Returns(new HttpClient()); return new TermsUpdateService( diff --git a/Covid19Radar/Tests/Covid19Radar.UnitTests/Services/UserDataServiceTests.cs b/Covid19Radar/Tests/Covid19Radar.UnitTests/Services/UserDataServiceTests.cs new file mode 100644 index 000000000..605d28e4f --- /dev/null +++ b/Covid19Radar/Tests/Covid19Radar.UnitTests/Services/UserDataServiceTests.cs @@ -0,0 +1,141 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. +using System; +using System.Net; +using System.Net.Http; +using System.Threading.Tasks; +using Covid19Radar.Repository; +using Covid19Radar.Services; +using Covid19Radar.Services.Logs; +using Covid19Radar.UnitTests.Mocks; +using Moq; +using Xunit; + +namespace Covid19Radar.UnitTests.Services +{ + public class UserDataServiceTests + { + private readonly MockRepository mockRepository; + private readonly Mock mockLoggerService; + private readonly Mock mockHttpClientService; + private readonly Mock mockUserDataRepository; + private readonly Mock mockServerConfigurationRepository; + + public UserDataServiceTests() + { + mockRepository = new MockRepository(MockBehavior.Default); + mockLoggerService = mockRepository.Create(); + mockHttpClientService = mockRepository.Create(); + mockUserDataRepository = mockRepository.Create(); + mockServerConfigurationRepository = mockRepository.Create(); + } + + private UserDataService CreateService() + { + return new UserDataService( + mockHttpClientService.Object, + mockLoggerService.Object, + mockUserDataRepository.Object, + mockServerConfigurationRepository.Object + ); + } + + #region PostRegisterUserAsync() + + [Fact] + public async Task PostRegisterUserAsyncTestsAsync_Success() + { + var mockHttpClient = new HttpClient(new MockHttpHandler((r, c) => + { + var absoluteUri = r.RequestUri.AbsoluteUri; + if (absoluteUri.EndsWith("/api/register")) + { + var response = new HttpResponseMessage(HttpStatusCode.OK); + response.Content = new StringContent("{}"); + response.Content.Headers.Remove("Content-Type"); + response.Content.Headers.Add("Content-Type", "application/json"); + return response; + } + return new HttpResponseMessage(HttpStatusCode.NotFound); + })); + + mockHttpClientService.Setup(x => x.ApiClient).Returns(mockHttpClient); + mockServerConfigurationRepository.Setup(x => x.UserRegisterApiEndpoint) + .Returns(IServerConfigurationRepository.CombineAsUrl(AppSettings.Instance.ApiUrlBase, "api/register")); + + var unitUnderTest = CreateService(); + + var result = await unitUnderTest.RegisterUserAsync(); + + mockLoggerService.Verify(x => x.StartMethod("RegisterUserAsync", It.IsAny(), It.IsAny()), Times.Once()); + mockLoggerService.Verify(x => x.EndMethod("RegisterUserAsync", It.IsAny(), It.IsAny()), Times.Once()); + mockLoggerService.Verify(x => x.Exception(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Never()); + + Assert.Null(mockHttpClient.DefaultRequestHeaders.Authorization); + } + + [Fact] + public async Task PostRegisterUserAsyncTestsAsync_Failure() + { + var mockHttpClient = new HttpClient(new MockHttpHandler((r, c) => + { + var absoluteUri = r.RequestUri.AbsoluteUri; + if (absoluteUri.EndsWith("/api/register")) + { + var response = new HttpResponseMessage(HttpStatusCode.ServiceUnavailable); + return response; + } + return new HttpResponseMessage(HttpStatusCode.NotFound); + })); + + mockHttpClientService.Setup(x => x.ApiClient).Returns(mockHttpClient); + mockServerConfigurationRepository.Setup(x => x.UserRegisterApiEndpoint) + .Returns(IServerConfigurationRepository.CombineAsUrl(AppSettings.Instance.ApiUrlBase, "api/register")); + + var unitUnderTest = CreateService(); + + var result = await unitUnderTest.RegisterUserAsync(); + + mockLoggerService.Verify(x => x.StartMethod("RegisterUserAsync", It.IsAny(), It.IsAny()), Times.Once()); + mockLoggerService.Verify(x => x.EndMethod("RegisterUserAsync", It.IsAny(), It.IsAny()), Times.Once()); + mockLoggerService.Verify(x => x.Exception(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Never()); + + Assert.Equal(HttpStatusCode.ServiceUnavailable, result); + } + + [Fact] + public void PostRegisterUserAsyncTestsAsync_Exception() + { + var exception = new HttpRequestException("unit-test"); + var mockHttpClient = new HttpClient(new MockHttpHandler((r, c) => + { + var absoluteUri = r.RequestUri.AbsoluteUri; + if (absoluteUri.EndsWith("/api/register")) + { + throw exception; + } + return new HttpResponseMessage(HttpStatusCode.NotFound); + })); + + mockHttpClientService.Setup(x => x.ApiClient).Returns(mockHttpClient); + mockServerConfigurationRepository.Setup(x => x.UserRegisterApiEndpoint) + .Returns(IServerConfigurationRepository.CombineAsUrl(AppSettings.Instance.ApiUrlBase, "api/register")); + + var unitUnderTest = CreateService(); + + + Assert.ThrowsAsync(async () => + { + await unitUnderTest.RegisterUserAsync(); + }); + + mockLoggerService.Verify(x => x.StartMethod("RegisterUserAsync", It.IsAny(), It.IsAny()), Times.Once()); + mockLoggerService.Verify(x => x.EndMethod("RegisterUserAsync", It.IsAny(), It.IsAny()), Times.Once()); + mockLoggerService.Verify(x => x.Exception(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Once()); + } + + #endregion + + } +} diff --git a/Covid19Radar/Tests/Covid19Radar.UnitTests/ViewModels/HelpPage/SendLogConfirmationPageViewModelTests.cs b/Covid19Radar/Tests/Covid19Radar.UnitTests/ViewModels/HelpPage/SendLogConfirmationPageViewModelTests.cs index c4ed0e1fe..1e185d939 100644 --- a/Covid19Radar/Tests/Covid19Radar.UnitTests/ViewModels/HelpPage/SendLogConfirmationPageViewModelTests.cs +++ b/Covid19Radar/Tests/Covid19Radar.UnitTests/ViewModels/HelpPage/SendLogConfirmationPageViewModelTests.cs @@ -3,10 +3,10 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ using System; +using System.Net; using System.Threading.Tasks; using Acr.UserDialogs; using Covid19Radar.Model; -using Covid19Radar.Services; using Covid19Radar.Services.Logs; using Covid19Radar.ViewModels; using Covid19Radar.Views; @@ -25,7 +25,6 @@ public class SendLogConfirmationPageViewModelTests private readonly Mock mockLogFileService; private readonly Mock mockLoggerService; private readonly Mock mockLogUploadService; - private readonly Mock mockHttpDataService; public SendLogConfirmationPageViewModelTests() { @@ -38,7 +37,6 @@ public SendLogConfirmationPageViewModelTests() mockLogFileService = mockRepository.Create(); mockLoggerService = mockRepository.Create(); mockLogUploadService = mockRepository.Create(); - mockHttpDataService = mockRepository.Create(); } private SendLogConfirmationPageViewModel CreateViewModel() @@ -47,8 +45,8 @@ private SendLogConfirmationPageViewModel CreateViewModel() mockNavigationService.Object, mockLoggerService.Object, mockLogFileService.Object, - mockLogUploadService.Object, - mockHttpDataService.Object) + mockLogUploadService.Object + ) { BeginInvokeOnMainThread = new Action((a) => { a.Invoke(); }), TaskRun = new Func((a) => { a.Invoke(); return Task.CompletedTask; }) @@ -124,8 +122,8 @@ public void OnClickSendLogCommandTests_Success() mockLogFileService.Invocations.Clear(); var testResponse = new ApiResponse(200, new LogStorageSas() { SasToken = "test-sas-token" }); - mockHttpDataService.Setup(x => x.GetLogStorageSas()).ReturnsAsync(testResponse); - mockLogUploadService.Setup(x => x.UploadAsync(testPublicZipFilePath, testResponse.Result.SasToken)).ReturnsAsync(true); + mockLogUploadService.Setup(x => x.GetLogStorageSas()).ReturnsAsync(testResponse); + mockLogUploadService.Setup(x => x.UploadAsync(testPublicZipFilePath, testResponse.Result.SasToken)).ReturnsAsync(HttpStatusCode.Created); unitUnderTest.OnClickSendLogCommand.Execute(null); @@ -158,8 +156,8 @@ public void OnClickSendLogCommandTests_Failure() mockLogFileService.Invocations.Clear(); var testResponse = new ApiResponse(200, new LogStorageSas() { SasToken = "test-sas-token" }); - mockHttpDataService.Setup(x => x.GetLogStorageSas()).ReturnsAsync(testResponse); - mockLogUploadService.Setup(x => x.UploadAsync(testPublicZipFilePath, testResponse.Result.SasToken)).ReturnsAsync(false); + mockLogUploadService.Setup(x => x.GetLogStorageSas()).ReturnsAsync(testResponse); + mockLogUploadService.Setup(x => x.UploadAsync(testPublicZipFilePath, testResponse.Result.SasToken)).ReturnsAsync(HttpStatusCode.Forbidden); unitUnderTest.OnClickSendLogCommand.Execute(null); @@ -194,8 +192,8 @@ public void OnClickSendLogCommandTests_DeleteLogFalure() mockLogFileService.Invocations.Clear(); var testResponse = new ApiResponse(200, new LogStorageSas() { SasToken = "test-sas-token" }); - mockHttpDataService.Setup(x => x.GetLogStorageSas()).ReturnsAsync(testResponse); - mockLogUploadService.Setup(x => x.UploadAsync(testPublicZipFilePath, testResponse.Result.SasToken)).ReturnsAsync(true); + mockLogUploadService.Setup(x => x.GetLogStorageSas()).ReturnsAsync(testResponse); + mockLogUploadService.Setup(x => x.UploadAsync(testPublicZipFilePath, testResponse.Result.SasToken)).ReturnsAsync(HttpStatusCode.Created); unitUnderTest.OnClickSendLogCommand.Execute(null);