Skip to content
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
2 changes: 1 addition & 1 deletion Split/Events/SplitEventsManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ class DefaultSplitEventsManager: SplitEventsManager {
}
case .splitKilledNotification:
if isTriggered(external: .sdkReady) {
trigger(event: .sdkUpdated)
trigger(event: .sdkUpdated, metadata: event.metadata)
continue
}
case .sdkReadyTimeoutReached:
Expand Down
2 changes: 1 addition & 1 deletion Split/Localhost/LocalhostSynchronizer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class LocalhostSynchronizer: FeatureFlagsSynchronizer {
func stopPeriodicSync() {
}

func notifyKilled() {
func notifyKilled(flag: String) {
}

func notifyUpdated(flagsList: [String]) {
Expand Down
24 changes: 12 additions & 12 deletions Split/Network/Streaming/SseNotificationProcessor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,18 +36,18 @@ class DefaultSseNotificationProcessor: SseNotificationProcessor {
func process(_ notification: IncomingNotification) {
Logger.d("Received notification \(notification.type)")
switch notification.type {
case .splitUpdate:
processTargetingRuleUpdate(notification)
case .ruleBasedSegmentUpdate:
processTargetingRuleUpdate(notification)
case .mySegmentsUpdate:
processSegmentsUpdate(notification, updateWorker: mySegmentsUpdateWorker)
case .myLargeSegmentsUpdate:
processSegmentsUpdate(notification, updateWorker: myLargeSegmentsUpdateWorker)
case .splitKill:
processSplitKill(notification)
default:
Logger.e("Unknown notification arrived: \(notification.jsonData ?? "null" )")
case .splitUpdate:
processTargetingRuleUpdate(notification)
case .ruleBasedSegmentUpdate:
processTargetingRuleUpdate(notification)
case .mySegmentsUpdate:
processSegmentsUpdate(notification, updateWorker: mySegmentsUpdateWorker)
case .myLargeSegmentsUpdate:
processSegmentsUpdate(notification, updateWorker: myLargeSegmentsUpdateWorker)
case .splitKill:
processSplitKill(notification)
default:
Logger.e("Unknown notification arrived: \(notification.jsonData ?? "null" )")
}
}

Expand Down
2 changes: 1 addition & 1 deletion Split/Network/Streaming/SyncUpdateWorker.swift
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ class SplitKillWorker: UpdateWorker<SplitKillNotification> {
splitToKill.changeNumber = notification.changeNumber
splitToKill.killed = true
splitsStorage.updateWithoutChecks(split: splitToKill)
synchronizer.notifySplitKilled()
synchronizer.notifySplitKilled(flag: splitToKill.name ?? "")
}
}
synchronizer.synchronizeSplits(changeNumber: notification.changeNumber)
Expand Down
6 changes: 3 additions & 3 deletions Split/Network/Sync/FeatureFlagsSynchronizer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ protocol FeatureFlagsSynchronizer {
func synchronize(changeNumber: Int64?, rbsChangeNumber: Int64?)
func startPeriodicSync()
func stopPeriodicSync()
func notifyKilled()
func notifyKilled(flag: String)
func notifyUpdated(flagsList: [String])
func pause()
func resume()
Expand Down Expand Up @@ -144,8 +144,8 @@ class DefaultFeatureFlagsSynchronizer: FeatureFlagsSynchronizer {
periodicSplitsSyncWorker?.stop()
}

func notifyKilled() {
splitEventsManager.notifyInternalEvent(.splitKilledNotification)
func notifyKilled(flag: String) {
splitEventsManager.notifyInternalEvent(.splitKilledNotification, metadata: EventMetadata(type: .FLAGS_KILLED, data: [flag]))
}

func notifyUpdated(flagsList: [String]) {
Expand Down
6 changes: 3 additions & 3 deletions Split/Network/Sync/Synchronizer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ protocol Synchronizer: ImpressionLogger {
func notifyFeatureFlagsUpdated(flags: [String])
func notifySegmentsUpdated(forKey key: String)
func notifyLargeSegmentsUpdated(forKey key: String)
func notifySplitKilled()
func notifySplitKilled(flag: String)
func pause()
func resume()
func flush()
Expand Down Expand Up @@ -219,8 +219,8 @@ class DefaultSynchronizer: Synchronizer {
byKeySynchronizer.notifyMyLargeSegmentsUpdated(forKey: key)
}

func notifySplitKilled() {
featureFlagsSynchronizer.notifyKilled()
func notifySplitKilled(flag: String) {
featureFlagsSynchronizer.notifyKilled(flag: flag)
}

func pause() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ class FeatureFlagsSynchronizerStub: FeatureFlagsSynchronizer {
}

var notifyKilledCalled = false
func notifyKilled() {
var killedFlag = ""
func notifyKilled(flag: String) {
killedFlag = flag
notifyKilledCalled = true
}

Expand Down
6 changes: 4 additions & 2 deletions SplitTests/Fake/Streaming/SynchronizerSpy.swift
Original file line number Diff line number Diff line change
Expand Up @@ -212,9 +212,11 @@ class SynchronizerSpy: Synchronizer {
notifyFeatureFlagsUpdatedCalled = true
}

func notifySplitKilled() {
var killedFlag = ""
func notifySplitKilled(flag: String) {
notifySplitKilledCalled = true
splitSynchronizer.notifySplitKilled()
killedFlag = flag
splitSynchronizer.notifySplitKilled(flag: flag)
}

func start(forKey key: Key) {
Expand Down
4 changes: 3 additions & 1 deletion SplitTests/Fake/Streaming/SynchronizerStub.swift
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,9 @@ class SynchronizerStub: Synchronizer {
notifyFeatureFlagsUpdatedCalled = true
}

func notifySplitKilled() {
var killedFlag = ""
func notifySplitKilled(flag: String) {
killedFlag = flag
notifySplitKilledCalled = true
}

Expand Down
14 changes: 7 additions & 7 deletions SplitTests/Integration/Sync/SplitSdkUpdatePollingTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,15 @@ class SplitSdkUpdatePollingTest: XCTestCase {

override func setUp() {
let session = HttpSessionMock()
let reqManager = HttpRequestManagerTestDispatcher(dispatcher: buildTestDispatcher(),
let reqManager = HttpRequestManagerTestDispatcher(dispatcher: buildTestDispatcher("splitchanges_int_test"),
streamingHandler: buildStreamingHandler())
httpClient = DefaultHttpClient(session: session, requestManager: reqManager)
}


private func buildTestDispatcher() -> HttpClientTestDispatcher {
private func buildTestDispatcher(_ file: String) -> HttpClientTestDispatcher {

let respData = responseSplitChanges()
let respData = responseSplitChanges(file)
var responses = [TestDispatcherResponse]()
for data in respData {
let rData = TargetingRulesChange(featureFlags: data, ruleBasedSegments: RuleBasedSegmentChange(segments: [], since: -1, till: -1))
Expand Down Expand Up @@ -307,12 +307,12 @@ class SplitSdkUpdatePollingTest: XCTestCase {
semaphore.wait()
}

private func responseSplitChanges() -> [SplitChange] {
private func responseSplitChanges(_ file: String) -> [SplitChange] {
var changes = [SplitChange]()

var prevChangeNumber: Int64 = 0
for i in 0..<4 {
let c = loadSplitsChangeFile()!
let c = loadSplitsChangeFile(file)!
c.since = c.till
if prevChangeNumber != 0 {
c.till = prevChangeNumber + kChangeNbInterval
Expand All @@ -331,8 +331,8 @@ class SplitSdkUpdatePollingTest: XCTestCase {
return changes
}

private func loadSplitsChangeFile() -> SplitChange? {
return FileHelper.loadSplitChangeFile(sourceClass: self, fileName: "splitchanges_int_test")
private func loadSplitsChangeFile(_ file: String) -> SplitChange? {
return FileHelper.loadSplitChangeFile(sourceClass: self, fileName: file)
}

private func getAndIncrement() -> Int {
Expand Down
86 changes: 69 additions & 17 deletions SplitTests/Integration/streaming/StreamingSplitKillTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,18 @@ class StreamingSplitKillTest: XCTestCase {
var exp2: XCTestExpectation!
var exp3: XCTestExpectation!
var exp4: XCTestExpectation!
var exp5: XCTestExpectation!

override func setUp() {
expIndex = 1
let session = HttpSessionMock()
let reqManager = HttpRequestManagerTestDispatcher(dispatcher: buildTestDispatcher(),
streamingHandler: buildStreamingHandler())
let reqManager = HttpRequestManagerTestDispatcher(dispatcher: buildTestDispatcher(), streamingHandler: buildStreamingHandler())
httpClient = DefaultHttpClient(session: session, requestManager: reqManager)
loadChanges()
}

func testSplitKill() {
// MARK: Tests
func testSplitKill() throws {
let splitConfig: SplitClientConfig = SplitClientConfig()
splitConfig.featuresRefreshRate = 9999
splitConfig.segmentsRefreshRate = 9999
Expand All @@ -55,19 +56,19 @@ class StreamingSplitKillTest: XCTestCase {
.setConfig(splitConfig).build()!

let client = factory.client
let expTimeout: TimeInterval = 5
let expTimeout: TimeInterval = 5

let sdkReadyExpectation = XCTestExpectation(description: "SDK READY Expectation")
exp1 = XCTestExpectation(description: "Exp1")
exp2 = XCTestExpectation(description: "Exp2")
exp3 = XCTestExpectation(description: "Exp3")
exp4 = XCTestExpectation(description: "Exp4")

client.on(event: SplitEvent.sdkReady) {
client.on(event: .sdkReady) {
sdkReadyExpectation.fulfill()
}

client.on(event: SplitEvent.sdkReadyTimedOut) {
client.on(event: .sdkReadyTimedOut) {
IntegrationHelper.tlog("TIMEOUT")
}

Expand All @@ -80,28 +81,25 @@ class StreamingSplitKillTest: XCTestCase {
let splitName = "workm"
let treatmentReady = client.getTreatment(splitName)

streamingBinding?.push(message:
StreamingIntegrationHelper.splitKillMessagge(splitName: splitName, defaultTreatment: "conta",
timestamp: numbers[splitsChangesHits],
changeNumber: numbers[splitsChangesHits]))
streamingBinding?.push(message: StreamingIntegrationHelper.splitKillMessagge(splitName: splitName, defaultTreatment: "conta",
timestamp: numbers[splitsChangesHits],
changeNumber: numbers[splitsChangesHits]))

wait(for: [exp2], timeout: expTimeout)
waitForUpdate(secs: 1)

let treatmentKill = client.getTreatment(splitName)

streamingBinding?.push(message:
StreamingIntegrationHelper.splitUpdateMessage(timestamp: numbers[splitsChangesHits],
changeNumber: numbers[splitsChangesHits]))
streamingBinding?.push(message: StreamingIntegrationHelper.splitUpdateMessage(timestamp: numbers[splitsChangesHits],
changeNumber: numbers[splitsChangesHits]))

wait(for: [exp3], timeout: expTimeout)
waitForUpdate(secs: 1)
let treatmentNoKill = client.getTreatment(splitName)

streamingBinding?.push(message:
StreamingIntegrationHelper.splitKillMessagge(splitName: splitName, defaultTreatment: "conta",
timestamp: numbers[0],
changeNumber: numbers[0]))
streamingBinding?.push(message: StreamingIntegrationHelper.splitKillMessagge(splitName: splitName, defaultTreatment: "conta",
timestamp: numbers[0],
changeNumber: numbers[0]))

ThreadUtils.delay(seconds: 2.0) // The server should not be hit here
let treatmentOldKill = client.getTreatment(splitName)
Expand All @@ -118,6 +116,60 @@ class StreamingSplitKillTest: XCTestCase {
semaphore.wait()
}

func testSplitKillWithMetadata() throws {

// Setup
let splitConfig: SplitClientConfig = SplitClientConfig()
splitConfig.featuresRefreshRate = 9999
splitConfig.segmentsRefreshRate = 9999
splitConfig.impressionRefreshRate = 999999
splitConfig.sdkReadyTimeOut = 60000
splitConfig.eventsPushRate = 999999

let key: Key = Key(matchingKey: userKey)
let builder = DefaultSplitFactoryBuilder()
_ = builder.setHttpClient(httpClient)
_ = builder.setReachabilityChecker(ReachabilityMock())
_ = builder.setTestDatabase(TestingHelper.createTestDatabase(name: "test"))
let factory = builder.setApiKey(apiKey).setKey(key).setConfig(splitConfig).build()!
let client = factory.client
let expTimeout: TimeInterval = 5

let sdkReadyExpectation = XCTestExpectation(description: "SDK READY Expectation")
exp1 = XCTestExpectation(description: "Streaming notification")
exp2 = XCTestExpectation(description: "Push notification")
exp5 = XCTestExpectation(description: "Wait for killed metadata event")

client.on(event: .sdkReady) { sdkReadyExpectation.fulfill() }

// Set listener
client.on(event: .sdkUpdated) { [weak self] metadata in
if metadata?.type == .FLAGS_KILLED {
XCTAssertEqual(metadata?.data, ["workm"])
self?.exp5.fulfill()
}
}

// Simulate Kill
wait(for: [sdkReadyExpectation, sseConnExp], timeout: expTimeout)
streamingBinding?.push(message: ":keepalive") // send keep alive to confirm streaming connection ok
wait(for: [exp1], timeout: expTimeout)
waitForUpdate(secs: 1)
streamingBinding?.push(message: StreamingIntegrationHelper.splitKillMessagge(splitName: "workm", defaultTreatment: "conta",
timestamp: numbers[splitsChangesHits],
changeNumber: numbers[splitsChangesHits]))
wait(for: [exp5, exp2], timeout: expTimeout)
waitForUpdate(secs: 1)

// Cleanup
let semaphore = DispatchSemaphore(value: 0)
client.destroy(completion: {
_ = semaphore.signal()
})
semaphore.wait()
}

//MARK: Testing Helpers
private func getChanges(for hitNumber: Int) -> Data {
if hitNumber < 4 {
return Data(self.changes[hitNumber].utf8)
Expand Down
Loading