| File: LogCollector.cs | Web Access |
| Project: src\test\Libraries\Microsoft.Extensions.Caching.Hybrid.Tests\Microsoft.Extensions.Caching.Hybrid.Tests.csproj (Microsoft.Extensions.Caching.Hybrid.Tests) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using Microsoft.Extensions.Logging; using Xunit.Abstractions; namespace Microsoft.Extensions.Caching.Hybrid.Tests; // dummy implementation for collecting test output internal class LogCollector : ILoggerProvider { private readonly List<(string categoryName, LogLevel logLevel, EventId eventId, Exception? exception, string message)> _items = []; public (string categoryName, LogLevel logLevel, EventId eventId, Exception? exception, string message)[] ToArray() { lock (_items) { return _items.ToArray(); } } public void WriteTo(ITestOutputHelper log) { lock (_items) { foreach (var logItem in _items) { var errSuffix = logItem.exception is null ? "" : $" - {logItem.exception.Message}"; log.WriteLine($"{logItem.categoryName} {logItem.eventId}: {logItem.message}{errSuffix}"); } } } public async Task WaitForLogsAsync(int[] expectedErrorIds, TimeSpan timeout) { var deadline = DateTime.UtcNow + timeout; while (DateTime.UtcNow < deadline) { lock (_items) { // Check for exact match to avoid race conditions with AssertErrors if (_items.Count == expectedErrorIds.Length) { bool match = true; for (int i = 0; i < expectedErrorIds.Length; i++) { if (_items[i].eventId.Id != expectedErrorIds[i]) { match = false; break; } } if (match) { return; // Success } } // If we have more logs than expected, something unexpected happened // Stop waiting to let AssertErrors report the mismatch if (_items.Count > expectedErrorIds.Length) { return; } } await Task.Delay(10); } // Timeout reached, will fail in AssertErrors } public void AssertErrors(int[] errorIds) { lock (_items) { bool same; if (errorIds.Length == _items.Count) { int index = 0; same = true; foreach (var item in _items) { if (item.eventId.Id != errorIds[index++]) { same = false; break; } } } else { same = false; } if (!same) { // we expect this to fail, then Assert.Equal(string.Join(",", errorIds), string.Join(",", _items.Select(static x => x.eventId.Id))); } } } ILogger ILoggerProvider.CreateLogger(string categoryName) => new TypedLogCollector(this, categoryName); void IDisposable.Dispose() { // nothing to do } private sealed class TypedLogCollector(LogCollector parent, string categoryName) : ILogger { IDisposable? ILogger.BeginScope<TState>(TState state) => null; bool ILogger.IsEnabled(LogLevel logLevel) => true; void ILogger.Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter) { lock (parent._items) { parent._items.Add((categoryName, logLevel, eventId, exception, formatter(state, exception))); } } } }