From 859df60b779331e6059b3ec0f773596ce17b5b0f Mon Sep 17 00:00:00 2001 From: Gaston Thea Date: Thu, 2 Nov 2023 14:50:41 -0300 Subject: [PATCH 01/28] Add flagSets constructor to SplitSyncConfig --- .../lib/split_sync_config.dart | 10 ++++++++++ .../test/split_sync_config_test.dart | 20 +++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 splitio_platform_interface/test/split_sync_config_test.dart diff --git a/splitio_platform_interface/lib/split_sync_config.dart b/splitio_platform_interface/lib/split_sync_config.dart index 6eec23d..d9abc8b 100644 --- a/splitio_platform_interface/lib/split_sync_config.dart +++ b/splitio_platform_interface/lib/split_sync_config.dart @@ -1,15 +1,19 @@ class SyncConfig { late Set _names; late Set _prefixes; + late Set _sets; Set get names => _names; Set get prefixes => _prefixes; + Set get sets => _sets; + SyncConfig( {List names = const [], List prefixes = const []}) { _names = names.toSet(); _prefixes = prefixes.toSet(); + _sets = {}; } SyncConfig.fromSet( @@ -17,4 +21,10 @@ class SyncConfig { _names = names; _prefixes = prefixes; } + + SyncConfig.flagSets({required List sets}) { + _sets = sets.toSet(); + _names = {}; + _prefixes = {}; + } } diff --git a/splitio_platform_interface/test/split_sync_config_test.dart b/splitio_platform_interface/test/split_sync_config_test.dart new file mode 100644 index 0000000..d8ba544 --- /dev/null +++ b/splitio_platform_interface/test/split_sync_config_test.dart @@ -0,0 +1,20 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:splitio_platform_interface/split_sync_config.dart'; + +void main() { + test('names and prefixes can be added simultaneously', () { + var syncConfig = SyncConfig(names: ['name1'], prefixes: ['prefix1']); + + expect(syncConfig.names, ['name1']); + expect(syncConfig.prefixes, ['prefix1']); + expect(syncConfig.sets, []); + }); + + test('flagSets constructor allows only sets', () { + var syncConfig = SyncConfig.flagSets(sets: ['set1','set2']); + + expect(syncConfig.names, []); + expect(syncConfig.prefixes, []); + expect(syncConfig.sets, ['set1','set2']); + }); +} From 1126d811242066214374c79fbf65b815d22e25d5 Mon Sep 17 00:00:00 2001 From: Gaston Thea Date: Thu, 2 Nov 2023 15:48:04 -0300 Subject: [PATCH 02/28] Add to SplitConfiguration --- .github/workflows/build.yml | 12 ------------ .../lib/split_configuration.dart | 3 ++- .../lib/split_sync_config.dart | 2 +- .../test/split_sync_config_test.dart | 2 +- .../test/splitio_configuration_test.dart | 15 +++++++++++++-- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index fa2869b..a2d5fff 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -41,18 +41,6 @@ jobs: - name: Run Android test run: cd splitio/example/android/; ./gradlew :splitio:testReleaseUnitTest; - build-ios: - name: Build iOS - runs-on: [ macos-latest ] - - steps: - - uses: actions/checkout@v3.5.2 - - uses: subosito/flutter-action@v2.10.0 - with: - channel: 'stable' - - name: Run Build iOS - run: cd splitio/example/ios; flutter build ios --no-codesign; - test-ios: name: Test iOS runs-on: [ macos-latest ] diff --git a/splitio_platform_interface/lib/split_configuration.dart b/splitio_platform_interface/lib/split_configuration.dart index 08496aa..4a56668 100644 --- a/splitio_platform_interface/lib/split_configuration.dart +++ b/splitio_platform_interface/lib/split_configuration.dart @@ -147,7 +147,8 @@ class SplitConfiguration { if (syncConfig != null) { configurationMap['syncConfig'] = { 'syncConfigNames': syncConfig.names.toList(growable: false), - 'syncConfigPrefixes': syncConfig.prefixes.toList(growable: false) + 'syncConfigPrefixes': syncConfig.prefixes.toList(growable: false), + 'syncConfigFlagSets': syncConfig.sets.toList(growable: false) }; } diff --git a/splitio_platform_interface/lib/split_sync_config.dart b/splitio_platform_interface/lib/split_sync_config.dart index d9abc8b..bc47f8d 100644 --- a/splitio_platform_interface/lib/split_sync_config.dart +++ b/splitio_platform_interface/lib/split_sync_config.dart @@ -22,7 +22,7 @@ class SyncConfig { _prefixes = prefixes; } - SyncConfig.flagSets({required List sets}) { + SyncConfig.flagSets(List sets) { _sets = sets.toSet(); _names = {}; _prefixes = {}; diff --git a/splitio_platform_interface/test/split_sync_config_test.dart b/splitio_platform_interface/test/split_sync_config_test.dart index d8ba544..254dd0c 100644 --- a/splitio_platform_interface/test/split_sync_config_test.dart +++ b/splitio_platform_interface/test/split_sync_config_test.dart @@ -11,7 +11,7 @@ void main() { }); test('flagSets constructor allows only sets', () { - var syncConfig = SyncConfig.flagSets(sets: ['set1','set2']); + var syncConfig = SyncConfig.flagSets(['set1','set2']); expect(syncConfig.names, []); expect(syncConfig.prefixes, []); diff --git a/splitio_platform_interface/test/splitio_configuration_test.dart b/splitio_platform_interface/test/splitio_configuration_test.dart index 0e22f77..9921f57 100644 --- a/splitio_platform_interface/test/splitio_configuration_test.dart +++ b/splitio_platform_interface/test/splitio_configuration_test.dart @@ -3,7 +3,7 @@ import 'package:splitio_platform_interface/split_configuration.dart'; import 'package:splitio_platform_interface/split_sync_config.dart'; void main() { - test('valuesAreMappedCorrectly', () async { + test('values are mapped correctly', () async { final SplitConfiguration config = SplitConfiguration( eventFlushInterval: 2000, eventsPerPush: 300, @@ -65,10 +65,21 @@ void main() { expect(config.configurationMap['readyTimeout'], 1); }); - test('noSpecialValuesLeavesMapEmpty', () async { + test('no special values leaves map empty', () async { final SplitConfiguration config = SplitConfiguration(); expect(config.configurationMap.length, 1); expect(config.configurationMap['readyTimeout'], 10); }); + + test('sets values are mapped correctly', () async { + final SplitConfiguration config = SplitConfiguration( + syncConfig: SyncConfig.flagSets(['one', 'two']), + ); + + expect(config.configurationMap['syncConfig']['syncConfigNames'], []); + expect(config.configurationMap['syncConfig']['syncConfigPrefixes'], []); + expect(config.configurationMap['syncConfig']['syncConfigFlagSets'], + ['one', 'two']); + }); } From d31b9f712e50b8f2a39f41211a65d7dfd91d8419 Mon Sep 17 00:00:00 2001 From: Gaston Thea Date: Thu, 2 Nov 2023 16:50:56 -0300 Subject: [PATCH 03/28] New evaluation methods in platform --- .../lib/method_channel_platform.dart | 68 +++++++++- .../lib/splitio_platform_interface.dart | 32 +++++ .../test/method_channel_platform_test.dart | 128 ++++++++++++++++++ 3 files changed, 227 insertions(+), 1 deletion(-) diff --git a/splitio_platform_interface/lib/method_channel_platform.dart b/splitio_platform_interface/lib/method_channel_platform.dart index 4bc0400..d3fb11d 100644 --- a/splitio_platform_interface/lib/method_channel_platform.dart +++ b/splitio_platform_interface/lib/method_channel_platform.dart @@ -33,7 +33,9 @@ class MethodChannelPlatform extends SplitioPlatform { Map arguments = { 'apiKey': apiKey, 'matchingKey': matchingKey, - 'sdkConfiguration': sdkConfiguration?.configurationMap ?? SplitConfiguration().configurationMap, // If sdkConfiguration is null, create a new SplitConfiguration to apply default values + 'sdkConfiguration': sdkConfiguration?.configurationMap ?? + SplitConfiguration().configurationMap, + // If sdkConfiguration is null, create a new SplitConfiguration to apply default values }; if (bucketingKey != null) { @@ -165,6 +167,70 @@ class MethodChannelPlatform extends SplitioPlatform { {for (var item in splitNames) item: _controlResult}; } + @override + Future> getTreatmentsByFlagSet( + {required String matchingKey, + required String? bucketingKey, + required String flagSet, + Map attributes = const {}}) async { + Map? treatments = await methodChannel.invokeMapMethod( + 'getTreatmentsByFlagSet', + _buildParameters(matchingKey, bucketingKey, + {'flagSet': flagSet, 'attributes': attributes})); + + return treatments + ?.map((key, value) => MapEntry(key, value)) ?? + {}; + } + + @override + Future> getTreatmentsByFlagSets( + {required String matchingKey, + required String? bucketingKey, + required List flagSets, + Map attributes = const {}}) async { + Map? treatments = await methodChannel.invokeMapMethod( + 'getTreatmentsByFlagSets', + _buildParameters(matchingKey, bucketingKey, + {'flagSets': flagSets, 'attributes': attributes})); + + return treatments + ?.map((key, value) => MapEntry(key, value)) ?? + {}; + } + + @override + Future> getTreatmentsWithConfigByFlagSet( + {required String matchingKey, + required String? bucketingKey, + required String flagSet, + Map attributes = const {}}) async { + Map? treatments = await methodChannel.invokeMapMethod( + 'getTreatmentsWithConfigByFlagSet', + _buildParameters(matchingKey, bucketingKey, + {'flagSet': flagSet, 'attributes': attributes})); + + return treatments?.map((key, value) => + MapEntry(key, SplitResult(value['treatment'], value['config']))) ?? + {}; + } + + @override + Future> getTreatmentsWithConfigByFlagSets( + {required String matchingKey, + required String? bucketingKey, + required List flagSets, + Map attributes = const {}}) async { + Map? treatments = await methodChannel.invokeMapMethod( + 'getTreatmentsWithConfigByFlagSets', + _buildParameters(matchingKey, bucketingKey, + {'flagSets': flagSets, 'attributes': attributes})); + + return treatments?.map((key, value) => + MapEntry(key, SplitResult(value['treatment'], value['config']))) ?? + {}; + } + @override Future removeAttribute( {required String matchingKey, diff --git a/splitio_platform_interface/lib/splitio_platform_interface.dart b/splitio_platform_interface/lib/splitio_platform_interface.dart index 3e71adb..a367fdf 100644 --- a/splitio_platform_interface/lib/splitio_platform_interface.dart +++ b/splitio_platform_interface/lib/splitio_platform_interface.dart @@ -90,6 +90,38 @@ abstract class _ClientPlatform { throw UnimplementedError(); } + Future> getTreatmentsByFlagSet( + {required String matchingKey, + required String? bucketingKey, + required String flagSet, + Map attributes = const {}}) { + throw UnimplementedError(); + } + + Future> getTreatmentsByFlagSets( + {required String matchingKey, + required String? bucketingKey, + required List flagSets, + Map attributes = const {}}) { + throw UnimplementedError(); + } + + Future> getTreatmentsWithConfigByFlagSet( + {required String matchingKey, + required String? bucketingKey, + required String flagSet, + Map attributes = const {}}) { + throw UnimplementedError(); + } + + Future> getTreatmentsWithConfigByFlagSets( + {required String matchingKey, + required String? bucketingKey, + required List flagSets, + Map attributes = const {}}) { + throw UnimplementedError(); + } + Future> getAllAttributes( {required String matchingKey, required String? bucketingKey}) { throw UnimplementedError(); diff --git a/splitio_platform_interface/test/method_channel_platform_test.dart b/splitio_platform_interface/test/method_channel_platform_test.dart index d03c4f5..5dceddf 100644 --- a/splitio_platform_interface/test/method_channel_platform_test.dart +++ b/splitio_platform_interface/test/method_channel_platform_test.dart @@ -33,8 +33,12 @@ void main() { case 'getTreatment': return ''; case 'getTreatments': + case 'getTreatmentsByFlagSet': + case 'getTreatmentsByFlagSets': return {'split1': 'on', 'split2': 'off'}; case 'getTreatmentsWithConfig': + case 'getTreatmentsWithConfigByFlagSet': + case 'getTreatmentsWithConfigByFlagSets': return { 'split1': {'treatment': 'on', 'config': null}, 'split2': {'treatment': 'off', 'config': null} @@ -185,6 +189,130 @@ void main() { 'attributes': {'attr1': true} }); }); + + test('getTreatmentsByFlagSet without attributes', () async { + _platform.getTreatmentsByFlagSet( + matchingKey: 'matching-key', + bucketingKey: 'bucketing-key', + flagSet: 'set_1'); + + expect(methodName, 'getTreatmentsByFlagSet'); + expect(methodArguments, { + 'flagSet': 'set_1', + 'matchingKey': 'matching-key', + 'bucketingKey': 'bucketing-key', + 'attributes': {} + }); + }); + + test('getTreatmentsByFlagSet with attributes', () async { + _platform.getTreatmentsByFlagSet( + matchingKey: 'matching-key', + bucketingKey: 'bucketing-key', + flagSet: 'set_1', + attributes: {'attr1': true}); + + expect(methodName, 'getTreatmentsByFlagSet'); + expect(methodArguments, { + 'flagSet': 'set_1', + 'matchingKey': 'matching-key', + 'bucketingKey': 'bucketing-key', + 'attributes': {'attr1': true} + }); + }); + + test('getTreatmentsByFlagSets without attributes', () async { + _platform.getTreatmentsByFlagSets( + matchingKey: 'matching-key', + bucketingKey: 'bucketing-key', + flagSets: ['set_1', 'set_2']); + + expect(methodName, 'getTreatmentsByFlagSets'); + expect(methodArguments, { + 'flagSets': ['set_1', 'set_2'], + 'matchingKey': 'matching-key', + 'bucketingKey': 'bucketing-key', + 'attributes': {} + }); + }); + + test('getTreatmentsByFlagSets with attributes', () async { + _platform.getTreatmentsByFlagSets( + matchingKey: 'matching-key', + bucketingKey: 'bucketing-key', + flagSets: ['set_1', 'set_2'], + attributes: {'attr1': true}); + + expect(methodName, 'getTreatmentsByFlagSets'); + expect(methodArguments, { + 'flagSets': ['set_1', 'set_2'], + 'matchingKey': 'matching-key', + 'bucketingKey': 'bucketing-key', + 'attributes': {'attr1': true} + }); + }); + + test('getTreatmentsWithConfigByFlagSet without attributes', () async { + _platform.getTreatmentsWithConfigByFlagSet( + matchingKey: 'matching-key', + bucketingKey: 'bucketing-key', + flagSet: 'set_1'); + + expect(methodName, 'getTreatmentsWithConfigByFlagSet'); + expect(methodArguments, { + 'flagSet': 'set_1', + 'matchingKey': 'matching-key', + 'bucketingKey': 'bucketing-key', + 'attributes': {} + }); + }); + + test('getTreatmentsWithConfigByFlagSet with attributes', () async { + _platform.getTreatmentsWithConfigByFlagSet( + matchingKey: 'matching-key', + bucketingKey: 'bucketing-key', + flagSet: 'set_1', + attributes: {'attr1': true}); + + expect(methodName, 'getTreatmentsWithConfigByFlagSet'); + expect(methodArguments, { + 'flagSet': 'set_1', + 'matchingKey': 'matching-key', + 'bucketingKey': 'bucketing-key', + 'attributes': {'attr1': true} + }); + }); + + test('getTreatmentsWithConfigByFlagSets without attributes', () async { + _platform.getTreatmentsWithConfigByFlagSets( + matchingKey: 'matching-key', + bucketingKey: 'bucketing-key', + flagSets: ['set_1', 'set_2']); + + expect(methodName, 'getTreatmentsWithConfigByFlagSets'); + expect(methodArguments, { + 'flagSets': ['set_1', 'set_2'], + 'matchingKey': 'matching-key', + 'bucketingKey': 'bucketing-key', + 'attributes': {} + }); + }); + + test('getTreatmentsWithConfigByFlagSets with attributes', () async { + _platform.getTreatmentsWithConfigByFlagSets( + matchingKey: 'matching-key', + bucketingKey: 'bucketing-key', + flagSets: ['set_1', 'set_2'], + attributes: {'attr1': true}); + + expect(methodName, 'getTreatmentsWithConfigByFlagSets'); + expect(methodArguments, { + 'flagSets': ['set_1', 'set_2'], + 'matchingKey': 'matching-key', + 'bucketingKey': 'bucketing-key', + 'attributes': {'attr1': true} + }); + }); }); group('track', () { From 34da30519d36b7c452dea23b88f3525c7e0c7259 Mon Sep 17 00:00:00 2001 From: Gaston Thea Date: Thu, 2 Nov 2023 17:37:41 -0300 Subject: [PATCH 04/28] Change toString implementation of split_result --- .../lib/split_result.dart | 6 +++--- .../test/split_result_test.dart | 20 +++++++++++++++++++ 2 files changed, 23 insertions(+), 3 deletions(-) create mode 100644 splitio_platform_interface/test/split_result_test.dart diff --git a/splitio_platform_interface/lib/split_result.dart b/splitio_platform_interface/lib/split_result.dart index 80b452b..f1c0896 100644 --- a/splitio_platform_interface/lib/split_result.dart +++ b/splitio_platform_interface/lib/split_result.dart @@ -13,8 +13,8 @@ class SplitResult { String toString() { return '{"treatment": "' + treatment + - '", config: "' + - (config ?? 'null') + - '"}'; + '", config: ' + + (config != null ? '"$config"' : 'null') + + '}'; } } diff --git a/splitio_platform_interface/test/split_result_test.dart b/splitio_platform_interface/test/split_result_test.dart new file mode 100644 index 0000000..a69928a --- /dev/null +++ b/splitio_platform_interface/test/split_result_test.dart @@ -0,0 +1,20 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:splitio_platform_interface/split_result.dart'; + +void main() { + test('result with config', () { + const result = SplitResult('on', 'config'); + + expect(result.treatment, 'on'); + expect(result.config, 'config'); + expect(result.toString(), '{"treatment": "on", config: "config"}'); + }); + + test('result with null config', () { + const result = SplitResult('on', null); + + expect(result.treatment, 'on'); + expect(result.config, null); + expect(result.toString(), '{"treatment": "on", config: null}'); + }); +} From 3b0e582321474efd76196b1d61813ed2f75a79fc Mon Sep 17 00:00:00 2001 From: Gaston Thea Date: Thu, 2 Nov 2023 17:42:11 -0300 Subject: [PATCH 05/28] defaultTreatment in SplitView --- splitio_platform_interface/lib/split_view.dart | 10 +++++++--- splitio_platform_interface/test/split_view_test.dart | 2 ++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/splitio_platform_interface/lib/split_view.dart b/splitio_platform_interface/lib/split_view.dart index be05ae0..c89247b 100644 --- a/splitio_platform_interface/lib/split_view.dart +++ b/splitio_platform_interface/lib/split_view.dart @@ -7,9 +7,10 @@ class SplitView { List treatments = []; int changeNumber; Map configs = {}; + String defaultTreatment; SplitView(this.name, this.trafficType, this.killed, this.treatments, - this.changeNumber, this.configs); + this.changeNumber, this.configs, [this.defaultTreatment = '']); static SplitView? fromEntry(Map? entry) { if (entry == null || entry.isEmpty) { @@ -27,7 +28,9 @@ class SplitView { entry['killed'], (entry['treatments'] as List).map((el) => el as String).toList(), entry['changeNumber'], - mappedConfig); + mappedConfig, + entry['defaultTreatment'] ?? '', + ); } @override @@ -38,7 +41,8 @@ class SplitView { killed: $killed, treatments: ${treatments.toString()}, changeNumber: $changeNumber, - config: $configs + config: $configs, + defaultTreatment: $defaultTreatment }'''; } } diff --git a/splitio_platform_interface/test/split_view_test.dart b/splitio_platform_interface/test/split_view_test.dart index 0268b42..50701e9 100644 --- a/splitio_platform_interface/test/split_view_test.dart +++ b/splitio_platform_interface/test/split_view_test.dart @@ -22,6 +22,7 @@ void main() { 'configs': {'yes': '{"abc"}', 'no': '"wasd"'}, 'changeNumber': 156246, 'trafficType': 'default', + 'defaultTreatment': 'on', }); expect(splitView?.name, 'my_split'); @@ -30,5 +31,6 @@ void main() { expect(splitView?.configs, {'yes': '{"abc"}', 'no': '"wasd"'}); expect(splitView?.changeNumber, 156246); expect(splitView?.trafficType, 'default'); + expect(splitView?.defaultTreatment, 'on'); }); } From f8a5060ab155a9f925bbeaa0a64d36f94636ac11 Mon Sep 17 00:00:00 2001 From: Gaston Thea Date: Thu, 2 Nov 2023 17:46:13 -0300 Subject: [PATCH 06/28] Add sets to SplitView --- splitio_platform_interface/lib/split_view.dart | 9 ++++++--- splitio_platform_interface/test/split_view_test.dart | 2 ++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/splitio_platform_interface/lib/split_view.dart b/splitio_platform_interface/lib/split_view.dart index c89247b..40451c5 100644 --- a/splitio_platform_interface/lib/split_view.dart +++ b/splitio_platform_interface/lib/split_view.dart @@ -8,9 +8,11 @@ class SplitView { int changeNumber; Map configs = {}; String defaultTreatment; + List sets = []; SplitView(this.name, this.trafficType, this.killed, this.treatments, - this.changeNumber, this.configs, [this.defaultTreatment = '']); + this.changeNumber, this.configs, + [this.defaultTreatment = '', this.sets = const []]); static SplitView? fromEntry(Map? entry) { if (entry == null || entry.isEmpty) { @@ -30,7 +32,7 @@ class SplitView { entry['changeNumber'], mappedConfig, entry['defaultTreatment'] ?? '', - ); + entry['sets'] ?? []); } @override @@ -42,7 +44,8 @@ class SplitView { treatments: ${treatments.toString()}, changeNumber: $changeNumber, config: $configs, - defaultTreatment: $defaultTreatment + defaultTreatment: $defaultTreatment, + sets: ${sets.toString()} }'''; } } diff --git a/splitio_platform_interface/test/split_view_test.dart b/splitio_platform_interface/test/split_view_test.dart index 50701e9..9a5aee1 100644 --- a/splitio_platform_interface/test/split_view_test.dart +++ b/splitio_platform_interface/test/split_view_test.dart @@ -23,6 +23,7 @@ void main() { 'changeNumber': 156246, 'trafficType': 'default', 'defaultTreatment': 'on', + 'sets': ['set1', 'set2'], }); expect(splitView?.name, 'my_split'); @@ -32,5 +33,6 @@ void main() { expect(splitView?.changeNumber, 156246); expect(splitView?.trafficType, 'default'); expect(splitView?.defaultTreatment, 'on'); + expect(splitView?.sets, ['set1', 'set2']); }); } From 9e329521e152ca49c1fa37499e48064685587a9b Mon Sep 17 00:00:00 2001 From: Gaston Thea Date: Thu, 2 Nov 2023 18:10:46 -0300 Subject: [PATCH 07/28] Revert --- splitio_platform_interface/lib/split_result.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/splitio_platform_interface/lib/split_result.dart b/splitio_platform_interface/lib/split_result.dart index f1c0896..80b452b 100644 --- a/splitio_platform_interface/lib/split_result.dart +++ b/splitio_platform_interface/lib/split_result.dart @@ -13,8 +13,8 @@ class SplitResult { String toString() { return '{"treatment": "' + treatment + - '", config: ' + - (config != null ? '"$config"' : 'null') + - '}'; + '", config: "' + + (config ?? 'null') + + '"}'; } } From 5973f3b80da6b0d150a6ca1d4e6aaca2a56778c8 Mon Sep 17 00:00:00 2001 From: Vince Varga Date: Thu, 2 Nov 2023 22:14:17 +0100 Subject: [PATCH 08/28] Update SplitResult.toString to display null values differently (#88) --- splitio_platform_interface/lib/split_result.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/splitio_platform_interface/lib/split_result.dart b/splitio_platform_interface/lib/split_result.dart index 80b452b..f1c0896 100644 --- a/splitio_platform_interface/lib/split_result.dart +++ b/splitio_platform_interface/lib/split_result.dart @@ -13,8 +13,8 @@ class SplitResult { String toString() { return '{"treatment": "' + treatment + - '", config: "' + - (config ?? 'null') + - '"}'; + '", config: ' + + (config != null ? '"$config"' : 'null') + + '}'; } } From bec7cc73d9837c800ddbc04e7c49e3ab3fd52866 Mon Sep 17 00:00:00 2001 From: Gaston Thea Date: Fri, 3 Nov 2023 10:47:34 -0300 Subject: [PATCH 09/28] Dev pubspec --- splitio/pubspec.yaml | 9 ++++++--- splitio_android/pubspec.yaml | 3 ++- splitio_ios/pubspec.yaml | 3 ++- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/splitio/pubspec.yaml b/splitio/pubspec.yaml index 8b566fe..0f26e06 100644 --- a/splitio/pubspec.yaml +++ b/splitio/pubspec.yaml @@ -19,9 +19,12 @@ flutter: dependencies: flutter: sdk: flutter - splitio_android: ^0.1.6 - splitio_ios: ^0.1.6 - splitio_platform_interface: ^1.3.0 + splitio_android: #^0.1.6 + path: ../splitio_android + splitio_ios: #^0.1.6 + path: ../splitio_ios + splitio_platform_interface: #^1.3.0 + path: ../splitio_platform_interface dev_dependencies: flutter_test: diff --git a/splitio_android/pubspec.yaml b/splitio_android/pubspec.yaml index 3381173..3975208 100644 --- a/splitio_android/pubspec.yaml +++ b/splitio_android/pubspec.yaml @@ -19,7 +19,8 @@ flutter: dependencies: flutter: sdk: flutter - splitio_platform_interface: ^1.3.0 + splitio_platform_interface: #^1.3.0 + path: ../splitio_platform_interface dev_dependencies: flutter_test: diff --git a/splitio_ios/pubspec.yaml b/splitio_ios/pubspec.yaml index 9539b32..a2c7860 100644 --- a/splitio_ios/pubspec.yaml +++ b/splitio_ios/pubspec.yaml @@ -18,7 +18,8 @@ flutter: dependencies: flutter: sdk: flutter - splitio_platform_interface: ^1.3.0 + splitio_platform_interface: #^1.3.0 + path: ../splitio_platform_interface dev_dependencies: flutter_test: From d3eeae572eec272b886602d19143704da14fb82c Mon Sep 17 00:00:00 2001 From: Gaston Thea Date: Fri, 3 Nov 2023 11:19:56 -0300 Subject: [PATCH 10/28] New evaluation methods in SplitClient --- splitio/example/pubspec.lock | 8 +- splitio/lib/split_client.dart | 76 ++++++++++++++++ splitio/test/splitio_client_test.dart | 112 ++++++++++++++++++++++++ splitio/test/splitio_platform_stub.dart | 72 +++++++++++++++ 4 files changed, 264 insertions(+), 4 deletions(-) diff --git a/splitio/example/pubspec.lock b/splitio/example/pubspec.lock index cad1492..bf2b499 100644 --- a/splitio/example/pubspec.lock +++ b/splitio/example/pubspec.lock @@ -150,28 +150,28 @@ packages: path: ".." relative: true source: path - version: "0.1.6-rc.1" + version: "0.1.6" splitio_android: dependency: transitive description: path: "../../splitio_android" relative: true source: path - version: "0.1.6-rc.1" + version: "0.1.6" splitio_ios: dependency: transitive description: path: "../../splitio_ios" relative: true source: path - version: "0.1.6-rc.1" + version: "0.1.6" splitio_platform_interface: dependency: transitive description: path: "../../splitio_platform_interface" relative: true source: path - version: "1.3.0-rc.1" + version: "1.3.0" stack_trace: dependency: transitive description: diff --git a/splitio/lib/split_client.dart b/splitio/lib/split_client.dart index 7252206..cb9b27f 100644 --- a/splitio/lib/split_client.dart +++ b/splitio/lib/split_client.dart @@ -49,6 +49,46 @@ abstract class SplitClient { Future> getTreatments(List featureFlagNames, [Map attributes = const {}]); + /// Convenience method to perform multiple evaluations by flag set. Returns a [Map] in + /// which the keys are feature flag names and the values are treatments. + /// + /// A flag set needs to be specified in [flagSet]. + /// + /// Optionally, a [Map] can be specified with the [attributes] parameter to + /// take into account when evaluating. + Future> getTreatmentsByFlagSet(String flagSet, + [Map attributes = const {}]); + + /// Convenience method to perform multiple evaluations by flag sets. Returns a [Map] in + /// which the keys are feature flag names and the values are treatments. + /// + /// A list of flag sets needs to be specified in [flagSets]. + /// + /// Optionally, a [Map] can be specified with the [attributes] parameter to + /// take into account when evaluating. + Future> getTreatmentsByFlagSets(List flagSets, + [Map attributes = const {}]); + + /// Convenience method to perform multiple evaluations by flag set. Returns a [Map] in + /// which the keys are feature flag names and the values are [SplitResult] objects. + /// + /// A flag set needs to be specified in [flagSet]. + /// + /// Optionally, a [Map] can be specified with the [attributes] parameter to + /// take into account when evaluating. + Future> getTreatmentsWithConfigByFlagSet(String flagSet, + [Map attributes = const {}]); + + /// Convenience method to perform multiple evaluations by flag sets. Returns a [Map] in + /// which the keys are feature flag names and the values are [SplitResult] objects. + /// + /// A list of flag sets needs to be specified in [flagSets]. + /// + /// Optionally, a [Map] can be specified with the [attributes] parameter to + /// take into account when evaluating. + Future> getTreatmentsWithConfigByFlagSets(List flagSets, + [Map attributes = const {}]); + /// Convenience method to perform multiple evaluations. Returns a [Map] in /// which the keys are feature flag names and the values are [SplitResult] objects. /// @@ -185,6 +225,42 @@ class DefaultSplitClient implements SplitClient { attributes: attributes); } + @override + Future> getTreatmentsByFlagSet(String flagSet, [Map attributes = const {}]) { + return _platform.getTreatmentsByFlagSet( + matchingKey: _matchingKey, + bucketingKey: _bucketingKey, + flagSet: flagSet, + attributes: attributes); + } + + @override + Future> getTreatmentsByFlagSets(List flagSets, [Map attributes = const {}]) { + return _platform.getTreatmentsByFlagSets( + matchingKey: _matchingKey, + bucketingKey: _bucketingKey, + flagSets: flagSets, + attributes: attributes); + } + + @override + Future> getTreatmentsWithConfigByFlagSet(String flagSet, [Map attributes = const {}]) { + return _platform.getTreatmentsWithConfigByFlagSet( + matchingKey: _matchingKey, + bucketingKey: _bucketingKey, + flagSet: flagSet, + attributes: attributes); + } + + @override + Future> getTreatmentsWithConfigByFlagSets(List flagSets, [Map attributes = const {}]) { + return _platform.getTreatmentsWithConfigByFlagSets( + matchingKey: _matchingKey, + bucketingKey: _bucketingKey, + flagSets: flagSets, + attributes: attributes); + } + @override Future track(String eventType, {String? trafficType, diff --git a/splitio/test/splitio_client_test.dart b/splitio/test/splitio_client_test.dart index 25e638f..de984a8 100644 --- a/splitio/test/splitio_client_test.dart +++ b/splitio/test/splitio_client_test.dart @@ -133,6 +133,118 @@ void main() { 'attributes': {'attr1': true} }); }); + + test('getTreatmentsByFlagSet without attributes', () async { + SplitClient client = _getClient(); + + client.getTreatmentsByFlagSet('set_1'); + + expect(_platform.methodName, 'getTreatmentsByFlagSet'); + expect(_platform.methodArguments, { + 'flagSet': 'set_1', + 'matchingKey': 'matching-key', + 'bucketingKey': 'bucketing-key', + 'attributes': {} + }); + }); + + test('getTreatmentsByFlagSet with attributes', () async { + SplitClient client = _getClient(); + + client.getTreatmentsByFlagSet('set_1', {'attr1': true}); + + expect(_platform.methodName, 'getTreatmentsByFlagSet'); + expect(_platform.methodArguments, { + 'flagSet': 'set_1', + 'matchingKey': 'matching-key', + 'bucketingKey': 'bucketing-key', + 'attributes': {'attr1': true} + }); + }); + + test('getTreatmentsByFlagSets without attributes', () async { + SplitClient client = _getClient(); + + client.getTreatmentsByFlagSets(['set_1', 'set_2']); + + expect(_platform.methodName, 'getTreatmentsByFlagSets'); + expect(_platform.methodArguments, { + 'flagSets': ['set_1', 'set_2'], + 'matchingKey': 'matching-key', + 'bucketingKey': 'bucketing-key', + 'attributes': {} + }); + }); + + test('getTreatmentsByFlagSets with attributes', () async { + SplitClient client = _getClient(); + + client.getTreatmentsByFlagSets(['set_1', 'set_2'], {'attr1': true}); + + expect(_platform.methodName, 'getTreatmentsByFlagSets'); + expect(_platform.methodArguments, { + 'flagSets': ['set_1', 'set_2'], + 'matchingKey': 'matching-key', + 'bucketingKey': 'bucketing-key', + 'attributes': {'attr1': true} + }); + }); + + test('getTreatmentsWithConfigByFlagSet without attributes', () async { + SplitClient client = _getClient(); + + client.getTreatmentsWithConfigByFlagSet('set_1'); + + expect(_platform.methodName, 'getTreatmentsWithConfigByFlagSet'); + expect(_platform.methodArguments, { + 'flagSet': 'set_1', + 'matchingKey': 'matching-key', + 'bucketingKey': 'bucketing-key', + 'attributes': {} + }); + }); + + test('getTreatmentsWithConfigByFlagSet with attributes', () async { + SplitClient client = _getClient(); + + client.getTreatmentsWithConfigByFlagSet('set_1', {'attr1': true}); + + expect(_platform.methodName, 'getTreatmentsWithConfigByFlagSet'); + expect(_platform.methodArguments, { + 'flagSet': 'set_1', + 'matchingKey': 'matching-key', + 'bucketingKey': 'bucketing-key', + 'attributes': {'attr1': true} + }); + }); + + test('getTreatmentsWithConfigByFlagSets without attributes', () async { + SplitClient client = _getClient(); + + client.getTreatmentsWithConfigByFlagSets(['set_1', 'set_2']); + + expect(_platform.methodName, 'getTreatmentsWithConfigByFlagSets'); + expect(_platform.methodArguments, { + 'flagSets': ['set_1', 'set_2'], + 'matchingKey': 'matching-key', + 'bucketingKey': 'bucketing-key', + 'attributes': {} + }); + }); + + test('getTreatmentsWithConfigByFlagSets with attributes', () async { + SplitClient client = _getClient(); + + client.getTreatmentsWithConfigByFlagSets(['set_1', 'set_2'], {'attr1': true}); + + expect(_platform.methodName, 'getTreatmentsWithConfigByFlagSets'); + expect(_platform.methodArguments, { + 'flagSets': ['set_1', 'set_2'], + 'matchingKey': 'matching-key', + 'bucketingKey': 'bucketing-key', + 'attributes': {'attr1': true} + }); + }); }); group('track', () { diff --git a/splitio/test/splitio_platform_stub.dart b/splitio/test/splitio_platform_stub.dart index 369cc83..a996c97 100644 --- a/splitio/test/splitio_platform_stub.dart +++ b/splitio/test/splitio_platform_stub.dart @@ -156,6 +156,78 @@ class SplitioPlatformStub return Future.value({}); } + @override + Future> getTreatmentsByFlagSet( + {required String matchingKey, + required String? bucketingKey, + required String flagSet, + Map attributes = const {}}) { + methodName = 'getTreatmentsByFlagSet'; + + methodArguments = { + 'matchingKey': matchingKey, + 'bucketingKey': bucketingKey, + 'flagSet': flagSet, + 'attributes': attributes, + }; + + return Future.value({}); + } + + @override + Future> getTreatmentsByFlagSets( + {required String matchingKey, + required String? bucketingKey, + required List flagSets, + Map attributes = const {}}) { + methodName = 'getTreatmentsByFlagSets'; + + methodArguments = { + 'matchingKey': matchingKey, + 'bucketingKey': bucketingKey, + 'flagSets': flagSets, + 'attributes': attributes, + }; + + return Future.value({}); + } + + @override + Future> getTreatmentsWithConfigByFlagSet( + {required String matchingKey, + required String? bucketingKey, + required String flagSet, + Map attributes = const {}}) { + methodName = 'getTreatmentsWithConfigByFlagSet'; + + methodArguments = { + 'matchingKey': matchingKey, + 'bucketingKey': bucketingKey, + 'flagSet': flagSet, + 'attributes': attributes, + }; + + return Future.value({}); + } + + @override + Future> getTreatmentsWithConfigByFlagSets( + {required String matchingKey, + required String? bucketingKey, + required List flagSets, + Map attributes = const {}}) { + methodName = 'getTreatmentsWithConfigByFlagSets'; + + methodArguments = { + 'matchingKey': matchingKey, + 'bucketingKey': bucketingKey, + 'flagSets': flagSets, + 'attributes': attributes, + }; + + return Future.value({}); + } + @override Stream impressionsStream() { methodName = 'impressionsStream'; From 6fd9433693c0027e3b858f94de42759e3dd2eafc Mon Sep 17 00:00:00 2001 From: Gaston Thea Date: Fri, 3 Nov 2023 16:06:14 -0300 Subject: [PATCH 11/28] Update android-client to 3.4.0 --- splitio_android/android/build.gradle | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/splitio_android/android/build.gradle b/splitio_android/android/build.gradle index 7a017ac..a2871bd 100644 --- a/splitio_android/android/build.gradle +++ b/splitio_android/android/build.gradle @@ -22,7 +22,7 @@ rootProject.allprojects { apply plugin: 'com.android.library' android { - compileSdkVersion 31 + compileSdk 31 compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 @@ -30,13 +30,13 @@ android { } defaultConfig { - minSdkVersion 16 + minSdk 16 consumerProguardFiles 'split-proguard-rules.pro' } dependencies { - implementation 'io.split.client:android-client:3.3.0' + implementation 'io.split.client:android-client:3.4.0' implementation 'com.squareup.okhttp3:okhttp:3.12.13' testImplementation 'junit:junit:4.13.2' From 84aa0c3a19ae507ad67f8284151684597d0af1d7 Mon Sep 17 00:00:00 2001 From: Gaston Thea Date: Fri, 3 Nov 2023 17:27:01 -0300 Subject: [PATCH 12/28] Evaluation & config in Android --- .../io/split/splitio/EvaluationWrapper.java | 8 +++ .../splitio/SplitClientConfigHelper.java | 16 ++++-- .../io/split/splitio/SplitWrapperImpl.java | 40 +++++++++++++++ .../splitio/SplitClientConfigHelperTest.java | 43 +++++++++++++--- .../split/splitio/SplitWrapperImplTest.java | 51 +++++++++++++++++++ 5 files changed, 145 insertions(+), 13 deletions(-) diff --git a/splitio_android/android/src/main/java/io/split/splitio/EvaluationWrapper.java b/splitio_android/android/src/main/java/io/split/splitio/EvaluationWrapper.java index c6dc7fa..62ed6d0 100644 --- a/splitio_android/android/src/main/java/io/split/splitio/EvaluationWrapper.java +++ b/splitio_android/android/src/main/java/io/split/splitio/EvaluationWrapper.java @@ -13,4 +13,12 @@ interface EvaluationWrapper { SplitResult getTreatmentWithConfig(String matchingKey, String bucketingKey, String splitName, Map attributes); Map getTreatmentsWithConfig(String matchingKey, String bucketingKey, List splitNames, Map attributes); + + Map getTreatmentsByFlagSet(String matchingKey, String bucketingKey, String flagSet, Map attributes); + + Map getTreatmentsByFlagSets(String matchingKey, String bucketingKey, List flagSets, Map attributes); + + Map getTreatmentsWithConfigByFlagSet(String matchingKey, String bucketingKey, String flagSet, Map attributes); + + Map getTreatmentsWithConfigByFlagSets(String matchingKey, String bucketingKey, List flagSets, Map attributes); } diff --git a/splitio_android/android/src/main/java/io/split/splitio/SplitClientConfigHelper.java b/splitio_android/android/src/main/java/io/split/splitio/SplitClientConfigHelper.java index 80f58cc..8aa0e78 100644 --- a/splitio_android/android/src/main/java/io/split/splitio/SplitClientConfigHelper.java +++ b/splitio_android/android/src/main/java/io/split/splitio/SplitClientConfigHelper.java @@ -39,6 +39,7 @@ class SplitClientConfigHelper { private static final String SYNC_CONFIG = "syncConfig"; private static final String SYNC_CONFIG_NAMES = "syncConfigNames"; private static final String SYNC_CONFIG_PREFIXES = "syncConfigPrefixes"; + private static final String SYNC_CONFIG_SETS = "syncConfigFlagSets"; private static final String IMPRESSIONS_MODE = "impressionsMode"; private static final String SYNC_ENABLED = "syncEnabled"; private static final String USER_CONSENT = "userConsent"; @@ -152,14 +153,19 @@ static SplitClientConfig fromMap(@NonNull Map configurationMap, if (syncConfig != null) { List names = syncConfig.get(SYNC_CONFIG_NAMES); List prefixes = syncConfig.get(SYNC_CONFIG_PREFIXES); + List flagSets = syncConfig.get(SYNC_CONFIG_SETS); SyncConfig.Builder syncConfigBuilder = SyncConfig.builder(); - if (names != null && !names.isEmpty()) { - syncConfigBuilder.addSplitFilter(SplitFilter.byName(names)); - } + if (flagSets != null && !flagSets.isEmpty()) { + syncConfigBuilder.addSplitFilter(SplitFilter.bySet(flagSets)); + } else { + if (names != null && !names.isEmpty()) { + syncConfigBuilder.addSplitFilter(SplitFilter.byName(names)); + } - if (prefixes != null && !prefixes.isEmpty()) { - syncConfigBuilder.addSplitFilter(SplitFilter.byPrefix(prefixes)); + if (prefixes != null && !prefixes.isEmpty()) { + syncConfigBuilder.addSplitFilter(SplitFilter.byPrefix(prefixes)); + } } builder.syncConfig(syncConfigBuilder.build()); diff --git a/splitio_android/android/src/main/java/io/split/splitio/SplitWrapperImpl.java b/splitio_android/android/src/main/java/io/split/splitio/SplitWrapperImpl.java index b445908..4e765ef 100644 --- a/splitio_android/android/src/main/java/io/split/splitio/SplitWrapperImpl.java +++ b/splitio_android/android/src/main/java/io/split/splitio/SplitWrapperImpl.java @@ -127,6 +127,46 @@ public Map getTreatmentsWithConfig(String matchingKey, Stri return client.getTreatmentsWithConfig(splitNames, attributes); } + @Override + public Map getTreatmentsByFlagSet(String matchingKey, String bucketingKey, String flagSet, Map attributes) { + SplitClient client = getInitializedClient(matchingKey, bucketingKey); + if (client == null) { + return new HashMap<>(); + } + + return client.getTreatmentsByFlagSet(flagSet, attributes); + } + + @Override + public Map getTreatmentsByFlagSets(String matchingKey, String bucketingKey, List flagSets, Map attributes) { + SplitClient client = getInitializedClient(matchingKey, bucketingKey); + if (client == null) { + return new HashMap<>(); + } + + return client.getTreatmentsByFlagSets(flagSets, attributes); + } + + @Override + public Map getTreatmentsWithConfigByFlagSet(String matchingKey, String bucketingKey, String flagSet, Map attributes) { + SplitClient client = getInitializedClient(matchingKey, bucketingKey); + if (client == null) { + return new HashMap<>(); + } + + return client.getTreatmentsWithConfigByFlagSet(flagSet, attributes); + } + + @Override + public Map getTreatmentsWithConfigByFlagSets(String matchingKey, String bucketingKey, List flagSets, Map attributes) { + SplitClient client = getInitializedClient(matchingKey, bucketingKey); + if (client == null) { + return new HashMap<>(); + } + + return client.getTreatmentsWithConfigByFlagSets(flagSets, attributes); + } + @Override public boolean setAttribute(String matchingKey, @Nullable String bucketingKey, String attributeName, Object value) { SplitClient client = getInitializedClient(matchingKey, bucketingKey); diff --git a/splitio_android/android/src/test/java/io/split/splitio/SplitClientConfigHelperTest.java b/splitio_android/android/src/test/java/io/split/splitio/SplitClientConfigHelperTest.java index aa9b7f4..6c16b8f 100644 --- a/splitio_android/android/src/test/java/io/split/splitio/SplitClientConfigHelperTest.java +++ b/splitio_android/android/src/test/java/io/split/splitio/SplitClientConfigHelperTest.java @@ -44,10 +44,6 @@ public void configValuesAreMappedCorrectly() { configValues.put("authServiceEndpoint", "sseAuthServiceEndpoint.split.io"); configValues.put("streamingServiceEndpoint", "streamingServiceEndpoint.split.io"); configValues.put("telemetryServiceEndpoint", "telemetryServiceEndpoint.split.io"); - Map> syncConfigMap = new HashMap<>(); - syncConfigMap.put("syncConfigNames", Arrays.asList("split1", "split2")); - syncConfigMap.put("syncConfigPrefixes", Arrays.asList("split_", "my_split_")); - configValues.put("syncConfig", syncConfigMap); configValues.put("impressionsMode", "none"); configValues.put("syncEnabled", false); configValues.put("userConsent", "declined"); @@ -73,10 +69,6 @@ public void configValuesAreMappedCorrectly() { assertEquals("sseAuthServiceEndpoint.split.io", splitClientConfig.authServiceUrl()); assertEquals("streamingServiceEndpoint.split.io", splitClientConfig.streamingServiceUrl()); assertEquals("telemetryServiceEndpoint.split.io", splitClientConfig.telemetryEndpoint()); - assertEquals(Arrays.asList("split1", "split2"), splitClientConfig.syncConfig().getFilters().get(0).getValues()); - assertEquals(SplitFilter.Type.BY_NAME, splitClientConfig.syncConfig().getFilters().get(0).getType()); - assertEquals(Arrays.asList("split_", "my_split_"), splitClientConfig.syncConfig().getFilters().get(1).getValues()); - assertEquals(SplitFilter.Type.BY_PREFIX, splitClientConfig.syncConfig().getFilters().get(1).getType()); assertEquals(ImpressionsMode.NONE, splitClientConfig.impressionsMode()); assertFalse(splitClientConfig.syncEnabled()); assertEquals(UserConsent.DECLINED, splitClientConfig.userConsent()); @@ -151,4 +143,39 @@ public void impressionsModeValuesAreMappedCorrectly() { assertEquals(ImpressionsMode.NONE, noneConfig.impressionsMode()); assertEquals(ImpressionsMode.OPTIMIZED, optimizedConfig.impressionsMode()); } + + @Test + public void syncConfigWithoutFlagSetsIsMappedCorrectly() { + Map configValues = new HashMap<>(); + Map> syncConfigMap = new HashMap<>(); + syncConfigMap.put("syncConfigNames", Arrays.asList("split1", "split2")); + syncConfigMap.put("syncConfigPrefixes", Arrays.asList("split_", "my_split_")); + configValues.put("syncConfig", syncConfigMap); + + SplitClientConfig splitClientConfig = SplitClientConfigHelper + .fromMap(configValues, mock(ImpressionListener.class)); + + assertEquals(2, splitClientConfig.syncConfig().getFilters().size()); + assertEquals(Arrays.asList("split1", "split2"), splitClientConfig.syncConfig().getFilters().get(0).getValues()); + assertEquals(SplitFilter.Type.BY_NAME, splitClientConfig.syncConfig().getFilters().get(0).getType()); + assertEquals(Arrays.asList("split_", "my_split_"), splitClientConfig.syncConfig().getFilters().get(1).getValues()); + assertEquals(SplitFilter.Type.BY_PREFIX, splitClientConfig.syncConfig().getFilters().get(1).getType()); + } + + @Test + public void syncConfigWithFlagSetsIsMappedCorrectly() { + Map configValues = new HashMap<>(); + Map> syncConfigMap = new HashMap<>(); + syncConfigMap.put("syncConfigNames", Arrays.asList("split1", "split2")); + syncConfigMap.put("syncConfigPrefixes", Arrays.asList("split_", "my_split_")); + syncConfigMap.put("syncConfigFlagSets", Arrays.asList("set_1", "set_2")); + configValues.put("syncConfig", syncConfigMap); + + SplitClientConfig splitClientConfig = SplitClientConfigHelper + .fromMap(configValues, mock(ImpressionListener.class)); + + assertEquals(1, splitClientConfig.syncConfig().getFilters().size()); + assertEquals(Arrays.asList("set_1", "set_2"), splitClientConfig.syncConfig().getFilters().get(0).getValues()); + assertEquals(SplitFilter.Type.BY_SET, splitClientConfig.syncConfig().getFilters().get(0).getType()); + } } diff --git a/splitio_android/android/src/test/java/io/split/splitio/SplitWrapperImplTest.java b/splitio_android/android/src/test/java/io/split/splitio/SplitWrapperImplTest.java index 200f785..733fb31 100644 --- a/splitio_android/android/src/test/java/io/split/splitio/SplitWrapperImplTest.java +++ b/splitio_android/android/src/test/java/io/split/splitio/SplitWrapperImplTest.java @@ -15,6 +15,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Set; @@ -100,6 +101,56 @@ public void testGetTreatmentsWithConfig() { verify(clientMock).getTreatmentsWithConfig(Arrays.asList("split1", "split2"), Collections.singletonMap("age", 50)); } + @Test + public void testGetTreatmentsByFlagSet() { + SplitClient clientMock = mock(SplitClient.class); + when(mSplitFactory.client("key", null)).thenReturn(clientMock); + when(mUsedKeys.contains(new Key("key", null))).thenReturn(true); + + Map attrs = Collections.singletonMap("age", 50); + mSplitWrapper.getTreatmentsByFlagSet("key", null, "flag-set", attrs); + + verify(clientMock).getTreatmentsByFlagSet("flag-set", attrs); + } + + @Test + public void testGetTreatmentsByFlagSets() { + SplitClient clientMock = mock(SplitClient.class); + when(mSplitFactory.client("key", null)).thenReturn(clientMock); + when(mUsedKeys.contains(new Key("key", null))).thenReturn(true); + + Map attrs = Collections.singletonMap("age", 50); + List sets = Arrays.asList("set_1", "set_2"); + mSplitWrapper.getTreatmentsByFlagSets("key", null, sets, attrs); + + verify(clientMock).getTreatmentsByFlagSets(sets, attrs); + } + + @Test + public void testGetTreatmentsWithConfigByFlagSet() { + SplitClient clientMock = mock(SplitClient.class); + when(mSplitFactory.client("key", null)).thenReturn(clientMock); + when(mUsedKeys.contains(new Key("key", null))).thenReturn(true); + + Map attrs = Collections.singletonMap("age", 50); + mSplitWrapper.getTreatmentsWithConfigByFlagSet("key", null,"set_1", attrs); + + verify(clientMock).getTreatmentsWithConfigByFlagSet("set_1", attrs); + } + + @Test + public void testGetTreatmentsWithConfigByFlagSets() { + SplitClient clientMock = mock(SplitClient.class); + when(mSplitFactory.client("key", null)).thenReturn(clientMock); + when(mUsedKeys.contains(new Key("key", null))).thenReturn(true); + + Map attrs = Collections.singletonMap("age", 50); + List sets = Arrays.asList("set_1", "set_2"); + mSplitWrapper.getTreatmentsWithConfigByFlagSets("key", null, sets, attrs); + + verify(clientMock).getTreatmentsWithConfigByFlagSets(sets, attrs); + } + @Test public void testTrack() { SplitClient clientMock = mock(SplitClient.class); From f2c04c558bd61adc01f12d461b687cf64381c1fe Mon Sep 17 00:00:00 2001 From: Gaston Thea Date: Tue, 7 Nov 2023 12:57:41 -0300 Subject: [PATCH 13/28] iOS evaluation methods & config --- .../SplitClientConfigHelperTests.swift | 27 +++++- .../SplitTests/SplitMethodParserTests.swift | 38 ++++++++ .../example/ios/SplitTests/SplitTests.swift | 93 +++++++++++++++---- .../ios/Classes/SplitClientConfigHelper.swift | 18 +++- splitio_ios/ios/Classes/SplitWrapper.swift | 40 ++++++++ splitio_ios/ios/splitio_ios.podspec | 4 +- 6 files changed, 195 insertions(+), 25 deletions(-) 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..61243b9 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..924ed4b 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 nil + } + + 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 nil + } + + 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 nil + } + + 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 nil + } + + 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. From 53025dfc7cfd8bb623af9003b9c4bff797e649c9 Mon Sep 17 00:00:00 2001 From: Gaston Thea Date: Tue, 7 Nov 2023 13:34:06 -0300 Subject: [PATCH 14/28] Podfile --- splitio_ios/example/ios/Podfile | 2 +- splitio_ios/example/ios/Podfile.lock | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) 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 From 4a7c39b175d45f9e7cbf95e92a2e28588d1e4225 Mon Sep 17 00:00:00 2001 From: Gaston Thea Date: Tue, 7 Nov 2023 16:33:24 -0300 Subject: [PATCH 15/28] New method parsing for Android --- .../main/java/io/split/splitio/Constants.java | 6 ++ .../split/splitio/SplitMethodParserImpl.java | 82 +++++++++++++++++++ .../splitio/SplitMethodParserImplTest.java | 82 +++++++++++++++++++ .../lib/split_view.dart | 2 +- 4 files changed, 171 insertions(+), 1 deletion(-) diff --git a/splitio_android/android/src/main/java/io/split/splitio/Constants.java b/splitio_android/android/src/main/java/io/split/splitio/Constants.java index 35ceb63..4537843 100644 --- a/splitio_android/android/src/main/java/io/split/splitio/Constants.java +++ b/splitio_android/android/src/main/java/io/split/splitio/Constants.java @@ -15,6 +15,10 @@ static class Method { static final String GET_TREATMENTS = "getTreatments"; static final String GET_TREATMENT_WITH_CONFIG = "getTreatmentWithConfig"; static final String GET_TREATMENTS_WITH_CONFIG = "getTreatmentsWithConfig"; + static final String GET_TREATMENTS_BY_FLAG_SET = "getTreatmentsByFlagSet"; + static final String GET_TREATMENTS_BY_FLAG_SETS = "getTreatmentsByFlagSets"; + static final String GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SET = "getTreatmentsWithConfigByFlagSet"; + static final String GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SETS = "getTreatmentsWithConfigByFlagSets"; static final String TRACK = "track"; static final String GET_ATTRIBUTE = "getAttribute"; static final String GET_ALL_ATTRIBUTES = "getAllAttributes"; @@ -42,6 +46,8 @@ static class Argument { static final String VALUE = "value"; static final String PROPERTIES = "properties"; static final String ATTRIBUTE_NAME = "attributeName"; + static final String FLAG_SET = "flagSet"; + static final String FLAG_SETS = "flagSets"; } static class Error { diff --git a/splitio_android/android/src/main/java/io/split/splitio/SplitMethodParserImpl.java b/splitio_android/android/src/main/java/io/split/splitio/SplitMethodParserImpl.java index fb3ad5d..19bd218 100644 --- a/splitio_android/android/src/main/java/io/split/splitio/SplitMethodParserImpl.java +++ b/splitio_android/android/src/main/java/io/split/splitio/SplitMethodParserImpl.java @@ -5,6 +5,8 @@ import static io.split.splitio.Constants.Argument.ATTRIBUTE_NAME; import static io.split.splitio.Constants.Argument.BUCKETING_KEY; import static io.split.splitio.Constants.Argument.EVENT_TYPE; +import static io.split.splitio.Constants.Argument.FLAG_SET; +import static io.split.splitio.Constants.Argument.FLAG_SETS; import static io.split.splitio.Constants.Argument.MATCHING_KEY; import static io.split.splitio.Constants.Argument.PROPERTIES; import static io.split.splitio.Constants.Argument.SDK_CONFIGURATION; @@ -25,7 +27,11 @@ import static io.split.splitio.Constants.Method.GET_ATTRIBUTE; import static io.split.splitio.Constants.Method.GET_TREATMENT; import static io.split.splitio.Constants.Method.GET_TREATMENTS; +import static io.split.splitio.Constants.Method.GET_TREATMENTS_BY_FLAG_SET; +import static io.split.splitio.Constants.Method.GET_TREATMENTS_BY_FLAG_SETS; import static io.split.splitio.Constants.Method.GET_TREATMENTS_WITH_CONFIG; +import static io.split.splitio.Constants.Method.GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SET; +import static io.split.splitio.Constants.Method.GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SETS; import static io.split.splitio.Constants.Method.GET_TREATMENT_WITH_CONFIG; import static io.split.splitio.Constants.Method.GET_USER_CONSENT; import static io.split.splitio.Constants.Method.INIT; @@ -132,6 +138,34 @@ public void onMethodCall(String methodName, Object arguments, @NonNull MethodCha mArgumentParser.getStringListArgument(SPLIT_NAME, arguments), mArgumentParser.getMapArgument(ATTRIBUTES, arguments))); break; + case GET_TREATMENTS_BY_FLAG_SET: + result.success(getTreatmentsByFlagSet( + mArgumentParser.getStringArgument(MATCHING_KEY, arguments), + mArgumentParser.getStringArgument(BUCKETING_KEY, arguments), + mArgumentParser.getStringArgument(FLAG_SET, arguments), + mArgumentParser.getMapArgument(ATTRIBUTES, arguments))); + break; + case GET_TREATMENTS_BY_FLAG_SETS: + result.success(getTreatmentsByFlagSets( + mArgumentParser.getStringArgument(MATCHING_KEY, arguments), + mArgumentParser.getStringArgument(BUCKETING_KEY, arguments), + mArgumentParser.getStringListArgument(FLAG_SETS, arguments), + mArgumentParser.getMapArgument(ATTRIBUTES, arguments))); + break; + case GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SET: + result.success(getTreatmentsWithConfigByFlagSet( + mArgumentParser.getStringArgument(MATCHING_KEY, arguments), + mArgumentParser.getStringArgument(BUCKETING_KEY, arguments), + mArgumentParser.getStringArgument(FLAG_SET, arguments), + mArgumentParser.getMapArgument(ATTRIBUTES, arguments))); + break; + case GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SETS: + result.success(getTreatmentsWithConfigByFlagSets( + mArgumentParser.getStringArgument(MATCHING_KEY, arguments), + mArgumentParser.getStringArgument(BUCKETING_KEY, arguments), + mArgumentParser.getStringListArgument(FLAG_SETS, arguments), + mArgumentParser.getMapArgument(ATTRIBUTES, arguments))); + break; case TRACK: result.success(track( mArgumentParser.getStringArgument(MATCHING_KEY, arguments), @@ -279,6 +313,52 @@ private Map> getTreatmentsWithConfig( return resultMap; } + private Map getTreatmentsByFlagSet( + String matchingKey, + String bucketingKey, + String flagSet, + Map attributes) { + return mSplitWrapper.getTreatmentsByFlagSet(matchingKey, bucketingKey, flagSet, attributes); + } + + private Map getTreatmentsByFlagSets( + String matchingKey, + String bucketingKey, + List flagSets, + Map attributes) { + return mSplitWrapper.getTreatmentsByFlagSets(matchingKey, bucketingKey, flagSets, attributes); + } + + private Map> getTreatmentsWithConfigByFlagSet( + String matchingKey, + String bucketingKey, + String flagSet, + Map attributes) { + Map treatmentsWithConfig = mSplitWrapper.getTreatmentsWithConfigByFlagSet(matchingKey, bucketingKey, flagSet, attributes); + Map> resultMap = new HashMap<>(); + + for (Map.Entry entry : treatmentsWithConfig.entrySet()) { + resultMap.put(entry.getKey(), getSplitResultMap(entry.getValue())); + } + + return resultMap; + } + + private Map> getTreatmentsWithConfigByFlagSets( + String matchingKey, + String bucketingKey, + List flagSets, + Map attributes) { + Map treatmentsWithConfig = mSplitWrapper.getTreatmentsWithConfigByFlagSets(matchingKey, bucketingKey, flagSets, attributes); + Map> resultMap = new HashMap<>(); + + for (Map.Entry entry : treatmentsWithConfig.entrySet()) { + resultMap.put(entry.getKey(), getSplitResultMap(entry.getValue())); + } + + return resultMap; + } + private boolean track(String matchingKey, String bucketingKey, String eventType, @@ -395,6 +475,8 @@ private static Map getSplitViewAsMap(@Nullable SplitView splitVi splitViewMap.put("treatments", splitView.treatments); splitViewMap.put("changeNumber", splitView.changeNumber); splitViewMap.put("configs", splitView.configs); + splitViewMap.put("defaultTreatment", splitView.defaultTreatment); + splitViewMap.put("sets", splitView.sets); return splitViewMap; } diff --git a/splitio_android/android/src/test/java/io/split/splitio/SplitMethodParserImplTest.java b/splitio_android/android/src/test/java/io/split/splitio/SplitMethodParserImplTest.java index 538ea0e..c2f98d6 100644 --- a/splitio_android/android/src/test/java/io/split/splitio/SplitMethodParserImplTest.java +++ b/splitio_android/android/src/test/java/io/split/splitio/SplitMethodParserImplTest.java @@ -504,4 +504,86 @@ public void setUserConsentDisabled() { verify(mResult).success(null); verify(mSplitWrapper).setUserConsent(false); } + + @Test + public void getTreatmentsByFlagSetWorksCorrectly() { + Map map = new HashMap<>(); + map.put("matchingKey", "user-key"); + map.put("bucketingKey", "bucketing-key"); + map.put("flagSet", "set_1"); + map.put("attributes", Collections.singletonMap("age", 10)); + + when(mArgumentParser.getStringArgument("matchingKey", map)).thenReturn("user-key"); + when(mArgumentParser.getStringArgument("bucketingKey", map)).thenReturn("bucketing-key"); + when(mArgumentParser.getStringArgument("flagSet", map)).thenReturn("set_1"); + when(mArgumentParser.getMapArgument("attributes", map)).thenReturn(Collections.singletonMap("age", 10)); + when(mSplitWrapper.getTreatmentsByFlagSet(any(), any(), any(), any())).thenReturn(Collections.singletonMap("flag_1", "on")); + + mMethodParser.onMethodCall("getTreatmentsByFlagSet", map, mResult); + + verify(mSplitWrapper).getTreatmentsByFlagSet("user-key", "bucketing-key", "set_1", Collections.singletonMap("age", 10)); + verify(mResult).success(Collections.singletonMap("flag_1", "on")); + } + + @Test + public void getTreatmentsByFlagSetsWorksCorrectly() { + Map map = new HashMap<>(); + map.put("matchingKey", "user-key"); + map.put("bucketingKey", "bucketing-key"); + map.put("flagSets", Arrays.asList("set_1", "set_2")); + map.put("attributes", Collections.singletonMap("age", 10)); + + when(mArgumentParser.getStringArgument("matchingKey", map)).thenReturn("user-key"); + when(mArgumentParser.getStringArgument("bucketingKey", map)).thenReturn("bucketing-key"); + when(mArgumentParser.getStringListArgument("flagSets", map)).thenReturn(Arrays.asList("set_1", "set_2")); + when(mArgumentParser.getMapArgument("attributes", map)).thenReturn(Collections.singletonMap("age", 10)); + when(mSplitWrapper.getTreatmentsByFlagSets(any(), any(), any(), any())).thenReturn(Collections.singletonMap("flag_1", "on")); + + mMethodParser.onMethodCall("getTreatmentsByFlagSets", map, mResult); + + verify(mSplitWrapper).getTreatmentsByFlagSets("user-key", "bucketing-key", Arrays.asList("set_1", "set_2"), Collections.singletonMap("age", 10)); + verify(mResult).success(Collections.singletonMap("flag_1", "on")); + } + + @Test + public void getTreatmentsWithConfigByFlagSetWorksCorrectly() { + Map map = new HashMap<>(); + map.put("matchingKey", "user-key"); + map.put("bucketingKey", "bucketing-key"); + map.put("flagSet", "set_1"); + map.put("attributes", Collections.singletonMap("age", 10)); + + when(mArgumentParser.getStringArgument("matchingKey", map)).thenReturn("user-key"); + when(mArgumentParser.getStringArgument("bucketingKey", map)).thenReturn("bucketing-key"); + when(mArgumentParser.getStringArgument("flagSet", map)).thenReturn("set_1"); + when(mArgumentParser.getMapArgument("attributes", map)).thenReturn(Collections.singletonMap("age", 10)); + SplitResult splitResult = new SplitResult("on", "{config}"); + when(mSplitWrapper.getTreatmentsWithConfigByFlagSet(any(), any(), any(), any())).thenReturn(Collections.singletonMap("flag_1", splitResult)); + + mMethodParser.onMethodCall("getTreatmentsWithConfigByFlagSet", map, mResult); + + verify(mSplitWrapper).getTreatmentsWithConfigByFlagSet("user-key", "bucketing-key", "set_1", Collections.singletonMap("age", 10)); + verify(mResult).success(Collections.singletonMap("flag_1", splitResult)); + } + + @Test + public void getTreatmentsWithConfigByFlagSetsWorksCorrectly() { + Map map = new HashMap<>(); + map.put("matchingKey", "user-key"); + map.put("bucketingKey", "bucketing-key"); + map.put("flagSets", Arrays.asList("set_1", "set_2")); + map.put("attributes", Collections.singletonMap("age", 10)); + + when(mArgumentParser.getStringArgument("matchingKey", map)).thenReturn("user-key"); + when(mArgumentParser.getStringArgument("bucketingKey", map)).thenReturn("bucketing-key"); + when(mArgumentParser.getStringListArgument("flagSets", map)).thenReturn(Arrays.asList("set_1", "set_2")); + when(mArgumentParser.getMapArgument("attributes", map)).thenReturn(Collections.singletonMap("age", 10)); + SplitResult splitResult = new SplitResult("on", "{config}"); + when(mSplitWrapper.getTreatmentsWithConfigByFlagSets(any(), any(), any(), any())).thenReturn(Collections.singletonMap("flag_1", splitResult)); + + mMethodParser.onMethodCall("getTreatmentsWithConfigByFlagSets", map, mResult); + + verify(mSplitWrapper).getTreatmentsWithConfigByFlagSets("user-key", "bucketing-key", Arrays.asList("set_1", "set_2"), Collections.singletonMap("age", 10)); + verify(mResult).success(Collections.singletonMap("flag_1", splitResult)); + } } diff --git a/splitio_platform_interface/lib/split_view.dart b/splitio_platform_interface/lib/split_view.dart index 40451c5..11e7508 100644 --- a/splitio_platform_interface/lib/split_view.dart +++ b/splitio_platform_interface/lib/split_view.dart @@ -32,7 +32,7 @@ class SplitView { entry['changeNumber'], mappedConfig, entry['defaultTreatment'] ?? '', - entry['sets'] ?? []); + (entry['sets'] as List).map((el) => el as String).toList()); } @override From f2ec3e92653d681d8321c83be8823db7bcf05865 Mon Sep 17 00:00:00 2001 From: Gaston Thea Date: Tue, 7 Nov 2023 16:35:38 -0300 Subject: [PATCH 16/28] refactor' --- .../split/splitio/SplitMethodParserImpl.java | 35 ++++++++----------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/splitio_android/android/src/main/java/io/split/splitio/SplitMethodParserImpl.java b/splitio_android/android/src/main/java/io/split/splitio/SplitMethodParserImpl.java index 19bd218..69ee124 100644 --- a/splitio_android/android/src/main/java/io/split/splitio/SplitMethodParserImpl.java +++ b/splitio_android/android/src/main/java/io/split/splitio/SplitMethodParserImpl.java @@ -304,13 +304,7 @@ private Map> getTreatmentsWithConfig( List splitNames, Map attributes) { Map treatmentsWithConfig = mSplitWrapper.getTreatmentsWithConfig(matchingKey, bucketingKey, splitNames, attributes); - Map> resultMap = new HashMap<>(); - - for (Map.Entry entry : treatmentsWithConfig.entrySet()) { - resultMap.put(entry.getKey(), getSplitResultMap(entry.getValue())); - } - - return resultMap; + return mapToSplitResults(treatmentsWithConfig); } private Map getTreatmentsByFlagSet( @@ -335,13 +329,7 @@ private Map> getTreatmentsWithConfigByFlagSet( String flagSet, Map attributes) { Map treatmentsWithConfig = mSplitWrapper.getTreatmentsWithConfigByFlagSet(matchingKey, bucketingKey, flagSet, attributes); - Map> resultMap = new HashMap<>(); - - for (Map.Entry entry : treatmentsWithConfig.entrySet()) { - resultMap.put(entry.getKey(), getSplitResultMap(entry.getValue())); - } - - return resultMap; + return mapToSplitResults(treatmentsWithConfig); } private Map> getTreatmentsWithConfigByFlagSets( @@ -350,13 +338,7 @@ private Map> getTreatmentsWithConfigByFlagSets( List flagSets, Map attributes) { Map treatmentsWithConfig = mSplitWrapper.getTreatmentsWithConfigByFlagSets(matchingKey, bucketingKey, flagSets, attributes); - Map> resultMap = new HashMap<>(); - - for (Map.Entry entry : treatmentsWithConfig.entrySet()) { - resultMap.put(entry.getKey(), getSplitResultMap(entry.getValue())); - } - - return resultMap; + return mapToSplitResults(treatmentsWithConfig); } private boolean track(String matchingKey, @@ -436,6 +418,17 @@ private static void invokeCallback(MethodChannel methodChannel, String matchingK methodChannel.invokeMethod(methodName, arguments); } + @NonNull + private static Map> mapToSplitResults(Map treatmentsWithConfig) { + Map> resultMap = new HashMap<>(); + + for (Map.Entry entry : treatmentsWithConfig.entrySet()) { + resultMap.put(entry.getKey(), getSplitResultMap(entry.getValue())); + } + + return resultMap; + } + private static Map getSplitResultMap(SplitResult splitResult) { if (splitResult == null) { return new HashMap<>(); From c7beb5a9afef3304da2107c1092cf1665dcf8111 Mon Sep 17 00:00:00 2001 From: Gaston Thea Date: Tue, 7 Nov 2023 16:37:08 -0300 Subject: [PATCH 17/28] Minor fix --- splitio_platform_interface/lib/split_view.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/splitio_platform_interface/lib/split_view.dart b/splitio_platform_interface/lib/split_view.dart index 11e7508..023ec0a 100644 --- a/splitio_platform_interface/lib/split_view.dart +++ b/splitio_platform_interface/lib/split_view.dart @@ -32,7 +32,7 @@ class SplitView { entry['changeNumber'], mappedConfig, entry['defaultTreatment'] ?? '', - (entry['sets'] as List).map((el) => el as String).toList()); + (entry['sets'] ?? [] as List).map((el) => el as String).toList()); } @override From 74e5a5054c4742980a3c4764a405b01e92d303b8 Mon Sep 17 00:00:00 2001 From: Gaston Thea Date: Tue, 7 Nov 2023 16:51:11 -0300 Subject: [PATCH 18/28] Fix test --- .../split/splitio/SplitMethodParserImpl.java | 4 ++++ .../splitio/SplitMethodParserImplTest.java | 18 ++++++++++++------ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/splitio_android/android/src/main/java/io/split/splitio/SplitMethodParserImpl.java b/splitio_android/android/src/main/java/io/split/splitio/SplitMethodParserImpl.java index 69ee124..812143c 100644 --- a/splitio_android/android/src/main/java/io/split/splitio/SplitMethodParserImpl.java +++ b/splitio_android/android/src/main/java/io/split/splitio/SplitMethodParserImpl.java @@ -422,6 +422,10 @@ private static void invokeCallback(MethodChannel methodChannel, String matchingK private static Map> mapToSplitResults(Map treatmentsWithConfig) { Map> resultMap = new HashMap<>(); + if (treatmentsWithConfig == null) { + return resultMap; + } + for (Map.Entry entry : treatmentsWithConfig.entrySet()) { resultMap.put(entry.getKey(), getSplitResultMap(entry.getValue())); } diff --git a/splitio_android/android/src/test/java/io/split/splitio/SplitMethodParserImplTest.java b/splitio_android/android/src/test/java/io/split/splitio/SplitMethodParserImplTest.java index c2f98d6..7f7a225 100644 --- a/splitio_android/android/src/test/java/io/split/splitio/SplitMethodParserImplTest.java +++ b/splitio_android/android/src/test/java/io/split/splitio/SplitMethodParserImplTest.java @@ -553,17 +553,20 @@ public void getTreatmentsWithConfigByFlagSetWorksCorrectly() { map.put("flagSet", "set_1"); map.put("attributes", Collections.singletonMap("age", 10)); + Map resultMap1 = new HashMap<>(); + resultMap1.put("treatment", "on"); + resultMap1.put("config", "{config}"); + when(mArgumentParser.getStringArgument("matchingKey", map)).thenReturn("user-key"); when(mArgumentParser.getStringArgument("bucketingKey", map)).thenReturn("bucketing-key"); when(mArgumentParser.getStringArgument("flagSet", map)).thenReturn("set_1"); when(mArgumentParser.getMapArgument("attributes", map)).thenReturn(Collections.singletonMap("age", 10)); - SplitResult splitResult = new SplitResult("on", "{config}"); - when(mSplitWrapper.getTreatmentsWithConfigByFlagSet(any(), any(), any(), any())).thenReturn(Collections.singletonMap("flag_1", splitResult)); + when(mSplitWrapper.getTreatmentsWithConfigByFlagSet(any(), any(), any(), any())).thenReturn(Collections.singletonMap("flag_1", new SplitResult("on", "{config}"))); mMethodParser.onMethodCall("getTreatmentsWithConfigByFlagSet", map, mResult); verify(mSplitWrapper).getTreatmentsWithConfigByFlagSet("user-key", "bucketing-key", "set_1", Collections.singletonMap("age", 10)); - verify(mResult).success(Collections.singletonMap("flag_1", splitResult)); + verify(mResult).success(Collections.singletonMap("flag_1", resultMap1)); } @Test @@ -574,16 +577,19 @@ public void getTreatmentsWithConfigByFlagSetsWorksCorrectly() { map.put("flagSets", Arrays.asList("set_1", "set_2")); map.put("attributes", Collections.singletonMap("age", 10)); + Map resultMap1 = new HashMap<>(); + resultMap1.put("treatment", "on"); + resultMap1.put("config", "{config}"); + when(mArgumentParser.getStringArgument("matchingKey", map)).thenReturn("user-key"); when(mArgumentParser.getStringArgument("bucketingKey", map)).thenReturn("bucketing-key"); when(mArgumentParser.getStringListArgument("flagSets", map)).thenReturn(Arrays.asList("set_1", "set_2")); when(mArgumentParser.getMapArgument("attributes", map)).thenReturn(Collections.singletonMap("age", 10)); - SplitResult splitResult = new SplitResult("on", "{config}"); - when(mSplitWrapper.getTreatmentsWithConfigByFlagSets(any(), any(), any(), any())).thenReturn(Collections.singletonMap("flag_1", splitResult)); + when(mSplitWrapper.getTreatmentsWithConfigByFlagSets(any(), any(), any(), any())).thenReturn(Collections.singletonMap("flag_1", new SplitResult("on", "{config}"))); mMethodParser.onMethodCall("getTreatmentsWithConfigByFlagSets", map, mResult); verify(mSplitWrapper).getTreatmentsWithConfigByFlagSets("user-key", "bucketing-key", Arrays.asList("set_1", "set_2"), Collections.singletonMap("age", 10)); - verify(mResult).success(Collections.singletonMap("flag_1", splitResult)); + verify(mResult).success(Collections.singletonMap("flag_1", resultMap1)); } } From 42d767765b76958385b114d145ff617ba4af0f3b Mon Sep 17 00:00:00 2001 From: Gaston Thea Date: Tue, 7 Nov 2023 12:57:41 -0300 Subject: [PATCH 19/28] iOS evaluation methods & config --- .../SplitClientConfigHelperTests.swift | 27 +++++- .../SplitTests/SplitMethodParserTests.swift | 38 ++++++++ .../example/ios/SplitTests/SplitTests.swift | 93 +++++++++++++++---- .../ios/Classes/SplitClientConfigHelper.swift | 18 +++- splitio_ios/ios/Classes/SplitWrapper.swift | 40 ++++++++ splitio_ios/ios/splitio_ios.podspec | 4 +- 6 files changed, 195 insertions(+), 25 deletions(-) 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..61243b9 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..924ed4b 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 nil + } + + 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 nil + } + + 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 nil + } + + 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 nil + } + + 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. From 59ed4fa23be9ef8e5e50f4f8a14a182f41f042f1 Mon Sep 17 00:00:00 2001 From: Gaston Thea Date: Tue, 7 Nov 2023 13:34:06 -0300 Subject: [PATCH 20/28] Podfile --- splitio_ios/example/ios/Podfile | 2 +- splitio_ios/example/ios/Podfile.lock | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) 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 From 9d1fe1364c2100dddacee80bb51186f9458a62ef Mon Sep 17 00:00:00 2001 From: Gaston Thea Date: Wed, 8 Nov 2023 10:57:35 -0300 Subject: [PATCH 21/28] New methods parsing in iOS; new fields in SplitView --- splitio_ios/ios/Classes/Constants.swift | 6 ++ splitio_ios/ios/Classes/Extensions.swift | 5 +- .../ios/Classes/SplitMethodParser.swift | 86 ++++++++++++++++--- splitio_ios/ios/Classes/SplitWrapper.swift | 24 +++--- .../lib/split_view.dart | 11 ++- 5 files changed, 104 insertions(+), 28 deletions(-) diff --git a/splitio_ios/ios/Classes/Constants.swift b/splitio_ios/ios/Classes/Constants.swift index bea9d65..ea6e2e6 100644 --- a/splitio_ios/ios/Classes/Constants.swift +++ b/splitio_ios/ios/Classes/Constants.swift @@ -13,6 +13,10 @@ enum Method: String { case getTreatments = "getTreatments" case getTreatmentWithConfig = "getTreatmentWithConfig" case getTreatmentsWithConfig = "getTreatmentsWithConfig" + case getTreatmentsByFlagSet = "getTreatmentsByFlagSet" + case getTreatmentsByFlagSets = "getTreatmentsByFlagSets" + case getTreatmentsWithConfigByFlagSet = "getTreatmentsWithConfigByFlagSet" + case getTreatmentsWithConfigByFlagSets = "getTreatmentsWithConfigByFlagSets" case track = "track" case getAttribute = "getAttribute" case getAllAttributes = "getAllAttributes" @@ -40,4 +44,6 @@ enum Argument: String { case value = "value" case properties = "properties" case attributeName = "attributeName" + case flagSet = "flagSet" + case flagSets = "flagSets" } diff --git a/splitio_ios/ios/Classes/Extensions.swift b/splitio_ios/ios/Classes/Extensions.swift index 5ff3bc7..d17250c 100644 --- a/splitio_ios/ios/Classes/Extensions.swift +++ b/splitio_ios/ios/Classes/Extensions.swift @@ -22,7 +22,10 @@ extension SplitView { "killed": splitView.killed, "treatments": splitView.treatments, "changeNumber": splitView.changeNumber, - "configs": splitView.configs] + "configs": splitView.configs, + "defaultTreatment": splitView.defaultTreatment, + "sets": splitView.sets + ] } else { return [:] } diff --git a/splitio_ios/ios/Classes/SplitMethodParser.swift b/splitio_ios/ios/Classes/SplitMethodParser.swift index 6c8a216..d54abd6 100644 --- a/splitio_ios/ios/Classes/SplitMethodParser.swift +++ b/splitio_ios/ios/Classes/SplitMethodParser.swift @@ -75,6 +75,34 @@ class DefaultSplitMethodParser: SplitMethodParser { splits: argumentParser.getStringListArgument(argumentName: .splitName, arguments: arguments), attributes: argumentParser.getMapArgument(argumentName: .attributes, arguments: arguments) as [String: Any])) break + case .getTreatmentsByFlagSet: + result(getTreatmentsByFlagSet( + matchingKey: argumentParser.getStringArgument(argumentName: .matchingKey, arguments: arguments) ?? "", + bucketingKey: argumentParser.getStringArgument(argumentName: .bucketingKey, arguments: arguments), + flagSet: argumentParser.getStringArgument(argumentName: .flagSet, arguments: arguments) ?? "", + attributes: argumentParser.getMapArgument(argumentName: .attributes, arguments: arguments) as [String: Any])) + break + case .getTreatmentsByFlagSets: + result(getTreatmentsByFlagSets( + matchingKey: argumentParser.getStringArgument(argumentName: .matchingKey, arguments: arguments) ?? "", + bucketingKey: argumentParser.getStringArgument(argumentName: .bucketingKey, arguments: arguments), + flagSets: argumentParser.getStringListArgument(argumentName: .flagSets, arguments: arguments), + attributes: argumentParser.getMapArgument(argumentName: .attributes, arguments: arguments) as [String: Any])) + break + case .getTreatmentsWithConfigByFlagSet: + result(getTreatmentsWithConfigByFlagSet( + matchingKey: argumentParser.getStringArgument(argumentName: .matchingKey, arguments: arguments) ?? "", + bucketingKey: argumentParser.getStringArgument(argumentName: .bucketingKey, arguments: arguments), + flagSet: argumentParser.getStringArgument(argumentName: .flagSet, arguments: arguments) ?? "", + attributes: argumentParser.getMapArgument(argumentName: .attributes, arguments: arguments) as [String: Any])) + break + case .getTreatmentsWithConfigByFlagSets: + result(getTreatmentsWithConfigByFlagSets( + matchingKey: argumentParser.getStringArgument(argumentName: .matchingKey, arguments: arguments) ?? "", + bucketingKey: argumentParser.getStringArgument(argumentName: .bucketingKey, arguments: arguments), + flagSets: argumentParser.getStringListArgument(argumentName: .flagSets, arguments: arguments), + attributes: argumentParser.getMapArgument(argumentName: .attributes, arguments: arguments) as [String: Any])) + break case .track: result(track(matchingKey: argumentParser.getStringArgument(argumentName: .matchingKey, arguments: arguments) ?? "", bucketingKey: argumentParser.getStringArgument(argumentName: .bucketingKey, arguments: arguments), @@ -215,6 +243,50 @@ class DefaultSplitMethodParser: SplitMethodParser { } } + private func getTreatmentsByFlagSet(matchingKey: String, bucketingKey: String? = nil, flagSet: String, attributes: [String: Any]? = [:]) -> [String: String] { + guard let splitWrapper = getSplitWrapper() else { + return [:] + } + + let treatments = splitWrapper.getTreatmentsByFlagSet(matchingKey: matchingKey, flagSet: flagSet, bucketingKey: bucketingKey, attributes: attributes) + + return treatments + } + + private func getTreatmentsByFlagSets(matchingKey: String, bucketingKey: String? = nil, flagSets: [String], attributes: [String: Any]? = [:]) -> [String: String] { + guard let splitWrapper = getSplitWrapper() else { + return [:] + } + + let treatments = splitWrapper.getTreatmentsByFlagSets(matchingKey: matchingKey, flagSets: flagSets, bucketingKey: bucketingKey, attributes: attributes) + + return treatments + } + + private func getTreatmentsWithConfigByFlagSet(matchingKey: String, bucketingKey: String? = nil, flagSet: String, attributes: [String: Any]? = [:]) -> [String: [String: String?]] { + guard let splitWrapper = getSplitWrapper() else { + return [:] + } + + let treatments = splitWrapper.getTreatmentsWithConfigByFlagSet(matchingKey: matchingKey, flagSet: flagSet, bucketingKey: bucketingKey, attributes: attributes) + + return treatments.mapValues { + ["treatment": $0.treatment, "config": $0.config] + } + } + + private func getTreatmentsWithConfigByFlagSets(matchingKey: String, bucketingKey: String? = nil, flagSets: [String], attributes: [String: Any]? = [:]) -> [String: [String: String?]] { + guard let splitWrapper = getSplitWrapper() else { + return [:] + } + + let treatments = splitWrapper.getTreatmentsWithConfigByFlagSets(matchingKey: matchingKey, flagSets: flagSets, bucketingKey: bucketingKey, attributes: attributes) + + return treatments.mapValues { + ["treatment": $0.treatment, "config": $0.config] + } + } + private func track(matchingKey: String, bucketingKey: String? = nil, eventType: String, trafficType: String? = nil, value: Double? = nil, properties: [String: Any?]) -> Bool { guard let splitWrapper = getSplitWrapper() else { return false @@ -320,18 +392,4 @@ class DefaultSplitMethodParser: SplitMethodParser { return splitWrapper } - - private func getSplitViewAsMap(splitView: SplitView?) -> [String: Any?] { - if let splitView = splitView { - return [ - "name": splitView.name, - "trafficType": splitView.trafficType, - "killed": splitView.killed, - "treatments": splitView.treatments, - "changeNumber": splitView.changeNumber, - "configs": splitView.configs] - } else { - return [:] - } - } } diff --git a/splitio_ios/ios/Classes/SplitWrapper.swift b/splitio_ios/ios/Classes/SplitWrapper.swift index 924ed4b..b25f9d2 100644 --- a/splitio_ios/ios/Classes/SplitWrapper.swift +++ b/splitio_ios/ios/Classes/SplitWrapper.swift @@ -32,13 +32,13 @@ protocol EvaluationWrapper { 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 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 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 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]? + func getTreatmentsWithConfigByFlagSets(matchingKey: String, flagSets: [String], bucketingKey: String?, attributes: [String: Any]?) -> [String: SplitResult] } protocol AttributesWrapper { @@ -129,33 +129,33 @@ class DefaultSplitWrapper: SplitWrapper { return client.getTreatmentsWithConfig(splits: splits, attributes: attributes) } - func getTreatmentsByFlagSet(matchingKey: String, flagSet: String, bucketingKey: String? = nil, attributes: [String: Any]? = [:]) -> [String: String]? { + func getTreatmentsByFlagSet(matchingKey: String, flagSet: String, bucketingKey: String? = nil, attributes: [String: Any]? = [:]) -> [String: String] { guard let client = getInitializedClient(matchingKey: matchingKey, bucketingKey: bucketingKey) else { - return nil + return [:] } return client.getTreatmentsByFlagSet(flagSet, attributes: attributes) } - func getTreatmentsByFlagSets(matchingKey: String, flagSets: [String], bucketingKey: String? = nil, attributes: [String: Any]? = [:]) -> [String: String]? { + func getTreatmentsByFlagSets(matchingKey: String, flagSets: [String], bucketingKey: String? = nil, attributes: [String: Any]? = [:]) -> [String: String] { guard let client = getInitializedClient(matchingKey: matchingKey, bucketingKey: bucketingKey) else { - return nil + return [:] } return client.getTreatmentsByFlagSets(flagSets, attributes: attributes) } - func getTreatmentsWithConfigByFlagSet(matchingKey: String, flagSet: String, bucketingKey: String? = nil, attributes: [String: Any]? = [:]) -> [String: SplitResult]? { + func getTreatmentsWithConfigByFlagSet(matchingKey: String, flagSet: String, bucketingKey: String? = nil, attributes: [String: Any]? = [:]) -> [String: SplitResult] { guard let client = getInitializedClient(matchingKey: matchingKey, bucketingKey: bucketingKey) else { - return nil + return [:] } return client.getTreatmentsWithConfigByFlagSet(flagSet, attributes: attributes) } - func getTreatmentsWithConfigByFlagSets(matchingKey: String, flagSets: [String], bucketingKey: String? = nil, attributes: [String: Any]? = [:]) -> [String: SplitResult]? { + func getTreatmentsWithConfigByFlagSets(matchingKey: String, flagSets: [String], bucketingKey: String? = nil, attributes: [String: Any]? = [:]) -> [String: SplitResult] { guard let client = getInitializedClient(matchingKey: matchingKey, bucketingKey: bucketingKey) else { - return nil + return [:] } return client.getTreatmentsWithConfigByFlagSets(flagSets, attributes: attributes) diff --git a/splitio_platform_interface/lib/split_view.dart b/splitio_platform_interface/lib/split_view.dart index 023ec0a..789daa1 100644 --- a/splitio_platform_interface/lib/split_view.dart +++ b/splitio_platform_interface/lib/split_view.dart @@ -24,6 +24,14 @@ class SplitView { mappedConfig.addAll({entry.key.toString(): entry.value.toString()}) }); + if (entry['treatments'] == null) { + entry['treatments'] = entry['treatments'] ?? []; + } + + if (entry['sets'] == null) { + entry['sets'] = []; + } + return SplitView( entry['name'], entry['trafficType'], @@ -32,7 +40,8 @@ class SplitView { entry['changeNumber'], mappedConfig, entry['defaultTreatment'] ?? '', - (entry['sets'] ?? [] as List).map((el) => el as String).toList()); + (entry['sets'] as List).map((el) => el as String).toList() + ); } @override From 26adc98d402efa7b3ae79c40cb8ff7c64aaf3fb6 Mon Sep 17 00:00:00 2001 From: Gaston Thea Date: Wed, 8 Nov 2023 14:42:55 -0300 Subject: [PATCH 22/28] Add missing platform tests --- .github/workflows/test.yml | 4 + .../test/splitio_android_test.dart | 138 +++++++++++++++- splitio_ios/test/splitio_ios_test.dart | 155 ++++++++++++++++++ 3 files changed, 293 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a503a2a..b8eb93c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -21,3 +21,7 @@ jobs: run: cd splitio/; flutter pub get - name: Run flutter test run: cd splitio/; flutter test + - name: Run flutter splitio_android test + run: cd splitio_android/; flutter test + - name: Run flutter splitio_ios test + run: cd splitio_ios/; flutter test diff --git a/splitio_android/test/splitio_android_test.dart b/splitio_android/test/splitio_android_test.dart index 7cc1f68..554d4cd 100644 --- a/splitio_android/test/splitio_android_test.dart +++ b/splitio_android/test/splitio_android_test.dart @@ -33,8 +33,12 @@ void main() { case 'getTreatment': return ''; case 'getTreatments': + case 'getTreatmentsByFlagSet': + case 'getTreatmentsByFlagSets': return {'split1': 'on', 'split2': 'off'}; case 'getTreatmentsWithConfig': + case 'getTreatmentsWithConfigByFlagSet': + case 'getTreatmentsWithConfigByFlagSets': return { 'split1': {'treatment': 'on', 'config': null}, 'split2': {'treatment': 'off', 'config': null} @@ -54,6 +58,8 @@ void main() { case 'removeAttribute': case 'clearAttributes': return true; + case 'getUserConsent': + return 'declined'; } return null; }); @@ -183,6 +189,130 @@ void main() { 'attributes': {'attr1': true} }); }); + + test('getTreatmentsByFlagSet without attributes', () async { + _platform.getTreatmentsByFlagSet( + matchingKey: 'matching-key', + bucketingKey: 'bucketing-key', + flagSet: 'set_1'); + + expect(methodName, 'getTreatmentsByFlagSet'); + expect(methodArguments, { + 'flagSet': 'set_1', + 'matchingKey': 'matching-key', + 'bucketingKey': 'bucketing-key', + 'attributes': {} + }); + }); + + test('getTreatmentsByFlagSet with attributes', () async { + _platform.getTreatmentsByFlagSet( + matchingKey: 'matching-key', + bucketingKey: 'bucketing-key', + flagSet: 'set_1', + attributes: {'attr1': true}); + + expect(methodName, 'getTreatmentsByFlagSet'); + expect(methodArguments, { + 'flagSet': 'set_1', + 'matchingKey': 'matching-key', + 'bucketingKey': 'bucketing-key', + 'attributes': {'attr1': true} + }); + }); + + test('getTreatmentsByFlagSets without attributes', () async { + _platform.getTreatmentsByFlagSets( + matchingKey: 'matching-key', + bucketingKey: 'bucketing-key', + flagSets: ['set_1', 'set_2']); + + expect(methodName, 'getTreatmentsByFlagSets'); + expect(methodArguments, { + 'flagSets': ['set_1', 'set_2'], + 'matchingKey': 'matching-key', + 'bucketingKey': 'bucketing-key', + 'attributes': {} + }); + }); + + test('getTreatmentsByFlagSets with attributes', () async { + _platform.getTreatmentsByFlagSets( + matchingKey: 'matching-key', + bucketingKey: 'bucketing-key', + flagSets: ['set_1', 'set_2'], + attributes: {'attr1': true}); + + expect(methodName, 'getTreatmentsByFlagSets'); + expect(methodArguments, { + 'flagSets': ['set_1', 'set_2'], + 'matchingKey': 'matching-key', + 'bucketingKey': 'bucketing-key', + 'attributes': {'attr1': true} + }); + }); + + test('getTreatmentsWithConfigByFlagSet without attributes', () async { + _platform.getTreatmentsWithConfigByFlagSet( + matchingKey: 'matching-key', + bucketingKey: 'bucketing-key', + flagSet: 'set_1'); + + expect(methodName, 'getTreatmentsWithConfigByFlagSet'); + expect(methodArguments, { + 'flagSet': 'set_1', + 'matchingKey': 'matching-key', + 'bucketingKey': 'bucketing-key', + 'attributes': {} + }); + }); + + test('getTreatmentsWithConfigByFlagSet with attributes', () async { + _platform.getTreatmentsWithConfigByFlagSet( + matchingKey: 'matching-key', + bucketingKey: 'bucketing-key', + flagSet: 'set_1', + attributes: {'attr1': true}); + + expect(methodName, 'getTreatmentsWithConfigByFlagSet'); + expect(methodArguments, { + 'flagSet': 'set_1', + 'matchingKey': 'matching-key', + 'bucketingKey': 'bucketing-key', + 'attributes': {'attr1': true} + }); + }); + + test('getTreatmentsWithConfigByFlagSets without attributes', () async { + _platform.getTreatmentsWithConfigByFlagSets( + matchingKey: 'matching-key', + bucketingKey: 'bucketing-key', + flagSets: ['set_1', 'set_2']); + + expect(methodName, 'getTreatmentsWithConfigByFlagSets'); + expect(methodArguments, { + 'flagSets': ['set_1', 'set_2'], + 'matchingKey': 'matching-key', + 'bucketingKey': 'bucketing-key', + 'attributes': {} + }); + }); + + test('getTreatmentsWithConfigByFlagSets with attributes', () async { + _platform.getTreatmentsWithConfigByFlagSets( + matchingKey: 'matching-key', + bucketingKey: 'bucketing-key', + flagSets: ['set_1', 'set_2'], + attributes: {'attr1': true}); + + expect(methodName, 'getTreatmentsWithConfigByFlagSets'); + expect(methodArguments, { + 'flagSets': ['set_1', 'set_2'], + 'matchingKey': 'matching-key', + 'bucketingKey': 'bucketing-key', + 'attributes': {'attr1': true} + }); + }); }); group('track', () { @@ -349,7 +479,7 @@ void main() { expect(methodArguments, { 'apiKey': 'api-key', 'matchingKey': 'matching-key', - 'sdkConfiguration': {} + 'sdkConfiguration': {'readyTimeout': 10} }); }); @@ -363,7 +493,7 @@ void main() { 'apiKey': 'api-key', 'matchingKey': 'matching-key', 'bucketingKey': 'bucketing-key', - 'sdkConfiguration': {} + 'sdkConfiguration': {'readyTimeout': 10} }); }); @@ -527,14 +657,14 @@ void main() { _platform.setUserConsent(true); expect(methodName, 'setUserConsent'); - expect(methodArguments, {'enabled': true}); + expect(methodArguments, {'value': true}); }); test('set user consent disabled', () { _platform.setUserConsent(false); expect(methodName, 'setUserConsent'); - expect(methodArguments, {'enabled': false}); + expect(methodArguments, {'value': false}); }); }); } diff --git a/splitio_ios/test/splitio_ios_test.dart b/splitio_ios/test/splitio_ios_test.dart index d037cb3..52f3f68 100644 --- a/splitio_ios/test/splitio_ios_test.dart +++ b/splitio_ios/test/splitio_ios_test.dart @@ -33,8 +33,12 @@ void main() { case 'getTreatment': return ''; case 'getTreatments': + case 'getTreatmentsByFlagSet': + case 'getTreatmentsByFlagSets': return {'split1': 'on', 'split2': 'off'}; case 'getTreatmentsWithConfig': + case 'getTreatmentsWithConfigByFlagSet': + case 'getTreatmentsWithConfigByFlagSets': return { 'split1': {'treatment': 'on', 'config': null}, 'split2': {'treatment': 'off', 'config': null} @@ -54,6 +58,8 @@ void main() { case 'removeAttribute': case 'clearAttributes': return true; + case 'getUserConsent': + return 'declined'; } return null; }); @@ -183,6 +189,131 @@ void main() { 'attributes': {'attr1': true} }); }); + + + test('getTreatmentsByFlagSet without attributes', () async { + _platform.getTreatmentsByFlagSet( + matchingKey: 'matching-key', + bucketingKey: 'bucketing-key', + flagSet: 'set_1'); + + expect(methodName, 'getTreatmentsByFlagSet'); + expect(methodArguments, { + 'flagSet': 'set_1', + 'matchingKey': 'matching-key', + 'bucketingKey': 'bucketing-key', + 'attributes': {} + }); + }); + + test('getTreatmentsByFlagSet with attributes', () async { + _platform.getTreatmentsByFlagSet( + matchingKey: 'matching-key', + bucketingKey: 'bucketing-key', + flagSet: 'set_1', + attributes: {'attr1': true}); + + expect(methodName, 'getTreatmentsByFlagSet'); + expect(methodArguments, { + 'flagSet': 'set_1', + 'matchingKey': 'matching-key', + 'bucketingKey': 'bucketing-key', + 'attributes': {'attr1': true} + }); + }); + + test('getTreatmentsByFlagSets without attributes', () async { + _platform.getTreatmentsByFlagSets( + matchingKey: 'matching-key', + bucketingKey: 'bucketing-key', + flagSets: ['set_1', 'set_2']); + + expect(methodName, 'getTreatmentsByFlagSets'); + expect(methodArguments, { + 'flagSets': ['set_1', 'set_2'], + 'matchingKey': 'matching-key', + 'bucketingKey': 'bucketing-key', + 'attributes': {} + }); + }); + + test('getTreatmentsByFlagSets with attributes', () async { + _platform.getTreatmentsByFlagSets( + matchingKey: 'matching-key', + bucketingKey: 'bucketing-key', + flagSets: ['set_1', 'set_2'], + attributes: {'attr1': true}); + + expect(methodName, 'getTreatmentsByFlagSets'); + expect(methodArguments, { + 'flagSets': ['set_1', 'set_2'], + 'matchingKey': 'matching-key', + 'bucketingKey': 'bucketing-key', + 'attributes': {'attr1': true} + }); + }); + + test('getTreatmentsWithConfigByFlagSet without attributes', () async { + _platform.getTreatmentsWithConfigByFlagSet( + matchingKey: 'matching-key', + bucketingKey: 'bucketing-key', + flagSet: 'set_1'); + + expect(methodName, 'getTreatmentsWithConfigByFlagSet'); + expect(methodArguments, { + 'flagSet': 'set_1', + 'matchingKey': 'matching-key', + 'bucketingKey': 'bucketing-key', + 'attributes': {} + }); + }); + + test('getTreatmentsWithConfigByFlagSet with attributes', () async { + _platform.getTreatmentsWithConfigByFlagSet( + matchingKey: 'matching-key', + bucketingKey: 'bucketing-key', + flagSet: 'set_1', + attributes: {'attr1': true}); + + expect(methodName, 'getTreatmentsWithConfigByFlagSet'); + expect(methodArguments, { + 'flagSet': 'set_1', + 'matchingKey': 'matching-key', + 'bucketingKey': 'bucketing-key', + 'attributes': {'attr1': true} + }); + }); + + test('getTreatmentsWithConfigByFlagSets without attributes', () async { + _platform.getTreatmentsWithConfigByFlagSets( + matchingKey: 'matching-key', + bucketingKey: 'bucketing-key', + flagSets: ['set_1', 'set_2']); + + expect(methodName, 'getTreatmentsWithConfigByFlagSets'); + expect(methodArguments, { + 'flagSets': ['set_1', 'set_2'], + 'matchingKey': 'matching-key', + 'bucketingKey': 'bucketing-key', + 'attributes': {} + }); + }); + + test('getTreatmentsWithConfigByFlagSets with attributes', () async { + _platform.getTreatmentsWithConfigByFlagSets( + matchingKey: 'matching-key', + bucketingKey: 'bucketing-key', + flagSets: ['set_1', 'set_2'], + attributes: {'attr1': true}); + + expect(methodName, 'getTreatmentsWithConfigByFlagSets'); + expect(methodArguments, { + 'flagSets': ['set_1', 'set_2'], + 'matchingKey': 'matching-key', + 'bucketingKey': 'bucketing-key', + 'attributes': {'attr1': true} + }); + }); }); group('track', () { @@ -514,4 +645,28 @@ void main() { 'attributes': {} }); }); + + + group('userConsent', () { + test('get user consent', () async { + UserConsent userConsent = await _platform.getUserConsent(); + + expect(methodName, 'getUserConsent'); + expect(userConsent, UserConsent.declined); + }); + + test('set user consent enabled', () { + _platform.setUserConsent(true); + + expect(methodName, 'setUserConsent'); + expect(methodArguments, {'value': true}); + }); + + test('set user consent disabled', () { + _platform.setUserConsent(false); + + expect(methodName, 'setUserConsent'); + expect(methodArguments, {'value': false}); + }); + }); } From 7e0c2a205396d3c385806e4417397405f308246f Mon Sep 17 00:00:00 2001 From: Gaston Thea Date: Wed, 8 Nov 2023 14:47:07 -0300 Subject: [PATCH 23/28] Fix tests --- splitio_ios/test/splitio_ios_test.dart | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/splitio_ios/test/splitio_ios_test.dart b/splitio_ios/test/splitio_ios_test.dart index 52f3f68..ab04f62 100644 --- a/splitio_ios/test/splitio_ios_test.dart +++ b/splitio_ios/test/splitio_ios_test.dart @@ -480,7 +480,7 @@ void main() { expect(methodArguments, { 'apiKey': 'api-key', 'matchingKey': 'matching-key', - 'sdkConfiguration': {} + 'sdkConfiguration': {'readyTimeout': 10} }); }); @@ -494,7 +494,7 @@ void main() { 'apiKey': 'api-key', 'matchingKey': 'matching-key', 'bucketingKey': 'bucketing-key', - 'sdkConfiguration': {} + 'sdkConfiguration': {'readyTimeout': 10} }); }); @@ -504,13 +504,13 @@ void main() { matchingKey: 'matching-key', bucketingKey: 'bucketing-key', sdkConfiguration: - SplitConfiguration(logLevel: SplitLogLevel.warning, streamingEnabled: false)); + SplitConfiguration(logLevel: SplitLogLevel.error, streamingEnabled: false, readyTimeout: 1)); expect(methodName, 'init'); expect(methodArguments, { 'apiKey': 'api-key', 'matchingKey': 'matching-key', 'bucketingKey': 'bucketing-key', - 'sdkConfiguration': {'logLevel': 'warning', 'streamingEnabled': false}, + 'sdkConfiguration': {'logLevel': 'error', 'streamingEnabled': false, 'readyTimeout': 1}, }); }); }); From d1b1744171ae5e448c65f817ddc88b23e4eb7db0 Mon Sep 17 00:00:00 2001 From: Gaston Thea Date: Wed, 8 Nov 2023 15:36:49 -0300 Subject: [PATCH 24/28] Missing tests --- .../SplitTests/SplitMethodParserTests.swift | 69 ++++++++++++++++--- 1 file changed, 61 insertions(+), 8 deletions(-) diff --git a/splitio_ios/example/ios/SplitTests/SplitMethodParserTests.swift b/splitio_ios/example/ios/SplitTests/SplitMethodParserTests.swift index 61243b9..fd2c688 100644 --- a/splitio_ios/example/ios/SplitTests/SplitMethodParserTests.swift +++ b/splitio_ios/example/ios/SplitTests/SplitMethodParserTests.swift @@ -86,6 +86,59 @@ class SplitMethodParserTests: XCTestCase { } } + func testGetTreatmentsByFlagSet() { + methodParser?.onMethodCall(methodName: "getTreatmentsByFlagSet", arguments: ["matchingKey": "user-key", "bucketingKey": "bucketing-key", "flagSet": "set_1", "attributes": ["age": 50]], result: { (_: Any?) in + return + }) + + if let splitWrapper = (splitWrapper as? SplitWrapperStub) { + XCTAssert(splitWrapper.matchingKeyValue == "user-key") + XCTAssert(splitWrapper.bucketingKeyValue == "bucketing-key") + XCTAssert(splitWrapper.flagSetValue == "set_1") + print(splitWrapper.attributesValue) + XCTAssert(NSDictionary(dictionary: ["age": 50]).isEqual(to: splitWrapper.attributesValue!)) + } + } + + func testGetTreatmentsByFlagSets() { + methodParser?.onMethodCall(methodName: "getTreatmentsByFlagSets", arguments: ["matchingKey": "user-key", "bucketingKey": "bucketing-key", "flagSets": ["set_1", "set_2"], "attributes": ["age": 50]], result: { (_: Any?) in + return + }) + + if let splitWrapper = (splitWrapper as? SplitWrapperStub) { + XCTAssert(splitWrapper.matchingKeyValue == "user-key") + XCTAssert(splitWrapper.bucketingKeyValue == "bucketing-key") + XCTAssert(splitWrapper.flagSetsValue == ["set_1", "set_2"]) + XCTAssert(NSDictionary(dictionary: ["age": 50]).isEqual(to: splitWrapper.attributesValue!)) + } + } + + func testGetTreatmentsWithConfigByFlagSet() { + methodParser?.onMethodCall(methodName: "getTreatmentsWithConfigByFlagSet", arguments: ["matchingKey": "user-key", "bucketingKey": "bucketing-key", "flagSet": "set_1", "attributes": ["age": 50]], result: { (_: Any?) in + return + }) + + if let splitWrapper = (splitWrapper as? SplitWrapperStub) { + XCTAssert(splitWrapper.matchingKeyValue == "user-key") + XCTAssert(splitWrapper.bucketingKeyValue == "bucketing-key") + XCTAssert(splitWrapper.flagSetValue == "set_1") + XCTAssert(NSDictionary(dictionary: ["age": 50]).isEqual(to: splitWrapper.attributesValue!)) + } + } + + func testGetTreatmentsWithConfigByFlagSets() { + methodParser?.onMethodCall(methodName: "getTreatmentsWithConfigByFlagSets", arguments: ["matchingKey": "user-key", "bucketingKey": "bucketing-key", "flagSets": ["set_1", "set_2"], "attributes": ["age": 50]], result: { (_: Any?) in + return + }) + + if let splitWrapper = (splitWrapper as? SplitWrapperStub) { + XCTAssert(splitWrapper.matchingKeyValue == "user-key") + XCTAssert(splitWrapper.bucketingKeyValue == "bucketing-key") + XCTAssert(splitWrapper.flagSetsValue == ["set_1", "set_2"]) + XCTAssert(NSDictionary(dictionary: ["age": 50]).isEqual(to: splitWrapper.attributesValue!)) + } + } + func testTrackWithValue() { methodParser?.onMethodCall(methodName: "track", arguments: ["matchingKey": "user-key", "bucketingKey": "bucketing-key", "eventType": "my_event", "value": 25.20], result: { (_: Any?) in return @@ -391,38 +444,38 @@ class SplitWrapperStub: SplitWrapper { return result } - func getTreatmentsByFlagSet(matchingKey: String, flagSet: String, bucketingKey: String?, attributes: [String : Any]?) -> [String : String]? { + func getTreatmentsByFlagSet(matchingKey: String, flagSet: String, bucketingKey: String?, attributes: [String : Any]?) -> [String : String] { matchingKeyValue = matchingKey bucketingKeyValue = bucketingKey flagSetValue = flagSet - attributeValue = attributes + attributesValue = attributes return [:] } - func getTreatmentsByFlagSets(matchingKey: String, flagSets: [String], bucketingKey: String?, attributes: [String : Any]?) -> [String : String]? { + func getTreatmentsByFlagSets(matchingKey: String, flagSets: [String], bucketingKey: String?, attributes: [String : Any]?) -> [String : String] { matchingKeyValue = matchingKey bucketingKeyValue = bucketingKey flagSetsValue = flagSets - attributeValue = attributes + attributesValue = attributes return [:] } - func getTreatmentsWithConfigByFlagSet(matchingKey: String, flagSet: String, bucketingKey: String?, attributes: [String : Any]?) -> [String : SplitResult]? { + func getTreatmentsWithConfigByFlagSet(matchingKey: String, flagSet: String, bucketingKey: String?, attributes: [String : Any]?) -> [String : SplitResult] { matchingKeyValue = matchingKey bucketingKeyValue = bucketingKey flagSetValue = flagSet - attributeValue = attributes + attributesValue = attributes return [:] } - func getTreatmentsWithConfigByFlagSets(matchingKey: String, flagSets: [String], bucketingKey: String?, attributes: [String : Any]?) -> [String : SplitResult]? { + func getTreatmentsWithConfigByFlagSets(matchingKey: String, flagSets: [String], bucketingKey: String?, attributes: [String : Any]?) -> [String : SplitResult] { matchingKeyValue = matchingKey bucketingKeyValue = bucketingKey flagSetsValue = flagSets - attributeValue = attributes + attributesValue = attributes return [:] } From 3a371307b7f1aea06bd797ef839a1dcca9ad6307 Mon Sep 17 00:00:00 2001 From: Gaston Thea Date: Wed, 8 Nov 2023 15:43:16 -0300 Subject: [PATCH 25/28] Fix --- splitio_ios/ios/Classes/SplitWrapper.swift | 24 +++++++++++----------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/splitio_ios/ios/Classes/SplitWrapper.swift b/splitio_ios/ios/Classes/SplitWrapper.swift index 924ed4b..b25f9d2 100644 --- a/splitio_ios/ios/Classes/SplitWrapper.swift +++ b/splitio_ios/ios/Classes/SplitWrapper.swift @@ -32,13 +32,13 @@ protocol EvaluationWrapper { 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 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 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 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]? + func getTreatmentsWithConfigByFlagSets(matchingKey: String, flagSets: [String], bucketingKey: String?, attributes: [String: Any]?) -> [String: SplitResult] } protocol AttributesWrapper { @@ -129,33 +129,33 @@ class DefaultSplitWrapper: SplitWrapper { return client.getTreatmentsWithConfig(splits: splits, attributes: attributes) } - func getTreatmentsByFlagSet(matchingKey: String, flagSet: String, bucketingKey: String? = nil, attributes: [String: Any]? = [:]) -> [String: String]? { + func getTreatmentsByFlagSet(matchingKey: String, flagSet: String, bucketingKey: String? = nil, attributes: [String: Any]? = [:]) -> [String: String] { guard let client = getInitializedClient(matchingKey: matchingKey, bucketingKey: bucketingKey) else { - return nil + return [:] } return client.getTreatmentsByFlagSet(flagSet, attributes: attributes) } - func getTreatmentsByFlagSets(matchingKey: String, flagSets: [String], bucketingKey: String? = nil, attributes: [String: Any]? = [:]) -> [String: String]? { + func getTreatmentsByFlagSets(matchingKey: String, flagSets: [String], bucketingKey: String? = nil, attributes: [String: Any]? = [:]) -> [String: String] { guard let client = getInitializedClient(matchingKey: matchingKey, bucketingKey: bucketingKey) else { - return nil + return [:] } return client.getTreatmentsByFlagSets(flagSets, attributes: attributes) } - func getTreatmentsWithConfigByFlagSet(matchingKey: String, flagSet: String, bucketingKey: String? = nil, attributes: [String: Any]? = [:]) -> [String: SplitResult]? { + func getTreatmentsWithConfigByFlagSet(matchingKey: String, flagSet: String, bucketingKey: String? = nil, attributes: [String: Any]? = [:]) -> [String: SplitResult] { guard let client = getInitializedClient(matchingKey: matchingKey, bucketingKey: bucketingKey) else { - return nil + return [:] } return client.getTreatmentsWithConfigByFlagSet(flagSet, attributes: attributes) } - func getTreatmentsWithConfigByFlagSets(matchingKey: String, flagSets: [String], bucketingKey: String? = nil, attributes: [String: Any]? = [:]) -> [String: SplitResult]? { + func getTreatmentsWithConfigByFlagSets(matchingKey: String, flagSets: [String], bucketingKey: String? = nil, attributes: [String: Any]? = [:]) -> [String: SplitResult] { guard let client = getInitializedClient(matchingKey: matchingKey, bucketingKey: bucketingKey) else { - return nil + return [:] } return client.getTreatmentsWithConfigByFlagSets(flagSets, attributes: attributes) From c4a99de4becba761e472f79988127fe435121eb4 Mon Sep 17 00:00:00 2001 From: Gaston Thea Date: Wed, 8 Nov 2023 15:59:41 -0300 Subject: [PATCH 26/28] Fix test --- .../example/ios/SplitTests/SplitMethodParserTests.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/splitio_ios/example/ios/SplitTests/SplitMethodParserTests.swift b/splitio_ios/example/ios/SplitTests/SplitMethodParserTests.swift index 61243b9..826c6f4 100644 --- a/splitio_ios/example/ios/SplitTests/SplitMethodParserTests.swift +++ b/splitio_ios/example/ios/SplitTests/SplitMethodParserTests.swift @@ -391,7 +391,7 @@ class SplitWrapperStub: SplitWrapper { return result } - func getTreatmentsByFlagSet(matchingKey: String, flagSet: String, bucketingKey: String?, attributes: [String : Any]?) -> [String : String]? { + func getTreatmentsByFlagSet(matchingKey: String, flagSet: String, bucketingKey: String?, attributes: [String : Any]?) -> [String : String] { matchingKeyValue = matchingKey bucketingKeyValue = bucketingKey flagSetValue = flagSet @@ -400,7 +400,7 @@ class SplitWrapperStub: SplitWrapper { return [:] } - func getTreatmentsByFlagSets(matchingKey: String, flagSets: [String], bucketingKey: String?, attributes: [String : Any]?) -> [String : String]? { + func getTreatmentsByFlagSets(matchingKey: String, flagSets: [String], bucketingKey: String?, attributes: [String : Any]?) -> [String : String] { matchingKeyValue = matchingKey bucketingKeyValue = bucketingKey flagSetsValue = flagSets @@ -409,7 +409,7 @@ class SplitWrapperStub: SplitWrapper { return [:] } - func getTreatmentsWithConfigByFlagSet(matchingKey: String, flagSet: String, bucketingKey: String?, attributes: [String : Any]?) -> [String : SplitResult]? { + func getTreatmentsWithConfigByFlagSet(matchingKey: String, flagSet: String, bucketingKey: String?, attributes: [String : Any]?) -> [String : SplitResult] { matchingKeyValue = matchingKey bucketingKeyValue = bucketingKey flagSetValue = flagSet @@ -418,7 +418,7 @@ class SplitWrapperStub: SplitWrapper { return [:] } - func getTreatmentsWithConfigByFlagSets(matchingKey: String, flagSets: [String], bucketingKey: String?, attributes: [String : Any]?) -> [String : SplitResult]? { + func getTreatmentsWithConfigByFlagSets(matchingKey: String, flagSets: [String], bucketingKey: String?, attributes: [String : Any]?) -> [String : SplitResult] { matchingKeyValue = matchingKey bucketingKeyValue = bucketingKey flagSetsValue = flagSets From d23fd6a2227e3e6750c7535579aafcfd3f5d5360 Mon Sep 17 00:00:00 2001 From: Gaston Thea Date: Wed, 8 Nov 2023 16:12:46 -0300 Subject: [PATCH 27/28] Retrigger checks From b682f6c3429c3940c6d7249ec90071ca1409b2c3 Mon Sep 17 00:00:00 2001 From: Gaston Thea Date: Wed, 8 Nov 2023 16:25:52 -0300 Subject: [PATCH 28/28] Retrigger checks