diff --git a/Sources/OpenFeature/FeatureProvider.swift b/Sources/OpenFeature/FeatureProvider.swift index 81ea221..0d90334 100644 --- a/Sources/OpenFeature/FeatureProvider.swift +++ b/Sources/OpenFeature/FeatureProvider.swift @@ -11,19 +11,19 @@ public protocol FeatureProvider { // Called by OpenFeatureAPI whenever a new EvaluationContext is set by the application func onContextSet(oldContext: EvaluationContext?, newContext: EvaluationContext) async - func getBooleanEvaluation(key: String, defaultValue: Bool) throws -> ProviderEvaluation< + func getBooleanEvaluation(key: String, defaultValue: Bool, context: EvaluationContext?) throws -> ProviderEvaluation< Bool > - func getStringEvaluation(key: String, defaultValue: String) throws -> ProviderEvaluation< + func getStringEvaluation(key: String, defaultValue: String, context: EvaluationContext?) throws -> ProviderEvaluation< String > - func getIntegerEvaluation(key: String, defaultValue: Int64) throws -> ProviderEvaluation< + func getIntegerEvaluation(key: String, defaultValue: Int64, context: EvaluationContext?) throws -> ProviderEvaluation< Int64 > - func getDoubleEvaluation(key: String, defaultValue: Double) throws -> ProviderEvaluation< + func getDoubleEvaluation(key: String, defaultValue: Double, context: EvaluationContext?) throws -> ProviderEvaluation< Double > - func getObjectEvaluation(key: String, defaultValue: Value) throws -> ProviderEvaluation< + func getObjectEvaluation(key: String, defaultValue: Value, context: EvaluationContext?) throws -> ProviderEvaluation< Value > } diff --git a/Sources/OpenFeature/HookContext.swift b/Sources/OpenFeature/HookContext.swift index 8d66620..2e613ad 100644 --- a/Sources/OpenFeature/HookContext.swift +++ b/Sources/OpenFeature/HookContext.swift @@ -4,7 +4,7 @@ public struct HookContext { var flagKey: String var type: FlagValueType var defaultValue: T - var ctx: EvaluationContext + var ctx: EvaluationContext? var clientMetadata: Metadata? var providerMetadata: Metadata? } diff --git a/Sources/OpenFeature/NoOpProvider.swift b/Sources/OpenFeature/NoOpProvider.swift index 3431e2d..1c25f09 100644 --- a/Sources/OpenFeature/NoOpProvider.swift +++ b/Sources/OpenFeature/NoOpProvider.swift @@ -14,35 +14,35 @@ class NoOpProvider: FeatureProvider { // no-op } - func getBooleanEvaluation(key: String, defaultValue: Bool) throws -> ProviderEvaluation< + func getBooleanEvaluation(key: String, defaultValue: Bool, context: EvaluationContext?) throws -> ProviderEvaluation< Bool > { return ProviderEvaluation( value: defaultValue, variant: NoOpProvider.passedInDefault, reason: Reason.defaultReason.rawValue) } - func getStringEvaluation(key: String, defaultValue: String) throws -> ProviderEvaluation< + func getStringEvaluation(key: String, defaultValue: String, context: EvaluationContext?) throws -> ProviderEvaluation< String > { return ProviderEvaluation( value: defaultValue, variant: NoOpProvider.passedInDefault, reason: Reason.defaultReason.rawValue) } - func getIntegerEvaluation(key: String, defaultValue: Int64) throws -> ProviderEvaluation< + func getIntegerEvaluation(key: String, defaultValue: Int64, context: EvaluationContext?) throws -> ProviderEvaluation< Int64 > { return ProviderEvaluation( value: defaultValue, variant: NoOpProvider.passedInDefault, reason: Reason.defaultReason.rawValue) } - func getDoubleEvaluation(key: String, defaultValue: Double) throws -> ProviderEvaluation< + func getDoubleEvaluation(key: String, defaultValue: Double, context: EvaluationContext?) throws -> ProviderEvaluation< Double > { return ProviderEvaluation( value: defaultValue, variant: NoOpProvider.passedInDefault, reason: Reason.defaultReason.rawValue) } - func getObjectEvaluation(key: String, defaultValue: Value) throws -> ProviderEvaluation< + func getObjectEvaluation(key: String, defaultValue: Value, context: EvaluationContext?) throws -> ProviderEvaluation< Value > { return ProviderEvaluation( diff --git a/Sources/OpenFeature/OpenFeatureClient.swift b/Sources/OpenFeature/OpenFeatureClient.swift index f51e998..1a71ae9 100644 --- a/Sources/OpenFeature/OpenFeatureClient.swift +++ b/Sources/OpenFeature/OpenFeatureClient.swift @@ -194,7 +194,7 @@ extension OpenFeatureClient { ) -> FlagEvaluationDetails { let options = options ?? FlagEvaluationOptions(hooks: [], hookHints: [:]) let hints = options.hookHints - let context = openFeatureApi.getEvaluationContext() ?? MutableContext() + let context = openFeatureApi.getEvaluationContext() var details = FlagEvaluationDetails(flagKey: key, value: defaultValue) let provider = openFeatureApi.getProvider() ?? NoOpProvider() @@ -213,6 +213,7 @@ extension OpenFeatureClient { let providerEval = try createProviderEvaluation( flagValueType: flagValueType, key: key, + context: context, defaultValue: defaultValue, provider: provider) @@ -247,6 +248,7 @@ extension OpenFeatureClient { private func createProviderEvaluation( flagValueType: FlagValueType, key: String, + context: EvaluationContext?, defaultValue: V, provider: FeatureProvider ) throws -> ProviderEvaluation { @@ -258,7 +260,8 @@ extension OpenFeatureClient { if let evaluation = try provider.getBooleanEvaluation( key: key, - defaultValue: defaultValue) as? ProviderEvaluation + defaultValue: defaultValue, + context: context) as? ProviderEvaluation { return evaluation } @@ -269,7 +272,8 @@ extension OpenFeatureClient { if let evaluation = try provider.getStringEvaluation( key: key, - defaultValue: defaultValue) as? ProviderEvaluation + defaultValue: defaultValue, + context: context) as? ProviderEvaluation { return evaluation } @@ -280,7 +284,8 @@ extension OpenFeatureClient { if let evaluation = try provider.getIntegerEvaluation( key: key, - defaultValue: defaultValue) as? ProviderEvaluation + defaultValue: defaultValue, + context: context) as? ProviderEvaluation { return evaluation } @@ -291,7 +296,8 @@ extension OpenFeatureClient { if let evaluation = try provider.getDoubleEvaluation( key: key, - defaultValue: defaultValue) as? ProviderEvaluation + defaultValue: defaultValue, + context: context) as? ProviderEvaluation { return evaluation } @@ -302,7 +308,8 @@ extension OpenFeatureClient { if let evaluation = try provider.getObjectEvaluation( key: key, - defaultValue: defaultValue) as? ProviderEvaluation + defaultValue: defaultValue, + context: context) as? ProviderEvaluation { return evaluation } diff --git a/Sources/OpenFeature/exceptions/OpenFeatureError.swift b/Sources/OpenFeature/exceptions/OpenFeatureError.swift index c595f3a..ab1cd53 100644 --- a/Sources/OpenFeature/exceptions/OpenFeatureError.swift +++ b/Sources/OpenFeature/exceptions/OpenFeatureError.swift @@ -40,7 +40,7 @@ extension OpenFeatureError: CustomStringConvertible { case .generalError(let message): return "General error: \(message)" case .invalidContextError: - return "Invalid context" + return "Invalid or missing context" case .parseError(let message): return "Parse error: \(message)" case .targetingKeyMissingError: diff --git a/Tests/OpenFeatureTests/Helpers/AlwaysBrokenProvider.swift b/Tests/OpenFeatureTests/Helpers/AlwaysBrokenProvider.swift index 871d7d2..3d3ec82 100644 --- a/Tests/OpenFeatureTests/Helpers/AlwaysBrokenProvider.swift +++ b/Tests/OpenFeatureTests/Helpers/AlwaysBrokenProvider.swift @@ -14,31 +14,31 @@ class AlwaysBrokenProvider: FeatureProvider { // no-op } - func getBooleanEvaluation(key: String, defaultValue: Bool) throws + func getBooleanEvaluation(key: String, defaultValue: Bool, context: EvaluationContext?) throws -> OpenFeature.ProviderEvaluation { throw OpenFeatureError.flagNotFoundError(key: key) } - func getStringEvaluation(key: String, defaultValue: String) throws + func getStringEvaluation(key: String, defaultValue: String, context: EvaluationContext?) throws -> OpenFeature.ProviderEvaluation { throw OpenFeatureError.flagNotFoundError(key: key) } - func getIntegerEvaluation(key: String, defaultValue: Int64) throws + func getIntegerEvaluation(key: String, defaultValue: Int64, context: EvaluationContext?) throws -> OpenFeature.ProviderEvaluation { throw OpenFeatureError.flagNotFoundError(key: key) } - func getDoubleEvaluation(key: String, defaultValue: Double) throws + func getDoubleEvaluation(key: String, defaultValue: Double, context: EvaluationContext?) throws -> OpenFeature.ProviderEvaluation { throw OpenFeatureError.flagNotFoundError(key: key) } - func getObjectEvaluation(key: String, defaultValue: OpenFeature.Value) throws + func getObjectEvaluation(key: String, defaultValue: OpenFeature.Value, context: EvaluationContext?) throws -> OpenFeature.ProviderEvaluation { throw OpenFeatureError.flagNotFoundError(key: key) diff --git a/Tests/OpenFeatureTests/Helpers/DoSomethingProvider.swift b/Tests/OpenFeatureTests/Helpers/DoSomethingProvider.swift index b67dca7..a04bc24 100644 --- a/Tests/OpenFeatureTests/Helpers/DoSomethingProvider.swift +++ b/Tests/OpenFeatureTests/Helpers/DoSomethingProvider.swift @@ -15,31 +15,31 @@ class DoSomethingProvider: FeatureProvider { var hooks: [OpenFeature.AnyHook] = [] var metadata: OpenFeature.Metadata = DoMetadata() - func getBooleanEvaluation(key: String, defaultValue: Bool) throws -> ProviderEvaluation< + func getBooleanEvaluation(key: String, defaultValue: Bool, context: EvaluationContext?) throws -> ProviderEvaluation< Bool > { return ProviderEvaluation(value: !defaultValue) } - func getStringEvaluation(key: String, defaultValue: String) throws -> ProviderEvaluation< + func getStringEvaluation(key: String, defaultValue: String, context: EvaluationContext?) throws -> ProviderEvaluation< String > { return ProviderEvaluation(value: String(defaultValue.reversed())) } - func getIntegerEvaluation(key: String, defaultValue: Int64) throws -> ProviderEvaluation< + func getIntegerEvaluation(key: String, defaultValue: Int64, context: EvaluationContext?) throws -> ProviderEvaluation< Int64 > { return ProviderEvaluation(value: defaultValue * 100) } - func getDoubleEvaluation(key: String, defaultValue: Double) throws -> ProviderEvaluation< + func getDoubleEvaluation(key: String, defaultValue: Double, context: EvaluationContext?) throws -> ProviderEvaluation< Double > { return ProviderEvaluation(value: defaultValue * 100) } - func getObjectEvaluation(key: String, defaultValue: Value) throws -> ProviderEvaluation< + func getObjectEvaluation(key: String, defaultValue: Value, context: EvaluationContext?) throws -> ProviderEvaluation< Value > { return ProviderEvaluation(value: .null) diff --git a/Tests/OpenFeatureTests/ProviderSpecTests.swift b/Tests/OpenFeatureTests/ProviderSpecTests.swift index bb7bb7c..a1e0ba6 100644 --- a/Tests/OpenFeatureTests/ProviderSpecTests.swift +++ b/Tests/OpenFeatureTests/ProviderSpecTests.swift @@ -7,52 +7,52 @@ final class ProviderSpecTests: XCTestCase { func testFlagValueSet() throws { let provider = NoOpProvider() - let boolResult = try provider.getBooleanEvaluation(key: "key", defaultValue: false) + let boolResult = try provider.getBooleanEvaluation(key: "key", defaultValue: false, context: MutableContext()) XCTAssertNotNil(boolResult.value) - let stringResult = try provider.getStringEvaluation(key: "key", defaultValue: "test") + let stringResult = try provider.getStringEvaluation(key: "key", defaultValue: "test", context: MutableContext()) XCTAssertNotNil(stringResult.value) - let intResult = try provider.getIntegerEvaluation(key: "key", defaultValue: 4) + let intResult = try provider.getIntegerEvaluation(key: "key", defaultValue: 4, context: MutableContext()) XCTAssertNotNil(intResult.value) - let doubleResult = try provider.getDoubleEvaluation(key: "key", defaultValue: 0.4) + let doubleResult = try provider.getDoubleEvaluation(key: "key", defaultValue: 0.4, context: MutableContext()) XCTAssertNotNil(doubleResult.value) - let objectResult = try provider.getObjectEvaluation(key: "key", defaultValue: .null) + let objectResult = try provider.getObjectEvaluation(key: "key", defaultValue: .null, context: MutableContext()) XCTAssertNotNil(objectResult.value) } func testHasReason() throws { let provider = NoOpProvider() - let boolResult = try provider.getBooleanEvaluation(key: "key", defaultValue: false) + let boolResult = try provider.getBooleanEvaluation(key: "key", defaultValue: false, context: MutableContext()) XCTAssertEqual(boolResult.reason, Reason.defaultReason.rawValue) } func testNoErrorCodeByDefault() throws { let provider = NoOpProvider() - let boolResult = try provider.getBooleanEvaluation(key: "key", defaultValue: false) + let boolResult = try provider.getBooleanEvaluation(key: "key", defaultValue: false, context: MutableContext()) XCTAssertNil(boolResult.errorCode) } func testVariantIsSet() throws { let provider = NoOpProvider() - let boolResult = try provider.getBooleanEvaluation(key: "key", defaultValue: false) + let boolResult = try provider.getBooleanEvaluation(key: "key", defaultValue: false, context: MutableContext()) XCTAssertNotNil(boolResult.variant) - let stringResult = try provider.getStringEvaluation(key: "key", defaultValue: "test") + let stringResult = try provider.getStringEvaluation(key: "key", defaultValue: "test", context: MutableContext()) XCTAssertNotNil(stringResult.variant) - let intResult = try provider.getIntegerEvaluation(key: "key", defaultValue: 4) + let intResult = try provider.getIntegerEvaluation(key: "key", defaultValue: 4, context: MutableContext()) XCTAssertNotNil(intResult.variant) - let doubleResult = try provider.getDoubleEvaluation(key: "key", defaultValue: 0.4) + let doubleResult = try provider.getDoubleEvaluation(key: "key", defaultValue: 0.4, context: MutableContext()) XCTAssertNotNil(doubleResult.variant) - let objectResult = try provider.getObjectEvaluation(key: "key", defaultValue: .null) + let objectResult = try provider.getObjectEvaluation(key: "key", defaultValue: .null, context: MutableContext()) XCTAssertNotNil(objectResult.variant) } }