mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-03-22 10:34:30 +08:00
- 为 AsyncLogAppender 添加完整功能测试,包括异步写入、缓冲区管理、并发处理等场景 - 为 CachedLoggerFactory 添加缓存机制测试,验证相同名称和级别的日志记录器重用 - 为 CompositeFilter 添加过滤器组合测试,验证多个过滤器的逻辑组合功能 - 为 CompositeLogger 添加复合日志记录器测试,验证多追加器写入和级别过滤功能 - 为 ConsoleAppender 添加控制台追加器测试,验证格式化输出和过滤器支持 - 为 DefaultLogFormatter 添加默认格式化器测试,验证基本格式化和异常处理功能 - 为 FileAppender 添加文件追加器测试,验证文件写入、目录创建和追加模式功能 - 为 JsonLogFormatter 添加 JSON 格式化器测试,验证 JSON 输出和属性序列化功能 - 为 LogContext 添加日志上下文测试,验证属性推送和作用域管理功能
219 lines
6.4 KiB
C#
219 lines
6.4 KiB
C#
using GFramework.Core.Abstractions.logging;
|
||
using GFramework.Core.logging.appenders;
|
||
using NUnit.Framework;
|
||
|
||
namespace GFramework.Core.Tests.logging;
|
||
|
||
/// <summary>
|
||
/// 测试 AsyncLogAppender 的功能和行为
|
||
/// </summary>
|
||
[TestFixture]
|
||
public class AsyncLogAppenderTests
|
||
{
|
||
[Test]
|
||
public void Constructor_WithNullInnerAppender_ShouldThrowArgumentNullException()
|
||
{
|
||
Assert.Throws<ArgumentNullException>(() => new AsyncLogAppender(null!));
|
||
}
|
||
|
||
[Test]
|
||
public void Constructor_WithInvalidBufferSize_ShouldThrowArgumentException()
|
||
{
|
||
var innerAppender = new TestAppender();
|
||
Assert.Throws<ArgumentException>(() => new AsyncLogAppender(innerAppender, bufferSize: 0));
|
||
Assert.Throws<ArgumentException>(() => new AsyncLogAppender(innerAppender, bufferSize: -1));
|
||
}
|
||
|
||
[Test]
|
||
public void Append_ShouldNotBlock()
|
||
{
|
||
var innerAppender = new SlowAppender(delayMs: 100);
|
||
using var asyncAppender = new AsyncLogAppender(innerAppender, bufferSize: 1000);
|
||
|
||
var startTime = DateTime.Now;
|
||
for (int i = 0; i < 10; i++)
|
||
{
|
||
var entry = new LogEntry(DateTime.Now, LogLevel.Info, "TestLogger", $"Message {i}", null, null);
|
||
asyncAppender.Append(entry);
|
||
}
|
||
|
||
var elapsed = (DateTime.Now - startTime).TotalMilliseconds;
|
||
|
||
// 异步写入应该非常快(< 100ms),不应该等待内部 Appender
|
||
Assert.That(elapsed, Is.LessThan(100));
|
||
}
|
||
|
||
[Test]
|
||
public void Append_ShouldEventuallyWriteToInnerAppender()
|
||
{
|
||
var innerAppender = new TestAppender();
|
||
using (var asyncAppender = new AsyncLogAppender(innerAppender, bufferSize: 1000))
|
||
{
|
||
for (int i = 0; i < 10; i++)
|
||
{
|
||
var entry = new LogEntry(DateTime.Now, LogLevel.Info, "TestLogger", $"Message {i}", null, null);
|
||
asyncAppender.Append(entry);
|
||
}
|
||
|
||
asyncAppender.Flush();
|
||
}
|
||
|
||
Assert.That(innerAppender.Entries.Count, Is.EqualTo(10));
|
||
}
|
||
|
||
[Test]
|
||
public void Flush_ShouldWaitForAllEntriesToBeProcessed()
|
||
{
|
||
var innerAppender = new TestAppender();
|
||
using var asyncAppender = new AsyncLogAppender(innerAppender, bufferSize: 1000);
|
||
|
||
for (int i = 0; i < 100; i++)
|
||
{
|
||
var entry = new LogEntry(DateTime.Now, LogLevel.Info, "TestLogger", $"Message {i}", null, null);
|
||
asyncAppender.Append(entry);
|
||
}
|
||
|
||
asyncAppender.Flush();
|
||
|
||
Assert.That(innerAppender.Entries.Count, Is.EqualTo(100));
|
||
}
|
||
|
||
[Test]
|
||
public void Dispose_ShouldProcessRemainingEntries()
|
||
{
|
||
var innerAppender = new TestAppender();
|
||
using (var asyncAppender = new AsyncLogAppender(innerAppender, bufferSize: 1000))
|
||
{
|
||
for (int i = 0; i < 50; i++)
|
||
{
|
||
var entry = new LogEntry(DateTime.Now, LogLevel.Info, "TestLogger", $"Message {i}", null, null);
|
||
asyncAppender.Append(entry);
|
||
}
|
||
} // Dispose 会等待所有日志处理完成
|
||
|
||
Assert.That(innerAppender.Entries.Count, Is.EqualTo(50));
|
||
}
|
||
|
||
[Test]
|
||
public void Append_AfterDispose_ShouldThrowObjectDisposedException()
|
||
{
|
||
var innerAppender = new TestAppender();
|
||
var asyncAppender = new AsyncLogAppender(innerAppender);
|
||
asyncAppender.Dispose();
|
||
|
||
var entry = new LogEntry(DateTime.Now, LogLevel.Info, "TestLogger", "Test", null, null);
|
||
|
||
Assert.Throws<ObjectDisposedException>(() => asyncAppender.Append(entry));
|
||
}
|
||
|
||
[Test]
|
||
public void PendingCount_ShouldReflectQueuedEntries()
|
||
{
|
||
var innerAppender = new SlowAppender(delayMs: 50);
|
||
using var asyncAppender = new AsyncLogAppender(innerAppender, bufferSize: 1000);
|
||
|
||
for (int i = 0; i < 10; i++)
|
||
{
|
||
var entry = new LogEntry(DateTime.Now, LogLevel.Info, "TestLogger", $"Message {i}", null, null);
|
||
asyncAppender.Append(entry);
|
||
}
|
||
|
||
// 应该有一些待处理的条目
|
||
Assert.That(asyncAppender.PendingCount, Is.GreaterThanOrEqualTo(0));
|
||
}
|
||
|
||
[Test]
|
||
public async Task Append_FromMultipleThreads_ShouldHandleConcurrency()
|
||
{
|
||
var innerAppender = new TestAppender();
|
||
using var asyncAppender = new AsyncLogAppender(innerAppender, bufferSize: 10000);
|
||
|
||
var tasks = new Task[10];
|
||
for (int t = 0; t < 10; t++)
|
||
{
|
||
int threadId = t;
|
||
tasks[t] = Task.Run(() =>
|
||
{
|
||
for (int i = 0; i < 100; i++)
|
||
{
|
||
var entry = new LogEntry(DateTime.Now, LogLevel.Info, "TestLogger",
|
||
$"Thread {threadId} Message {i}", null, null);
|
||
asyncAppender.Append(entry);
|
||
}
|
||
});
|
||
}
|
||
|
||
await Task.WhenAll(tasks);
|
||
asyncAppender.Flush();
|
||
|
||
Assert.That(innerAppender.Entries.Count, Is.EqualTo(1000));
|
||
}
|
||
|
||
[Test]
|
||
public void Append_WhenInnerAppenderThrows_ShouldNotCrash()
|
||
{
|
||
var innerAppender = new ThrowingAppender();
|
||
using var asyncAppender = new AsyncLogAppender(innerAppender, bufferSize: 1000);
|
||
|
||
// 即使内部 Appender 抛出异常,也不应该影响调用线程
|
||
Assert.DoesNotThrow(() =>
|
||
{
|
||
for (int i = 0; i < 10; i++)
|
||
{
|
||
var entry = new LogEntry(DateTime.Now, LogLevel.Info, "TestLogger", $"Message {i}", null, null);
|
||
asyncAppender.Append(entry);
|
||
}
|
||
});
|
||
|
||
Thread.Sleep(100); // 等待后台处理
|
||
}
|
||
|
||
// 辅助测试类
|
||
private class TestAppender : ILogAppender
|
||
{
|
||
public List<LogEntry> Entries { get; } = new();
|
||
|
||
public void Append(LogEntry entry)
|
||
{
|
||
lock (Entries)
|
||
{
|
||
Entries.Add(entry);
|
||
}
|
||
}
|
||
|
||
public void Flush()
|
||
{
|
||
}
|
||
}
|
||
|
||
private class SlowAppender : ILogAppender
|
||
{
|
||
private readonly int _delayMs;
|
||
|
||
public SlowAppender(int delayMs)
|
||
{
|
||
_delayMs = delayMs;
|
||
}
|
||
|
||
public void Append(LogEntry entry)
|
||
{
|
||
Thread.Sleep(_delayMs);
|
||
}
|
||
|
||
public void Flush()
|
||
{
|
||
}
|
||
}
|
||
|
||
private class ThrowingAppender : ILogAppender
|
||
{
|
||
public void Append(LogEntry entry)
|
||
{
|
||
throw new InvalidOperationException("Test exception");
|
||
}
|
||
|
||
public void Flush()
|
||
{
|
||
}
|
||
}
|
||
} |