diff --git a/.github/workflows/device-tests-android.yml b/.github/workflows/device-tests-android.yml index 953dab0a49..9da13e57be 100644 --- a/.github/workflows/device-tests-android.yml +++ b/.github/workflows/device-tests-android.yml @@ -59,7 +59,8 @@ jobs: matrix: tfm: [net9.0] # We run against both an older and a newer API - api-level: [27, 33] + # targetSdk must be 34+ for new apps and app updates as of August 31, 2024. + api-level: [34, 36] env: DOTNET_CLI_TELEMETRY_OPTOUT: 1 DOTNET_NOLOGO: 1 diff --git a/CHANGELOG.md b/CHANGELOG.md index df552003c7..e6623f1d50 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ - Sentry now decompresses Request bodies in ASP.NET Core when RequestDecompression middleware is enabled ([#4315](https://github.com/getsentry/sentry-dotnet/pull/4315)) - Custom ISentryEventProcessors are now run for native iOS events ([#4318](https://github.com/getsentry/sentry-dotnet/pull/4318)) - Crontab validation when capturing checkins ([#4314](https://github.com/getsentry/sentry-dotnet/pull/4314)) +- Source context for class libraries when running on Android in Release mode ([#4294](https://github.com/getsentry/sentry-dotnet/pull/4294)) - Fixed an issue with the way Sentry detects build settings. This was causing Sentry to produce code that could fail at runtime in AOT compiled applications. ([#4333](https://github.com/getsentry/sentry-dotnet/pull/4333)) - Native AOT: link to static `lzma` on Linux/MUSL ([#4326](https://github.com/getsentry/sentry-dotnet/pull/4326)) - AppDomain.CurrentDomain.ProcessExit hook is now removed on shutdown ([#4323](https://github.com/getsentry/sentry-dotnet/pull/4323)) diff --git a/src/Sentry.Android.AssemblyReader/V2/AndroidAssemblyStoreReaderV2.cs b/src/Sentry.Android.AssemblyReader/V2/AndroidAssemblyStoreReaderV2.cs index f88e0ca237..e49fbf7147 100644 --- a/src/Sentry.Android.AssemblyReader/V2/AndroidAssemblyStoreReaderV2.cs +++ b/src/Sentry.Android.AssemblyReader/V2/AndroidAssemblyStoreReaderV2.cs @@ -100,11 +100,19 @@ public static bool TryReadStore(string inputFile, IList supportedAbis, D return assembly; } + // If the assembly name ends with .dll or .exe, try to find it without the extension. if ((IsFileType(".dll") || IsFileType(".exe")) && FindBestAssembly(name[..^4], out assembly)) { return assembly; } + // Conversely, if there is no extension, try with the dll extension (sometimes required for class libraries). + // See: https://github.com/getsentry/sentry-dotnet/issues/4278#issuecomment-2986009125 + if (!IsFileType(".dll") && !IsFileType(".exe") && FindBestAssembly(name + ".dll", out assembly)) + { + return assembly; + } + return null; bool IsFileType(string extension) @@ -119,10 +127,12 @@ private bool FindBestAssembly(string name, out ExplorerStoreItem? explorerAssemb { if (explorer.AssembliesByName?.TryGetValue(name, out var assembly) is true) { + _logger?.Invoke("Found best assembly {0} in APK AssemblyStore for target arch {1}", name, explorer.TargetArch); explorerAssembly = new(explorer, assembly); return true; } } + _logger?.Invoke("No best assembly for {0} in APK AssemblyStore", name); explorerAssembly = null; return false; } diff --git a/src/Sentry.Android.AssemblyReader/V2/AssemblyStoreExplorer.cs b/src/Sentry.Android.AssemblyReader/V2/AssemblyStoreExplorer.cs index de2148ddeb..424109bcee 100644 --- a/src/Sentry.Android.AssemblyReader/V2/AssemblyStoreExplorer.cs +++ b/src/Sentry.Android.AssemblyReader/V2/AssemblyStoreExplorer.cs @@ -33,6 +33,7 @@ private AssemblyStoreExplorer(Stream storeStream, string path, DebugLogger? logg { foreach (var item in Assemblies) { + logger?.Invoke("Assembly {0} indexed from AssemblyStore {1}", item.Name, path); dict.Add(item.Name, item); } } diff --git a/test/Sentry.Maui.Device.TestApp/Sentry.Maui.Device.TestApp.csproj b/test/Sentry.Maui.Device.TestApp/Sentry.Maui.Device.TestApp.csproj index d6d124e287..15beeb7e92 100644 --- a/test/Sentry.Maui.Device.TestApp/Sentry.Maui.Device.TestApp.csproj +++ b/test/Sentry.Maui.Device.TestApp/Sentry.Maui.Device.TestApp.csproj @@ -100,6 +100,9 @@ + diff --git a/test/Sentry.Maui.Device.TestApp/Startup.cs b/test/Sentry.Maui.Device.TestApp/Startup.cs index 9f3e614d9c..ad93281b3c 100644 --- a/test/Sentry.Maui.Device.TestApp/Startup.cs +++ b/test/Sentry.Maui.Device.TestApp/Startup.cs @@ -14,7 +14,7 @@ public static MauiApp CreateMauiApp() [ typeof(Sentry.Tests.SentrySdkTests).Assembly, typeof(Sentry.Extensions.Logging.Tests.LogLevelExtensionsTests).Assembly, - typeof(Sentry.Maui.Tests.SentryMauiOptionsTests).Assembly, + // typeof(Sentry.Maui.Tests.SentryMauiOptionsTests).Assembly, #if NET9_0_OR_GREATER typeof(Sentry.Maui.CommunityToolkit.Mvvm.Tests.MauiCommunityToolkitMvvmEventsBinderTests).Assembly, #endif diff --git a/test/Sentry.Tests/Internals/Http/CachingTransportTests.cs b/test/Sentry.Tests/Internals/Http/CachingTransportTests.cs index e903b7f3ca..8f5d821a1c 100644 --- a/test/Sentry.Tests/Internals/Http/CachingTransportTests.cs +++ b/test/Sentry.Tests/Internals/Http/CachingTransportTests.cs @@ -3,31 +3,38 @@ namespace Sentry.Tests.Internals.Http; -public class CachingTransportTests +public class CachingTransportTests : IDisposable { private readonly TestOutputDiagnosticLogger _logger; + private readonly TempDirectory _cacheDirectory; + private readonly SentryOptions _options; public CachingTransportTests(ITestOutputHelper testOutputHelper) { _logger = Substitute.ForPartsOf(testOutputHelper); - } - - [Fact] - public async Task WithAttachment() - { - // Arrange - using var cacheDirectory = new TempDirectory(); - var options = new SentryOptions + _cacheDirectory = new TempDirectory(); + _options = new SentryOptions { Dsn = ValidDsn, DiagnosticLogger = _logger, Debug = true, - CacheDirectoryPath = cacheDirectory.Path + CacheDirectoryPath = _cacheDirectory.Path, + NetworkStatusListener = FakeReliableNetworkStatusListener.Instance }; + } + + public void Dispose() + { + _cacheDirectory.Dispose(); + } + [Fact] + public async Task WithAttachment() + { + // Arrange string httpContent = null; Exception exception = null; - var innerTransport = new HttpTransport(options, new HttpClient(new CallbackHttpClientHandler(async message => + var innerTransport = new HttpTransport(_options, new HttpClient(new CallbackHttpClientHandler(async message => { try { @@ -39,7 +46,7 @@ public async Task WithAttachment() } }))); - await using var transport = CachingTransport.Create(innerTransport, options, startWorker: false); + await using var transport = CachingTransport.Create(innerTransport, _options, startWorker: false); const string attachmentContent = "test-attachment"; var tempFile = Path.GetTempFileName(); @@ -76,17 +83,8 @@ public async Task WithAttachment() public async Task WorksInBackground() { // Arrange - using var cacheDirectory = new TempDirectory(); - var options = new SentryOptions - { - Dsn = ValidDsn, - DiagnosticLogger = _logger, - Debug = true, - CacheDirectoryPath = cacheDirectory.Path - }; - using var innerTransport = new FakeTransport(); - await using var transport = CachingTransport.Create(innerTransport, options); + await using var transport = CachingTransport.Create(innerTransport, _options); // Attach to the EnvelopeSent event. We'll wait for that below. // ReSharper disable once AccessToDisposedClosure @@ -108,16 +106,6 @@ public async Task WorksInBackground() public async Task ShouldNotLogOperationCanceledExceptionWhenIsCancellationRequested() { // Arrange - using var cacheDirectory = new TempDirectory(); - - var options = new SentryOptions - { - Dsn = ValidDsn, - DiagnosticLogger = _logger, - CacheDirectoryPath = cacheDirectory.Path, - Debug = true - }; - var capturingCompletionSource = new TaskCompletionSource(); var cancelingCompletionSource = new TaskCompletionSource(); @@ -132,7 +120,7 @@ public async Task ShouldNotLogOperationCanceledExceptionWhenIsCancellationReques throw new OperationCanceledException(); }); - await using var transport = CachingTransport.Create(innerTransport, options); + await using var transport = CachingTransport.Create(innerTransport, _options); using var envelope = Envelope.FromEvent(new SentryEvent()); await transport.SendEnvelopeAsync(envelope); @@ -151,7 +139,6 @@ public async Task ShouldNotLogOperationCanceledExceptionWhenIsCancellationReques public async Task ShouldLogOperationCanceledExceptionWhenNotIsCancellationRequested() { // Arrange - using var cacheDirectory = new TempDirectory(); var loggerCompletionSource = new TaskCompletionSource(); _logger @@ -162,14 +149,6 @@ public async Task ShouldLogOperationCanceledExceptionWhenNotIsCancellationReques Arg.Any())) .Do(_ => loggerCompletionSource.SetResult(null)); - var options = new SentryOptions - { - Dsn = ValidDsn, - DiagnosticLogger = _logger, - CacheDirectoryPath = cacheDirectory.Path, - Debug = true - }; - var innerTransport = Substitute.For(); var capturingCompletionSource = new TaskCompletionSource(); @@ -181,7 +160,7 @@ public async Task ShouldLogOperationCanceledExceptionWhenNotIsCancellationReques return new OperationCanceledException(); }); - await using var transport = CachingTransport.Create(innerTransport, options); + await using var transport = CachingTransport.Create(innerTransport, _options); using var envelope = Envelope.FromEvent(new SentryEvent()); await transport.SendEnvelopeAsync(envelope); @@ -196,17 +175,8 @@ public async Task ShouldLogOperationCanceledExceptionWhenNotIsCancellationReques public async Task EnvelopeReachesInnerTransport() { // Arrange - using var cacheDirectory = new TempDirectory(); - var options = new SentryOptions - { - Dsn = ValidDsn, - DiagnosticLogger = _logger, - Debug = true, - CacheDirectoryPath = cacheDirectory.Path - }; - using var innerTransport = new FakeTransport(); - await using var transport = CachingTransport.Create(innerTransport, options, startWorker: false); + await using var transport = CachingTransport.Create(innerTransport, _options, startWorker: false); // Act using var envelope = Envelope.FromEvent(new SentryEvent()); @@ -222,46 +192,27 @@ public async Task EnvelopeReachesInnerTransport() public async Task MaintainsLimit() { // Arrange - using var cacheDirectory = new TempDirectory(); - var options = new SentryOptions - { - Dsn = ValidDsn, - DiagnosticLogger = _logger, - Debug = true, - CacheDirectoryPath = cacheDirectory.Path, - MaxCacheItems = 2 - }; - var innerTransport = Substitute.For(); - await using var transport = CachingTransport.Create(innerTransport, options, startWorker: false); + await using var transport = CachingTransport.Create(innerTransport, _options, startWorker: false); // Act - for (var i = 0; i < options.MaxCacheItems + 2; i++) + for (var i = 0; i < _options.MaxCacheItems + 2; i++) { using var envelope = Envelope.FromEvent(new SentryEvent()); await transport.SendEnvelopeAsync(envelope); } // Assert - transport.GetCacheLength().Should().BeLessOrEqualTo(options.MaxCacheItems); + transport.GetCacheLength().Should().BeLessOrEqualTo(_options.MaxCacheItems); } [Fact] public async Task AwareOfExistingFiles() { // Arrange - using var cacheDirectory = new TempDirectory(); - var options = new SentryOptions - { - Dsn = ValidDsn, - DiagnosticLogger = _logger, - Debug = true, - CacheDirectoryPath = cacheDirectory.Path - }; - // Send some envelopes with a failing transport to make sure they all stay in cache var initialInnerTransport = new FakeFailingTransport(); - await using var initialTransport = CachingTransport.Create(initialInnerTransport, options, startWorker: false); + await using var initialTransport = CachingTransport.Create(initialInnerTransport, _options, startWorker: false); for (var i = 0; i < 3; i++) { @@ -276,7 +227,7 @@ public async Task AwareOfExistingFiles() // Creating the transport should move files from processing during initialization. using var innerTransport = new FakeTransport(); - await using var transport = CachingTransport.Create(innerTransport, options, startWorker: false); + await using var transport = CachingTransport.Create(innerTransport, _options, startWorker: false); // Flushing the worker will ensure all files are processed. await transport.FlushAsync(); @@ -289,55 +240,38 @@ public async Task AwareOfExistingFiles() public async Task Handle_Malformed_Envelopes_Gracefully() { // Arrange - using var cacheDirectory = new TempDirectory(); - var options = new SentryOptions - { - Dsn = ValidDsn, - DiagnosticLogger = _logger, - Debug = true, - CacheDirectoryPath = cacheDirectory.Path, - }; var cacheDirectoryPath = - options.TryGetProcessSpecificCacheDirectoryPath() ?? + _options.TryGetProcessSpecificCacheDirectoryPath() ?? throw new InvalidOperationException("Cache directory or DSN is not set."); var processingDirectoryPath = Path.Combine(cacheDirectoryPath, "__processing"); var fileName = $"{Guid.NewGuid()}.envelope"; var filePath = Path.Combine(processingDirectoryPath, fileName); - options.FileSystem.CreateDirectory(processingDirectoryPath); // Create the processing directory - options.FileSystem.CreateFileForWriting(filePath, out var file); + _options.FileSystem.CreateDirectory(processingDirectoryPath); // Create the processing directory + _options.FileSystem.CreateFileForWriting(filePath, out var file); file.Dispose(); // Make a malformed envelope... just an empty file - options.FileSystem.FileExists(filePath).Should().BeTrue(); + _options.FileSystem.FileExists(filePath).Should().BeTrue(); // Act using var innerTransport = new FakeTransport(); - await using var transport = CachingTransport.Create(innerTransport, options, startWorker: false); + await using var transport = CachingTransport.Create(innerTransport, _options, startWorker: false); await transport.FlushAsync(); // Flush the worker to process // Assert - options.FileSystem.FileExists(filePath).Should().BeFalse(); + _options.FileSystem.FileExists(filePath).Should().BeFalse(); } [Fact] public async Task NonTransientExceptionShouldLog() { // Arrange - using var cacheDirectory = new TempDirectory(); - var options = new SentryOptions - { - Dsn = ValidDsn, - DiagnosticLogger = _logger, - Debug = true, - CacheDirectoryPath = cacheDirectory.Path - }; - var innerTransport = Substitute.For(); innerTransport .SendEnvelopeAsync(Arg.Any(), Arg.Any()) .Returns(_ => Task.FromException(new Exception("The Message"))); - await using var transport = CachingTransport.Create(innerTransport, options, startWorker: false); + await using var transport = CachingTransport.Create(innerTransport, _options, startWorker: false); // Act using var envelope = Envelope.FromEvent(new SentryEvent()); @@ -358,15 +292,6 @@ public async Task NonTransientExceptionShouldLog() public async Task DoesNotRetryOnNonTransientExceptions() { // Arrange - using var cacheDirectory = new TempDirectory(); - var options = new SentryOptions - { - Dsn = ValidDsn, - DiagnosticLogger = _logger, - Debug = true, - CacheDirectoryPath = cacheDirectory.Path - }; - var innerTransport = Substitute.For(); var isFailing = true; @@ -378,7 +303,7 @@ public async Task DoesNotRetryOnNonTransientExceptions() ? Task.FromException(new InvalidOperationException()) : Task.CompletedTask); - await using var transport = CachingTransport.Create(innerTransport, options, startWorker: false); + await using var transport = CachingTransport.Create(innerTransport, _options, startWorker: false); // Act for (var i = 0; i < 3; i++) @@ -403,15 +328,7 @@ public async Task DoesNotRetryOnNonTransientExceptions() public async Task RecordsDiscardedEventOnNonTransientExceptions() { // Arrange - using var cacheDirectory = new TempDirectory(); - var options = new SentryOptions - { - Dsn = ValidDsn, - DiagnosticLogger = _logger, - Debug = true, - CacheDirectoryPath = cacheDirectory.Path, - ClientReportRecorder = Substitute.For() - }; + _options.ClientReportRecorder = Substitute.For(); var innerTransport = Substitute.For(); @@ -419,7 +336,7 @@ public async Task RecordsDiscardedEventOnNonTransientExceptions() .SendEnvelopeAsync(Arg.Any(), Arg.Any()) .Returns(_ => Task.FromException(new InvalidOperationException())); - await using var transport = CachingTransport.Create(innerTransport, options, startWorker: false); + await using var transport = CachingTransport.Create(innerTransport, _options, startWorker: false); // Act using var envelope = Envelope.FromEvent(new SentryEvent()); @@ -427,7 +344,7 @@ public async Task RecordsDiscardedEventOnNonTransientExceptions() await transport.FlushAsync(); // Test that we recorded the discarded event - options.ClientReportRecorder.Received(1) + _options.ClientReportRecorder.Received(1) .RecordDiscardedEvent(DiscardReason.CacheOverflow, DataCategory.Error); } @@ -435,22 +352,13 @@ public async Task RecordsDiscardedEventOnNonTransientExceptions() public async Task RoundtripsClientReports() { // Arrange - using var cacheDirectory = new TempDirectory(); - var options = new SentryOptions - { - Dsn = ValidDsn, - DiagnosticLogger = _logger, - Debug = true, - CacheDirectoryPath = cacheDirectory.Path - }; - var timestamp = DateTimeOffset.UtcNow; var clock = new MockClock(timestamp); - var recorder = new ClientReportRecorder(options, clock); - options.ClientReportRecorder = recorder; + var recorder = new ClientReportRecorder(_options, clock); + _options.ClientReportRecorder = recorder; var innerTransport = new FakeTransportWithRecorder(recorder); - await using var transport = CachingTransport.Create(innerTransport, options, startWorker: false); + await using var transport = CachingTransport.Create(innerTransport, _options, startWorker: false); // Act recorder.RecordDiscardedEvent(DiscardReason.BeforeSend, DataCategory.Error); @@ -481,18 +389,9 @@ public async Task RoundtripsClientReports() public async Task RestoresDiscardedEventCounts() { // Arrange - using var cacheDirectory = new TempDirectory(); - var options = new SentryOptions - { - Dsn = ValidDsn, - DiagnosticLogger = _logger, - Debug = true, - CacheDirectoryPath = cacheDirectory.Path - }; - - var recorder = (ClientReportRecorder)options.ClientReportRecorder; + var recorder = (ClientReportRecorder)_options.ClientReportRecorder; var innerTransport = new FakeTransportWithRecorder(recorder); - await using var transport = CachingTransport.Create(innerTransport, options, + await using var transport = CachingTransport.Create(innerTransport, _options, startWorker: false, failStorage: true); // some arbitrary discarded events ahead of time @@ -534,17 +433,9 @@ await Assert.ThrowsAnyAsync(async () => public async Task TestNetworkException(Exception exception) { // Arrange - network unavailable - using var cacheDirectory = new TempDirectory(); var pingHost = Substitute.For(); pingHost.IsAvailableAsync(Arg.Any()).Returns(Task.FromResult(true)); - var options = new SentryOptions - { - Dsn = ValidDsn, - DiagnosticLogger = _logger, - Debug = true, - CacheDirectoryPath = cacheDirectory.Path, - NetworkStatusListener = new PollingNetworkStatusListener(pingHost) - }; + _options.NetworkStatusListener = new PollingNetworkStatusListener(pingHost); var receivedException = new Exception(); var innerTransport = Substitute.For(); @@ -553,7 +444,7 @@ public async Task TestNetworkException(Exception exception) .SendEnvelopeAsync(Arg.Any(), Arg.Any()) .Returns(_ => Task.FromException(exception)); - await using var transport = CachingTransport.Create(innerTransport, options, startWorker: false); + await using var transport = CachingTransport.Create(innerTransport, _options, startWorker: false); using var envelope = Envelope.FromEvent(new SentryEvent()); await transport.SendEnvelopeAsync(envelope); @@ -570,7 +461,7 @@ public async Task TestNetworkException(Exception exception) // Assert receivedException.Should().Be(exception); - var files = options.FileSystem.EnumerateFiles(cacheDirectory.Path, "*", SearchOption.AllDirectories).ToArray(); + var files = _options.FileSystem.EnumerateFiles(_options.CacheDirectoryPath!, "*", SearchOption.AllDirectories).ToArray(); files.Should().NotBeEmpty(); // Arrange - network recovery @@ -584,7 +475,7 @@ public async Task TestNetworkException(Exception exception) // Assert receivedException.Should().Be(exception); - files = options.FileSystem.EnumerateFiles(cacheDirectory.Path, "*", SearchOption.AllDirectories).ToArray(); + files = _options.FileSystem.EnumerateFiles(_options.CacheDirectoryPath, "*", SearchOption.AllDirectories).ToArray(); files.Should().NotContain(file => file.Contains("__processing", StringComparison.OrdinalIgnoreCase)); } @@ -597,18 +488,10 @@ public async Task TransportSendsWithoutWaitingWhenNetworkIsOnline() listener.WaitForNetworkOnlineAsync(Arg.Any()) .Throws(new Exception("We should not be waiting for the network status if we know it's online.")); - using var cacheDirectory = new TempDirectory(); - var options = new SentryOptions - { - Dsn = ValidDsn, - DiagnosticLogger = _logger, - Debug = true, - CacheDirectoryPath = cacheDirectory.Path, - NetworkStatusListener = listener - }; + _options.NetworkStatusListener = listener; using var innerTransport = new FakeTransport(); - await using var transport = CachingTransport.Create(innerTransport, options, startWorker: false); + await using var transport = CachingTransport.Create(innerTransport, _options, startWorker: false); // Act using var envelope = Envelope.FromEvent(new SentryEvent()); @@ -634,18 +517,10 @@ public async Task TransportPausesWhenNetworkIsOffline() return Task.Delay(Timeout.Infinite, callInfo.Arg()); }); - using var cacheDirectory = new TempDirectory(); - var options = new SentryOptions - { - Dsn = ValidDsn, - DiagnosticLogger = _logger, - Debug = true, - CacheDirectoryPath = cacheDirectory.Path, - NetworkStatusListener = listener - }; + _options.NetworkStatusListener = listener; using var innerTransport = new FakeTransport(); - await using var transport = CachingTransport.Create(innerTransport, options, startWorker: false); + await using var transport = CachingTransport.Create(innerTransport, _options, startWorker: false); using var cts = new CancellationTokenSource(); try { @@ -688,18 +563,10 @@ public async Task TransportResumesWhenNetworkComesBackOnline() return Task.CompletedTask; }); - using var cacheDirectory = new TempDirectory(); - var options = new SentryOptions - { - Dsn = ValidDsn, - DiagnosticLogger = _logger, - Debug = true, - CacheDirectoryPath = cacheDirectory.Path, - NetworkStatusListener = listener - }; + _options.NetworkStatusListener = listener; using var innerTransport = new FakeTransport(); - await using var transport = CachingTransport.Create(innerTransport, options, startWorker: false); + await using var transport = CachingTransport.Create(innerTransport, _options, startWorker: false); // Act using var envelope = Envelope.FromEvent(new SentryEvent()); @@ -718,23 +585,15 @@ public async Task FlushAsync_RejectedByServer_DiscardsEnvelope() var listener = Substitute.For(); listener.Online.Returns(_ => true); - using var cacheDirectory = new TempDirectory(); - var options = new SentryOptions - { - Dsn = ValidDsn, - DiagnosticLogger = _logger, - Debug = true, - CacheDirectoryPath = cacheDirectory.Path, - NetworkStatusListener = listener, - ClientReportRecorder = Substitute.For() - }; + _options.NetworkStatusListener = listener; + _options.ClientReportRecorder = Substitute.For(); using var envelope = Envelope.FromEvent(new SentryEvent()); var innerTransport = Substitute.For(); innerTransport.SendEnvelopeAsync(Arg.Any(), Arg.Any()) .Returns(_ => throw new SocketException(32 /* Bad pipe exception */)); - await using var transport = CachingTransport.Create(innerTransport, options, startWorker: false); + await using var transport = CachingTransport.Create(innerTransport, _options, startWorker: false); // Act await transport.SendEnvelopeAsync(envelope); @@ -743,7 +602,7 @@ public async Task FlushAsync_RejectedByServer_DiscardsEnvelope() // Assert foreach (var item in envelope.Items) { - options.ClientReportRecorder.Received(1) + _options.ClientReportRecorder.Received(1) .RecordDiscardedEvent(DiscardReason.BufferOverflow, item.DataCategory); } } @@ -752,19 +611,10 @@ public async Task FlushAsync_RejectedByServer_DiscardsEnvelope() public async Task DoesntWriteSentAtHeaderToCacheFile() { // Arrange - using var cacheDirectory = new TempDirectory(); - var options = new SentryOptions - { - Dsn = ValidDsn, - DiagnosticLogger = _logger, - Debug = true, - CacheDirectoryPath = cacheDirectory.Path, - // This keeps all writing-to-file operations in memory instead of actually writing to disk - FileSystem = new FakeFileSystem() - }; + _options.FileSystem = new FakeFileSystem(); // Keeps file write operations in memory instead of writing to disk var innerTransport = Substitute.For(); - await using var transport = CachingTransport.Create(innerTransport, options, startWorker: false); + await using var transport = CachingTransport.Create(innerTransport, _options, startWorker: false); using var envelope = Envelope.FromEvent(new SentryEvent()); @@ -772,11 +622,30 @@ public async Task DoesntWriteSentAtHeaderToCacheFile() await transport.SendEnvelopeAsync(envelope); // Assert - var filePath = options.FileSystem - .EnumerateFiles(cacheDirectory.Path, "*", SearchOption.AllDirectories) + var filePath = _options.FileSystem + .EnumerateFiles(_options.CacheDirectoryPath!, "*", SearchOption.AllDirectories) .Single(); - var contents = options.FileSystem.ReadAllTextFromFile(filePath); + var contents = _options.FileSystem.ReadAllTextFromFile(filePath); Assert.DoesNotContain("sent_at", contents); } } + +/// +/// We don't want the real network status to affect the reliability of our tests +/// +file class FakeReliableNetworkStatusListener : INetworkStatusListener +{ + public static readonly FakeReliableNetworkStatusListener Instance = new(); + + private FakeReliableNetworkStatusListener() + { + } + + public bool Online => true; + + public Task WaitForNetworkOnlineAsync(CancellationToken cancellationToken) + { + return Task.CompletedTask; + } +}