diff --git a/mobile/library/objective-c/BUILD b/mobile/library/objective-c/BUILD index deacdbdfa9e13..2553480f43ba6 100644 --- a/mobile/library/objective-c/BUILD +++ b/mobile/library/objective-c/BUILD @@ -7,7 +7,6 @@ exports_files([ objc_library( name = "envoy_engine_objc_lib", srcs = [ - "EnvoyAliases.h", "EnvoyConfiguration.h", "EnvoyConfiguration.m", "EnvoyEngineImpl.m", @@ -23,7 +22,6 @@ objc_library( "EnvoyHTTPFilterFactory.m", "EnvoyHTTPStream.h", "EnvoyHTTPStreamImpl.m", - "EnvoyKeyValueStore.h", "EnvoyLogger.h", "EnvoyLogger.m", "EnvoyNativeFilterConfig.h", @@ -49,6 +47,8 @@ objc_library( }), visibility = ["//visibility:public"], deps = [ + ":envoy_key_value_store_bridge_impl_lib", + ":envoy_key_value_store_lib", ":envoy_objc_bridge_lib", "//library/common:envoy_main_interface_lib", "//library/common/api:c_types", @@ -61,6 +61,30 @@ objc_library( hdrs = ["EnvoyBridgeUtility.h"], visibility = ["//visibility:public"], deps = [ + ":envoy_aliases_lib", "//library/common/types:c_types_lib", ], ) + +objc_library( + name = "envoy_aliases_lib", + hdrs = ["EnvoyAliases.h"], + visibility = ["//visibility:public"], +) + +objc_library( + name = "envoy_key_value_store_bridge_impl_lib", + srcs = ["EnvoyKeyValueStoreBridgeImpl.m"], + hdrs = ["EnvoyKeyValueStoreBridgeImpl.h"], + visibility = ["//visibility:public"], + deps = [ + ":envoy_key_value_store_lib", + ":envoy_objc_bridge_lib", + ], +) + +objc_library( + name = "envoy_key_value_store_lib", + hdrs = ["EnvoyKeyValueStore.h"], + visibility = ["//visibility:public"], +) diff --git a/mobile/library/objective-c/EnvoyBridgeUtility.h b/mobile/library/objective-c/EnvoyBridgeUtility.h index 9eaa9d746e5e0..23e23d02d2dde 100644 --- a/mobile/library/objective-c/EnvoyBridgeUtility.h +++ b/mobile/library/objective-c/EnvoyBridgeUtility.h @@ -1,6 +1,7 @@ #import #import "library/common/types/c_types.h" +#import "library/objective-c/EnvoyAliases.h" static inline envoy_data toNativeData(NSData *data) { if (data == nil || [data isEqual:[NSNull null]]) { diff --git a/mobile/library/objective-c/EnvoyEngineImpl.m b/mobile/library/objective-c/EnvoyEngineImpl.m index e2a735800322e..406a3141c3902 100644 --- a/mobile/library/objective-c/EnvoyEngineImpl.m +++ b/mobile/library/objective-c/EnvoyEngineImpl.m @@ -1,6 +1,7 @@ #import "library/objective-c/EnvoyEngine.h" #import "library/objective-c/EnvoyBridgeUtility.h" #import "library/objective-c/EnvoyHTTPFilterCallbacksImpl.h" +#import "library/objective-c/EnvoyKeyValueStoreBridgeImpl.h" #include "library/common/api/c_types.h" @@ -382,46 +383,6 @@ static envoy_data ios_get_string(const void *context) { return toManagedNativeString(accessor.getEnvoyString()); } -static envoy_data ios_kv_store_read(envoy_data native_key, const void *context) { - // This code block runs inside the Envoy event loop. Therefore, an explicit autoreleasepool block - // is necessary to act as a breaker for any Objective-C allocation that happens. - @autoreleasepool { - id keyValueStore = (__bridge id)context; - NSString *key = [[NSString alloc] initWithBytes:native_key.bytes - length:native_key.length - encoding:NSUTF8StringEncoding]; - NSString *value = [keyValueStore readValueForKey:key]; - return value != nil ? toManagedNativeString(value) : envoy_nodata; - } -} - -static void ios_kv_store_save(envoy_data native_key, envoy_data native_value, const void *context) { - // This code block runs inside the Envoy event loop. Therefore, an explicit autoreleasepool block - // is necessary to act as a breaker for any Objective-C allocation that happens. - @autoreleasepool { - id keyValueStore = (__bridge id)context; - NSString *key = [[NSString alloc] initWithBytes:native_key.bytes - length:native_key.length - encoding:NSUTF8StringEncoding]; - NSString *value = [[NSString alloc] initWithBytes:native_key.bytes - length:native_key.length - encoding:NSUTF8StringEncoding]; - [keyValueStore saveValue:value toKey:key]; - } -} - -static void ios_kv_store_remove(envoy_data native_key, const void *context) { - // This code block runs inside the Envoy event loop. Therefore, an explicit autoreleasepool block - // is necessary to act as a breaker for any Objective-C allocation that happens. - @autoreleasepool { - id keyValueStore = (__bridge id)context; - NSString *key = [[NSString alloc] initWithBytes:native_key.bytes - length:native_key.length - encoding:NSUTF8StringEncoding]; - [keyValueStore removeKey:key]; - } -} - static void ios_track_event(envoy_map map, const void *context) { // This code block runs inside the Envoy event loop. Therefore, an explicit autoreleasepool block // is necessary to act as a breaker for any Objective-C allocation that happens. diff --git a/mobile/library/objective-c/EnvoyKeyValueStoreBridgeImpl.h b/mobile/library/objective-c/EnvoyKeyValueStoreBridgeImpl.h new file mode 100644 index 0000000000000..78253ef7aa6e5 --- /dev/null +++ b/mobile/library/objective-c/EnvoyKeyValueStoreBridgeImpl.h @@ -0,0 +1,11 @@ +#import "library/common/types/c_types.h" +#import "library/objective-c/EnvoyKeyValueStore.h" + +/// Save a value to the key value store that's passed as an opaque context. +void ios_kv_store_save(envoy_data native_key, envoy_data native_value, const void* context); + +/// Read a value from the key value store that's passed as an opaque context. +envoy_data ios_kv_store_read(envoy_data native_key, const void* context); + +/// Remove a value from the key value store that's passed as an opaque context. +void ios_kv_store_remove(envoy_data native_key, const void* context); diff --git a/mobile/library/objective-c/EnvoyKeyValueStoreBridgeImpl.m b/mobile/library/objective-c/EnvoyKeyValueStoreBridgeImpl.m new file mode 100644 index 0000000000000..6e89b03b66b03 --- /dev/null +++ b/mobile/library/objective-c/EnvoyKeyValueStoreBridgeImpl.m @@ -0,0 +1,43 @@ +#import "library/objective-c/EnvoyKeyValueStoreBridgeImpl.h" + +#import "library/objective-c/EnvoyBridgeUtility.h" + +envoy_data ios_kv_store_read(envoy_data native_key, const void *context) { + // This code block runs inside the Envoy event loop. Therefore, an explicit autoreleasepool block + // is necessary to act as a breaker for any Objective-C allocation that happens. + @autoreleasepool { + id keyValueStore = (__bridge id)context; + NSString *key = [[NSString alloc] initWithBytes:native_key.bytes + length:native_key.length + encoding:NSUTF8StringEncoding]; + NSString *value = [keyValueStore readValueForKey:key]; + return value != nil ? toManagedNativeString(value) : envoy_nodata; + } +} + +void ios_kv_store_save(envoy_data native_key, envoy_data native_value, const void *context) { + // This code block runs inside the Envoy event loop. Therefore, an explicit autoreleasepool block + // is necessary to act as a breaker for any Objective-C allocation that happens. + @autoreleasepool { + id keyValueStore = (__bridge id)context; + NSString *key = [[NSString alloc] initWithBytes:native_key.bytes + length:native_key.length + encoding:NSUTF8StringEncoding]; + NSString *value = [[NSString alloc] initWithBytes:native_value.bytes + length:native_value.length + encoding:NSUTF8StringEncoding]; + [keyValueStore saveValue:value toKey:key]; + } +} + +void ios_kv_store_remove(envoy_data native_key, const void *context) { + // This code block runs inside the Envoy event loop. Therefore, an explicit autoreleasepool block + // is necessary to act as a breaker for any Objective-C allocation that happens. + @autoreleasepool { + id keyValueStore = (__bridge id)context; + NSString *key = [[NSString alloc] initWithBytes:native_key.bytes + length:native_key.length + encoding:NSUTF8StringEncoding]; + [keyValueStore removeKey:key]; + } +} diff --git a/mobile/test/objective-c/BUILD b/mobile/test/objective-c/BUILD index 92f54d66a3096..906bafba724c8 100644 --- a/mobile/test/objective-c/BUILD +++ b/mobile/test/objective-c/BUILD @@ -12,3 +12,15 @@ envoy_mobile_objc_test( "//library/objective-c:envoy_objc_bridge_lib", ], ) + +envoy_mobile_objc_test( + name = "envoy_key_value_store_bridge_impl_test", + srcs = [ + "EnvoyKeyValueStoreBridgeImplTest.m", + ], + visibility = ["//visibility:public"], + deps = [ + "//library/objective-c:envoy_key_value_store_bridge_impl_lib", + "//library/objective-c:envoy_objc_bridge_lib", + ], +) diff --git a/mobile/test/objective-c/EnvoyKeyValueStoreBridgeImplTest.m b/mobile/test/objective-c/EnvoyKeyValueStoreBridgeImplTest.m new file mode 100644 index 0000000000000..9a48c13c0e413 --- /dev/null +++ b/mobile/test/objective-c/EnvoyKeyValueStoreBridgeImplTest.m @@ -0,0 +1,92 @@ +#import + +#import "library/objective-c/EnvoyKeyValueStoreBridgeImpl.h" +#import "library/objective-c/EnvoyBridgeUtility.h" + +@interface TestKeyValueStore : NSObject + +@property (nonatomic, copy) NSString * (^readValueBlock)(NSString *key); +@property (nonatomic, copy) void (^saveValueBlock)(NSString *key, NSString *value); +@property (nonatomic, copy) void (^removeValueBlock)(NSString *key); + +@end + +@implementation TestKeyValueStore + +- (NSString *_Nullable)readValueForKey:(NSString *)key { + return self.readValueBlock(key); +} + +- (void)saveValue:(NSString *)value toKey:(NSString *)key { + self.saveValueBlock(key, value); +} + +- (void)removeKey:(NSString *)key { + self.removeValueBlock(key); +} + +@end + +@interface EnvoyEngineImplTest : XCTestCase +@end + +@implementation EnvoyEngineImplTest + +- (void)testReadValue { + NSString *expectedKey = @"key"; + NSString *expectedValue = @"value"; + + TestKeyValueStore *store = [TestKeyValueStore new]; + __block NSString *actualKey = @""; + store.readValueBlock = ^NSString *(NSString *key) { + actualKey = key; + return expectedValue; + }; + + NSData *keyData = [expectedKey dataUsingEncoding:NSUTF8StringEncoding]; + envoy_data data = ios_kv_store_read(toNativeData(keyData), CFBridgingRetain(store)); + NSData *valueData = to_ios_data(data); + NSString *actualValue = [[NSString alloc] initWithBytes:valueData.bytes + length:valueData.length + encoding:NSUTF8StringEncoding]; + + XCTAssertEqualObjects(expectedKey, actualKey); + XCTAssertEqualObjects(expectedValue, actualValue); +} + +- (void)testSaveValue { + NSString *expectedKey = @"key"; + NSString *expectedValue = @"value"; + + TestKeyValueStore *store = [TestKeyValueStore new]; + __block NSString *actualKey = @""; + __block NSString *actualValue = @""; + store.saveValueBlock = ^void(NSString *key, NSString *value) { + actualKey = key; + actualValue = value; + }; + + NSData *keyData = [expectedKey dataUsingEncoding:NSUTF8StringEncoding]; + NSData *valueData = [expectedValue dataUsingEncoding:NSUTF8StringEncoding]; + ios_kv_store_save(toNativeData(keyData), toNativeData(valueData), CFBridgingRetain(store)); + + XCTAssertEqualObjects(expectedKey, actualKey); + XCTAssertEqualObjects(expectedValue, actualValue); +} + +- (void)testRemoveValue { + NSString *expectedKey = @"key"; + + TestKeyValueStore *store = [TestKeyValueStore new]; + __block NSString *actualKey = @""; + store.removeValueBlock = ^void(NSString *key) { + actualKey = key; + }; + + NSData *keyData = [expectedKey dataUsingEncoding:NSUTF8StringEncoding]; + ios_kv_store_remove(toNativeData(keyData), CFBridgingRetain(store)); + + XCTAssertEqualObjects(expectedKey, actualKey); +} + +@end