Skip to content

test(profiling): reproduce root span tracking issue #5071

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 6 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion Sentry.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -650,6 +650,7 @@
84281C472A57905700EE88F2 /* SentrySample.m in Sources */ = {isa = PBXBuildFile; fileRef = 84281C452A57905700EE88F2 /* SentrySample.m */; };
84281C622A579D0700EE88F2 /* SentryProfilerMocksSwiftCompatible.mm in Sources */ = {isa = PBXBuildFile; fileRef = 84281C4D2A579A0C00EE88F2 /* SentryProfilerMocksSwiftCompatible.mm */; };
84281C632A579D0700EE88F2 /* SentryProfilerMocks.mm in Sources */ = {isa = PBXBuildFile; fileRef = 84281C492A57933600EE88F2 /* SentryProfilerMocks.mm */; };
842D53102DA5A52B00D3528B /* SentryProfiledTracerConcurrencyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842D530F2DA5A52B00D3528B /* SentryProfiledTracerConcurrencyTests.swift */; };
84302A812B5767A50027A629 /* SentryLaunchProfiling.m in Sources */ = {isa = PBXBuildFile; fileRef = 84302A7F2B5767A50027A629 /* SentryLaunchProfiling.m */; };
8431D4552BE1745A009EAEC1 /* SentryProfileTestFixture.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8431D4522BE1741E009EAEC1 /* SentryProfileTestFixture.swift */; };
8431D4562BE1745F009EAEC1 /* SentryContinuousProfilerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8446F5182BE172290040D57E /* SentryContinuousProfilerTests.swift */; };
Expand Down Expand Up @@ -1792,6 +1793,8 @@
84281C4C2A579A0C00EE88F2 /* SentryProfilerMocksSwiftCompatible.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SentryProfilerMocksSwiftCompatible.h; sourceTree = "<group>"; };
84281C4D2A579A0C00EE88F2 /* SentryProfilerMocksSwiftCompatible.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = SentryProfilerMocksSwiftCompatible.mm; sourceTree = "<group>"; };
84281C642A57D36100EE88F2 /* SentryProfilerState+ObjCpp.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "SentryProfilerState+ObjCpp.h"; path = "../include/SentryProfilerState+ObjCpp.h"; sourceTree = "<group>"; };
842D530E2DA5A45C00D3528B /* SentryProfiledTracerConcurrency+Test.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SentryProfiledTracerConcurrency+Test.h"; sourceTree = "<group>"; };
842D530F2DA5A52B00D3528B /* SentryProfiledTracerConcurrencyTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryProfiledTracerConcurrencyTests.swift; sourceTree = "<group>"; };
84302A7F2B5767A50027A629 /* SentryLaunchProfiling.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryLaunchProfiling.m; sourceTree = "<group>"; };
8431D4522BE1741E009EAEC1 /* SentryProfileTestFixture.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryProfileTestFixture.swift; sourceTree = "<group>"; };
8431D4572BE175A1009EAEC1 /* SentryContinuousProfiler+Test.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SentryContinuousProfiler+Test.h"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -3627,7 +3630,6 @@
8454CF8B293EAF9A006AC140 /* SentryMetricProfiler.mm */,
8459FCBD2BD73E810038E9C9 /* SentryProfilerSerialization.h */,
8459FCBF2BD73EB20038E9C9 /* SentryProfilerSerialization.mm */,
8459FCC12BD73EEF0038E9C9 /* SentryProfilerSerialization+Test.h */,
84AF45A429A7FFA500FBB177 /* SentryProfiledTracerConcurrency.h */,
84AF45A529A7FFA500FBB177 /* SentryProfiledTracerConcurrency.mm */,
840B7EF22BBF83DF008B8120 /* SentryProfiler+Private.h */,
Expand Down Expand Up @@ -3667,6 +3669,8 @@
8431EFDB29B27B3D00D8DC56 /* SentryProfilerTests */ = {
isa = PBXGroup;
children = (
8459FCC12BD73EEF0038E9C9 /* SentryProfilerSerialization+Test.h */,
842D530E2DA5A45C00D3528B /* SentryProfiledTracerConcurrency+Test.h */,
849472802971C107002603DE /* SentrySystemWrapperTests.swift */,
849472822971C2CD002603DE /* SentryNSProcessInfoWrapperTests.swift */,
849472842971C41A002603DE /* SentryNSTimerFactoryTest.swift */,
Expand All @@ -3680,6 +3684,7 @@
845CEAEE2D83F79500B6B325 /* SentryProfilingPublicAPITests.swift */,
8419C0C328C1889D001C8259 /* SentryTraceProfilerTests.swift */,
8446F5182BE172290040D57E /* SentryContinuousProfilerTests.swift */,
842D530F2DA5A52B00D3528B /* SentryProfiledTracerConcurrencyTests.swift */,
8431D4522BE1741E009EAEC1 /* SentryProfileTestFixture.swift */,
);
path = SentryProfilerTests;
Expand Down Expand Up @@ -5560,6 +5565,7 @@
845CEB172D8A979700B6B325 /* SentryAppStartProfilingConfigurationTests.swift in Sources */,
8431EFE529B27BAD00D8DC56 /* SentryNSProcessInfoWrapperTests.swift in Sources */,
8431EFDE29B27B5300D8DC56 /* SentryTraceProfilerTests.swift in Sources */,
842D53102DA5A52B00D3528B /* SentryProfiledTracerConcurrencyTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
static NSMutableDictionary</* SentryTracer.internalTraceId */ NSString *, SentryProfiler *>
*_gTracersToProfilers;

static unsigned int _gInFlightRootSpans = 0;
unsigned int _gInFlightRootSpans = 0;

namespace {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ final class SentryContinuousProfilerTests: XCTestCase {
// test that when stop is called, the profiler runs to the end of the last
// chunk and transmits that before stopping
func testStoppingProfilerTransmitsLastFullChunk() throws {
fixture.givenSdkWithHub()
SentryContinuousProfiler.start()
XCTAssert(SentryContinuousProfiler.isCurrentlyProfiling())

Expand All @@ -142,6 +143,7 @@ final class SentryContinuousProfilerTests: XCTestCase {
}

func testChunkSerializationAfterBufferInterval() throws {
fixture.givenSdkWithHub()
SentryContinuousProfiler.start()
XCTAssert(SentryContinuousProfiler.isCurrentlyProfiling())

Expand Down Expand Up @@ -202,6 +204,7 @@ private extension SentryContinuousProfilerTests {
}

func performContinuousProfilingTest(expectedEnvironment: String = kSentryDefaultEnvironment) throws {
fixture.givenSdkWithHub()
XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling())
SentryContinuousProfiler.start()
XCTAssert(SentryContinuousProfiler.isCurrentlyProfiling())
Expand All @@ -225,15 +228,13 @@ private extension SentryContinuousProfilerTests {
try runTestPart(expectedAddresses: [0x4, 0x5, 0x6], mockMetrics: SentryProfileTestFixture.MockMetric(cpuUsage: 1.23, memoryFootprint: 456, cpuEnergyUsage: 7), countMetricsReadingAtProfileStart: false)
try runTestPart(expectedAddresses: [0x7, 0x8, 0x9], mockMetrics: SentryProfileTestFixture.MockMetric(cpuUsage: 9.87, memoryFootprint: 654, cpuEnergyUsage: 3), countMetricsReadingAtProfileStart: false)

XCTAssert(SentryContinuousProfiler.isCurrentlyProfiling())
SentryContinuousProfiler.stop()
try assertContinuousProfileStoppage()
}

func assertContinuousProfileStoppage() throws {
XCTAssert(SentryContinuousProfiler.isCurrentlyProfiling())
fixture.currentDateProvider.advance(by: 60)
try fixture.timeoutTimerFactory.check()
try fixture.allowContinuousProfilerToStop()
XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling())
}

Expand Down
41 changes: 31 additions & 10 deletions Tests/SentryProfilerTests/SentryProfileTestFixture.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,13 @@ class SentryProfileTestFixture {
private static let dsnAsString = TestConstants.dsnAsString(username: "SentryProfileTestFixture")

let options: Options
let client: TestClient?
let hub: SentryHub
lazy var client = TestClient(options: options)
lazy var hub = SentryHub(client: client, andScope: scope)
let scope = Scope()
let message = "some message"
let transactionName = "Some Transaction"
let transactionOperation = "Some Operation"
let rootSpanDescription = "Some Root Span"

let fixedRandomValue = 0.5

Expand All @@ -31,7 +32,8 @@ class SentryProfileTestFixture {
var timeoutTimerFactory: TestSentryNSTimerFactory
let dispatchQueueWrapper = TestSentryDispatchQueueWrapper()
let notificationCenter = TestNSNotificationCenterWrapper()

lazy var sessionTracker = SessionTracker(options: options, notificationCenter: notificationCenter)

let currentDateProvider = TestCurrentDateProvider()

#if !os(macOS)
Expand Down Expand Up @@ -75,10 +77,6 @@ class SentryProfileTestFixture {
options = Options()
options.dsn = SentryProfileTestFixture.dsnAsString
options.debug = true
client = TestClient(options: options)
hub = SentryHub(client: client, andScope: scope)
hub.bindClient(client)
SentrySDK.setCurrentHub(hub)

options.profilesSampleRate = 1.0
options.tracesSampleRate = 1.0
Expand All @@ -95,12 +93,19 @@ class SentryProfileTestFixture {
}

/// Advance the mock date provider, start a new transaction and return its handle.
func newTransaction(testingAppLaunchSpans: Bool = false, automaticTransaction: Bool = false, idleTimeout: TimeInterval? = nil) throws -> SentryTracer {
func newTransaction(testingAppLaunchSpans: Bool = false, automaticTransaction: Bool = false, idleTimeout: TimeInterval? = nil, rootSpan: Bool = false) throws -> SentryTracer {
let operation = testingAppLaunchSpans ? SentrySpanOperationUiLoad : transactionOperation


let context: TransactionContext
if rootSpan {
context = TransactionContext(trace: SentryId(), spanId: SpanId(), parentId: nil, operation: operation, spanDescription: rootSpanDescription, sampled: .yes)
} else {
context = TransactionContext(name: transactionName, operation: operation)
}

if automaticTransaction {
return hub.startTransaction(
with: TransactionContext(name: transactionName, operation: operation),
with: context,
bindToScope: false,
customSamplingContext: [:],
configuration: SentryTracerConfiguration(block: {
Expand Down Expand Up @@ -400,6 +405,22 @@ class SentryProfileTestFixture {
sdkStartTimestamp: appStart, didFinishLaunchingTimestamp: didFinishLaunching)
}
#endif // !os(macOS)

func givenSdkWithHub() {
hub.bindClient(client)
SentrySDK.setCurrentHub(hub)
sentry_sdkInitProfilerTasks(options, hub)
}

func stopContinuousProfiler() throws {
SentrySDK.stopProfiler()
try allowContinuousProfilerToStop()
}

func allowContinuousProfilerToStop() throws {
currentDateProvider.advance(by: 60)
try timeoutTimerFactory.check()
}
}

#endif // os(iOS) || os(macOS) || targetEnvironment(macCatalyst)
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#import "SentryProfilingConditionals.h"

#if SENTRY_TARGET_PROFILING_SUPPORTED

# if defined(SENTRY_TEST) || defined(SENTRY_TEST_CI) || defined(DEBUG)

# import "SentryDefines.h"

SENTRY_EXTERN unsigned int _gInFlightRootSpans;

# endif // defined(SENTRY_TEST) || defined(SENTRY_TEST_CI) || defined(DEBUG)

#endif // SENTRY_TARGET_PROFILING_SUPPORTED
Loading
Loading