Пример #1
0
        public async Task LoggingSource_WhileLogging_ShouldNotLoseLogFile(bool compressing)
        {
            var name = GetTestName();

            var path          = NewDataPath(forceCreateDir: true);
            var retentionTime = TimeSpan.MaxValue;
            var retentionSize = long.MaxValue;
            var loggingSource = new LoggingSource(
                LogMode.Information,
                path,
                "LoggingSource" + name,
                retentionTime,
                retentionSize,
                compressing);

            loggingSource.MaxFileSizeInBytes = 1024;
            //This is just to make sure the MaxFileSizeInBytes is get action for the first file
            loggingSource.SetupLogMode(LogMode.Operations, path, retentionTime, retentionSize, compressing);

            var logger = new Logger(loggingSource, "Source" + name, "Logger" + name);

            for (var i = 0; i < 1000; i++)
            {
                await logger.OperationsAsync("Some message");
            }

            var beforeEndFiles = Directory.GetFiles(path);

            loggingSource.EndLogging();

            var afterEndFiles = Directory.GetFiles(path);

            AssertNoFileMissing(beforeEndFiles);
            AssertNoFileMissing(afterEndFiles);
        }
Пример #2
0
        public async Task LoggingSource_WhileRetentionBySizeOn_ShouldKeepRetentionPolicy(bool compressing)
        {
            const int fileSize      = Constants.Size.Kilobyte;
            const int retentionSize = 5 * Constants.Size.Kilobyte;

            var name = GetTestName();

            var path          = NewDataPath(forceCreateDir: true);
            var retentionTime = TimeSpan.MaxValue;
            var loggingSource = new LoggingSource(
                LogMode.Information,
                path,
                "LoggingSource" + name,
                retentionTime,
                retentionSize,
                compressing);

            loggingSource.MaxFileSizeInBytes = fileSize;
            //This is just to make sure the MaxFileSizeInBytes is get action for the first file
            loggingSource.SetupLogMode(LogMode.Operations, path, retentionTime, retentionSize, compressing);

            var logger = new Logger(loggingSource, "Source" + name, "Logger" + name);

            for (var i = 0; i < 100; i++)
            {
                for (var j = 0; j < 5; j++)
                {
                    await logger.OperationsAsync("Some message");
                }
                Thread.Sleep(10);
            }

            const int threshold = 2 * fileSize;
            long      size      = 0;

            string[] afterEndFiles            = null;
            var      isRetentionPolicyApplied = WaitForValue(() =>
            {
                Task.Delay(TimeSpan.FromSeconds(1));

                afterEndFiles = Directory.GetFiles(path);
                AssertNoFileMissing(afterEndFiles);
                size = afterEndFiles.Select(f => new FileInfo(f)).Sum(f => f.Length);

                return(Math.Abs(size - retentionSize) <= threshold);
            }, true, 10_000, 1_000);

            Assert.True(isRetentionPolicyApplied,
                        $"ActualSize({size}), retentionSize({retentionSize}), threshold({threshold})" +
                        Environment.NewLine +
                        JustFileNamesAsString(afterEndFiles));

            loggingSource.EndLogging();
        }
Пример #3
0
        public async Task LoggingSource_WhenExistFileFromToday_ShouldIncrementNumberByOne(string extension)
        {
            const int fileSize = Constants.Size.Kilobyte;

            var testName = GetTestName();
            var path     = NewDataPath(forceCreateDir: true);

            path = Path.Combine(path, Guid.NewGuid().ToString("N"));
            Directory.CreateDirectory(path);

            const long retentionSize = long.MaxValue;
            var        retentionTimeConfiguration = TimeSpan.FromDays(3);

            var now      = DateTime.Now;
            var existLog = Path.Combine(path, $"{LoggingSource.LogInfo.DateToLogFormat(now)}.010.{extension}");

            await using (var file = File.Create(existLog))
            {
                file.SetLength(fileSize);
            }
            var loggingSource = new LoggingSource(
                LogMode.Information,
                path,
                "LoggingSource" + testName,
                retentionTimeConfiguration,
                retentionSize)
            {
                MaxFileSizeInBytes = fileSize
            };

            //This is just to make sure the MaxFileSizeInBytes is get action for the first file
            loggingSource.SetupLogMode(LogMode.Operations, path, retentionTimeConfiguration, retentionSize, false);

            var logger = new Logger(loggingSource, "Source" + testName, "Logger" + testName);
            await logger.OperationsAsync("Some message");

            var result = WaitForValue(() =>
            {
                var strings = Directory.GetFiles(path);
                return(strings.Any(f =>
                {
                    if (LoggingSource.LogInfo.TryGetDate(f, out var d) == false || d.Date.Equals(DateTime.Today) == false)
                    {
                        return false;
                    }

                    return LoggingSource.LogInfo.TryGetNumber(f, out var n) && n == 11;
                }));
            }, true, 10_000, 1_000);

            Assert.True(result);

            loggingSource.EndLogging();
        }
Пример #4
0
        public async Task Register_WhenLogModeIsNone_ShouldNotWriteToLogFile()
        {
            var name = GetTestName();
            var path = NewDataPath(forceCreateDir: true);

            path = Path.Combine(path, Guid.NewGuid().ToString());
            Directory.CreateDirectory(path);

            var loggingSource = new LoggingSource(
                LogMode.None,
                path,
                "LoggingSource" + name,
                TimeSpan.MaxValue,
                long.MaxValue,
                false);

            var logger = new Logger(loggingSource, "Source" + name, "Logger" + name);
            var tcs    = new TaskCompletionSource <WebSocketReceiveResult>(TaskCreationOptions.RunContinuationsAsynchronously);
            var socket = new DummyWebSocket();

            socket.ReceiveAsyncFunc = () => tcs.Task;
            var context = new LoggingSource.WebSocketContext();

            var _ = loggingSource.Register(socket, context, CancellationToken.None);

            var uniqForOperation   = Guid.NewGuid().ToString();
            var uniqForInformation = Guid.NewGuid().ToString();

            var logTasks = Task.WhenAll(logger.OperationsAsync(uniqForOperation), logger.InfoAsync(uniqForInformation));
            var timeout  = TimeSpan.FromSeconds(10);
            await Task.WhenAny(logTasks, Task.Delay(timeout));

            Assert.True(logTasks.IsCompleted, $"Waited over {timeout.TotalSeconds} seconds for log tasks to finish");

            tcs.SetResult(new WebSocketReceiveResult(1, WebSocketMessageType.Text, true, WebSocketCloseStatus.NormalClosure, ""));
            loggingSource.EndLogging();

            Assert.Contains(uniqForOperation, socket.LogsReceived);
            Assert.Contains(uniqForInformation, socket.LogsReceived);

            var logFile    = Directory.GetFiles(path).First();
            var logContent = await File.ReadAllTextAsync(logFile);

            Assert.DoesNotContain(uniqForOperation, logContent);
            Assert.DoesNotContain(uniqForInformation, logContent);
        }
Пример #5
0
        public async Task LoggingSource_WhenExistFileFromYesterdayAndCreateNewFileForToday_ShouldResetNumberToZero(string extension)
        {
            var testName = GetTestName();
            var path     = NewDataPath(forceCreateDir: true);

            path = Path.Combine(path, Guid.NewGuid().ToString("N"));
            Directory.CreateDirectory(path);

            const long retentionSize = long.MaxValue;
            var        retentionTimeConfiguration = TimeSpan.FromDays(3);

            var yesterday    = DateTime.Now - TimeSpan.FromDays(1);
            var yesterdayLog = Path.Combine(path, $"{LoggingSource.LogInfo.DateToLogFormat(yesterday)}.010.{extension}");
            await File.Create(yesterdayLog).DisposeAsync();

            File.SetLastWriteTime(yesterdayLog, yesterday);

            var loggingSource = new LoggingSource(
                LogMode.Information,
                path,
                "LoggingSource" + testName,
                retentionTimeConfiguration,
                retentionSize);

            var logger = new Logger(loggingSource, "Source" + testName, "Logger" + testName);
            await logger.OperationsAsync("Some message");

            var todayLog = string.Empty;

            WaitForValue(() =>
            {
                var afterEndFiles = Directory.GetFiles(path);
                todayLog          = afterEndFiles.FirstOrDefault(f =>
                                                                 LoggingSource.LogInfo.TryGetDate(f, out var date) && date.Date.Equals(DateTime.Today));
                return(todayLog != null);
            }, true, 10_000, 1_000);

            Assert.True(LoggingSource.LogInfo.TryGetNumber(todayLog, out var n) && n == 0);

            loggingSource.EndLogging();
        }
Пример #6
0
        public async Task LoggingSource_WhileRetentionByTimeOn_ShouldKeepRetentionPolicy(bool compressing)
        {
            const int fileSize = Constants.Size.Kilobyte;

            var name = GetTestName();
            var path = NewDataPath(forceCreateDir: true);

            path = Path.Combine(path, Guid.NewGuid().ToString());
            Directory.CreateDirectory(path);
            var retentionTime = TimeSpan.FromDays(3);

            var retentionDate   = DateTime.Now.Date - retentionTime;
            var toCheckLogFiles = new List <(string, bool)>();

            for (var date = retentionDate - TimeSpan.FromDays(1); date <= retentionDate + TimeSpan.FromDays(1); date += TimeSpan.FromDays(1))
            {
                var fileName = Path.Combine(path, LoggingSource.LogInfo.GetFileName(date) + ".001.log");
                toCheckLogFiles.Add((fileName, date >= retentionDate));
                var file = File.Create(fileName);
                file.Dispose();
            }

            var retentionSize = long.MaxValue;
            var loggingSource = new LoggingSource(
                LogMode.Information,
                path,
                "LoggingSource" + name,
                retentionTime,
                retentionSize,
                compressing);

            loggingSource.MaxFileSizeInBytes = fileSize;
            //This is just to make sure the MaxFileSizeInBytes is get action for the first file
            loggingSource.SetupLogMode(LogMode.Operations, path, retentionTime, retentionSize, compressing);

            var logger = new Logger(loggingSource, "Source" + name, "Logger" + name);

            for (var j = 0; j < 50; j++)
            {
                for (var i = 0; i < 5; i++)
                {
                    await logger.OperationsAsync("Some message");
                }
                Thread.Sleep(10);
            }

            loggingSource.EndLogging();

            var afterEndFiles = Directory.GetFiles(path);

            AssertNoFileMissing(afterEndFiles);

            try
            {
                foreach (var(fileName, shouldExist) in toCheckLogFiles)
                {
                    var compressedFileName = fileName + ".gz";
                    if (shouldExist)
                    {
                        Assert.True(afterEndFiles.Contains(fileName) || afterEndFiles.Contains(compressedFileName),
                                    $"The log file \"{Path.GetFileNameWithoutExtension(fileName)}\" and all log files from and after {retentionDate} " +
                                    "should be deleted due to time retention");
                    }
                    else
                    {
                        Assert.False(afterEndFiles.Contains(fileName),
                                     $"The file \"{fileName}\" and all log files from before {retentionDate} should be deleted due to time retention");

                        Assert.False(afterEndFiles.Contains(compressedFileName),
                                     $"The file \"{compressedFileName}\" and all log files from before {retentionDate} should be deleted due to time retention");
                    }
                }
            }
            catch (Exception e)
            {
                throw new InvalidOperationException($"Logs after end - {JustFileNamesAsString(afterEndFiles)}", e);
            }
        }
Пример #7
0
        public async Task LoggingSource_WhileStopAndStartAgain_ShouldNotOverrideOld(bool compressing)
        {
            const int taskTimeout = 10000;
            var       name        = GetTestName();

            var path          = NewDataPath(forceCreateDir: true);
            var retentionTime = TimeSpan.MaxValue;
            var retentionSize = long.MaxValue;

            var firstLoggingSource = new LoggingSource(
                LogMode.Information,
                path,
                "FirstLoggingSource" + name,
                retentionTime,
                retentionSize,
                compressing);

            firstLoggingSource.MaxFileSizeInBytes = 1024;
            //This is just to make sure the MaxFileSizeInBytes is get action for the first file
            firstLoggingSource.SetupLogMode(LogMode.Operations, path, retentionTime, retentionSize, compressing);

            try
            {
                var logger = new Logger(firstLoggingSource, "Source" + name, "Logger" + name);

                for (var i = 0; i < 100; i++)
                {
                    var task = logger.OperationsAsync("Some message");
                    await Task.WhenAny(task, Task.Delay(taskTimeout));

                    if (task.IsCompleted == false)
                    {
                        throw new TimeoutException($"The log task took more then one second");
                    }
                }
            }
            finally
            {
                firstLoggingSource.EndLogging();
            }

            var beforeRestartFiles = Directory.GetFiles(path);

            var restartDateTime = DateTime.Now;


            Exception anotherThreadException = null;
            //To start new LoggingSource the object need to be construct on another thread
            var anotherThread = new Thread(() =>
            {
                var secondLoggingSource = new LoggingSource(
                    LogMode.Information,
                    path,
                    "SecondLoggingSource" + name,
                    retentionTime,
                    retentionSize);

                try
                {
                    secondLoggingSource.MaxFileSizeInBytes = 1024;
                    var secondLogger = new Logger(secondLoggingSource, "Source" + name, "Logger" + name);

                    for (var i = 0; i < 100; i++)
                    {
                        var task = secondLogger.OperationsAsync("Some message");
                        Task.WhenAny(task, Task.Delay(taskTimeout)).GetAwaiter().GetResult();
                        if (task.IsCompleted == false)
                        {
                            throw new TimeoutException($"The log task took more then one second");
                        }
                    }
                }
                catch (Exception e)
                {
                    anotherThreadException = e;
                }
                finally
                {
                    secondLoggingSource.EndLogging();
                }
            });

            anotherThread.Start();
            anotherThread.Join();
            if (anotherThreadException != null)
            {
                throw anotherThreadException;
            }

            foreach (var file in beforeRestartFiles.OrderBy(f => f).SkipLast(1)) //The last is skipped because it is still written
            {
                var lastWriteTime = File.GetLastWriteTime(file);
                Assert.True(
                    restartDateTime > lastWriteTime,
                    $"{file} was changed (time:" +
                    $"{lastWriteTime.ToString("yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture)}) after the restart (time:" +
                    $"{restartDateTime.ToString("yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture)})" +
                    Environment.NewLine +
                    JustFileNamesAsString(beforeRestartFiles));
            }
        }
Пример #8
0
        public async Task LoggingSource_WhileRetentionByTimeInHours_ShouldKeepRetentionPolicy(bool compressing)
        {
            const int fileSize = Constants.Size.Kilobyte;

            var name = GetTestName();
            var path = NewDataPath(forceCreateDir: true);

            path = Path.Combine(path, Guid.NewGuid().ToString());
            Directory.CreateDirectory(path);
            var retentionTimeConfiguration = TimeSpan.FromHours(3);

            var now             = DateTime.Now;
            var retentionTime   = now - retentionTimeConfiguration;
            var toCheckLogFiles = new List <(string fileName, bool shouldExist)>();

            const int artificialLogsCount = 9;

            for (int i = 0; i < artificialLogsCount; i++)
            {
                var lastModified = now - TimeSpan.FromHours(i);
                var fileName     = Path.Combine(path, $"{LoggingSource.LogInfo.DateToLogFormat(lastModified)}.00{artificialLogsCount - i}.log");
                toCheckLogFiles.Add((fileName, lastModified > retentionTime));
                await using (File.Create(fileName))
                { }
                File.SetLastWriteTime(fileName, lastModified);
            }

            const long retentionSize = long.MaxValue;
            var        loggingSource = new LoggingSource(
                LogMode.Information,
                path,
                "LoggingSource" + name,
                retentionTimeConfiguration,
                retentionSize,
                compressing)
            {
                MaxFileSizeInBytes = fileSize
            };

            //This is just to make sure the MaxFileSizeInBytes is get action for the first file
            loggingSource.SetupLogMode(LogMode.Operations, path, retentionTimeConfiguration, retentionSize, compressing);

            var logger = new Logger(loggingSource, "Source" + name, "Logger" + name);

            for (var j = 0; j < 50; j++)
            {
                for (var i = 0; i < 5; i++)
                {
                    await logger.OperationsWithWait("Some message");
                }
                Thread.Sleep(10);
            }

            string[] afterEndFiles = null;
            await WaitForValueAsync(async() =>
            {
                for (var i = 0; i < 10; i++)
                {
                    await logger.OperationsWithWait("Some message");
                }
                afterEndFiles = Directory.GetFiles(path);
                return(DoesContainFilesThatShouldNotBeFound(afterEndFiles, toCheckLogFiles, compressing));
            }, false, 10_000, 1_000);

            loggingSource.EndLogging();

            AssertNoFileMissing(afterEndFiles);

            try
            {
                Assert.All(toCheckLogFiles, toCheck =>
                {
                    (string fileName, bool shouldExist) = toCheck;
                    fileName     = $"{fileName}{(compressing ? ".gz" : string.Empty)}";
                    var fileInfo = new FileInfo(fileName);
                    if (shouldExist)
                    {
                        Assert.True(fileInfo.Exists, $"The log file \"{fileInfo.Name}\" should be exist");
                    }
                    else
                    {
                        Assert.False(fileInfo.Exists, $"The log file \"{fileInfo.Name}\" last modified {fileInfo.LastWriteTime} should not be exist. retentionTime({retentionTime})");
                    }
                });
            }
            catch (Exception e)
            {
                throw new InvalidOperationException($"Logs after end - {JustFileNamesAsString(afterEndFiles)}", e);
            }
        }
Пример #9
0
        public async Task AttachPipeSink_WhenLogModeIsOperations_ShouldWriteToLogFileJustOperations(LogMode logMode)
        {
            var timeout = TimeSpan.FromSeconds(10);

            var name = GetTestName();
            var path = NewDataPath(forceCreateDir: true);

            path = Path.Combine(path, Guid.NewGuid().ToString());
            Directory.CreateDirectory(path);

            var loggingSource = new LoggingSource(
                logMode,
                path,
                "LoggingSource" + name,
                TimeSpan.MaxValue,
                long.MaxValue,
                false);

            var logger = new Logger(loggingSource, "Source" + name, "Logger" + name);
            var tcs    = new TaskCompletionSource <WebSocketReceiveResult>(TaskCreationOptions.RunContinuationsAsynchronously);

            await using var stream = new MemoryStream();

            //Attach Pipe
            loggingSource.AttachPipeSink(stream);
            var beforeDetachOperation   = Guid.NewGuid().ToString();
            var beforeDetachInformation = Guid.NewGuid().ToString();

            var logTasks = Task.WhenAll(logger.OperationsAsync(beforeDetachOperation), logger.InfoAsync(beforeDetachInformation));
            await Task.WhenAny(logTasks, Task.Delay(timeout));

            Assert.True(logTasks.IsCompleted, $"Waited over {timeout.TotalSeconds} seconds for log tasks to finish");

            //Detach Pipe
            loggingSource.DetachPipeSink();
            await stream.FlushAsync();

            var afterDetachOperation   = Guid.NewGuid().ToString();
            var afterDetachInformation = Guid.NewGuid().ToString();

            logTasks = Task.WhenAll(logger.OperationsAsync(afterDetachOperation), logger.InfoAsync(afterDetachInformation));
            await Task.WhenAny(logTasks, Task.Delay(timeout));

            Assert.True(logTasks.IsCompleted || logMode == LogMode.None,
                        $"Waited over {timeout.TotalSeconds} seconds for log tasks to finish");

            tcs.SetResult(new WebSocketReceiveResult(1, WebSocketMessageType.Text, true, WebSocketCloseStatus.NormalClosure, ""));
            loggingSource.EndLogging();

            var logsFromPipe = Encodings.Utf8.GetString(stream.ToArray());

            Assert.Contains(beforeDetachInformation, logsFromPipe);
            Assert.Contains(beforeDetachOperation, logsFromPipe);
            Assert.DoesNotContain(afterDetachInformation, logsFromPipe);
            Assert.DoesNotContain(afterDetachOperation, logsFromPipe);

            string logsFileContentAfter = await ReadLogsFileContent(path);

            AssertContainsLog(LogMode.Information, logMode)(beforeDetachInformation, logsFileContentAfter);
            AssertContainsLog(LogMode.Operations, logMode)(beforeDetachOperation, logsFileContentAfter);

            AssertContainsLog(LogMode.Information, logMode)(afterDetachInformation, logsFileContentAfter);
            AssertContainsLog(LogMode.Operations, logMode)(afterDetachOperation, logsFileContentAfter);
        }
Пример #10
0
        public async Task Register_WhenLogModeIsOperations_ShouldWriteToLogFileJustAsLogMode(LogMode logMode)
        {
            var timeout = TimeSpan.FromSeconds(10);

            var name = GetTestName();
            var path = NewDataPath(forceCreateDir: true);

            path = Path.Combine(path, Guid.NewGuid().ToString());
            Directory.CreateDirectory(path);

            var loggingSource = new LoggingSource(
                logMode,
                path,
                "LoggingSource" + name,
                TimeSpan.MaxValue,
                long.MaxValue,
                false);

            var logger = new Logger(loggingSource, "Source" + name, "Logger" + name);
            var tcs    = new TaskCompletionSource <WebSocketReceiveResult>(TaskCreationOptions.RunContinuationsAsynchronously);
            var socket = new DummyWebSocket();

            socket.ReceiveAsyncFunc = () => tcs.Task;
            var context = new LoggingSource.WebSocketContext();

            //Register
            var _ = loggingSource.Register(socket, context, CancellationToken.None);
            var beforeCloseOperation   = Guid.NewGuid().ToString();
            var beforeCloseInformation = Guid.NewGuid().ToString();

            var logTasks = Task.WhenAll(logger.OperationsAsync(beforeCloseOperation), logger.InfoAsync(beforeCloseInformation));
            await Task.WhenAny(logTasks, Task.Delay(timeout));

            Assert.True(logTasks.IsCompleted, $"Waited over {timeout.TotalSeconds} seconds for log tasks to finish");

            const int socketTimeout      = 5000;
            var       socketContainsLogs = WaitForValue(() => socket.LogsReceived.Contains(beforeCloseInformation) && socket.LogsReceived.Contains(beforeCloseOperation),
                                                        true, socketTimeout, 100);

            Assert.True(socketContainsLogs, $"Waited over {socketTimeout} seconds for log to be written to socket");

            //Close socket
            socket.Close();
            tcs.SetResult(new WebSocketReceiveResult(1, WebSocketMessageType.Text, true, WebSocketCloseStatus.NormalClosure, string.Empty));

            var afterCloseOperation   = Guid.NewGuid().ToString();
            var afterCloseInformation = Guid.NewGuid().ToString();

            logTasks = Task.WhenAll(logger.OperationsAsync(afterCloseOperation), logger.InfoAsync(afterCloseInformation));
            await Task.WhenAny(logTasks, Task.Delay(timeout));

            Assert.True(logTasks.IsCompleted || logMode == LogMode.None,
                        $"Waited over {timeout.TotalSeconds} seconds for log tasks to finish");

            loggingSource.EndLogging();

            string logsFileContentAfter = await ReadLogsFileContent(path);

            AssertContainsLog(LogMode.Information, logMode)(beforeCloseInformation, logsFileContentAfter);
            AssertContainsLog(LogMode.Operations, logMode)(beforeCloseOperation, logsFileContentAfter);

            AssertContainsLog(LogMode.Information, logMode)(afterCloseInformation, logsFileContentAfter);
            AssertContainsLog(LogMode.Operations, logMode)(afterCloseOperation, logsFileContentAfter);
        }
Пример #11
0
        public async Task LoggingSource_WhileRetentionBySizeOn_ShouldKeepRetentionPolicy(bool compressing)
        {
            const int fileSize      = Constants.Size.Kilobyte;
            const int retentionSize = 5 * Constants.Size.Kilobyte;

            var name = GetTestName();

            var path          = NewDataPath(forceCreateDir: true);
            var retentionTime = TimeSpan.MaxValue;
            var loggingSource = new LoggingSource(
                LogMode.Information,
                path,
                "LoggingSource" + name,
                retentionTime,
                retentionSize,
                compressing);

            loggingSource.MaxFileSizeInBytes = fileSize;
            //This is just to make sure the MaxFileSizeInBytes is get action for the first file
            loggingSource.SetupLogMode(LogMode.Operations, path, retentionTime, retentionSize, compressing);

            var logger = new Logger(loggingSource, "Source" + name, "Logger" + name);

            for (var i = 0; i < 100; i++)
            {
                for (var j = 0; j < 5; j++)
                {
                    await logger.OperationsAsync("Some message");
                }
                Thread.Sleep(10);
            }

            var sw = Stopwatch.StartNew();

            while (true)
            {
                await Task.Delay(TimeSpan.FromSeconds(1));

                var afterEndFiles = Directory.GetFiles(path);
                AssertNoFileMissing(afterEndFiles);
                var       size      = afterEndFiles.Select(f => new FileInfo(f)).Sum(f => f.Length);
                const int threshold = 2 * fileSize;

                if (Math.Abs(size - retentionSize) <= threshold)
                {
                    break;
                }

                if (sw.Elapsed < TimeSpan.FromSeconds(10))
                {
                    continue;
                }

                Assert.True(false,
                            $"ActualSize({size}), retentionSize({retentionSize}), threshold({threshold})" +
                            Environment.NewLine +
                            JustFileNamesAsString(afterEndFiles));
            }

            loggingSource.EndLogging();
        }