Skip to content

Commit 15fa7d5

Browse files
authored
Merge pull request #262 from apache/Feature/262-mocked-DateTimeStrategy-to-speedup-test
#250 mocked DateTimeStrategy to speedup test
2 parents 2d315a7 + 3ba1806 commit 15fa7d5

File tree

10 files changed

+227
-155
lines changed

10 files changed

+227
-155
lines changed

src/changelog/3.2.0/.release.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22
<release xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
33
xmlns="https://logging.apache.org/xml/ns"
44
xsi:schemaLocation="https://logging.apache.org/xml/ns https://logging.apache.org/xml/ns/log4j-changelog-0.xsd"
5-
date="2025-07-12"
5+
date="2025-08-12"
66
version="3.2.0"/>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<entry xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xmlns="https://logging.apache.org/xml/ns"
4+
xsi:schemaLocation="https://logging.apache.org/xml/ns https://logging.apache.org/xml/ns/log4j-changelog-0.xsd"
5+
type="fixed">
6+
<issue id="250" link="https://github.com/apache/logging-log4net/issues/250"/>
7+
<issue id="257" link="https://github.com/apache/logging-log4net/pull/257"/>
8+
<issue id="262" link="https://github.com/apache/logging-log4net/pull/262"/>
9+
<description format="asciidoc">
10+
The rolling of logfiles was fixed (reported by @maedula, fixed by @gdziadkiewicz)
11+
</description>
12+
</entry>

src/log4net.Tests/Appender/RemoteSyslogAppenderTest.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#endregion
1919

2020
using System.Text;
21+
using System.Threading;
2122
using log4net.Appender;
2223
using log4net.Appender.Internal;
2324
using log4net.Core;
@@ -64,11 +65,17 @@ public void RemoteSyslogTest()
6465
Domain = "TestDomain",
6566
});
6667
appender.DoAppend(loggingEvent);
68+
for (int i = 0; i < 20; i++)
69+
{
70+
if (appender.Mock.Sent.Count == 0)
71+
{
72+
Thread.Sleep(10);
73+
}
74+
}
6775
appender.Close();
6876
Assert.That(appender.Mock.ConnectedTo, Is.EqualTo((0, ipAddress, 514)));
6977
Assert.That(appender.Mock.Sent, Has.Count.EqualTo(1));
7078
Assert.That(appender.Mock.WasDisposed, Is.True);
71-
Assert.That(appender.Mock.Sent, Has.Count.EqualTo(1));
7279
const string expectedData = @"<14>TestDomain: INFO - Test message";
7380
Assert.That(Encoding.ASCII.GetString(appender.Mock.Sent[0].Datagram), Is.EqualTo(expectedData));
7481
}
Lines changed: 138 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,29 @@
1+
#region Apache License
2+
//
3+
// Licensed to the Apache Software Foundation (ASF) under one or more
4+
// contributor license agreements. See the NOTICE file distributed with
5+
// this work for additional information regarding copyright ownership.
6+
// The ASF licenses this file to you under the Apache License, Version 2.0
7+
// (the "License"); you may not use this file except in compliance with
8+
// the License. You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
//
18+
#endregion
19+
120
using System;
2-
using System.IO;
321
using System.Collections.Generic;
22+
using System.IO;
423
using System.Linq;
5-
using log4net;
24+
using log4net.Appender;
625
using log4net.Config;
26+
using log4net.Repository;
727
using NUnit.Framework;
828

929
namespace log4net.Tests.Integration
@@ -13,8 +33,9 @@ namespace log4net.Tests.Integration
1333
/// <para>
1434
/// Expectations for test log files and directories:
1535
/// <list type="bullet">
16-
/// <item>Test log files may be placed directly in the test directory with names starting with <c>TestLogFilePrefix</c>, or inside directories whose names start with <c>TestLogDirectoryPrefix</c> and may have arbitrary file names.</item>
17-
/// <item>Each test run starts with a clean environment: any files or directories from previous runs matching these prefixes are deleted in <c>SetUp</c>.</item>
36+
/// <item>Test log files may be placed directly in the test directory with names starting with <see cref="TestLogFilePrefix"/>,
37+
/// or inside directories whose names start with <see cref="TestLogDirectoryPrefix"/> and may have arbitrary file names.</item>
38+
/// <item>Each test run starts with a clean environment: any files or directories from previous runs matching these prefixes are deleted in <see cref="SetUp"/>.</item>
1839
/// <item>Tests assert the existence, count, and content of log files and directories as part of their validation.</item>
1940
/// </list>
2041
/// </para>
@@ -44,16 +65,16 @@ public void SetUp()
4465
[Test]
4566
public void Log4Net_WritesLogFile_AndContentIsCorrect()
4667
{
47-
var (log, repo) = ArrangeLogger("log4net.integration.basic.config");
48-
log.Info("Hello integration test");
49-
log.Error("This is an error");
50-
repo.Shutdown();
68+
(ILog log, ILoggerRepository repo) = ArrangeLogger("log4net.integration.basic.config");
69+
log.Info("Hello integration test");
70+
log.Error("This is an error");
71+
repo.Shutdown();
5172

52-
// Assert: log file exists and contains expected content
53-
string[] logLines = File.ReadAllLines("integrationTestLogFile_integration.log");
54-
Assert.That(logLines.Length, Is.EqualTo(2));
55-
Assert.That(logLines[0], Does.Contain("Hello integration test"));
56-
Assert.That(logLines[1], Does.Contain("This is an error"));
73+
// Assert: log file exists and contains expected content
74+
string[] logLines = File.ReadAllLines("integrationTestLogFile_integration.log");
75+
Assert.That(logLines, Has.Length.EqualTo(2));
76+
Assert.That(logLines[0], Does.Contain("Hello integration test"));
77+
Assert.That(logLines[1], Does.Contain("This is an error"));
5778
}
5879

5980
/// <summary>
@@ -67,21 +88,21 @@ public void Log4Net_WritesLogFile_AndContentIsCorrect()
6788
[Test]
6889
public void Log4Net_WritesLogFile_AndContentIsCorrectAfterRestart()
6990
{
70-
for (int i = 0; i < 10; i++)
71-
{
72-
var (log, repo) = ArrangeLogger("log4net.integration.basic.config");
73-
log.Info("Hello integration test");
74-
log.Error("This is an error");
75-
repo.Shutdown();
76-
}
77-
// Assert: log file exists and contains expected content
78-
string[] logLines = File.ReadAllLines("integrationTestLogFile_integration.log");
79-
Assert.That(logLines.Length, Is.EqualTo(20));
80-
for (int i = 0; i < 10; i++)
81-
{
82-
Assert.That(logLines[i * 2], Does.Contain("Hello integration test"));
83-
Assert.That(logLines[i * 2 + 1], Does.Contain("This is an error"));
84-
}
91+
for (int i = 0; i < 10; i++)
92+
{
93+
(ILog log, ILoggerRepository repo) = ArrangeLogger("log4net.integration.basic.config");
94+
log.Info("Hello integration test");
95+
log.Error("This is an error");
96+
repo.Shutdown();
97+
}
98+
// Assert: log file exists and contains expected content
99+
string[] logLines = File.ReadAllLines("integrationTestLogFile_integration.log");
100+
Assert.That(logLines, Has.Length.EqualTo(20));
101+
for (int i = 0; i < 10; i++)
102+
{
103+
Assert.That(logLines[i * 2], Does.Contain("Hello integration test"));
104+
Assert.That(logLines[i * 2 + 1], Does.Contain("This is an error"));
105+
}
85106
}
86107

87108
/// <summary>
@@ -96,18 +117,18 @@ public void Log4Net_WritesLogFile_AndContentIsCorrectAfterRestart()
96117
[Test]
97118
public void Log4Net_WritesLogFile_WithRollAndNoAppend_AndContentIsCorrectAfterRestart()
98119
{
99-
for (int i = 0; i < 20; i++)
120+
for (int i = 0; i < 20; i++)
121+
{
122+
(ILog log, ILoggerRepository repo) = ArrangeLogger("log4net.roll.config");
123+
for (int j = 0; j < 10; ++j)
100124
{
101-
var (log, repo) = ArrangeLogger("log4net.roll.config");
102-
for (int j = 0; j < 10; ++j)
103-
{
104-
log.Info($"Hello, log4net! {i} {j}");
105-
}
106-
repo.Shutdown();
125+
log.Info($"Hello, log4net! {i} {j}");
107126
}
108-
// Assert: log file exists and contains expected content
109-
string[] logFiles = Directory.GetFiles("integrationTestLogDir_roll");
110-
Assert.That(logFiles.Length, Is.EqualTo(12 + 1));
127+
repo.Shutdown();
128+
}
129+
// Assert: log file exists and contains expected content
130+
string[] logFiles = Directory.GetFiles("integrationTestLogDir_roll");
131+
Assert.That(logFiles, Has.Length.EqualTo(12 + 1));
111132
}
112133

113134
/// <summary>
@@ -122,21 +143,19 @@ public void Log4Net_WritesLogFile_WithRollAndNoAppend_AndContentIsCorrectAfterRe
122143
[Test]
123144
public void Log4Net_WritesLogFile_WithMaxSizeRoll_Config_Works()
124145
{
125-
string logDir = Path.Combine(TestContext.CurrentContext.TestDirectory, "integrationTestLogDir_maxsizeroll");
126-
if (Directory.Exists(logDir)) Directory.Delete(logDir, true);
127-
Directory.CreateDirectory(logDir);
128-
var (log, repo) = ArrangeLogger("log4net.maxsizeroll.config");
129-
for (int i = 0; i < 1000; ++i)
130-
{
131-
log.Info($"Log entry {i}");
132-
}
133-
repo.Shutdown();
134-
// Assert: rolled files exist
135-
string[] logFiles = Directory.GetFiles(logDir, "*.log");
136-
Assert.That(logFiles.Length, Is.EqualTo(4)); // 1 current + 3 backups
137-
// Optionally, check that each file is <= 10KB
138-
foreach (var file in logFiles)
139-
Assert.That(new FileInfo(file).Length, Is.LessThanOrEqualTo(10 * 1024 + 100));
146+
DirectoryInfo logDir = CreateLogDirectory("integrationTestLogDir_maxsizeroll");
147+
(ILog log, ILoggerRepository repo) = ArrangeLogger("log4net.maxsizeroll.config");
148+
for (int i = 0; i < 1000; ++i)
149+
{
150+
log.Info($"Log entry {i}");
151+
}
152+
repo.Shutdown();
153+
// Assert: rolled files exist
154+
FileInfo[] logFiles = logDir.GetFiles("*.log");
155+
Assert.That(logFiles, Has.Length.EqualTo(4)); // 1 current + 3 backups
156+
// Check that each file is <= 10KB
157+
foreach (FileInfo file in logFiles)
158+
Assert.That(file.Length, Is.LessThanOrEqualTo(10 * 1024 + 100));
140159
}
141160

142161
/// <summary>
@@ -152,32 +171,35 @@ public void Log4Net_WritesLogFile_WithMaxSizeRoll_Config_Works()
152171
[Test]
153172
public void Log4Net_WritesLogFile_WithDateAndSizeRoll_Config_Works()
154173
{
155-
string logDir = Path.Combine(TestContext.CurrentContext.TestDirectory, "integrationTestLogDir_maxsizerolldate");
156-
if (Directory.Exists(logDir)) Directory.Delete(logDir, true);
157-
Directory.CreateDirectory(logDir);
158-
var (log, repo) = ArrangeLogger("log4net.maxsizeroll_date.config");
159-
// Write enough lines to trigger rolling by size and date
160-
for (int i = 1; i < 10000; ++i)
161-
{
162-
log.Debug($"DateRoll entry {i}");
163-
if (i % 5000 == 0) System.Threading.Thread.Sleep(TimeSpan.FromMinutes(1)); // allow time for date to change if needed
164-
}
165-
repo.Shutdown();
166-
// Assert: rolled files exist (date+size pattern)
167-
string[] logFiles = Directory.GetFiles(logDir, "*.log");
168-
Assert.That(logFiles.Length, Is.EqualTo(8));
169-
// Group files by date part in the filename (yyyy-MM-dd-mm)
170-
var dateGroups = logFiles
171-
.Select(f => Path.GetFileNameWithoutExtension(f))
172-
.Select(name => name.Split('.').First())
173-
.GroupBy(date => date)
174-
.ToDictionary(g => g.Key, g => g.Count());
175-
// Assert that at least one group exists and print group counts
176-
Assert.That(dateGroups.Count, Is.EqualTo(2));
177-
foreach (var group in dateGroups)
174+
DirectoryInfo logDir = CreateLogDirectory("integrationTestLogDir_maxsizerolldate");
175+
(ILog log, ILoggerRepository repo) = ArrangeLogger("log4net.maxsizeroll_date.config");
176+
MockDateTime mockDateTime = new();
177+
repo.GetAppenders().OfType<RollingFileAppender>().First().DateTimeStrategy = mockDateTime;
178+
// Write enough lines to trigger rolling by size and date
179+
for (int i = 1; i < 10000; ++i)
180+
{
181+
log.Debug($"DateRoll entry {i}");
182+
if (i % 5000 == 0)
178183
{
179-
TestContext.Out.WriteLine($"Date group: {group.Key}, file count: {group.Value}");
184+
mockDateTime.Offset = TimeSpan.FromMinutes(1); // allow time for date to change if needed
180185
}
186+
}
187+
repo.Shutdown();
188+
// Assert: rolled files exist (date+size pattern)
189+
FileInfo[] logFiles = logDir.GetFiles("*.log");
190+
Assert.That(logFiles, Has.Length.EqualTo(8));
191+
// Group files by date part in the filename (yyyy-MM-dd-mm)
192+
Dictionary<string, int> dateGroups = logFiles
193+
.Select(f => Path.GetFileNameWithoutExtension(f.Name))
194+
.Select(name => name.Split('.').First())
195+
.GroupBy(date => date)
196+
.ToDictionary(g => g.Key, g => g.Count());
197+
// Assert that at least one group exists and print group counts
198+
Assert.That(dateGroups, Has.Count.EqualTo(2));
199+
foreach (KeyValuePair<string, int> group in dateGroups)
200+
{
201+
TestContext.Out.WriteLine($"Date group: {group.Key}, file count: {group.Value}");
202+
}
181203
}
182204

183205
/// <summary>
@@ -192,53 +214,61 @@ public void Log4Net_WritesLogFile_WithDateAndSizeRoll_Config_Works()
192214
[Test]
193215
public void Log4Net_ConfigWithoutFileName_CreatesOneFile()
194216
{
195-
string logDir = Path.Combine(TestContext.CurrentContext.TestDirectory, "integrationTestLogDir_no_file_name");
196-
if (Directory.Exists(logDir)) Directory.Delete(logDir, true);
197-
Directory.CreateDirectory(logDir);
198-
var (log, repo) = ArrangeLogger("log4net.no_file_name.config");
199-
log.Info("Test entry with no file name");
200-
repo.Shutdown();
201-
// Assert: exactly one log file was created in the directory
202-
var files = Directory.GetFiles(logDir, "*", SearchOption.AllDirectories);
203-
Assert.That(files.Length, Is.EqualTo(1), "Should create exactly one log file");
204-
var fileName = Path.GetFileName(files[0]);
205-
TestContext.Out.WriteLine($"Created file: {fileName}");
206-
// Assert the file name matches the date pattern yyyy-MM-dd.log
207-
string todayPattern = DateTime.Now.ToString("yyyy-MM-dd") + ".log";
208-
Assert.That(fileName, Is.EqualTo(todayPattern), $"File name should match pattern: {todayPattern}");
217+
DirectoryInfo logDir = CreateLogDirectory("integrationTestLogDir_no_file_name");
218+
(ILog log, ILoggerRepository repo) = ArrangeLogger("log4net.no_file_name.config");
219+
log.Info("Test entry with no file name");
220+
repo.Shutdown();
221+
// Assert: exactly one log file was created in the directory
222+
FileInfo[] files = logDir.GetFiles("*", SearchOption.AllDirectories);
223+
Assert.That(files, Has.Length.EqualTo(1), "Should create exactly one log file");
224+
TestContext.Out.WriteLine($"Created file: {files[0].Name}");
225+
// Assert the file name matches the date pattern yyyy-MM-dd.log
226+
string todayPattern = DateTime.Now.ToString("yyyy-MM-dd") + ".log";
227+
Assert.That(files[0].Name, Is.EqualTo(todayPattern), $"File name should match pattern: {todayPattern}");
228+
}
229+
230+
private static DirectoryInfo CreateLogDirectory(string name)
231+
{
232+
DirectoryInfo logDir = new(Path.Combine(TestContext.CurrentContext.TestDirectory, name));
233+
if (logDir.Exists)
234+
{
235+
logDir.Delete(true);
236+
}
237+
logDir.Create();
238+
return logDir;
209239
}
210240

211241
private const string TestLogFilePrefix = "integrationTestLogFile";
212242
private const string TestLogDirectoryPrefix = "integrationTestLogDir";
213243

214244
private static void RemoveDirsFromPreviousRuns()
215245
{
216-
List<string> directoriesFromPreviousRuns =
217-
Directory.EnumerateDirectories(TestContext.CurrentContext.TestDirectory)
218-
.Where(dirPath => Path.GetFileName(dirPath).StartsWith(TestLogDirectoryPrefix, StringComparison.InvariantCultureIgnoreCase))
219-
.ToList();
220-
directoriesFromPreviousRuns.ForEach(d => Directory.Delete(d, true));
246+
List<DirectoryInfo> directoriesFromPreviousRuns = new DirectoryInfo(TestContext.CurrentContext.TestDirectory)
247+
.EnumerateDirectories()
248+
.Where(directory => directory.Name.StartsWith(TestLogDirectoryPrefix, StringComparison.InvariantCultureIgnoreCase))
249+
.ToList();
250+
directoriesFromPreviousRuns.ForEach(d => d.Delete(true));
221251
}
222252

223253
private static void RemoveFilesFromPreviousRuns()
224254
{
225-
List<string> filesFromPreviousRuns =
226-
Directory.EnumerateFiles(TestContext.CurrentContext.TestDirectory)
227-
.Where(filePath => Path.GetFileName(filePath).StartsWith(TestLogFilePrefix, StringComparison.InvariantCultureIgnoreCase))
228-
.ToList();
229-
filesFromPreviousRuns.ForEach(File.Delete);
255+
List<FileInfo> filesFromPreviousRuns = new DirectoryInfo(TestContext.CurrentContext.TestDirectory)
256+
.EnumerateFiles()
257+
.Where(filePath => filePath.Name.StartsWith(TestLogFilePrefix, StringComparison.InvariantCultureIgnoreCase))
258+
.ToList();
259+
filesFromPreviousRuns.ForEach(file => file.Delete());
230260
}
231261

232262
private static string GetConfigPath(string configFile)
233263
=> Path.Combine(TestContext.CurrentContext.TestDirectory, "Integration", configFile);
234264

235-
private static (ILog log, log4net.Repository.ILoggerRepository repo) ArrangeLogger(string configFile)
265+
private static (ILog log, ILoggerRepository repo) ArrangeLogger(string configFile)
236266
{
237-
string configPath = GetConfigPath(configFile);
238-
var repo = LogManager.CreateRepository(Guid.NewGuid().ToString());
239-
XmlConfigurator.Configure(repo, new FileInfo(configPath));
240-
var log = LogManager.GetLogger(repo.Name, "IntegrationTestLogger");
241-
return (log, repo);
267+
string configPath = GetConfigPath(configFile);
268+
ILoggerRepository repo = LogManager.CreateRepository(Guid.NewGuid().ToString());
269+
XmlConfigurator.Configure(repo, new FileInfo(configPath));
270+
ILog log = LogManager.GetLogger(repo.Name, "IntegrationTestLogger");
271+
return (log, repo);
242272
}
243273
}
244-
}
274+
}

0 commit comments

Comments
 (0)