Skip to content
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

fix: Watchdog Termination is not supported in Synthetics env #1937

Merged
merged 1 commit into from
Jul 3, 2024
Merged
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
3 changes: 2 additions & 1 deletion DatadogRUM/Sources/Feature/RUMFeature.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ internal final class RUMFeature: DatadogRemoteFeature {
if configuration.trackWatchdogTerminations {
let appStateManager = WatchdogTerminationAppStateManager(
featureScope: featureScope,
processId: configuration.processID
processId: configuration.processID,
syntheticsEnvironment: configuration.syntheticsEnvironment
)
let monitor = WatchdogTerminationMonitor(
appStateManager: appStateManager,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ internal struct WatchdogTerminationAppState: Codable {

/// The user's tracking consent at the recoding time.
let trackingConsent: TrackingConsent

/// Returns true, if the app is running in a synthetic environment.
let syntheticsEnvironment: Bool
}

extension WatchdogTerminationAppState: CustomDebugStringConvertible {
Expand All @@ -56,6 +59,7 @@ extension WatchdogTerminationAppState: CustomDebugStringConvertible {
- vendorId: \(vendorId ?? "nil")
- processId: \(processId)
- trackingConsent: \(trackingConsent)
- syntheticsEnvironment: \(syntheticsEnvironment)
"""
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,17 @@ internal final class WatchdogTerminationAppStateManager {
/// The process identifier of the app whose state is being monitored.
let processId: UUID

init(featureScope: FeatureScope, processId: UUID) {
/// Returns true, if the app is running in a synthetic environment.
let syntheticsEnvironment: Bool

init(
featureScope: FeatureScope,
processId: UUID,
syntheticsEnvironment: Bool
) {
self.featureScope = featureScope
self.processId = processId
self.syntheticsEnvironment = syntheticsEnvironment
}

/// Deletes the app state from the data store.
Expand Down Expand Up @@ -99,7 +107,8 @@ internal final class WatchdogTerminationAppStateManager {
isActive: true,
vendorId: context.device.vendorId,
processId: self.processId,
trackingConsent: context.trackingConsent
trackingConsent: context.trackingConsent,
syntheticsEnvironment: self.syntheticsEnvironment
)
completion(state)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,13 @@ internal final class WatchdogTerminationChecker {
return false
}

// We can't reliably tell if it was a Watchdog Termination or not if the app was running in a synthetic environment.
// Synthetics uses terminateApp API https://github.com/appium/appium-xcuitest-driver/blob/main/lib/real-device.js#L216
// for restarting the app which we can't distinguish from Watchdog Termination.
guard previous.syntheticsEnvironment == false else {
return false
}

// Watchdog Termination detection doesn't work on simulators.
guard deviceInfo.isSimulator == false else {
return false
Expand Down
3 changes: 3 additions & 0 deletions DatadogRUM/Sources/RUMConfiguration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,9 @@ extension RUM {
internal var ciTestExecutionID: String? = ProcessInfo.processInfo.environment["CI_VISIBILITY_TEST_EXECUTION_ID"]
internal var syntheticsTestId: String? = ProcessInfo.processInfo.environment["_dd.synthetics.test_id"]
internal var syntheticsResultId: String? = ProcessInfo.processInfo.environment["_dd.synthetics.result_id"]
internal var syntheticsEnvironment: Bool {
syntheticsTestId != nil || syntheticsResultId != nil
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ final class WatchdogTerminationAppStateManagerTests: XCTestCase {
featureScope = FeatureScopeMock()
sut = WatchdogTerminationAppStateManager(
featureScope: featureScope,
processId: .init()
processId: .init(),
syntheticsEnvironment: false
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,22 @@ final class WatchdogTerminationCheckerTests: XCTestCase {
XCTAssertFalse(sut.isWatchdogTermination(launch: .mockRandom(), deviceInfo: .mockWith(isSimulator: false), from: nil, to: .mockRandom()))
}

func testSyntheticsEnvironment_NoWatchdogTermination() throws {
let previous = WatchdogTerminationAppState(
appVersion: .mockAny(),
osVersion: .mockAny(),
systemBootTime: .mockAny(),
isDebugging: true,
wasTerminated: .mockAny(),
isActive: .mockAny(),
vendorId: .mockAny(),
processId: .mockAny(),
trackingConsent: .mockRandom(),
syntheticsEnvironment: true
)
XCTAssertFalse(sut.isWatchdogTermination(launch: .mockRandom(), deviceInfo: .mockWith(isSimulator: false), from: previous, to: .mockRandom()))
}

func testIsSimulatorBuild_NoWatchdogTermination() throws {
XCTAssertFalse(sut.isWatchdogTermination(launch: .mockRandom(), deviceInfo: .mockWith(isSimulator: false), from: .mockRandom(), to: .mockRandom()))
}
Expand All @@ -30,7 +46,8 @@ final class WatchdogTerminationCheckerTests: XCTestCase {
isActive: .mockAny(),
vendorId: .mockAny(),
processId: .mockAny(),
trackingConsent: .mockRandom()
trackingConsent: .mockRandom(),
syntheticsEnvironment: false
)
XCTAssertFalse(sut.isWatchdogTermination(launch: .mockRandom(), deviceInfo: .mockWith(isSimulator: false), from: previous, to: .mockRandom()))
}
Expand All @@ -45,7 +62,8 @@ final class WatchdogTerminationCheckerTests: XCTestCase {
isActive: .mockAny(),
vendorId: .mockAny(),
processId: .mockAny(),
trackingConsent: .mockRandom()
trackingConsent: .mockRandom(),
syntheticsEnvironment: false
)

let current = WatchdogTerminationAppState(
Expand All @@ -57,7 +75,8 @@ final class WatchdogTerminationCheckerTests: XCTestCase {
isActive: .mockAny(),
vendorId: .mockAny(),
processId: .mockAny(),
trackingConsent: .mockRandom()
trackingConsent: .mockRandom(),
syntheticsEnvironment: false
)

XCTAssertFalse(sut.isWatchdogTermination(launch: .mockRandom(), deviceInfo: .mockWith(isSimulator: false), from: previous, to: current))
Expand All @@ -73,7 +92,8 @@ final class WatchdogTerminationCheckerTests: XCTestCase {
isActive: .mockAny(),
vendorId: .mockAny(),
processId: .mockAny(),
trackingConsent: .mockRandom()
trackingConsent: .mockRandom(),
syntheticsEnvironment: false
)

let current = WatchdogTerminationAppState(
Expand All @@ -85,7 +105,8 @@ final class WatchdogTerminationCheckerTests: XCTestCase {
isActive: .mockAny(),
vendorId: .mockAny(),
processId: .mockAny(),
trackingConsent: .mockRandom()
trackingConsent: .mockRandom(),
syntheticsEnvironment: false
)

XCTAssertFalse(sut.isWatchdogTermination(launch: .init(didCrash: true), deviceInfo: .mockWith(isSimulator: false), from: previous, to: current))
Expand All @@ -101,7 +122,8 @@ final class WatchdogTerminationCheckerTests: XCTestCase {
isActive: .mockAny(),
vendorId: .mockAny(),
processId: .mockAny(),
trackingConsent: .mockRandom()
trackingConsent: .mockRandom(),
syntheticsEnvironment: false
)

let current = WatchdogTerminationAppState(
Expand All @@ -113,7 +135,8 @@ final class WatchdogTerminationCheckerTests: XCTestCase {
isActive: .mockAny(),
vendorId: .mockAny(),
processId: .mockAny(),
trackingConsent: .mockRandom()
trackingConsent: .mockRandom(),
syntheticsEnvironment: false
)

XCTAssertFalse(sut.isWatchdogTermination(launch: .init(didCrash: false), deviceInfo: .mockWith(isSimulator: false), from: previous, to: current))
Expand All @@ -129,7 +152,8 @@ final class WatchdogTerminationCheckerTests: XCTestCase {
isActive: .mockAny(),
vendorId: .mockAny(),
processId: .mockAny(),
trackingConsent: .mockRandom()
trackingConsent: .mockRandom(),
syntheticsEnvironment: false
)

let current = WatchdogTerminationAppState(
Expand All @@ -141,7 +165,8 @@ final class WatchdogTerminationCheckerTests: XCTestCase {
isActive: .mockAny(),
vendorId: .mockAny(),
processId: .mockAny(),
trackingConsent: .mockRandom()
trackingConsent: .mockRandom(),
syntheticsEnvironment: false
)

XCTAssertFalse(sut.isWatchdogTermination(launch: .init(didCrash: false), deviceInfo: .mockWith(isSimulator: false), from: previous, to: current))
Expand All @@ -157,7 +182,8 @@ final class WatchdogTerminationCheckerTests: XCTestCase {
isActive: .mockAny(),
vendorId: .mockAny(),
processId: .mockAny(),
trackingConsent: .mockRandom()
trackingConsent: .mockRandom(),
syntheticsEnvironment: false
)

let current = WatchdogTerminationAppState(
Expand All @@ -169,7 +195,8 @@ final class WatchdogTerminationCheckerTests: XCTestCase {
isActive: .mockAny(),
vendorId: .mockAny(),
processId: .mockAny(),
trackingConsent: .mockRandom()
trackingConsent: .mockRandom(),
syntheticsEnvironment: false
)

XCTAssertFalse(sut.isWatchdogTermination(launch: .init(didCrash: false), deviceInfo: .mockWith(isSimulator: false), from: previous, to: current))
Expand All @@ -185,7 +212,8 @@ final class WatchdogTerminationCheckerTests: XCTestCase {
isActive: .mockAny(),
vendorId: "foo",
processId: .mockAny(),
trackingConsent: .mockRandom()
trackingConsent: .mockRandom(),
syntheticsEnvironment: false
)

let current = WatchdogTerminationAppState(
Expand All @@ -197,7 +225,8 @@ final class WatchdogTerminationCheckerTests: XCTestCase {
isActive: .mockAny(),
vendorId: "bar",
processId: .mockAny(),
trackingConsent: .mockRandom()
trackingConsent: .mockRandom(),
syntheticsEnvironment: false
)

XCTAssertFalse(sut.isWatchdogTermination(launch: .init(didCrash: false), deviceInfo: .mockWith(isSimulator: false), from: previous, to: current))
Expand All @@ -215,7 +244,8 @@ final class WatchdogTerminationCheckerTests: XCTestCase {
isActive: .mockAny(),
vendorId: "foo",
processId: pid,
trackingConsent: .mockRandom()
trackingConsent: .mockRandom(),
syntheticsEnvironment: false
)

let current = WatchdogTerminationAppState(
Expand All @@ -227,7 +257,8 @@ final class WatchdogTerminationCheckerTests: XCTestCase {
isActive: .mockAny(),
vendorId: "foo",
processId: pid,
trackingConsent: .mockRandom()
trackingConsent: .mockRandom(),
syntheticsEnvironment: false
)

XCTAssertFalse(sut.isWatchdogTermination(launch: .init(didCrash: false), deviceInfo: .mockWith(isSimulator: false), from: previous, to: current))
Expand All @@ -243,7 +274,8 @@ final class WatchdogTerminationCheckerTests: XCTestCase {
isActive: false,
vendorId: "foo",
processId: .mockAny(),
trackingConsent: .mockRandom()
trackingConsent: .mockRandom(),
syntheticsEnvironment: false
)

let current = WatchdogTerminationAppState(
Expand All @@ -255,7 +287,8 @@ final class WatchdogTerminationCheckerTests: XCTestCase {
isActive: .mockAny(),
vendorId: "foo",
processId: .mockAny(),
trackingConsent: .mockRandom()
trackingConsent: .mockRandom(),
syntheticsEnvironment: false
)

XCTAssertFalse(sut.isWatchdogTermination(launch: .init(didCrash: false), deviceInfo: .mockWith(isSimulator: false), from: previous, to: current))
Expand All @@ -271,7 +304,8 @@ final class WatchdogTerminationCheckerTests: XCTestCase {
isActive: true,
vendorId: "foo",
processId: UUID(),
trackingConsent: .mockRandom()
trackingConsent: .mockRandom(),
syntheticsEnvironment: false
)

let current = WatchdogTerminationAppState(
Expand All @@ -283,7 +317,8 @@ final class WatchdogTerminationCheckerTests: XCTestCase {
isActive: true,
vendorId: "foo",
processId: UUID(),
trackingConsent: .mockRandom()
trackingConsent: .mockRandom(),
syntheticsEnvironment: false
)

XCTAssertTrue(sut.isWatchdogTermination(launch: .init(didCrash: false), deviceInfo: .mockWith(isSimulator: false), from: previous, to: current))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ extension WatchdogTerminationAppState: RandomMockable, AnyMockable {
isActive: .mockAny(),
vendorId: .mockAny(),
processId: .mockAny(),
trackingConsent: .mockRandom()
trackingConsent: .mockRandom(),
syntheticsEnvironment: .mockRandom()
)
}

Expand All @@ -34,7 +35,8 @@ extension WatchdogTerminationAppState: RandomMockable, AnyMockable {
isActive: .mockRandom(),
vendorId: .mockRandom(),
processId: .mockAny(),
trackingConsent: .mockRandom()
trackingConsent: .mockRandom(),
syntheticsEnvironment: .mockRandom()
)
}
}
Expand Down Expand Up @@ -78,7 +80,8 @@ extension WatchdogTerminationAppStateManager: RandomMockable {
public static func mockRandom() -> WatchdogTerminationAppStateManager {
return .init(
featureScope: FeatureScopeMock(),
processId: .mockRandom()
processId: .mockRandom(),
syntheticsEnvironment: .mockRandom()
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,8 @@ final class WatchdogTerminationMonitorTests: XCTestCase {

let appStateManager = WatchdogTerminationAppStateManager(
featureScope: featureScope,
processId: processId
processId: processId,
syntheticsEnvironment: false
)

let checker = WatchdogTerminationChecker(appStateManager: appStateManager, featureScope: featureScope)
Expand Down