diff --git a/splitio_ios/example/ios/Podfile b/splitio_ios/example/ios/Podfile index e3a7db2..8629561 100644 --- a/splitio_ios/example/ios/Podfile +++ b/splitio_ios/example/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your project -platform :ios, '11.0' +platform :ios, '12.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' diff --git a/splitio_ios/example/ios/Podfile.lock b/splitio_ios/example/ios/Podfile.lock index 1040a02..6f6ec46 100644 --- a/splitio_ios/example/ios/Podfile.lock +++ b/splitio_ios/example/ios/Podfile.lock @@ -1,9 +1,9 @@ PODS: - Flutter (1.0.0) - - Split (2.21.0) - - splitio_ios (0.3.0): + - Split (2.23.0) + - splitio_ios (0.4.0): - Flutter - - Split (~> 2.21.0) + - Split (~> 2.23.0) DEPENDENCIES: - Flutter (from `Flutter`) @@ -21,9 +21,9 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 - Split: e4324a8fe3fcb19c36a9e4fd84a893fc6d4bbeb0 - splitio_ios: 8293cb4e46661f9403f92a0d143c5bf6ad5053d4 + Split: 8140864905cd12cb66e2cf31e6ba9052d09c086b + splitio_ios: 1c1d7cd88e6756b3b40cf37cdf8610b8720164b0 -PODFILE CHECKSUM: 9eb4e99975f80022b373afce31dc8b3feb22df78 +PODFILE CHECKSUM: aed42fc5c94ade572556b7ed357c5c57f1bd83a2 COCOAPODS: 1.11.3 diff --git a/splitio_ios/example/ios/SplitTests/SplitClientConfigHelperTests.swift b/splitio_ios/example/ios/SplitTests/SplitClientConfigHelperTests.swift index e107644..339e629 100644 --- a/splitio_ios/example/ios/SplitTests/SplitClientConfigHelperTests.swift +++ b/splitio_ios/example/ios/SplitTests/SplitClientConfigHelperTests.swift @@ -21,7 +21,6 @@ class SplitClientConfigHelperTests: XCTestCase { "ready": 25, "streamingEnabled": true, "persistentAttributesEnabled": true, - "syncConfig": ["syncConfigNames": ["split1", "split2"], "syncConfigPrefixes": ["split_", "my_split_"]], "impressionsMode": "none", "syncEnabled": false, "userConsent": "declined", @@ -89,4 +88,30 @@ class SplitClientConfigHelperTests: XCTestCase { XCTAssertEqual(expectedImpressionsModes[index].rawValue, config.impressionsMode) } } + + func testSyncConfigWithoutFlagSetsIsMappedCorrectly() { + let configValues = [ + "syncConfig": ["syncConfigNames": ["split1", "split2"], "syncConfigPrefixes": ["split_", "my_split_"]], + ] + + let splitClientConfig: SplitClientConfig = SplitClientConfigHelper.fromMap(configurationMap: configValues, impressionListener: nil) + + XCTAssertEqual(2, splitClientConfig.sync.filters.count) + XCTAssertEqual(.byName, splitClientConfig.sync.filters[0].type) + XCTAssertEqual(["split1", "split2"], splitClientConfig.sync.filters[0].values) + XCTAssertEqual(.byPrefix, splitClientConfig.sync.filters[1].type) + XCTAssertEqual(["split_", "my_split_"], splitClientConfig.sync.filters[1].values) + } + + func testSyncConfigWithFlagSetsIsMappedCorrectly() { + let configValues = [ + "syncConfig": ["syncConfigNames": ["split1", "split2"], "syncConfigPrefixes": ["split_", "my_split_"] , "syncConfigFlagSets": ["set_1", "set_2"]], + ] + + let splitClientConfig: SplitClientConfig = SplitClientConfigHelper.fromMap(configurationMap: configValues, impressionListener: nil) + + XCTAssertEqual(1, splitClientConfig.sync.filters.count) + XCTAssertEqual(.bySet, splitClientConfig.sync.filters[0].type) + XCTAssertEqual(["set_1", "set_2"], splitClientConfig.sync.filters[0].values) + } } diff --git a/splitio_ios/example/ios/SplitTests/SplitMethodParserTests.swift b/splitio_ios/example/ios/SplitTests/SplitMethodParserTests.swift index e2d96a2..826c6f4 100644 --- a/splitio_ios/example/ios/SplitTests/SplitMethodParserTests.swift +++ b/splitio_ios/example/ios/SplitTests/SplitMethodParserTests.swift @@ -328,6 +328,8 @@ class SplitWrapperStub: SplitWrapper { var matchingKeyValue = "" var bucketingKeyValue: String? var splitNameValue = "" + var flagSetValue = "" + var flagSetsValue: [String] = [] var splitsValue: [String]? var attributesValue: [String: Any]? var eventTypeValue: String = "" @@ -389,6 +391,42 @@ class SplitWrapperStub: SplitWrapper { return result } + func getTreatmentsByFlagSet(matchingKey: String, flagSet: String, bucketingKey: String?, attributes: [String : Any]?) -> [String : String] { + matchingKeyValue = matchingKey + bucketingKeyValue = bucketingKey + flagSetValue = flagSet + attributeValue = attributes + + return [:] + } + + func getTreatmentsByFlagSets(matchingKey: String, flagSets: [String], bucketingKey: String?, attributes: [String : Any]?) -> [String : String] { + matchingKeyValue = matchingKey + bucketingKeyValue = bucketingKey + flagSetsValue = flagSets + attributeValue = attributes + + return [:] + } + + func getTreatmentsWithConfigByFlagSet(matchingKey: String, flagSet: String, bucketingKey: String?, attributes: [String : Any]?) -> [String : SplitResult] { + matchingKeyValue = matchingKey + bucketingKeyValue = bucketingKey + flagSetValue = flagSet + attributeValue = attributes + + return [:] + } + + func getTreatmentsWithConfigByFlagSets(matchingKey: String, flagSets: [String], bucketingKey: String?, attributes: [String : Any]?) -> [String : SplitResult] { + matchingKeyValue = matchingKey + bucketingKeyValue = bucketingKey + flagSetsValue = flagSets + attributeValue = attributes + + return [:] + } + func track(matchingKey: String, bucketingKey: String?, eventType: String, trafficType: String?, value: Double?, properties: [String: Any]) -> Bool { matchingKeyValue = matchingKey bucketingKeyValue = bucketingKey diff --git a/splitio_ios/example/ios/SplitTests/SplitTests.swift b/splitio_ios/example/ios/SplitTests/SplitTests.swift index e4c02ad..c01d314 100644 --- a/splitio_ios/example/ios/SplitTests/SplitTests.swift +++ b/splitio_ios/example/ios/SplitTests/SplitTests.swift @@ -18,7 +18,7 @@ class SplitTests: XCTestCase { splitWrapper.getClient(matchingKey: "key", bucketingKey: "bucketing") let treatment = splitWrapper.getTreatment(matchingKey: "key", splitName: "split", bucketingKey: "bucketing", attributes: nil) XCTAssert(treatment != nil) - XCTAssert(client.getTreatmentCalled) + XCTAssert(client.methodCalls["getTreatment"] == true) } func testGetTreatments() { @@ -27,7 +27,7 @@ class SplitTests: XCTestCase { splitWrapper.getClient(matchingKey: "key", bucketingKey: "bucketing") let treatment = splitWrapper.getTreatments(matchingKey: "key", splits: ["split"], bucketingKey: "bucketing", attributes: nil) XCTAssert(!treatment.isEmpty) - XCTAssert(client.getTreatmentsCalled) + XCTAssert(client.methodCalls["getTreatments"] == true) } func testGetTreatmentWithConfig() { @@ -36,7 +36,7 @@ class SplitTests: XCTestCase { splitWrapper.getClient(matchingKey: "key", bucketingKey: "bucketing") let treatment = splitWrapper.getTreatmentWithConfig(matchingKey: "key", splitName: "split", bucketingKey: "bucketing", attributes: nil) XCTAssert(treatment != nil) - XCTAssert(client.getTreatmentWithConfigCalled) + XCTAssert(client.methodCalls["getTreatmentWithConfig"] == true) } func testGetTreatmentsWithConfig() { @@ -45,7 +45,40 @@ class SplitTests: XCTestCase { splitWrapper.getClient(matchingKey: "key", bucketingKey: "bucketing") let treatment = splitWrapper.getTreatmentsWithConfig(matchingKey: "key", splits: ["split"], bucketingKey: "bucketing", attributes: nil) XCTAssert(!treatment.isEmpty) - XCTAssert(client.getTreatmentsWithConfigCalled) + XCTAssert(client.methodCalls["getTreatmentsWithConfig"] == true) + } + + func testGetTreatmentsByFlagSet() { + let client = SplitClientStub() + splitWrapper = DefaultSplitWrapper(splitFactoryProvider: SplitFactoryProviderStubWithClient(client: client)) + splitWrapper.getClient(matchingKey: "key", bucketingKey: "bucketing") + let treatment = splitWrapper.getTreatmentsByFlagSet(matchingKey: "key", flagSet: "set_1", bucketingKey: "bucketing", attributes: nil) + XCTAssert(client.methodCalls["getTreatmentsByFlagSet"] == true) + } + + func testGetTreatmentsByFlagSets() { + let client = SplitClientStub() + splitWrapper = DefaultSplitWrapper(splitFactoryProvider: SplitFactoryProviderStubWithClient(client: client)) + splitWrapper.getClient(matchingKey: "key", bucketingKey: "bucketing") + let treatment = splitWrapper.getTreatmentsByFlagSets(matchingKey: "key", flagSets: ["set_1"], bucketingKey: "bucketing", attributes: nil) + XCTAssert(client.methodCalls["getTreatmentsByFlagSets"] == true) + } + + func testGetTreatmentsWithConfigByFlagSet() { + let client = SplitClientStub() + splitWrapper = DefaultSplitWrapper(splitFactoryProvider: SplitFactoryProviderStubWithClient(client: client)) + splitWrapper.getClient(matchingKey: "key", bucketingKey: "bucketing") + let treatment = splitWrapper.getTreatmentsWithConfigByFlagSet(matchingKey: "key", flagSet: "set_1", bucketingKey: "bucketing", attributes: nil) + XCTAssert(client.methodCalls["getTreatmentsWithConfigByFlagSet"] == true) + } + + func testGetTreatmentsWithConfigByFlagSets() { + let client = SplitClientStub() + splitWrapper = DefaultSplitWrapper(splitFactoryProvider: SplitFactoryProviderStubWithClient(client: client)) + splitWrapper.getClient(matchingKey: "key", bucketingKey: "bucketing") + let treatment = splitWrapper.getTreatmentsWithConfigByFlagSets(matchingKey: "key", flagSets: ["set_1"], bucketingKey: "bucketing", attributes: nil) + + XCTAssert(client.methodCalls["getTreatmentsWithConfigByFlagSets"] == true) } func testTrack() { @@ -146,7 +179,7 @@ class SplitTests: XCTestCase { usedKeys.insert(Key(matchingKey: "key", bucketingKey: "bucketing")) splitWrapper = DefaultSplitWrapper(splitFactoryProvider: SplitFactoryProviderStubWithClient(client: client), usedKeys: usedKeys) splitWrapper.flush(matchingKey: "key", bucketingKey: "bucketing") - XCTAssert(client.flushCalled) + XCTAssert((client.methodCalls["flush"] != nil)) } func testDestroy() { @@ -303,11 +336,17 @@ class SplitFactoryStub: SplitFactory { class SplitClientStub: SplitClient { var destroyCalled: Bool = false - var getTreatmentCalled: Bool = false - var getTreatmentWithConfigCalled: Bool = false - var getTreatmentsCalled: Bool = false - var getTreatmentsWithConfigCalled: Bool = false - var flushCalled: Bool = false + var methodCalls = [ + "getTreatment": false, + "getTreatmentWithConfig": false, + "getTreatments": false, + "getTreatmentsWithConfig": false, + "getTreatmentsByFlagSet": false, + "getTreatmentsByFlagSets": false, + "getTreatmentsWithConfigByFlagSet": false, + "getTreatmentsWithConfigByFlagSets": false, + "flush": false, + ] var eventTypeValue: String = "" var trafficTypeValue: String? var valueValue: Double? @@ -319,35 +358,55 @@ class SplitClientStub: SplitClient { var sdkReadyEventAction: SplitAction? func getTreatment(_ split: String, attributes: [String: Any]?) -> String { - getTreatmentCalled = true + methodCalls["getTreatment"] = true return SplitConstants.control } func getTreatment(_ split: String) -> String { - getTreatmentCalled = true + methodCalls["getTreatment"] = true return SplitConstants.control } func getTreatments(splits: [String], attributes: [String: Any]?) -> [String: String] { - getTreatmentsCalled = true + methodCalls["getTreatments"] = true return ["feature": SplitConstants.control] } func getTreatmentWithConfig(_ split: String) -> SplitResult { - getTreatmentWithConfigCalled = true + methodCalls["getTreatmentWithConfig"] = true return SplitResult(treatment: SplitConstants.control) } func getTreatmentWithConfig(_ split: String, attributes: [String: Any]?) -> SplitResult { - getTreatmentWithConfigCalled = true + methodCalls["getTreatmentWithConfig"] = true return SplitResult(treatment: SplitConstants.control) } func getTreatmentsWithConfig(splits: [String], attributes: [String: Any]?) -> [String: SplitResult] { - getTreatmentsWithConfigCalled = true + methodCalls["getTreatmentsWithConfig"] = true return ["feature": SplitResult(treatment: SplitConstants.control)] } + func getTreatmentsByFlagSet(_ flagSet: String, attributes: [String : Any]?) -> [String : String] { + methodCalls["getTreatmentsByFlagSet"] = true + return [:] + } + + func getTreatmentsByFlagSets(_ flagSets: [String], attributes: [String : Any]?) -> [String : String] { + methodCalls["getTreatmentsByFlagSets"] = true + return [:] + } + + func getTreatmentsWithConfigByFlagSet(_ flagSet: String, attributes: [String : Any]?) -> [String : SplitResult] { + methodCalls["getTreatmentsWithConfigByFlagSet"] = true + return [:] + } + + func getTreatmentsWithConfigByFlagSets(_ flagSets: [String], attributes: [String : Any]?) -> [String : SplitResult] { + methodCalls["getTreatmentsWithConfigByFlagSets"] = true + return [:] + } + func on(event: SplitEvent, execute action: @escaping SplitAction) { if event == SplitEvent.sdkReady { sdkReadyEventAction = action @@ -430,7 +489,7 @@ class SplitClientStub: SplitClient { } func flush() { - flushCalled = true + methodCalls["flush"] = true } func destroy() { diff --git a/splitio_ios/ios/Classes/SplitClientConfigHelper.swift b/splitio_ios/ios/Classes/SplitClientConfigHelper.swift index 2febd19..feaaa5d 100644 --- a/splitio_ios/ios/Classes/SplitClientConfigHelper.swift +++ b/splitio_ios/ios/Classes/SplitClientConfigHelper.swift @@ -24,6 +24,7 @@ class SplitClientConfigHelper { static private let SYNC_CONFIG = "syncConfig" static private let SYNC_CONFIG_NAMES = "syncConfigNames" static private let SYNC_CONFIG_PREFIXES = "syncConfigPrefixes" + static private let SYNC_CONFIG_SETS = "syncConfigFlagSets" static private let IMPRESSIONS_MODE = "impressionsMode" static private let SYNC_ENABLED = "syncEnabled" static private let USER_CONSENT = "userConsent" @@ -149,12 +150,19 @@ class SplitClientConfigHelper { if configurationMap[SYNC_CONFIG] != nil { if let syncConfig = configurationMap[SYNC_CONFIG] as? [String: [String]] { let syncConfigBuilder = SyncConfig.builder() - if let syncNames = syncConfig[SYNC_CONFIG_NAMES] as? [String] { - syncConfigBuilder.addSplitFilter(SplitFilter.byName(syncNames)) - } - if let syncPrefixes = syncConfig[SYNC_CONFIG_NAMES] as? [String] { - syncConfigBuilder.addSplitFilter(SplitFilter.byPrefix(syncPrefixes)) + if (syncConfig[SYNC_CONFIG_SETS] != nil && syncConfig[SYNC_CONFIG_SETS]?.isEmpty == false) { + if let syncFlagSets = syncConfig[SYNC_CONFIG_SETS] as? [String] { + syncConfigBuilder.addSplitFilter(SplitFilter.bySet(syncFlagSets)) + } + } else { + if let syncNames = syncConfig[SYNC_CONFIG_NAMES] as? [String] { + syncConfigBuilder.addSplitFilter(SplitFilter.byName(syncNames)) + } + + if let syncPrefixes = syncConfig[SYNC_CONFIG_PREFIXES] as? [String] { + syncConfigBuilder.addSplitFilter(SplitFilter.byPrefix(syncPrefixes)) + } } config.sync = syncConfigBuilder.build() diff --git a/splitio_ios/ios/Classes/SplitWrapper.swift b/splitio_ios/ios/Classes/SplitWrapper.swift index 69e764f..b25f9d2 100644 --- a/splitio_ios/ios/Classes/SplitWrapper.swift +++ b/splitio_ios/ios/Classes/SplitWrapper.swift @@ -31,6 +31,14 @@ protocol EvaluationWrapper { func getTreatmentWithConfig(matchingKey: String, splitName: String, bucketingKey: String?, attributes: [String: Any]?) -> SplitResult? func getTreatmentsWithConfig(matchingKey: String, splits: [String], bucketingKey: String?, attributes: [String: Any]?) -> [String: SplitResult] + + func getTreatmentsByFlagSet(matchingKey: String, flagSet: String, bucketingKey: String?, attributes: [String: Any]?) -> [String: String] + + func getTreatmentsByFlagSets(matchingKey: String, flagSets: [String], bucketingKey: String?, attributes: [String: Any]?) -> [String: String] + + func getTreatmentsWithConfigByFlagSet(matchingKey: String, flagSet: String, bucketingKey: String?, attributes: [String: Any]?) -> [String: SplitResult] + + func getTreatmentsWithConfigByFlagSets(matchingKey: String, flagSets: [String], bucketingKey: String?, attributes: [String: Any]?) -> [String: SplitResult] } protocol AttributesWrapper { @@ -121,6 +129,38 @@ class DefaultSplitWrapper: SplitWrapper { return client.getTreatmentsWithConfig(splits: splits, attributes: attributes) } + func getTreatmentsByFlagSet(matchingKey: String, flagSet: String, bucketingKey: String? = nil, attributes: [String: Any]? = [:]) -> [String: String] { + guard let client = getInitializedClient(matchingKey: matchingKey, bucketingKey: bucketingKey) else { + return [:] + } + + return client.getTreatmentsByFlagSet(flagSet, attributes: attributes) + } + + func getTreatmentsByFlagSets(matchingKey: String, flagSets: [String], bucketingKey: String? = nil, attributes: [String: Any]? = [:]) -> [String: String] { + guard let client = getInitializedClient(matchingKey: matchingKey, bucketingKey: bucketingKey) else { + return [:] + } + + return client.getTreatmentsByFlagSets(flagSets, attributes: attributes) + } + + func getTreatmentsWithConfigByFlagSet(matchingKey: String, flagSet: String, bucketingKey: String? = nil, attributes: [String: Any]? = [:]) -> [String: SplitResult] { + guard let client = getInitializedClient(matchingKey: matchingKey, bucketingKey: bucketingKey) else { + return [:] + } + + return client.getTreatmentsWithConfigByFlagSet(flagSet, attributes: attributes) + } + + func getTreatmentsWithConfigByFlagSets(matchingKey: String, flagSets: [String], bucketingKey: String? = nil, attributes: [String: Any]? = [:]) -> [String: SplitResult] { + guard let client = getInitializedClient(matchingKey: matchingKey, bucketingKey: bucketingKey) else { + return [:] + } + + return client.getTreatmentsWithConfigByFlagSets(flagSets, attributes: attributes) + } + func track(matchingKey: String, bucketingKey: String?, eventType: String, trafficType: String?, value: Double?, properties: [String: Any]) -> Bool { guard let client = getInitializedClient(matchingKey: matchingKey, bucketingKey: bucketingKey) else { return false diff --git a/splitio_ios/ios/splitio_ios.podspec b/splitio_ios/ios/splitio_ios.podspec index 61453f6..7371662 100644 --- a/splitio_ios/ios/splitio_ios.podspec +++ b/splitio_ios/ios/splitio_ios.podspec @@ -4,7 +4,7 @@ # Pod::Spec.new do |s| s.name = 'splitio_ios' - s.version = '0.3.0' + s.version = '0.4.0' s.summary = 'split.io official Flutter plugin.' s.description = <<-DESC split.io official Flutter plugin. @@ -15,7 +15,7 @@ split.io official Flutter plugin. s.source = { :path => '.' } s.source_files = 'Classes/**/*' s.dependency 'Flutter' - s.dependency 'Split', '~> 2.21.0' + s.dependency 'Split', '~> 2.23.0' s.platform = :ios, '9.0' # Flutter.framework does not contain a i386 slice.