diff --git a/Sentry-CI-Build-Linux.slnf b/Sentry-CI-Build-Linux.slnf
index f48a6c3ca8..e7fa0ed7de 100644
--- a/Sentry-CI-Build-Linux.slnf
+++ b/Sentry-CI-Build-Linux.slnf
@@ -49,6 +49,7 @@
"test\\Sentry.AspNetCore.Grpc.Tests\\Sentry.AspNetCore.Grpc.Tests.csproj",
"test\\Sentry.AspNetCore.Tests\\Sentry.AspNetCore.Tests.csproj",
"test\\Sentry.Azure.Functions.Worker.Tests\\Sentry.Azure.Functions.Worker.Tests.csproj",
+ "test\\Sentry.Coyote.Tests\\Sentry.Coyote.Tests.csproj",
"test\\Sentry.DiagnosticSource.IntegrationTests\\Sentry.DiagnosticSource.IntegrationTests.csproj",
"test\\Sentry.DiagnosticSource.Tests\\Sentry.DiagnosticSource.Tests.csproj",
"test\\Sentry.EntityFramework.Tests\\Sentry.EntityFramework.Tests.csproj",
diff --git a/Sentry-CI-Build-Windows.slnf b/Sentry-CI-Build-Windows.slnf
index e08b88d7f9..ab4e250d0a 100644
--- a/Sentry-CI-Build-Windows.slnf
+++ b/Sentry-CI-Build-Windows.slnf
@@ -50,6 +50,7 @@
"test\\Sentry.AspNetCore.Tests\\Sentry.AspNetCore.Tests.csproj",
"test\\Sentry.AspNetCore.TestUtils\\Sentry.AspNetCore.TestUtils.csproj",
"test\\Sentry.Azure.Functions.Worker.Tests\\Sentry.Azure.Functions.Worker.Tests.csproj",
+ "test\\Sentry.Coyote.Tests\\Sentry.Coyote.Tests.csproj",
"test\\Sentry.DiagnosticSource.IntegrationTests\\Sentry.DiagnosticSource.IntegrationTests.csproj",
"test\\Sentry.DiagnosticSource.Tests\\Sentry.DiagnosticSource.Tests.csproj",
"test\\Sentry.EntityFramework.Tests\\Sentry.EntityFramework.Tests.csproj",
diff --git a/Sentry-CI-Build-macOS.slnf b/Sentry-CI-Build-macOS.slnf
index 336e58f89e..0aeda4491b 100644
--- a/Sentry-CI-Build-macOS.slnf
+++ b/Sentry-CI-Build-macOS.slnf
@@ -55,6 +55,7 @@
"test\\Sentry.AspNetCore.Tests\\Sentry.AspNetCore.Tests.csproj",
"test\\Sentry.AspNetCore.TestUtils\\Sentry.AspNetCore.TestUtils.csproj",
"test\\Sentry.Azure.Functions.Worker.Tests\\Sentry.Azure.Functions.Worker.Tests.csproj",
+ "test\\Sentry.Coyote.Tests\\Sentry.Coyote.Tests.csproj",
"test\\Sentry.DiagnosticSource.IntegrationTests\\Sentry.DiagnosticSource.IntegrationTests.csproj",
"test\\Sentry.DiagnosticSource.Tests\\Sentry.DiagnosticSource.Tests.csproj",
"test\\Sentry.EntityFramework.Tests\\Sentry.EntityFramework.Tests.csproj",
diff --git a/Sentry.NoMobile.sln b/Sentry.NoMobile.sln
index ac60374e4b..9f45f09943 100644
--- a/Sentry.NoMobile.sln
+++ b/Sentry.NoMobile.sln
@@ -163,6 +163,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FastSerialization", "module
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sentry.Samples.Console.Native", "samples\Sentry.Samples.Console.Native\Sentry.Samples.Console.Native.csproj", "{FC8AEABA-1A40-4891-9EBA-4B6A1F7244B2}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sentry.Coyote.Tests", "test\Sentry.Coyote.Tests\Sentry.Coyote.Tests.csproj", "{79C0F367-CF2E-4021-B9FE-6912A61A1516}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -465,6 +467,10 @@ Global
{FC8AEABA-1A40-4891-9EBA-4B6A1F7244B2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FC8AEABA-1A40-4891-9EBA-4B6A1F7244B2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FC8AEABA-1A40-4891-9EBA-4B6A1F7244B2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {79C0F367-CF2E-4021-B9FE-6912A61A1516}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {79C0F367-CF2E-4021-B9FE-6912A61A1516}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {79C0F367-CF2E-4021-B9FE-6912A61A1516}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {79C0F367-CF2E-4021-B9FE-6912A61A1516}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -545,5 +551,6 @@ Global
{67269916-C417-4CEE-BD7D-CA66C3830AEE} = {A3CCA27E-4DF8-479D-833C-CAA0950715AA}
{8032310D-3C06-442C-A318-F365BCC4C804} = {A3CCA27E-4DF8-479D-833C-CAA0950715AA}
{FC8AEABA-1A40-4891-9EBA-4B6A1F7244B2} = {21B42F60-5802-404E-90F0-AEBCC56760C0}
+ {79C0F367-CF2E-4021-B9FE-6912A61A1516} = {6987A1CC-608E-4868-A02C-09D30C8B7B2D}
EndGlobalSection
EndGlobal
diff --git a/Sentry.sln b/Sentry.sln
index ac60374e4b..9f45f09943 100644
--- a/Sentry.sln
+++ b/Sentry.sln
@@ -163,6 +163,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FastSerialization", "module
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sentry.Samples.Console.Native", "samples\Sentry.Samples.Console.Native\Sentry.Samples.Console.Native.csproj", "{FC8AEABA-1A40-4891-9EBA-4B6A1F7244B2}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sentry.Coyote.Tests", "test\Sentry.Coyote.Tests\Sentry.Coyote.Tests.csproj", "{79C0F367-CF2E-4021-B9FE-6912A61A1516}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -465,6 +467,10 @@ Global
{FC8AEABA-1A40-4891-9EBA-4B6A1F7244B2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FC8AEABA-1A40-4891-9EBA-4B6A1F7244B2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FC8AEABA-1A40-4891-9EBA-4B6A1F7244B2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {79C0F367-CF2E-4021-B9FE-6912A61A1516}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {79C0F367-CF2E-4021-B9FE-6912A61A1516}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {79C0F367-CF2E-4021-B9FE-6912A61A1516}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {79C0F367-CF2E-4021-B9FE-6912A61A1516}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -545,5 +551,6 @@ Global
{67269916-C417-4CEE-BD7D-CA66C3830AEE} = {A3CCA27E-4DF8-479D-833C-CAA0950715AA}
{8032310D-3C06-442C-A318-F365BCC4C804} = {A3CCA27E-4DF8-479D-833C-CAA0950715AA}
{FC8AEABA-1A40-4891-9EBA-4B6A1F7244B2} = {21B42F60-5802-404E-90F0-AEBCC56760C0}
+ {79C0F367-CF2E-4021-B9FE-6912A61A1516} = {6987A1CC-608E-4868-A02C-09D30C8B7B2D}
EndGlobalSection
EndGlobal
diff --git a/SentryCore.slnf b/SentryCore.slnf
index e5e06b98b5..70fe1cc494 100644
--- a/SentryCore.slnf
+++ b/SentryCore.slnf
@@ -7,6 +7,7 @@
"samples\\Sentry.Samples.Console.Profiling\\Sentry.Samples.Console.Profiling.csproj",
"src\\Sentry.Profiling\\Sentry.Profiling.csproj",
"src\\Sentry\\Sentry.csproj",
+ "test\\Sentry.Coyote.Tests\\Sentry.Coyote.Tests.csproj",
"test\\Sentry.Profiling.Tests\\Sentry.Profiling.Tests.csproj",
"test\\Sentry.Testing.CrashableApp\\Sentry.Testing.CrashableApp.csproj",
"test\\Sentry.Testing\\Sentry.Testing.csproj",
diff --git a/SentryNoMobile.slnf b/SentryNoMobile.slnf
index effba4f145..d0da805a60 100644
--- a/SentryNoMobile.slnf
+++ b/SentryNoMobile.slnf
@@ -46,6 +46,7 @@
"test\\Sentry.AspNetCore.Tests\\Sentry.AspNetCore.Tests.csproj",
"test\\Sentry.AspNetCore.TestUtils\\Sentry.AspNetCore.TestUtils.csproj",
"test\\Sentry.Azure.Functions.Worker.Tests\\Sentry.Azure.Functions.Worker.Tests.csproj",
+ "test\\Sentry.Coyote.Tests\\Sentry.Coyote.Tests.csproj",
"test\\Sentry.DiagnosticSource.IntegrationTests\\Sentry.DiagnosticSource.IntegrationTests.csproj",
"test\\Sentry.DiagnosticSource.Tests\\Sentry.DiagnosticSource.Tests.csproj",
"test\\Sentry.EntityFramework.Tests\\Sentry.EntityFramework.Tests.csproj",
diff --git a/SentryNoSamples.slnf b/SentryNoSamples.slnf
index 3e12250192..aa5778bbd3 100644
--- a/SentryNoSamples.slnf
+++ b/SentryNoSamples.slnf
@@ -25,6 +25,7 @@
"test\\Sentry.AspNetCore.Tests\\Sentry.AspNetCore.Tests.csproj",
"test\\Sentry.AspNetCore.TestUtils\\Sentry.AspNetCore.TestUtils.csproj",
"test\\Sentry.Azure.Functions.Worker.Tests\\Sentry.Azure.Functions.Worker.Tests.csproj",
+ "test\\Sentry.Coyote.Tests\\Sentry.Coyote.Tests.csproj",
"test\\Sentry.DiagnosticSource.IntegrationTests\\Sentry.DiagnosticSource.IntegrationTests.csproj",
"test\\Sentry.DiagnosticSource.Tests\\Sentry.DiagnosticSource.Tests.csproj",
"test\\Sentry.EntityFramework.Tests\\Sentry.EntityFramework.Tests.csproj",
diff --git a/scripts/generate-solution-filters-config.yaml b/scripts/generate-solution-filters-config.yaml
index 80900ec608..0a14c84698 100644
--- a/scripts/generate-solution-filters-config.yaml
+++ b/scripts/generate-solution-filters-config.yaml
@@ -116,6 +116,7 @@ filterConfigs:
- "**/Sentry.Profiling.csproj"
- "**/Sentry.csproj"
- "**/Sentry.Profiling.Tests.csproj"
+ - "**/Sentry.Coyote.Tests.csproj"
- "**/Sentry.Testing.csproj"
- "**/Sentry.Testing.CrashableApp.csproj"
- "**/Sentry.Tests.csproj"
diff --git a/src/Sentry/Sentry.csproj b/src/Sentry/Sentry.csproj
index c8bb8dad48..1c377fa845 100644
--- a/src/Sentry/Sentry.csproj
+++ b/src/Sentry/Sentry.csproj
@@ -174,6 +174,7 @@
+
diff --git a/test/Sentry.Coyote.Tests/.config/dotnet-tools.json b/test/Sentry.Coyote.Tests/.config/dotnet-tools.json
new file mode 100644
index 0000000000..65e00e8db3
--- /dev/null
+++ b/test/Sentry.Coyote.Tests/.config/dotnet-tools.json
@@ -0,0 +1,12 @@
+{
+ "version": 1,
+ "isRoot": true,
+ "tools": {
+ "microsoft.coyote.cli": {
+ "version": "1.7.10",
+ "commands": [
+ "coyote"
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/Sentry.Coyote.Tests/BackgroundWorkerTests.cs b/test/Sentry.Coyote.Tests/BackgroundWorkerTests.cs
new file mode 100644
index 0000000000..eece50fa6f
--- /dev/null
+++ b/test/Sentry.Coyote.Tests/BackgroundWorkerTests.cs
@@ -0,0 +1,35 @@
+using Sentry.Internal.Http;
+using BackgroundWorker = Sentry.Internal.BackgroundWorker;
+
+namespace Sentry.Coyote.Tests;
+
+public static class BackgroundWorkerTests
+{
+ [Microsoft.Coyote.SystematicTesting.Test]
+ public static async Task EnqueueFlushAndDisposeAsync()
+ {
+ var path = Path.Combine("envelopes", Guid.NewGuid().ToString());
+ var options = new SentryOptions
+ {
+ Dsn = "https://test@testsentry.dev/id",
+ CacheDirectoryPath = path,
+ };
+ var bg = new BackgroundWorker(CachingTransport.Create(new NoOpTransport(), options), options);
+
+ await bg.FlushAsync(TimeSpan.FromSeconds(3));
+ bg.EnqueueEnvelope(Envelope.FromEvent(new SentryEvent()));
+ bg.EnqueueEnvelope(Envelope.FromEvent(new SentryEvent()));
+ await bg.FlushAsync(TimeSpan.FromSeconds(3));
+ bg.EnqueueEnvelope(Envelope.FromEvent(new SentryEvent()));
+ bg.Dispose();
+ Directory.Delete(path);
+ }
+
+ private class NoOpTransport : ITransport
+ {
+ public System.Threading.Tasks.Task SendEnvelopeAsync(
+ Envelope envelope,
+ CancellationToken cancellationToken = default)
+ => Task.CompletedTask;
+ }
+}
diff --git a/test/Sentry.Coyote.Tests/Sentry.Coyote.Tests.csproj b/test/Sentry.Coyote.Tests/Sentry.Coyote.Tests.csproj
new file mode 100644
index 0000000000..060c8a160a
--- /dev/null
+++ b/test/Sentry.Coyote.Tests/Sentry.Coyote.Tests.csproj
@@ -0,0 +1,18 @@
+
+
+
+ net7.0
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test/Sentry.Coyote.Tests/run.sh b/test/Sentry.Coyote.Tests/run.sh
new file mode 100755
index 0000000000..8aec607657
--- /dev/null
+++ b/test/Sentry.Coyote.Tests/run.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+set -euo pipefail
+
+export COYOTE_CLI_TELEMETRY_OPTOUT=1
+export configuration=Debug
+export outputPath=bin/$configuration/coyote
+
+dotnet build -c $configuration -o $outputPath
+
+dotnet tool restore
+dotnet tool run coyote rewrite $outputPath/Sentry.dll
+dotnet tool run coyote rewrite $outputPath/Sentry.Testing.dll
+dotnet tool run coyote rewrite $outputPath/Sentry.Coyote.Tests.dll
+
+dotnet tool run coyote test $outputPath/Sentry.Coyote.Tests.dll --method EnqueueFlushAndDisposeAsync --iterations 10000