Skip to content

Commit

Permalink
fix: feature_flag_called after reloadFeatureFlags (#232)
Browse files Browse the repository at this point in the history
* fix: feature_flag_called after reloadFeatureFlags

* chore: lint

* feat: calculate updated keys and invalidate flag

* Update CHANGELOG.md

Co-authored-by: Manoel Aranda Neto <[email protected]>

* feat: revert changes to calculated updated keys

* fix: revert project file changes

* feat: address feedback

---------

Co-authored-by: Manoel Aranda Neto <[email protected]>
  • Loading branch information
ioannisj and marandaneto authored Nov 7, 2024
1 parent 30d509e commit 3970387
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 8 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
## Next

- fix $feature_flag_called not captured after reloading flags ([#232](https://github.com/PostHog/posthog-ios/pull/232))

## 3.14.1 - 2024-11-05

- recording: fix RN iOS masking ([#230](https://github.com/PostHog/posthog-ios/pull/230))
Expand Down
32 changes: 24 additions & 8 deletions PostHog/PostHogSDK.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ let maxRetryDelay = 30.0
private let setupLock = NSLock()
private let optOutLock = NSLock()
private let groupsLock = NSLock()
private let flagCallReportedLock = NSLock()
private let personPropsLock = NSLock()

private var queue: PostHogQueue?
Expand Down Expand Up @@ -347,7 +348,9 @@ let maxRetryDelay = 30.0
// storage also removes all feature flags
storage?.reset()
config.storageManager?.reset()
flagCallReported.removeAll()
flagCallReportedLock.withLock {
flagCallReported.removeAll()
}
PostHogSessionManager.shared.endSession {
self.resetViews()
}
Expand Down Expand Up @@ -797,7 +800,12 @@ let maxRetryDelay = 30.0
distinctId: storageManager.getDistinctId(),
anonymousId: storageManager.getAnonymousId(),
groups: groups ?? [:],
callback: callback
callback: {
self.flagCallReportedLock.withLock {
self.flagCallReported.removeAll()
}
callback()
}
)
}

Expand Down Expand Up @@ -850,14 +858,20 @@ let maxRetryDelay = 30.0
}

private func reportFeatureFlagCalled(flagKey: String, flagValue: Any?) {
if !flagCallReported.contains(flagKey) {
let properties: [String: Any] = [
var shouldCapture = false

flagCallReportedLock.withLock {
if !flagCallReported.contains(flagKey) {
flagCallReported.insert(flagKey)
shouldCapture = true
}
}

if shouldCapture {
let properties = [
"$feature_flag": flagKey,
"$feature_flag_response": flagValue ?? "",
]

flagCallReported.insert(flagKey)

capture("$feature_flag_called", properties: properties)
}
}
Expand Down Expand Up @@ -932,7 +946,9 @@ let maxRetryDelay = 30.0
self.reachability?.stopNotifier()
reachability = nil
#endif
flagCallReported.removeAll()
flagCallReportedLock.withLock {
flagCallReported.removeAll()
}
context = nil
PostHogSessionManager.shared.endSession {
self.resetViews()
Expand Down
49 changes: 49 additions & 0 deletions PostHogTests/PostHogSDKTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,21 @@ import Nimble
import Quick

@testable import PostHog
import XCTest

class PostHogSDKTest: QuickSpec {
func getSut(preloadFeatureFlags: Bool = false,
sendFeatureFlagEvent: Bool = false,
captureApplicationLifecycleEvents: Bool = false,
flushAt: Int = 1,
maxBatchSize: Int = 50,
optOut: Bool = false,
propertiesSanitizer: PostHogPropertiesSanitizer? = nil,
personProfiles: PostHogPersonProfiles = .identifiedOnly) -> PostHogSDK
{
let config = PostHogConfig(apiKey: "123", host: "http://localhost:9001")
config.flushAt = flushAt
config.maxBatchSize = maxBatchSize
config.preloadFeatureFlags = preloadFeatureFlags
config.sendFeatureFlagEvent = sendFeatureFlagEvent
config.disableReachabilityForTesting = true
Expand Down Expand Up @@ -850,6 +853,52 @@ class PostHogSDKTest: QuickSpec {
sut.reset()
sut.close()
}

it("captures $feature_flag_called when getFeatureFlag is called") {
let sut = self.getSut(
sendFeatureFlagEvent: true,
flushAt: 1
)

_ = sut.getFeatureFlag("some_key")

let event = getBatchedEvents(server)
expect(event.first!.event).to(equal("$feature_flag_called"))
}

it("does not capture $feature_flag_called when getFeatureFlag is called twice") {
let sut = self.getSut(
sendFeatureFlagEvent: true,
flushAt: 2
)

_ = sut.getFeatureFlag("some_key")
_ = sut.getFeatureFlag("some_key")
sut.capture("force_batch_flush")

let event = getBatchedEvents(server)
expect(event.count).to(equal(2))
expect(event[0].event).to(equal("$feature_flag_called"))
expect(event[1].event).to(equal("force_batch_flush"))
}

it("captures $feature_flag_called when getFeatureFlag called twice after reloading flags") {
let sut = self.getSut(
sendFeatureFlagEvent: true,
flushAt: 2
)

_ = sut.getFeatureFlag("some_key")

sut.reloadFeatureFlags {
_ = sut.getFeatureFlag("some_key")
}

let event = getBatchedEvents(server)
expect(event.count).to(equal(2))
expect(event[0].event).to(equal("$feature_flag_called"))
expect(event[1].event).to(equal("$feature_flag_called"))
}
}
}

Expand Down

0 comments on commit 3970387

Please sign in to comment.