From 8855b1bb0191606e9a58deb53bcaa17328755e59 Mon Sep 17 00:00:00 2001 From: bezzad Date: Sun, 17 Nov 2024 01:26:44 +0330 Subject: [PATCH] add ILogger of Microsoft.Extensions.Logging namespace to all integration tests --- .../Helper/TestOutputLogger.cs | 17 ++++++++++++++++ .../Helper/TestOutputLoggerProvider.cs | 11 ++++++++++ .../DownloadIntegrationTest.cs | 15 +++++++++++--- .../IntegrationTests/DownloadServiceTest.cs | 20 +++++++++++++------ .../ParallelDownloadIntegrationTest.cs | 2 +- .../SerialDownloadIntegrationTest.cs | 2 +- .../UnitTests/DownloadBuilderTest.cs | 2 +- .../UnitTests/DownloadPackageTestOnFile.cs | 12 +++++++---- .../UnitTests/DownloadPackageTestOnMemory.cs | 8 +++++--- src/Downloader/AbstractDownloadService.cs | 10 +++++----- src/Downloader/ConcurrentStream.cs | 10 +++++----- src/Downloader/DownloadService.cs | 18 ++++++++++++----- src/Downloader/RequestConfiguration.cs | 4 ++-- .../VideoDownloaderHelper.cs | 2 +- 14 files changed, 96 insertions(+), 37 deletions(-) create mode 100644 src/Downloader.Test/Helper/TestOutputLogger.cs create mode 100644 src/Downloader.Test/Helper/TestOutputLoggerProvider.cs diff --git a/src/Downloader.Test/Helper/TestOutputLogger.cs b/src/Downloader.Test/Helper/TestOutputLogger.cs new file mode 100644 index 0000000..a61040e --- /dev/null +++ b/src/Downloader.Test/Helper/TestOutputLogger.cs @@ -0,0 +1,17 @@ +using System; +using Microsoft.Extensions.Logging; +using Xunit.Abstractions; + +namespace Downloader.Test.Helper; + +public class TestOutputLogger(ITestOutputHelper outputHelper, string categoryName) : ILogger +{ + public IDisposable BeginScope(TState state) => null; + + public bool IsEnabled(LogLevel logLevel) => true; + + public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) + { + outputHelper.WriteLine($"{categoryName} [{logLevel}]: {formatter(state, exception)}"); + } +} \ No newline at end of file diff --git a/src/Downloader.Test/Helper/TestOutputLoggerProvider.cs b/src/Downloader.Test/Helper/TestOutputLoggerProvider.cs new file mode 100644 index 0000000..05b6722 --- /dev/null +++ b/src/Downloader.Test/Helper/TestOutputLoggerProvider.cs @@ -0,0 +1,11 @@ +using Microsoft.Extensions.Logging; +using Xunit.Abstractions; + +namespace Downloader.Test.Helper; + +public class TestOutputLoggerProvider(ITestOutputHelper outputHelper) : ILoggerProvider +{ + public ILogger CreateLogger(string categoryName) => new TestOutputLogger(outputHelper, categoryName); + + public void Dispose() { } +} \ No newline at end of file diff --git a/src/Downloader.Test/IntegrationTests/DownloadIntegrationTest.cs b/src/Downloader.Test/IntegrationTests/DownloadIntegrationTest.cs index 65d26da..b357cc6 100644 --- a/src/Downloader.Test/IntegrationTests/DownloadIntegrationTest.cs +++ b/src/Downloader.Test/IntegrationTests/DownloadIntegrationTest.cs @@ -1,4 +1,6 @@ using Downloader.DummyHttpServer; +using Downloader.Test.Helper; +using Microsoft.Extensions.Logging; using Newtonsoft.Json; using System; using System.IO; @@ -15,6 +17,7 @@ public abstract class DownloadIntegrationTest : IDisposable { protected static byte[] FileData { get; set; } protected readonly ITestOutputHelper Output; + protected readonly ILoggerFactory LogFactory; protected string Url { get; set; } protected int FileSize { get; set; } protected string Filename { get; set; } @@ -25,6 +28,10 @@ public abstract class DownloadIntegrationTest : IDisposable public DownloadIntegrationTest(ITestOutputHelper output) { Output = output; + // Create an ILoggerFactory that logs to the ITestOutputHelper + LogFactory = LoggerFactory.Create(builder => { + builder.AddProvider(new TestOutputLoggerProvider(output)); + }); Filename = Path.GetRandomFileName(); FilePath = Path.Combine(Path.GetTempPath(), Filename); FileSize = DummyFileHelper.FileSize16Kb; @@ -240,6 +247,7 @@ public async Task StopResumeDownloadTest() // resume download from stopped point. await Downloader.DownloadFileTaskAsync(Downloader.Package); } + var stream = await File.ReadAllBytesAsync(Downloader.Package.FileName); // assert @@ -300,7 +308,7 @@ public async Task StopResumeDownloadFromLastPositionTest() var totalReceivedBytes = 0L; Config.BufferBlockSize = 1024; Config.EnableLiveStreaming = true; - + Downloader.DownloadProgressChanged += (_, e) => { totalProgressedByteSize += e.ProgressedByteSize; totalReceivedBytes += e.ReceivedBytes.Length; @@ -334,7 +342,7 @@ public async Task StopResumeDownloadOverFirstPackagePositionTest() var isSavingStateOnCancel = false; var isSavingStateBeforCancel = false; Config.EnableLiveStreaming = true; - + Downloader.DownloadProgressChanged += async (_, _) => { isSavingStateBeforCancel |= Downloader.Package.IsSaving; if (--cancellationCount > 0) @@ -452,7 +460,8 @@ public async Task SpeedLimitTest() // assert Assert.Equal(FileSize, Downloader.Package.TotalFileSize); - Assert.True(averageSpeed <= Config.MaximumBytesPerSecond * 1.5, $"Average Speed: {averageSpeed} , Speed Limit: {Config.MaximumBytesPerSecond}"); + Assert.True(averageSpeed <= Config.MaximumBytesPerSecond * 1.5, + $"Average Speed: {averageSpeed} , Speed Limit: {Config.MaximumBytesPerSecond}"); } [Fact] diff --git a/src/Downloader.Test/IntegrationTests/DownloadServiceTest.cs b/src/Downloader.Test/IntegrationTests/DownloadServiceTest.cs index 222974f..76c58be 100644 --- a/src/Downloader.Test/IntegrationTests/DownloadServiceTest.cs +++ b/src/Downloader.Test/IntegrationTests/DownloadServiceTest.cs @@ -11,21 +11,29 @@ using System.Net; using System.Threading.Tasks; using Xunit; +using Xunit.Abstractions; namespace Downloader.Test.IntegrationTests; -public class DownloadServiceTest : DownloadService, IAsyncLifetime +public class DownloadServiceTest : DownloadService, IAsyncDisposable { + protected readonly ITestOutputHelper TestOutputHelper; private string Filename { get; set; } - public Task InitializeAsync() + public DownloadServiceTest(ITestOutputHelper testOutputHelper) { Filename = Path.GetRandomFileName(); - return Task.CompletedTask; + TestOutputHelper = testOutputHelper; + // Create an ILoggerFactory that logs to the ITestOutputHelper + ILoggerFactory loggerFactory = LoggerFactory.Create(builder => { + builder.AddProvider(new TestOutputLoggerProvider(testOutputHelper)); + }); + AddLogger(loggerFactory.CreateLogger(GetType())); } - public new virtual async Task DisposeAsync() + public override async ValueTask DisposeAsync() { + await base.DisposeAsync(); Package?.Clear(); if (Package?.Storage != null) await Package.Storage.DisposeAsync(); @@ -764,10 +772,10 @@ public void TestAddLogger() { // arrange var logFile = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); - + // act AddLogger(FileLogger.Factory(logFile)); - + // assert Assert.NotNull(Logger); } diff --git a/src/Downloader.Test/IntegrationTests/ParallelDownloadIntegrationTest.cs b/src/Downloader.Test/IntegrationTests/ParallelDownloadIntegrationTest.cs index 46fac99..01b7e6a 100644 --- a/src/Downloader.Test/IntegrationTests/ParallelDownloadIntegrationTest.cs +++ b/src/Downloader.Test/IntegrationTests/ParallelDownloadIntegrationTest.cs @@ -14,7 +14,7 @@ public ParallelDownloadIntegrationTest(ITestOutputHelper output) : base(output) MaxTryAgainOnFailover = 100 }; - Downloader = new DownloadService(Config); + Downloader = new DownloadService(Config, LogFactory); Downloader.DownloadFileCompleted += DownloadFileCompleted; } } diff --git a/src/Downloader.Test/IntegrationTests/SerialDownloadIntegrationTest.cs b/src/Downloader.Test/IntegrationTests/SerialDownloadIntegrationTest.cs index 1639cfb..3786fb0 100644 --- a/src/Downloader.Test/IntegrationTests/SerialDownloadIntegrationTest.cs +++ b/src/Downloader.Test/IntegrationTests/SerialDownloadIntegrationTest.cs @@ -14,7 +14,7 @@ public SerialDownloadIntegrationTest(ITestOutputHelper output) : base(output) MaxTryAgainOnFailover = 100 }; - Downloader = new DownloadService(Config); + Downloader = new DownloadService(Config, LogFactory); Downloader.DownloadFileCompleted += DownloadFileCompleted; } } diff --git a/src/Downloader.Test/UnitTests/DownloadBuilderTest.cs b/src/Downloader.Test/UnitTests/DownloadBuilderTest.cs index 6a72937..21bb93f 100644 --- a/src/Downloader.Test/UnitTests/DownloadBuilderTest.cs +++ b/src/Downloader.Test/UnitTests/DownloadBuilderTest.cs @@ -134,7 +134,7 @@ public async Task TestPackageWhenResume() { // arrange DownloadPackage package = new DownloadPackage() { - Urls = new[] { _url }, + Urls = [_url], IsSupportDownloadInRange = true }; IDownload download = DownloadBuilder.New().Build(package); diff --git a/src/Downloader.Test/UnitTests/DownloadPackageTestOnFile.cs b/src/Downloader.Test/UnitTests/DownloadPackageTestOnFile.cs index ec783ae..2e1d1c6 100644 --- a/src/Downloader.Test/UnitTests/DownloadPackageTestOnFile.cs +++ b/src/Downloader.Test/UnitTests/DownloadPackageTestOnFile.cs @@ -15,7 +15,9 @@ public override async Task InitializeAsync() Package = new DownloadPackage() { FileName = _path, - Urls = new[] { DummyFileHelper.GetFileWithNameUrl(DummyFileHelper.SampleFile16KbName, DummyFileHelper.FileSize16Kb) }, + Urls = [ + DummyFileHelper.GetFileWithNameUrl(DummyFileHelper.SampleFile16KbName, DummyFileHelper.FileSize16Kb) + ], TotalFileSize = DummyFileHelper.FileSize16Kb }; @@ -29,7 +31,7 @@ public override async Task DisposeAsync() } [Theory] - [InlineData(true)] // BuildStorageWithReserveSpaceTest + [InlineData(true)] // BuildStorageWithReserveSpaceTest [InlineData(false)] // BuildStorageTest public async Task BuildStorageTest(bool reserveSpace) { @@ -37,7 +39,9 @@ public async Task BuildStorageTest(bool reserveSpace) _path = Path.GetTempFileName(); Package = new DownloadPackage() { FileName = _path, - Urls = new[] { DummyFileHelper.GetFileWithNameUrl(DummyFileHelper.SampleFile16KbName, DummyFileHelper.FileSize16Kb) }, + Urls = [ + DummyFileHelper.GetFileWithNameUrl(DummyFileHelper.SampleFile16KbName, DummyFileHelper.FileSize16Kb) + ], TotalFileSize = DummyFileHelper.FileSize16Kb }; @@ -49,4 +53,4 @@ public async Task BuildStorageTest(bool reserveSpace) Assert.IsType(stream); Assert.Equal(reserveSpace ? DummyFileHelper.FileSize16Kb : 0, Package.Storage.Length); } -} +} \ No newline at end of file diff --git a/src/Downloader.Test/UnitTests/DownloadPackageTestOnMemory.cs b/src/Downloader.Test/UnitTests/DownloadPackageTestOnMemory.cs index fda02b8..7b2b4ad 100644 --- a/src/Downloader.Test/UnitTests/DownloadPackageTestOnMemory.cs +++ b/src/Downloader.Test/UnitTests/DownloadPackageTestOnMemory.cs @@ -7,11 +7,13 @@ public class DownloadPackageTestOnMemory : DownloadPackageTest { public override async Task InitializeAsync() { - Package = new DownloadPackage() { - Urls = new[] { DummyFileHelper.GetFileWithNameUrl(DummyFileHelper.SampleFile16KbName, DummyFileHelper.FileSize16Kb) }, + Package = new DownloadPackage { + Urls = [ + DummyFileHelper.GetFileWithNameUrl(DummyFileHelper.SampleFile16KbName, DummyFileHelper.FileSize16Kb) + ], TotalFileSize = DummyFileHelper.FileSize16Kb }; await base.InitializeAsync(); } -} +} \ No newline at end of file diff --git a/src/Downloader/AbstractDownloadService.cs b/src/Downloader/AbstractDownloadService.cs index c5d920b..7629104 100644 --- a/src/Downloader/AbstractDownloadService.cs +++ b/src/Downloader/AbstractDownloadService.cs @@ -172,7 +172,7 @@ public Task DownloadFileTaskAsync(DownloadPackage package, CancellationT public Task DownloadFileTaskAsync(DownloadPackage package, string address, CancellationToken cancellationToken = default) { - return DownloadFileTaskAsync(package, new[] { address }, cancellationToken); + return DownloadFileTaskAsync(package, [address], cancellationToken); } /// @@ -198,7 +198,7 @@ public virtual async Task DownloadFileTaskAsync(DownloadPackage package, /// A task that represents the asynchronous download operation. The task result contains the downloaded stream. public Task DownloadFileTaskAsync(string address, CancellationToken cancellationToken = default) { - return DownloadFileTaskAsync(new[] { address }, cancellationToken); + return DownloadFileTaskAsync([address], cancellationToken); } /// @@ -223,7 +223,7 @@ public virtual async Task DownloadFileTaskAsync(string[] urls, /// A task that represents the asynchronous download operation. public Task DownloadFileTaskAsync(string address, string fileName, CancellationToken cancellationToken = default) { - return DownloadFileTaskAsync(new[] { address }, fileName, cancellationToken); + return DownloadFileTaskAsync([address], fileName, cancellationToken); } /// @@ -250,7 +250,7 @@ public virtual async Task DownloadFileTaskAsync(string[] urls, string fileName, public Task DownloadFileTaskAsync(string address, DirectoryInfo folder, CancellationToken cancellationToken = default) { - return DownloadFileTaskAsync(new[] { address }, folder, cancellationToken); + return DownloadFileTaskAsync([address], folder, cancellationToken); } /// @@ -486,7 +486,7 @@ public void Dispose() /// /// Disposes asynchronously of the download service, including clearing the current download operation. /// - public async ValueTask DisposeAsync() + public virtual async ValueTask DisposeAsync() { await Clear().ConfigureAwait(false); } diff --git a/src/Downloader/ConcurrentStream.cs b/src/Downloader/ConcurrentStream.cs index 29985e2..c63ef73 100644 --- a/src/Downloader/ConcurrentStream.cs +++ b/src/Downloader/ConcurrentStream.cs @@ -25,11 +25,11 @@ public string Path get => _path; set { - if (!string.IsNullOrWhiteSpace(value)) - { - _path = value; - _stream = new FileStream(_path, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite); - } + if (string.IsNullOrWhiteSpace(value)) + return; + + _path = value; + _stream = new FileStream(_path, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite); } } diff --git a/src/Downloader/DownloadService.cs b/src/Downloader/DownloadService.cs index 1a114d9..d269856 100644 --- a/src/Downloader/DownloadService.cs +++ b/src/Downloader/DownloadService.cs @@ -1,4 +1,5 @@ using Downloader.Extensions.Helpers; +using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; using System.ComponentModel; @@ -18,12 +19,16 @@ public class DownloadService : AbstractDownloadService /// Initializes a new instance of the class with the specified options. /// /// The configuration options for the download service. - public DownloadService(DownloadConfiguration options) : base(options) { } + /// Pass standard logger factory + public DownloadService(DownloadConfiguration options, ILoggerFactory loggerFactory = null) : base(options) + { + Logger = loggerFactory?.CreateLogger(); + } /// /// Initializes a new instance of the class with default options. /// - public DownloadService() : base(null) { } + public DownloadService(ILoggerFactory loggerFactory = null) : this(null, loggerFactory) { } /// /// Starts the download operation. @@ -35,7 +40,8 @@ protected override async Task StartDownload() { await SingleInstanceSemaphore.WaitAsync().ConfigureAwait(false); Package.TotalFileSize = await RequestInstances.First().GetFileSize().ConfigureAwait(false); - Package.IsSupportDownloadInRange = await RequestInstances.First().IsSupportDownloadInRange().ConfigureAwait(false); + Package.IsSupportDownloadInRange = + await RequestInstances.First().IsSupportDownloadInRange().ConfigureAwait(false); Package.BuildStorage(Options.ReserveStorageSpaceBeforeStartingDownload, Options.MaximumMemoryBufferBytes); ValidateBeforeChunking(); ChunkHub.SetFileChunks(Package); @@ -106,7 +112,8 @@ private void SetRangedSizes() { if (!Package.IsSupportDownloadInRange) { - throw new NotSupportedException("The server of your desired address does not support download in a specific range"); + throw new NotSupportedException( + "The server of your desired address does not support download in a specific range"); } if (Options.RangeHigh < Options.RangeLow) @@ -230,7 +237,8 @@ private IEnumerable GetChunksTasks(PauseToken pauseToken) /// The pause token for pausing the download. /// The cancellation token source for cancelling the download. /// A task that represents the asynchronous operation. The task result contains the downloaded chunk. - private async Task DownloadChunk(Chunk chunk, Request request, PauseToken pause, CancellationTokenSource cancellationTokenSource) + private async Task DownloadChunk(Chunk chunk, Request request, PauseToken pause, + CancellationTokenSource cancellationTokenSource) { ChunkDownloader chunkDownloader = new ChunkDownloader(chunk, Options, Package.Storage, Logger); chunkDownloader.DownloadProgressChanged += OnChunkDownloadProgressChanged; diff --git a/src/Downloader/RequestConfiguration.cs b/src/Downloader/RequestConfiguration.cs index 4db761c..1dc1bdc 100644 --- a/src/Downloader/RequestConfiguration.cs +++ b/src/Downloader/RequestConfiguration.cs @@ -18,11 +18,11 @@ public class RequestConfiguration /// public RequestConfiguration() { - Headers = new WebHeaderCollection(); + Headers = []; AllowAutoRedirect = true; AuthenticationLevel = AuthenticationLevel.MutualAuthRequested; AutomaticDecompression = DecompressionMethods.None; - ClientCertificates = new X509CertificateCollection(); + ClientCertificates = []; ImpersonationLevel = TokenImpersonationLevel.Delegation; KeepAlive = false; // Please keep this in false. Because of an error (An existing connection was forcibly closed by the remote host) MaximumAutomaticRedirections = 50; diff --git a/src/Samples/Downloader.Sample/VideoDownloaderHelper.cs b/src/Samples/Downloader.Sample/VideoDownloaderHelper.cs index 5c6c213..14c7e36 100644 --- a/src/Samples/Downloader.Sample/VideoDownloaderHelper.cs +++ b/src/Samples/Downloader.Sample/VideoDownloaderHelper.cs @@ -47,7 +47,7 @@ public async Task DownloadM3U8File(string m3U8Url, string outputFilePath) static string[] ParseM3U8(string m3U8Content, string baseUrl) { string[] lines = m3U8Content.Split(["\r\n", "\r", "\n"], StringSplitOptions.None); - List segmentUrls = new(); + List segmentUrls = []; foreach (string line in lines) {