diff --git a/src/Stats.AzureCdnLogs.Common/Collect/AzureStatsLogDestination.cs b/src/Stats.AzureCdnLogs.Common/Collect/AzureStatsLogDestination.cs index c394d3be6..0837857ad 100644 --- a/src/Stats.AzureCdnLogs.Common/Collect/AzureStatsLogDestination.cs +++ b/src/Stats.AzureCdnLogs.Common/Collect/AzureStatsLogDestination.cs @@ -24,9 +24,9 @@ public class AzureStatsLogDestination : ILogDestination private CloudBlobClient _cloudBlobClient; private CloudBlobContainer _cloudBlobContainer; - public AzureStatsLogDestination(string connectionString, string containerName) + public AzureStatsLogDestination(CloudStorageAccount storageAccount, string containerName) { - _azureAccount = CloudStorageAccount.Parse(connectionString); + _azureAccount = storageAccount; _cloudBlobClient = _azureAccount.CreateCloudBlobClient(); _cloudBlobContainer = _cloudBlobClient.GetContainerReference(containerName); _cloudBlobContainer.CreateIfNotExists(); diff --git a/src/Stats.AzureCdnLogs.Common/Collect/AzureStatsLogSource.cs b/src/Stats.AzureCdnLogs.Common/Collect/AzureStatsLogSource.cs index 51d47a0b4..6265a0082 100644 --- a/src/Stats.AzureCdnLogs.Common/Collect/AzureStatsLogSource.cs +++ b/src/Stats.AzureCdnLogs.Common/Collect/AzureStatsLogSource.cs @@ -33,9 +33,9 @@ public class AzureStatsLogSource : ILogSource /// /// The connection string for the Azure account. /// The container name. - public AzureStatsLogSource(string connectionString, string containerName, int azureServerTimeoutInSeconds) + public AzureStatsLogSource(CloudStorageAccount storageAccount, string containerName, int azureServerTimeoutInSeconds) { - _azureAccount = CloudStorageAccount.Parse(connectionString); + _azureAccount = storageAccount; _blobClient = _azureAccount.CreateCloudBlobClient(); _container = _blobClient.GetContainerReference(containerName); _blobRequestOptions = new BlobRequestOptions(); diff --git a/src/Stats.CollectAzureCdnLogs/Configuration/CollectAzureCdnLogsConfiguration.cs b/src/Stats.CollectAzureCdnLogs/Configuration/CollectAzureCdnLogsConfiguration.cs new file mode 100644 index 000000000..53507bc69 --- /dev/null +++ b/src/Stats.CollectAzureCdnLogs/Configuration/CollectAzureCdnLogsConfiguration.cs @@ -0,0 +1,22 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace Stats.CollectAzureCdnLogs +{ + public class CollectAzureCdnLogsConfiguration + { + public string AzureCdnAccountNumber { get; set; } + + public string AzureCdnCloudStorageAccount { get; set; } + + public string AzureCdnCloudStorageContainerName { get; set; } + + public string AzureCdnPlatform { get; set; } + + public string FtpSourceUri { get; set; } + + public string FtpSourceUsername { get; set; } + + public string FtpSourcePassword { get; set; } + } +} diff --git a/src/Stats.CollectAzureCdnLogs/Job.cs b/src/Stats.CollectAzureCdnLogs/Job.cs index 9b8351b2a..14d69ee93 100644 --- a/src/Stats.CollectAzureCdnLogs/Job.cs +++ b/src/Stats.CollectAzureCdnLogs/Job.cs @@ -9,9 +9,13 @@ using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; +using Autofac; using ICSharpCode.SharpZipLib; using ICSharpCode.SharpZipLib.GZip; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using Microsoft.WindowsAzure.Storage; using NuGet.Jobs; using Stats.AzureCdnLogs.Common; @@ -20,31 +24,50 @@ namespace Stats.CollectAzureCdnLogs { - public class Job - : JobBase + public class Job : JsonConfigurationJob { private static readonly DateTime _unixTimestamp = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc); private Uri _ftpServerUri; - private string _ftpUsername; - private string _ftpPassword; - private string _azureCdnAccountNumber; private AzureCdnPlatform _azureCdnPlatform; private CloudStorageAccount _cloudStorageAccount; - private string _cloudStorageContainerName; + + private CollectAzureCdnLogsConfiguration _configuration; public override void Init(IServiceContainer serviceContainer, IDictionary jobArgsDictionary) { - var ftpLogFolder = JobConfigurationManager.GetArgument(jobArgsDictionary, JobArgumentNames.FtpSourceUri); - var azureCdnPlatform = JobConfigurationManager.GetArgument(jobArgsDictionary, JobArgumentNames.AzureCdnPlatform); - var cloudStorageAccount = JobConfigurationManager.GetArgument(jobArgsDictionary, JobArgumentNames.AzureCdnCloudStorageAccount); - _cloudStorageContainerName = JobConfigurationManager.GetArgument(jobArgsDictionary, JobArgumentNames.AzureCdnCloudStorageContainerName); - _azureCdnAccountNumber = JobConfigurationManager.GetArgument(jobArgsDictionary, JobArgumentNames.AzureCdnAccountNumber); - _ftpUsername = JobConfigurationManager.GetArgument(jobArgsDictionary, JobArgumentNames.FtpSourceUsername); - _ftpPassword = JobConfigurationManager.GetArgument(jobArgsDictionary, JobArgumentNames.FtpSourcePassword); - - _ftpServerUri = ValidateFtpUri(ftpLogFolder); - _azureCdnPlatform = ValidateAzureCdnPlatform(azureCdnPlatform); - _cloudStorageAccount = ValidateAzureCloudStorageAccount(cloudStorageAccount); + base.Init(serviceContainer, jobArgsDictionary); + + InitializeJobConfiguration(_serviceProvider); + } + + public void InitializeJobConfiguration(IServiceProvider serviceProvider) + { + _configuration = serviceProvider.GetRequiredService>().Value; + + if (string.IsNullOrEmpty(_configuration.AzureCdnAccountNumber)) + { + throw new ArgumentException("Configuration 'AzureCdnAccountNumber' is required", nameof(_configuration)); + } + + if (string.IsNullOrEmpty(_configuration.AzureCdnCloudStorageContainerName)) + { + throw new ArgumentException("Configuration 'AzureCdnCloudStorageContainerName' is required", nameof(_configuration)); + } + + if (string.IsNullOrEmpty(_configuration.FtpSourceUsername)) { + throw new ArgumentException("Configuration 'FtpSourceUsername' is required", nameof(_configuration)); + } + + if (string.IsNullOrEmpty(_configuration.FtpSourcePassword)) + { + throw new ArgumentException("Configuration 'FtpSourcePassword' is required", nameof(_configuration)); + } + + _cloudStorageAccount = ValidateAzureCloudStorageAccount(_configuration.AzureCdnCloudStorageAccount); + + _azureCdnPlatform = ValidateAzureCdnPlatform(_configuration.AzureCdnPlatform); + + _ftpServerUri = ValidateFtpUri(_configuration.FtpSourceUri); } private static CloudStorageAccount ValidateAzureCloudStorageAccount(string cloudStorageAccount) @@ -110,14 +133,14 @@ private static Uri ValidateFtpUri(string serverUrl) public override async Task Run() { - var ftpClient = new FtpRawLogClient(LoggerFactory, _ftpUsername, _ftpPassword); + var ftpClient = new FtpRawLogClient(LoggerFactory, _configuration.FtpSourceUsername, _configuration.FtpSourcePassword); var azureClient = new CloudBlobRawLogClient(LoggerFactory, _cloudStorageAccount); // Collect directory listing. var rawLogFileUris = await ftpClient.GetRawLogFileUris(_ftpServerUri); // Prepare cloud storage blob container. - var cloudBlobContainer = await azureClient.CreateContainerIfNotExistsAsync(_cloudStorageContainerName); + var cloudBlobContainer = await azureClient.CreateContainerIfNotExistsAsync(_configuration.AzureCdnCloudStorageContainerName); foreach (var rawLogFileUri in rawLogFileUris) { @@ -126,7 +149,7 @@ public override async Task Run() var rawLogFile = new RawLogFileInfo(rawLogFileUri); if (_azureCdnPlatform != rawLogFile.AzureCdnPlatform - || !_azureCdnAccountNumber.Equals(rawLogFile.AzureCdnAccountNumber, StringComparison.InvariantCultureIgnoreCase)) + || !_configuration.AzureCdnAccountNumber.Equals(rawLogFile.AzureCdnAccountNumber, StringComparison.InvariantCultureIgnoreCase)) { // Only process the raw log files matching the target CDN platform and account number. continue; @@ -367,5 +390,14 @@ private static string ToUnixTimeStamp(DateTime dateTime) var secondsPastEpoch = (dateTime - _unixTimestamp).TotalSeconds; return secondsPastEpoch.ToString(CultureInfo.InvariantCulture); } + + protected override void ConfigureAutofacServices(ContainerBuilder containerBuilder) + { + } + + protected override void ConfigureJobServices(IServiceCollection services, IConfigurationRoot configurationRoot) + { + ConfigureInitializationSection(services, configurationRoot); + } } } diff --git a/src/Stats.CollectAzureCdnLogs/Scripts/Stats.CollectAzureCdnLogs.cmd b/src/Stats.CollectAzureCdnLogs/Scripts/Stats.CollectAzureCdnLogs.cmd index 39943a693..bda6afb0a 100644 --- a/src/Stats.CollectAzureCdnLogs/Scripts/Stats.CollectAzureCdnLogs.cmd +++ b/src/Stats.CollectAzureCdnLogs/Scripts/Stats.CollectAzureCdnLogs.cmd @@ -3,12 +3,16 @@ cd bin :Top - echo "Starting job - #{Jobs.stats.collectazurecdnlogs.Title}" +echo "Starting job - #{Jobs.stats.collectazurecdnlogs.Title}" - title #{Jobs.stats.collectazurecdnlogs.Title} +title #{Jobs.stats.collectazurecdnlogs.Title} - start /w stats.collectazurecdnlogs.exe -VaultName "#{Deployment.Azure.KeyVault.VaultName}" -ClientId "#{Deployment.Azure.KeyVault.ClientId}" -CertificateThumbprint "#{Deployment.Azure.KeyVault.CertificateThumbprint}" -FtpSourceUri "#{Jobs.stats.collectazurecdnlogs.FtpSource.Uri}" -FtpSourceUsername "#{Jobs.stats.collectazurecdnlogs.FtpSource.Username}" -FtpSourcePassword "#{Jobs.stats.collectazurecdnlogs.FtpSource.Password}" -AzureCdnAccountNumber "#{Jobs.stats.collectazurecdnlogs.AzureCdn.AccountNumber}" -AzureCdnPlatform "#{Jobs.stats.collectazurecdnlogs.AzureCdn.Platform}" -AzureCdnCloudStorageAccount "#{Jobs.stats.collectazurecdnlogs.AzureCdn.CloudStorageAccount}" -AzureCdnCloudStorageContainerName "#{Jobs.stats.collectazurecdnlogs.AzureCdn.CloudStorageContainerName}" -InstrumentationKey "#{Jobs.stats.collectazurecdnlogs.InstrumentationKey}" -verbose true -Interval #{Jobs.stats.collectazurecdnlogs.Interval} +start /w stats.collectazurecdnlogs.exe ^ +-Configuration "#{Jobs.stats.collectazurecdnlogs.Configuration}" ^ +-InstrumentationKey "#{Jobs.stats.collectazurecdnlogs.InstrumentationKey}" ^ +-verbose true ^ +-Interval #{Jobs.stats.collectazurecdnlogs.Interval} - echo "Finished #{Jobs.stats.collectazurecdnlogs.Title}" +echo "Finished #{Jobs.stats.collectazurecdnlogs.Title}" - goto Top \ No newline at end of file +goto Top \ No newline at end of file diff --git a/src/Stats.CollectAzureCdnLogs/Settings/dev.json b/src/Stats.CollectAzureCdnLogs/Settings/dev.json new file mode 100644 index 000000000..dba31e592 --- /dev/null +++ b/src/Stats.CollectAzureCdnLogs/Settings/dev.json @@ -0,0 +1,18 @@ +{ + "Initialization": { + "FtpSourceUri": "#{Jobs.stats.collectazurecdnlogs.FtpSource.Uri}", + "FtpSourceUsername": "#{Jobs.stats.collectazurecdnlogs.FtpSource.Username}", + "FtpSourcePassword": "#{Jobs.stats.collectazurecdnlogs.FtpSource.Password}", + "AzureCdnAccountNumber": "#{Jobs.stats.collectazurecdnlogs.AzureCdn.AccountNumber}", + "AzureCdnPlatform": "#{Jobs.stats.collectazurecdnlogs.AzureCdn.Platform}", + "AzureCdnCloudStorageAccount": "#{Jobs.stats.collectazurecdnlogs.AzureCdn.CloudStorageAccount}", + "AzureCdnCloudStorageContainerName": "#{Jobs.stats.collectazurecdnlogs.AzureCdn.CloudStorageContainerName}" + }, + + "KeyVault_VaultName": "#{Deployment.Azure.KeyVault.VaultName}", + "KeyVault_ClientId": "#{Deployment.Azure.KeyVault.ClientId}", + "KeyVault_CertificateThumbprint": "#{Deployment.Azure.KeyVault.CertificateThumbprint}", + "KeyVault_ValidateCertificate": true, + "KeyVault_StoreName": "My", + "KeyVault_StoreLocation": "LocalMachine" +} \ No newline at end of file diff --git a/src/Stats.CollectAzureCdnLogs/Settings/int.json b/src/Stats.CollectAzureCdnLogs/Settings/int.json new file mode 100644 index 000000000..dba31e592 --- /dev/null +++ b/src/Stats.CollectAzureCdnLogs/Settings/int.json @@ -0,0 +1,18 @@ +{ + "Initialization": { + "FtpSourceUri": "#{Jobs.stats.collectazurecdnlogs.FtpSource.Uri}", + "FtpSourceUsername": "#{Jobs.stats.collectazurecdnlogs.FtpSource.Username}", + "FtpSourcePassword": "#{Jobs.stats.collectazurecdnlogs.FtpSource.Password}", + "AzureCdnAccountNumber": "#{Jobs.stats.collectazurecdnlogs.AzureCdn.AccountNumber}", + "AzureCdnPlatform": "#{Jobs.stats.collectazurecdnlogs.AzureCdn.Platform}", + "AzureCdnCloudStorageAccount": "#{Jobs.stats.collectazurecdnlogs.AzureCdn.CloudStorageAccount}", + "AzureCdnCloudStorageContainerName": "#{Jobs.stats.collectazurecdnlogs.AzureCdn.CloudStorageContainerName}" + }, + + "KeyVault_VaultName": "#{Deployment.Azure.KeyVault.VaultName}", + "KeyVault_ClientId": "#{Deployment.Azure.KeyVault.ClientId}", + "KeyVault_CertificateThumbprint": "#{Deployment.Azure.KeyVault.CertificateThumbprint}", + "KeyVault_ValidateCertificate": true, + "KeyVault_StoreName": "My", + "KeyVault_StoreLocation": "LocalMachine" +} \ No newline at end of file diff --git a/src/Stats.CollectAzureCdnLogs/Settings/prod.json b/src/Stats.CollectAzureCdnLogs/Settings/prod.json new file mode 100644 index 000000000..dba31e592 --- /dev/null +++ b/src/Stats.CollectAzureCdnLogs/Settings/prod.json @@ -0,0 +1,18 @@ +{ + "Initialization": { + "FtpSourceUri": "#{Jobs.stats.collectazurecdnlogs.FtpSource.Uri}", + "FtpSourceUsername": "#{Jobs.stats.collectazurecdnlogs.FtpSource.Username}", + "FtpSourcePassword": "#{Jobs.stats.collectazurecdnlogs.FtpSource.Password}", + "AzureCdnAccountNumber": "#{Jobs.stats.collectazurecdnlogs.AzureCdn.AccountNumber}", + "AzureCdnPlatform": "#{Jobs.stats.collectazurecdnlogs.AzureCdn.Platform}", + "AzureCdnCloudStorageAccount": "#{Jobs.stats.collectazurecdnlogs.AzureCdn.CloudStorageAccount}", + "AzureCdnCloudStorageContainerName": "#{Jobs.stats.collectazurecdnlogs.AzureCdn.CloudStorageContainerName}" + }, + + "KeyVault_VaultName": "#{Deployment.Azure.KeyVault.VaultName}", + "KeyVault_ClientId": "#{Deployment.Azure.KeyVault.ClientId}", + "KeyVault_CertificateThumbprint": "#{Deployment.Azure.KeyVault.CertificateThumbprint}", + "KeyVault_ValidateCertificate": true, + "KeyVault_StoreName": "My", + "KeyVault_StoreLocation": "LocalMachine" +} \ No newline at end of file diff --git a/src/Stats.CollectAzureCdnLogs/Stats.CollectAzureCdnLogs.csproj b/src/Stats.CollectAzureCdnLogs/Stats.CollectAzureCdnLogs.csproj index 9af044a00..c96e6974b 100644 --- a/src/Stats.CollectAzureCdnLogs/Stats.CollectAzureCdnLogs.csproj +++ b/src/Stats.CollectAzureCdnLogs/Stats.CollectAzureCdnLogs.csproj @@ -49,6 +49,7 @@ + @@ -70,6 +71,9 @@ Designer + + + @@ -110,6 +114,7 @@ 7.1.2 + ..\..\build diff --git a/src/Stats.CollectAzureCdnLogs/Stats.CollectAzureCdnLogs.nuspec b/src/Stats.CollectAzureCdnLogs/Stats.CollectAzureCdnLogs.nuspec index 412a098df..6b97144bf 100644 --- a/src/Stats.CollectAzureCdnLogs/Stats.CollectAzureCdnLogs.nuspec +++ b/src/Stats.CollectAzureCdnLogs/Stats.CollectAzureCdnLogs.nuspec @@ -18,5 +18,7 @@ + + \ No newline at end of file diff --git a/src/Stats.CollectAzureChinaCDNLogs/ArgumentNames.cs b/src/Stats.CollectAzureChinaCDNLogs/ArgumentNames.cs deleted file mode 100644 index 1384c7a1d..000000000 --- a/src/Stats.CollectAzureChinaCDNLogs/ArgumentNames.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -namespace Stats.CollectAzureChinaCDNLogs -{ - public class ArgumentNames - { - internal const string AzureAccountConnectionStringSource = "AzureAccountConnectionStringSource"; - internal const string AzureAccountConnectionStringDestination = "AzureAccountConnectionStringDestination"; - internal const string AzureContainerNameDestination = "AzureContainerNameDestination"; - internal const string AzureContainerNameSource = "AzureContainerNameSource"; - internal const string DestinationFilePrefix = "DestinationFilePrefix"; - //a timeout in seconds for an execution loop - internal const string ExecutionTimeoutInSeconds = "ExecutionTimeoutInSeconds"; - } -} diff --git a/src/Stats.CollectAzureChinaCDNLogs/Configuration/CollectAzureChinaCdnLogsConfiguration.cs b/src/Stats.CollectAzureChinaCDNLogs/Configuration/CollectAzureChinaCdnLogsConfiguration.cs new file mode 100644 index 000000000..267464209 --- /dev/null +++ b/src/Stats.CollectAzureChinaCDNLogs/Configuration/CollectAzureChinaCdnLogsConfiguration.cs @@ -0,0 +1,20 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace Stats.CollectAzureChinaCDNLogs +{ + public class CollectAzureChinaCdnLogsConfiguration + { + public string AzureAccountConnectionStringSource { get; set; } + + public string AzureAccountConnectionStringDestination { get; set; } + + public string AzureContainerNameSource { get; set; } + + public string AzureContainerNameDestination { get; set; } + + public string DestinationFilePrefix { get; set; } + + public int? ExecutionTimeoutInSeconds { get; set; } + } +} diff --git a/src/Stats.CollectAzureChinaCDNLogs/Job.cs b/src/Stats.CollectAzureChinaCDNLogs/Job.cs index dc91f8acc..aafda542f 100644 --- a/src/Stats.CollectAzureChinaCDNLogs/Job.cs +++ b/src/Stats.CollectAzureChinaCDNLogs/Job.cs @@ -6,39 +6,47 @@ using System.ComponentModel.Design; using System.Threading; using System.Threading.Tasks; +using Autofac; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using Microsoft.WindowsAzure.Storage; using NuGet.Jobs; using Stats.AzureCdnLogs.Common.Collect; namespace Stats.CollectAzureChinaCDNLogs { - public class Job : JobBase + public class Job : JsonConfigurationJob { private const int DefaultExecutionTimeoutInSeconds = 14400; // 4 hours private const int MaxFilesToProcess = 4; - - private CloudStorageAccount _cloudStorageAccountSource; - private CloudStorageAccount _cloudStorageAccountDestination; - private string _cloudStorageContainerNameDestination; - private string _cloudStorageContainerNameSource; - private Collector _chinaCollector; + + private CollectAzureChinaCdnLogsConfiguration _configuration; private int _executionTimeoutInSeconds; - private string _destinationFilePrefix; + private Collector _chinaCollector; public override void Init(IServiceContainer serviceContainer, IDictionary jobArgsDictionary) { - var cloudStorageAccountConnStringSource = JobConfigurationManager.GetArgument(jobArgsDictionary, ArgumentNames.AzureAccountConnectionStringSource); - var cloudStorageAccountConnStringDest = JobConfigurationManager.GetArgument(jobArgsDictionary, ArgumentNames.AzureAccountConnectionStringDestination); - _cloudStorageAccountSource = ValidateAzureCloudStorageAccount(cloudStorageAccountConnStringSource); - _cloudStorageAccountDestination = ValidateAzureCloudStorageAccount(cloudStorageAccountConnStringDest); - _cloudStorageContainerNameDestination = JobConfigurationManager.GetArgument(jobArgsDictionary, ArgumentNames.AzureContainerNameDestination); - _cloudStorageContainerNameSource = JobConfigurationManager.GetArgument(jobArgsDictionary, ArgumentNames.AzureContainerNameSource); - _destinationFilePrefix = JobConfigurationManager.GetArgument(jobArgsDictionary, ArgumentNames.DestinationFilePrefix); - _executionTimeoutInSeconds = JobConfigurationManager.TryGetIntArgument(jobArgsDictionary, ArgumentNames.ExecutionTimeoutInSeconds) ?? DefaultExecutionTimeoutInSeconds; + base.Init(serviceContainer, jobArgsDictionary); + + InitializeJobConfiguration(_serviceProvider); + } + + public void InitializeJobConfiguration(IServiceProvider serviceProvider) + { + _configuration = serviceProvider.GetRequiredService>().Value; + _executionTimeoutInSeconds = _configuration.ExecutionTimeoutInSeconds ?? DefaultExecutionTimeoutInSeconds; + + var source = new AzureStatsLogSource( + ValidateAzureCloudStorageAccount(_configuration.AzureAccountConnectionStringSource), + _configuration.AzureContainerNameSource, + _executionTimeoutInSeconds / MaxFilesToProcess); + + var dest = new AzureStatsLogDestination( + ValidateAzureCloudStorageAccount(_configuration.AzureAccountConnectionStringDestination), + _configuration.AzureContainerNameDestination); - var source = new AzureStatsLogSource(cloudStorageAccountConnStringSource, _cloudStorageContainerNameSource, _executionTimeoutInSeconds/MaxFilesToProcess); - var dest = new AzureStatsLogDestination(cloudStorageAccountConnStringDest,_cloudStorageContainerNameDestination); _chinaCollector = new ChinaStatsCollector(source, dest); } @@ -47,7 +55,7 @@ public override async Task Run() CancellationTokenSource cts = new CancellationTokenSource(); cts.CancelAfter(_executionTimeoutInSeconds*1000); var aggregateExceptions = await _chinaCollector.TryProcessAsync(maxFileCount: MaxFilesToProcess, - fileNameTransform: s => $"{_destinationFilePrefix}_{s}", + fileNameTransform: s => $"{_configuration.DestinationFilePrefix}_{s}", sourceContentType: ContentType.GZip, destinationContentType: ContentType.GZip, token: cts.Token); @@ -80,5 +88,14 @@ private static CloudStorageAccount ValidateAzureCloudStorageAccount(string cloud } throw new ArgumentException("Job parameter for Azure CDN Cloud Storage Account is invalid."); } + + protected override void ConfigureAutofacServices(ContainerBuilder containerBuilder) + { + } + + protected override void ConfigureJobServices(IServiceCollection services, IConfigurationRoot configurationRoot) + { + ConfigureInitializationSection(services, configurationRoot); + } } } diff --git a/src/Stats.CollectAzureChinaCDNLogs/Scripts/Stats.CollectAzureChinaCDNLogs.cmd b/src/Stats.CollectAzureChinaCDNLogs/Scripts/Stats.CollectAzureChinaCDNLogs.cmd index 3ddf24d91..dc61f6cd4 100644 --- a/src/Stats.CollectAzureChinaCDNLogs/Scripts/Stats.CollectAzureChinaCDNLogs.cmd +++ b/src/Stats.CollectAzureChinaCDNLogs/Scripts/Stats.CollectAzureChinaCDNLogs.cmd @@ -3,24 +3,15 @@ cd bin :Top - echo "Starting job - #{Jobs.Stats.CollectAzureChinaCDNLogs.Title}" +echo "Starting job - #{Jobs.Stats.CollectAzureChinaCDNLogs.Title}" - title #{Jobs.Stats.CollectAzureChinaCDNLogs.Title} +title #{Jobs.Stats.CollectAzureChinaCDNLogs.Title} - start /w Stats.CollectAzureChinaCDNLogs.exe ^ - -VaultName "#{Deployment.Azure.KeyVault.VaultName}" ^ - -ClientId "#{Deployment.Azure.KeyVault.ClientId}" ^ - -CertificateThumbprint "#{Deployment.Azure.KeyVault.CertificateThumbprint}" ^ - -AzureAccountConnectionStringSource "#{Jobs.Stats.CollectAzureChinaCDNLogs.AzureAccountConnectionStringSource}" ^ - -AzureAccountConnectionStringDestination "#{Jobs.Stats.CollectAzureChinaCDNLogs.AzureAccountConnectionStringDestination}" ^ - -AzureContainerNameSource "#{Jobs.Stats.CollectAzureChinaCDNLogs.AzureContainerNameSource}" ^ - -AzureContainerNameDestination "#{Jobs.Stats.CollectAzureChinaCDNLogs.AzureContainerNameDestination}" ^ - -DestinationFilePrefix "#{Jobs.Stats.CollectAzureChinaCDNLogs.DestinationFilePrefix}" ^ - -ExecutionTimeoutInSeconds "#{Jobs.Stats.CollectAzureChinaCDNLogs.ExecutionTimeoutInSeconds}" ^ - -InstrumentationKey "#{Jobs.Stats.CollectAzureChinaCDNLogs.InstrumentationKey}" ^ - -verbose true ^ - -Interval #{Jobs.Stats.CollectAzureChinaCDNLogs.Interval} +start /w Stats.CollectAzureChinaCDNLogs.exe ^ +-InstrumentationKey "#{Jobs.Stats.CollectAzureChinaCDNLogs.InstrumentationKey}" ^ +-verbose true ^ +-Interval #{Jobs.Stats.CollectAzureChinaCDNLogs.Interval} - echo "Finished #{Jobs.Stats.CollectAzureChinaCDNLogs.Title}" +echo "Finished #{Jobs.Stats.CollectAzureChinaCDNLogs.Title}" - goto Top \ No newline at end of file +goto Top \ No newline at end of file diff --git a/src/Stats.CollectAzureChinaCDNLogs/Settings/dev.json b/src/Stats.CollectAzureChinaCDNLogs/Settings/dev.json new file mode 100644 index 000000000..f143fedd7 --- /dev/null +++ b/src/Stats.CollectAzureChinaCDNLogs/Settings/dev.json @@ -0,0 +1,17 @@ +{ + "Initialization": { + "AzureAccountConnectionStringSource": "#{Jobs.Stats.CollectAzureChinaCDNLogs.AzureAccountConnectionStringSource}", + "AzureAccountConnectionStringDestination": "#{Jobs.Stats.CollectAzureChinaCDNLogs.AzureAccountConnectionStringDestination}", + "AzureContainerNameSource": "#{Jobs.Stats.CollectAzureChinaCDNLogs.AzureContainerNameSource}", + "AzureContainerNameDestination": "#{Jobs.Stats.CollectAzureChinaCDNLogs.AzureContainerNameDestination}", + "DestinationFilePrefix": "#{Jobs.Stats.CollectAzureChinaCDNLogs.DestinationFilePrefix}", + "ExecutionTimeoutInSeconds": "#{Jobs.Stats.CollectAzureChinaCDNLogs.ExecutionTimeoutInSeconds}" + }, + + "KeyVault_VaultName": "#{Deployment.Azure.KeyVault.VaultName}", + "KeyVault_ClientId": "#{Deployment.Azure.KeyVault.ClientId}", + "KeyVault_CertificateThumbprint": "#{Deployment.Azure.KeyVault.CertificateThumbprint}", + "KeyVault_ValidateCertificate": true, + "KeyVault_StoreName": "My", + "KeyVault_StoreLocation": "LocalMachine" +} \ No newline at end of file diff --git a/src/Stats.CollectAzureChinaCDNLogs/Settings/int.json b/src/Stats.CollectAzureChinaCDNLogs/Settings/int.json new file mode 100644 index 000000000..f143fedd7 --- /dev/null +++ b/src/Stats.CollectAzureChinaCDNLogs/Settings/int.json @@ -0,0 +1,17 @@ +{ + "Initialization": { + "AzureAccountConnectionStringSource": "#{Jobs.Stats.CollectAzureChinaCDNLogs.AzureAccountConnectionStringSource}", + "AzureAccountConnectionStringDestination": "#{Jobs.Stats.CollectAzureChinaCDNLogs.AzureAccountConnectionStringDestination}", + "AzureContainerNameSource": "#{Jobs.Stats.CollectAzureChinaCDNLogs.AzureContainerNameSource}", + "AzureContainerNameDestination": "#{Jobs.Stats.CollectAzureChinaCDNLogs.AzureContainerNameDestination}", + "DestinationFilePrefix": "#{Jobs.Stats.CollectAzureChinaCDNLogs.DestinationFilePrefix}", + "ExecutionTimeoutInSeconds": "#{Jobs.Stats.CollectAzureChinaCDNLogs.ExecutionTimeoutInSeconds}" + }, + + "KeyVault_VaultName": "#{Deployment.Azure.KeyVault.VaultName}", + "KeyVault_ClientId": "#{Deployment.Azure.KeyVault.ClientId}", + "KeyVault_CertificateThumbprint": "#{Deployment.Azure.KeyVault.CertificateThumbprint}", + "KeyVault_ValidateCertificate": true, + "KeyVault_StoreName": "My", + "KeyVault_StoreLocation": "LocalMachine" +} \ No newline at end of file diff --git a/src/Stats.CollectAzureChinaCDNLogs/Settings/prod.json b/src/Stats.CollectAzureChinaCDNLogs/Settings/prod.json new file mode 100644 index 000000000..f143fedd7 --- /dev/null +++ b/src/Stats.CollectAzureChinaCDNLogs/Settings/prod.json @@ -0,0 +1,17 @@ +{ + "Initialization": { + "AzureAccountConnectionStringSource": "#{Jobs.Stats.CollectAzureChinaCDNLogs.AzureAccountConnectionStringSource}", + "AzureAccountConnectionStringDestination": "#{Jobs.Stats.CollectAzureChinaCDNLogs.AzureAccountConnectionStringDestination}", + "AzureContainerNameSource": "#{Jobs.Stats.CollectAzureChinaCDNLogs.AzureContainerNameSource}", + "AzureContainerNameDestination": "#{Jobs.Stats.CollectAzureChinaCDNLogs.AzureContainerNameDestination}", + "DestinationFilePrefix": "#{Jobs.Stats.CollectAzureChinaCDNLogs.DestinationFilePrefix}", + "ExecutionTimeoutInSeconds": "#{Jobs.Stats.CollectAzureChinaCDNLogs.ExecutionTimeoutInSeconds}" + }, + + "KeyVault_VaultName": "#{Deployment.Azure.KeyVault.VaultName}", + "KeyVault_ClientId": "#{Deployment.Azure.KeyVault.ClientId}", + "KeyVault_CertificateThumbprint": "#{Deployment.Azure.KeyVault.CertificateThumbprint}", + "KeyVault_ValidateCertificate": true, + "KeyVault_StoreName": "My", + "KeyVault_StoreLocation": "LocalMachine" +} \ No newline at end of file diff --git a/src/Stats.CollectAzureChinaCDNLogs/Stats.CollectAzureChinaCDNLogs.csproj b/src/Stats.CollectAzureChinaCDNLogs/Stats.CollectAzureChinaCDNLogs.csproj index c509d4c1d..c2e867581 100644 --- a/src/Stats.CollectAzureChinaCDNLogs/Stats.CollectAzureChinaCDNLogs.csproj +++ b/src/Stats.CollectAzureChinaCDNLogs/Stats.CollectAzureChinaCDNLogs.csproj @@ -42,8 +42,8 @@ - + @@ -55,6 +55,10 @@ + + + + diff --git a/src/Stats.CollectAzureChinaCDNLogs/Stats.CollectAzureChinaCDNLogs.nuspec b/src/Stats.CollectAzureChinaCDNLogs/Stats.CollectAzureChinaCDNLogs.nuspec index 99b00aeda..a483014e2 100644 --- a/src/Stats.CollectAzureChinaCDNLogs/Stats.CollectAzureChinaCDNLogs.nuspec +++ b/src/Stats.CollectAzureChinaCDNLogs/Stats.CollectAzureChinaCDNLogs.nuspec @@ -16,5 +16,7 @@ + + \ No newline at end of file diff --git a/tests/Tests.Stats.CollectAzureCdnLogs/JobTests.cs b/tests/Tests.Stats.CollectAzureCdnLogs/JobTests.cs index de30880a0..25692967c 100644 --- a/tests/Tests.Stats.CollectAzureCdnLogs/JobTests.cs +++ b/tests/Tests.Stats.CollectAzureCdnLogs/JobTests.cs @@ -4,6 +4,8 @@ using System; using System.Collections.Generic; using System.ComponentModel.Design; +using Microsoft.Extensions.Options; +using Moq; using Stats.CollectAzureCdnLogs; using Xunit; @@ -30,115 +32,95 @@ public void InitFailsWhenEmptyArguments() } [Fact] - public void InitSucceedsWhenValidArguments() + public void InitSucceedsWhenValidConfiguration() { - var jobArgsDictionary = CreateValidJobArgsDictionary(); - var job = new Job(); - job.Init(ServiceContainer, jobArgsDictionary); - } - - [Theory] - [InlineData("")] - [InlineData(null)] - [InlineData("http://localhost")] - [InlineData("ftps://someserver/folder")] - [InlineData("ftp://")] - public void InitFailsForInvalidFtpServerUri(string serverUri) - { - var jobArgsDictionary = CreateValidJobArgsDictionary(); - jobArgsDictionary["FtpSourceUri"] = serverUri; - - var job = new Job(); - Assert.ThrowsAny(() => job.Init(ServiceContainer, jobArgsDictionary)); - } + var configuration = GetDefaultConfiguration(); - [Theory] - [InlineData("")] - [InlineData(null)] - public void InitFailsForMissingFtpUsername(string username) - { - var jobArgsDictionary = CreateValidJobArgsDictionary(); - jobArgsDictionary["FtpSourceUsername"] = username; - - var job = new Job(); - Assert.ThrowsAny(() => job.Init(ServiceContainer, jobArgsDictionary)); + job.InitializeJobConfiguration(GetMockServiceProvider(configuration)); } [Theory] - [InlineData("")] - [InlineData(null)] - public void InitFailsForMissingFtpPassword(string password) + // null values + [InlineData("AzureCdnAccountNumber", null, typeof(ArgumentException))] + [InlineData("AzureCdnCloudStorageAccount", null, typeof(ArgumentException))] + [InlineData("AzureCdnCloudStorageContainerName", null, typeof(ArgumentException))] + [InlineData("AzureCdnPlatform", null, typeof(ArgumentException))] + [InlineData("FtpSourceUri", null, typeof(ArgumentException))] + [InlineData("FtpSourceUsername", null, typeof(ArgumentException))] + [InlineData("FtpSourcePassword", null, typeof(ArgumentException))] + // empty values + [InlineData("AzureCdnAccountNumber", "", typeof(ArgumentException))] + [InlineData("AzureCdnCloudStorageAccount", "", typeof(ArgumentException))] + [InlineData("AzureCdnCloudStorageContainerName", "", typeof(ArgumentException))] + [InlineData("AzureCdnPlatform", "", typeof(ArgumentException))] + [InlineData("FtpSourceUri", "", typeof(ArgumentException))] + [InlineData("FtpSourceUsername", "", typeof(ArgumentException))] + [InlineData("FtpSourcePassword", "", typeof(ArgumentException))] + // invalid values + [InlineData("FtpSourceUri", "http://localhost", typeof(UriFormatException))] + [InlineData("FtpSourceUri", "ftps://someserver/folder", typeof(UriFormatException))] + [InlineData("FtpSourceUri", "ftp://", typeof(UriFormatException))] + [InlineData("AzureCdnPlatform", "bla", typeof(ArgumentException))] + [InlineData("AzureCdnCloudStorageAccount", "bla", typeof(ArgumentException))] + public void InitFailsWhenInvalidConfiguration(string property, object value, Type exceptionType) { - var jobArgsDictionary = CreateValidJobArgsDictionary(); - jobArgsDictionary["FtpSourcePassword"] = password; - var job = new Job(); - Assert.ThrowsAny(() => job.Init(ServiceContainer, jobArgsDictionary)); - } - - [Theory] - [InlineData("")] - [InlineData(null)] - [InlineData("bla")] - public void InitFailsForMissingOrInvalidAzureCdnPlatform(string platform) - { - var jobArgsDictionary = CreateValidJobArgsDictionary(); - jobArgsDictionary["AzureCdnPlatform"] = platform; + var configuration = GetModifiedConfiguration(property, value); - var job = new Job(); - Assert.ThrowsAny(() => job.Init(ServiceContainer, jobArgsDictionary)); + Assert.Throws(exceptionType, () => job.InitializeJobConfiguration(GetMockServiceProvider(configuration))); } - [Theory] - [InlineData("")] - [InlineData(null)] - public void InitFailsForMissingAzureCdnAccountNumber(string accountNumber) + private static CollectAzureCdnLogsConfiguration GetModifiedConfiguration(string property, object value) { - var jobArgsDictionary = CreateValidJobArgsDictionary(); - jobArgsDictionary["AzureCdnAccountNumber"] = accountNumber; - - var job = new Job(); - Assert.ThrowsAny(() => job.Init(ServiceContainer, jobArgsDictionary)); - } + var configuration = GetDefaultConfiguration(); - [Theory] - [InlineData("")] - [InlineData(null)] - [InlineData("bla")] - public void InitFailsForMissingOrInvalidAzureCdnCloudStorageAccount(string cloudStorageAccount) - { - var jobArgsDictionary = CreateValidJobArgsDictionary(); - jobArgsDictionary["AzureCdnCloudStorageAccount"] = cloudStorageAccount; + typeof(CollectAzureCdnLogsConfiguration) + .GetProperty(property) + .SetValue(configuration, value); - var job = new Job(); - Assert.ThrowsAny(() => job.Init(ServiceContainer, jobArgsDictionary)); + return configuration; } - [Theory] - [InlineData("")] - [InlineData(null)] - public void InitFailsForMissingAzureCdnCloudStorageContainerName(string containerName) + private static CollectAzureCdnLogsConfiguration GetDefaultConfiguration() { - var jobArgsDictionary = CreateValidJobArgsDictionary(); - jobArgsDictionary["AzureCdnCloudStorageContainerName"] = containerName; - - var job = new Job(); - Assert.ThrowsAny(() => job.Init(ServiceContainer, jobArgsDictionary)); + return new CollectAzureCdnLogsConfiguration + { + AzureCdnAccountNumber = "AA00", + AzureCdnCloudStorageAccount = "UseDevelopmentStorage=true;", + AzureCdnCloudStorageContainerName = "cdnLogs", + AzureCdnPlatform = "HttpLargeObject", + FtpSourceUri = "ftp://someserver/logFolder", + FtpSourceUsername = @"domain\alias", + FtpSourcePassword = "secret" + }; } - private static Dictionary CreateValidJobArgsDictionary() + private static IServiceProvider GetMockServiceProvider(CollectAzureCdnLogsConfiguration configuration) { - var jobArgsDictionary = new Dictionary(); - jobArgsDictionary.Add("FtpSourceUri", "ftp://someserver/logFolder"); - jobArgsDictionary.Add("FtpSourceUsername", @"domain\alias"); - jobArgsDictionary.Add("FtpSourcePassword", "secret"); - jobArgsDictionary.Add("AzureCdnPlatform", "HttpLargeObject"); - jobArgsDictionary.Add("AzureCdnAccountNumber", "AA00"); - jobArgsDictionary.Add("AzureCdnCloudStorageAccount", "UseDevelopmentStorage=true;"); - jobArgsDictionary.Add("AzureCdnCloudStorageContainerName", "cdnLogs"); - - return jobArgsDictionary; + var mockOptionsSnapshot = new Mock>(); + + mockOptionsSnapshot + .Setup(x => x.Value) + .Returns(configuration); + + var mockProvider = new Mock(); + + mockProvider + .Setup(sp => sp.GetService(It.IsAny())) + .Returns(serviceType => + { + if (serviceType == typeof(IOptionsSnapshot)) + { + return mockOptionsSnapshot.Object; + } + else + { + throw new InvalidOperationException($"Unexpected service lookup: {serviceType.Name}"); + } + }); + + return mockProvider.Object; } } } \ No newline at end of file diff --git a/tests/Tests.Stats.CollectAzureCdnLogs/Tests.Stats.CollectAzureCdnLogs.csproj b/tests/Tests.Stats.CollectAzureCdnLogs/Tests.Stats.CollectAzureCdnLogs.csproj index 271a8e906..f51817c41 100644 --- a/tests/Tests.Stats.CollectAzureCdnLogs/Tests.Stats.CollectAzureCdnLogs.csproj +++ b/tests/Tests.Stats.CollectAzureCdnLogs/Tests.Stats.CollectAzureCdnLogs.csproj @@ -68,6 +68,9 @@ + + 4.7.145 + 2.3.1 diff --git a/tests/Tests.Stats.CollectAzureChinaCDNLogs/JobTests.cs b/tests/Tests.Stats.CollectAzureChinaCDNLogs/JobTests.cs index 4a89a6559..0ba32657a 100644 --- a/tests/Tests.Stats.CollectAzureChinaCDNLogs/JobTests.cs +++ b/tests/Tests.Stats.CollectAzureChinaCDNLogs/JobTests.cs @@ -4,7 +4,9 @@ using System; using System.Collections.Generic; using System.ComponentModel.Design; +using Microsoft.Extensions.Options; using Microsoft.WindowsAzure.Storage; +using Moq; using Stats.CollectAzureChinaCDNLogs; using Xunit; @@ -12,7 +14,7 @@ namespace Tests.Stats.CollectAzureChinaCDNLogs { public class JobTests { - private static IServiceContainer ServiceContainer = new ServiceContainer(); + private static Mock MockServiceContainer = new Mock(); [Fact] public void InitFailsWhenEmptyArguments() @@ -20,45 +22,88 @@ public void InitFailsWhenEmptyArguments() var jobArgsDictionary = new Dictionary(); var job = new Job(); - Assert.ThrowsAny(() => job.Init(ServiceContainer, jobArgsDictionary)); + Assert.ThrowsAny(() => job.Init(MockServiceContainer.Object, jobArgsDictionary)); } [Fact] public void InitFailsWithInvalidAccount() { - var jobArgsDictionary = CreateValidJobArgsDictionary(); - var job = new Job(); - Assert.ThrowsAny(() => job.Init(ServiceContainer, jobArgsDictionary)); + var configuration = GetDefaultConfiguration(); + + Assert.ThrowsAny(() => job.InitializeJobConfiguration(GetMockServiceProvider(configuration))); } [Theory] - [InlineData("AzureAccountConStringSource")] - [InlineData("AzureAccountConStringDest")] - [InlineData("AzureContainerNameDest")] - [InlineData("AzureContainerNameSource")] - [InlineData("DestinationFilePrefix")] - public void InitMissingArgArguments(string keyToRemove) + // null values + [InlineData("AzureAccountConnectionStringSource", null, typeof(ArgumentException))] + [InlineData("AzureAccountConnectionStringDestination", null, typeof(ArgumentException))] + [InlineData("AzureContainerNameDestination", null, typeof(ArgumentNullException))] + [InlineData("AzureContainerNameSource", null, typeof(ArgumentNullException))] + [InlineData("DestinationFilePrefix", null, typeof(StorageException))] + // empty values + [InlineData("AzureAccountConnectionStringSource", "", typeof(ArgumentException))] + [InlineData("AzureAccountConnectionStringDestination", "", typeof(ArgumentException))] + [InlineData("AzureContainerNameDestination", "", typeof(ArgumentException))] + [InlineData("AzureContainerNameSource", "", typeof(ArgumentException))] + [InlineData("DestinationFilePrefix", "", typeof(StorageException))] + public void InitMissingArgArguments(string property, object value, Type exceptionType) { - var jobArgsDictionary = CreateValidJobArgsDictionary(); - jobArgsDictionary.Remove(keyToRemove); var job = new Job(); - Assert.ThrowsAny(() => job.Init(ServiceContainer, jobArgsDictionary)); + var configuration = GetModifiedConfiguration(property, value); + + Assert.Throws(exceptionType, () => job.InitializeJobConfiguration(GetMockServiceProvider(configuration))); } + private static CollectAzureChinaCdnLogsConfiguration GetModifiedConfiguration(string property, object value) + { + var configuration = GetDefaultConfiguration(); + + typeof(CollectAzureChinaCdnLogsConfiguration) + .GetProperty(property) + .SetValue(configuration, value); + + return configuration; + } - private static Dictionary CreateValidJobArgsDictionary() + private static CollectAzureChinaCdnLogsConfiguration GetDefaultConfiguration() { - var jobArgsDictionary = new Dictionary(); - jobArgsDictionary.Add("AzureAccountConnectionStringSource", "DefaultEndpointsProtocol=https;AccountName=name;AccountKey=cdummy4aadummyAAWhdummyAdummyA6A+dummydoAdummyJqdummymnm+H+2dummyA/dummygdummyqdummyKK==;EndpointSuffix=core.chinacloudapi.cn"); - jobArgsDictionary.Add("AzureAccountConnectionStringDestination", "DefaultEndpointsProtocol=https;AccountName=name;AccountKey=cdummy4aadummyAAWhdummyAdummyA6A+dummydoAdummyJqdummymnm+H+2dummyA/dummygdummyqdummyKK==;EndpointSuffix=core.windows.net"); - jobArgsDictionary.Add("AzureContainerNameDestination", "DestContainer"); - jobArgsDictionary.Add("AzureContainerNameSource", "SourceContainer"); - jobArgsDictionary.Add("DestinationFilePrefix", "SomePrfix"); - jobArgsDictionary.Add("ExecutionTimeoutInSeconds", "60"); - - return jobArgsDictionary; + return new CollectAzureChinaCdnLogsConfiguration + { + AzureAccountConnectionStringSource = "DefaultEndpointsProtocol=https;AccountName=name;AccountKey=cdummy4aadummyAAWhdummyAdummyA6A+dummydoAdummyJqdummymnm+H+2dummyA/dummygdummyqdummyKK==;EndpointSuffix=core.chinacloudapi.cn", + AzureAccountConnectionStringDestination = "DefaultEndpointsProtocol=https;AccountName=name;AccountKey=cdummy4aadummyAAWhdummyAdummyA6A+dummydoAdummyJqdummymnm+H+2dummyA/dummygdummyqdummyKK==;EndpointSuffix=core.windows.net", + AzureContainerNameDestination = "DestContainer", + AzureContainerNameSource = "SourceContainer", + DestinationFilePrefix = "SomePrfix", + ExecutionTimeoutInSeconds = 60 + }; } + private static IServiceProvider GetMockServiceProvider(CollectAzureChinaCdnLogsConfiguration configuration) + { + var mockOptionsSnapshot = new Mock>(); + + mockOptionsSnapshot + .Setup(x => x.Value) + .Returns(configuration); + + var mockProvider = new Mock(); + + mockProvider + .Setup(sp => sp.GetService(It.IsAny())) + .Returns(serviceType => + { + if (serviceType == typeof(IOptionsSnapshot)) + { + return mockOptionsSnapshot.Object; + } + else + { + throw new InvalidOperationException($"Unexpected service lookup: {serviceType.Name}"); + } + }); + + return mockProvider.Object; + } } } diff --git a/tests/Tests.Stats.CollectAzureChinaCDNLogs/Tests.Stats.CollectAzureChinaCDNLogs.csproj b/tests/Tests.Stats.CollectAzureChinaCDNLogs/Tests.Stats.CollectAzureChinaCDNLogs.csproj index 69a33bb4e..4643530ac 100644 --- a/tests/Tests.Stats.CollectAzureChinaCDNLogs/Tests.Stats.CollectAzureChinaCDNLogs.csproj +++ b/tests/Tests.Stats.CollectAzureChinaCDNLogs/Tests.Stats.CollectAzureChinaCDNLogs.csproj @@ -79,6 +79,9 @@ 5.7.0 + + 4.7.145 + 2.3.1