Skip to content

Commit b9d4710

Browse files
Add retry for ProfilerIntegration_FullRoundtrip_Works test (#4651)
1 parent e7d6b84 commit b9d4710

File tree

1 file changed

+90
-84
lines changed

1 file changed

+90
-84
lines changed

test/Sentry.Profiling.Tests/SamplingTransactionProfilerTests.cs

Lines changed: 90 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -235,106 +235,112 @@ public void ProfilerIntegration_FullRoundtrip_Works(bool offlineCaching)
235235
{
236236
Skip.If(TestEnvironment.IsGitHubActions, "Flaky in CI");
237237

238-
var tcs = new TaskCompletionSource<string>();
239-
async Task VerifyAsync(HttpRequestMessage message)
238+
TestHelpers.RetryTest(maxAttempts: 2, ExecuteTest);
239+
return;
240+
241+
void ExecuteTest()
240242
{
241-
var payload = await message.Content!.ReadAsStringAsync();
242-
// We're actually looking for type:profile but it must be sent in the same envelope as the transaction.
243-
if (payload.Contains("\"type\":\"transaction\""))
243+
var tcs = new TaskCompletionSource<string>();
244+
async Task VerifyAsync(HttpRequestMessage message)
244245
{
245-
tcs.TrySetResult(payload);
246+
var payload = await message.Content!.ReadAsStringAsync();
247+
// We're actually looking for type:profile but it must be sent in the same envelope as the transaction.
248+
if (payload.Contains("\"type\":\"transaction\""))
249+
{
250+
tcs.TrySetResult(payload);
251+
}
246252
}
247-
}
248-
249-
var cts = new CancellationTokenSource();
250-
cts.Token.Register(() => tcs.TrySetCanceled());
251253

252-
// envelope cache dir
253-
using var cacheDirectory = offlineCaching ? new TempDirectory() : null;
254+
var cts = new CancellationTokenSource();
255+
cts.Token.Register(() => tcs.TrySetCanceled());
254256

255-
// profiler temp dir (doesn't support `FileSystem`)
256-
var tempDir = new TempDirectory();
257-
258-
var options = new SentryOptions
259-
{
260-
Dsn = ValidDsn,
261-
// To go through a round trip serialization of cached envelope
262-
CacheDirectoryPath = cacheDirectory?.Path,
263-
// So we don't need to deal with gzip'ed payload
264-
RequestBodyCompressionLevel = CompressionLevel.NoCompression,
265-
CreateHttpMessageHandler = () => new CallbackHttpClientHandler(VerifyAsync),
266-
// Not to send some session envelope
267-
AutoSessionTracking = false,
268-
Debug = true,
269-
DiagnosticLogger = _testOutputLogger,
270-
TracesSampleRate = 1.0,
271-
ProfilesSampleRate = 1.0,
272-
// This keeps all writing-to-file operations in memory instead of actually writing to disk
273-
FileSystem = new FakeFileSystem()
274-
};
257+
// envelope cache dir
258+
using var cacheDirectory = offlineCaching ? new TempDirectory() : null;
275259

276-
// Disable process exit flush to resolve "There is no currently active test." errors.
277-
options.DisableAppDomainProcessExitFlush();
260+
// profiler temp dir (doesn't support `FileSystem`)
261+
var tempDir = new TempDirectory();
278262

279-
options.AddProfilingIntegration(TimeSpan.FromSeconds(10));
263+
var options = new SentryOptions
264+
{
265+
Dsn = ValidDsn,
266+
// To go through a round trip serialization of cached envelope
267+
CacheDirectoryPath = cacheDirectory?.Path,
268+
// So we don't need to deal with gzip'ed payload
269+
RequestBodyCompressionLevel = CompressionLevel.NoCompression,
270+
CreateHttpMessageHandler = () => new CallbackHttpClientHandler(VerifyAsync),
271+
// Not to send some session envelope
272+
AutoSessionTracking = false,
273+
Debug = true,
274+
DiagnosticLogger = _testOutputLogger,
275+
TracesSampleRate = 1.0,
276+
ProfilesSampleRate = 1.0,
277+
// This keeps all writing-to-file operations in memory instead of actually writing to disk
278+
FileSystem = new FakeFileSystem()
279+
};
280+
281+
// Disable process exit flush to resolve "There is no currently active test." errors.
282+
options.DisableAppDomainProcessExitFlush();
283+
284+
options.AddProfilingIntegration(TimeSpan.FromSeconds(10));
280285

281-
try
282-
{
283-
using var hub = new Hub(options);
286+
try
287+
{
288+
using var hub = new Hub(options);
284289

285-
var factory = (options.TransactionProfilerFactory as SamplingTransactionProfilerFactory)!;
286-
Skip.If(TestEnvironment.IsGitHubActions && factory.StartupTimedOut, "Session sometimes takes too long to start in CI.");
287-
Assert.False(factory.StartupTimedOut);
290+
var factory = (options.TransactionProfilerFactory as SamplingTransactionProfilerFactory)!;
291+
Skip.If(TestEnvironment.IsGitHubActions && factory.StartupTimedOut, "Session sometimes takes too long to start in CI.");
292+
Assert.False(factory.StartupTimedOut);
288293

289-
var clock = SentryStopwatch.StartNew();
290-
var tx = hub.StartTransaction("name", "op");
291-
RunForMs(RuntimeMs);
292-
tx.Finish();
293-
var elapsedNanoseconds = (ulong)((clock.CurrentDateTimeOffset - clock.StartDateTimeOffset).TotalMilliseconds * 1_000_000);
294+
var clock = SentryStopwatch.StartNew();
295+
var tx = hub.StartTransaction("name", "op");
296+
RunForMs(RuntimeMs);
297+
tx.Finish();
298+
var elapsedNanoseconds = (ulong)((clock.CurrentDateTimeOffset - clock.StartDateTimeOffset).TotalMilliseconds * 1_000_000);
294299

295-
hub.FlushAsync().Wait();
300+
hub.FlushAsync().Wait();
296301

297-
// Synchronizing in the tests to go through the caching and http transports
298-
cts.CancelAfter(options.FlushTimeout + TimeSpan.FromSeconds(1));
299-
var ex = Record.Exception(tcs.Task.Wait);
300-
Assert.Null(ex);
301-
Assert.True(tcs.Task.IsCompleted);
302+
// Synchronizing in the tests to go through the caching and http transports
303+
cts.CancelAfter(options.FlushTimeout + TimeSpan.FromSeconds(1));
304+
var ex = Record.Exception(tcs.Task.Wait);
305+
Assert.Null(ex);
306+
Assert.True(tcs.Task.IsCompleted);
302307

303-
var envelopeLines = tcs.Task.Result.Split('\n');
304-
SkipIfFailsInCI(() =>
308+
var envelopeLines = tcs.Task.Result.Split('\n');
309+
SkipIfFailsInCI(() =>
310+
{
311+
if (envelopeLines.Length != 6)
312+
{
313+
throw new ArgumentOutOfRangeException("envelopeLines", "Invalid number of envelope lines.");
314+
}
315+
});
316+
317+
// header rows before payloads
318+
envelopeLines[1].Should().StartWith("{\"type\":\"transaction\"");
319+
envelopeLines[3].Should().StartWith("{\"type\":\"profile\"");
320+
321+
var transaction = Json.Parse(envelopeLines[2], SentryTransaction.FromJson);
322+
323+
// TODO do we want to bother with JSON parsing just to do this? Doing at least simple checks for now...
324+
// var profileInfo = Json.Parse(envelopeLines[4], ProfileInfo.FromJson);
325+
// ValidateProfile(profileInfo.Profile, elapsedNanoseconds);
326+
envelopeLines[4].Should().Contain("\"profile\":{");
327+
envelopeLines[4].Should().Contain($"\"id\":\"{transaction.EventId}\"");
328+
envelopeLines[4].Length.Should().BeGreaterThan(10000);
329+
330+
Directory.GetFiles(tempDir.Path).Should().BeEmpty("When profiling is done, the temp dir should be empty.");
331+
}
332+
finally
305333
{
306-
if (envelopeLines.Length != 6)
334+
// ensure the task is complete before leaving the test
335+
tcs.TrySetResult("");
336+
tcs.Task.Wait();
337+
338+
if (options.Transport is CachingTransport cachingTransport)
307339
{
308-
throw new ArgumentOutOfRangeException("envelopeLines", "Invalid number of envelope lines.");
340+
// Disposing the caching transport will ensure its worker
341+
// is shut down before we try to dispose and delete the temp folder
342+
cachingTransport.Dispose();
309343
}
310-
});
311-
312-
// header rows before payloads
313-
envelopeLines[1].Should().StartWith("{\"type\":\"transaction\"");
314-
envelopeLines[3].Should().StartWith("{\"type\":\"profile\"");
315-
316-
var transaction = Json.Parse(envelopeLines[2], SentryTransaction.FromJson);
317-
318-
// TODO do we want to bother with JSON parsing just to do this? Doing at least simple checks for now...
319-
// var profileInfo = Json.Parse(envelopeLines[4], ProfileInfo.FromJson);
320-
// ValidateProfile(profileInfo.Profile, elapsedNanoseconds);
321-
envelopeLines[4].Should().Contain("\"profile\":{");
322-
envelopeLines[4].Should().Contain($"\"id\":\"{transaction.EventId}\"");
323-
envelopeLines[4].Length.Should().BeGreaterThan(10000);
324-
325-
Directory.GetFiles(tempDir.Path).Should().BeEmpty("When profiling is done, the temp dir should be empty.");
326-
}
327-
finally
328-
{
329-
// ensure the task is complete before leaving the test
330-
tcs.TrySetResult("");
331-
tcs.Task.Wait();
332-
333-
if (options.Transport is CachingTransport cachingTransport)
334-
{
335-
// Disposing the caching transport will ensure its worker
336-
// is shut down before we try to dispose and delete the temp folder
337-
cachingTransport.Dispose();
338344
}
339345
}
340346
}

0 commit comments

Comments
 (0)