Skip to content

Commit

Permalink
fix: TypeMismatch error is handled (#170)
Browse files Browse the repository at this point in the history
* fix: TypeMismatch error is handled

* docs: Add explanatory comment on null values
  • Loading branch information
fabriziodemaria authored Nov 6, 2024
1 parent 58c3a71 commit 6a04cda
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 9 deletions.
38 changes: 30 additions & 8 deletions Sources/Confidence/FlagEvaluation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public enum ErrorCode {
case invalidContext
case flagNotFound
case evaluationError
case typeMismatch
}

struct FlagResolution: Encodable, Decodable, Equatable {
Expand Down Expand Up @@ -68,20 +69,41 @@ extension FlagResolution {
}

let parsedValue = try getValue(path: parsedKey.path, value: value)
let pathValue: T = getTyped(value: parsedValue) ?? defaultValue
let typedValue: T? = getTyped(value: parsedValue)

if resolvedFlag.resolveReason == .match {
var resolveReason: ResolveReason = .match
if self.context != context {
resolveReason = .stale
}
return Evaluation(
value: pathValue,
variant: resolvedFlag.variant,
reason: resolveReason,
errorCode: nil,
errorMessage: nil
)
if let typedValue = typedValue {
return Evaluation(
value: typedValue,
variant: resolvedFlag.variant,
reason: resolveReason,
errorCode: nil,
errorMessage: nil
)
} else {
// `null` type from backend instructs to use client-side default value
if parsedValue == .init(null: ()) {
return Evaluation(
value: defaultValue,
variant: resolvedFlag.variant,
reason: resolveReason,
errorCode: nil,
errorMessage: nil
)
} else {
return Evaluation(
value: defaultValue,
variant: nil,
reason: .error,
errorCode: .typeMismatch,
errorMessage: nil
)
}
}
} else {
return Evaluation(
value: defaultValue,
Expand Down
2 changes: 2 additions & 0 deletions Sources/ConfidenceProvider/ConfidenceFeatureProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,8 @@ extension Evaluation {
throw OpenFeatureError.flagNotFoundError(key: self.errorMessage ?? "unknown key")
case .evaluationError:
throw OpenFeatureError.generalError(message: self.errorMessage ?? "unknown error")
case .typeMismatch:
throw OpenFeatureError.typeMismatchError
}
}
return ProviderEvaluation(
Expand Down
2 changes: 1 addition & 1 deletion Tests/ConfidenceTests/ConfidenceIntegrationTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class ConfidenceIntegrationTests: XCTestCase {
.withContext(initialContext: ctx)
.build()
try await confidence.fetchAndActivate()
let intResult = confidence.getEvaluation(key: "\(resolveFlag).my-integer", defaultValue: "1")
let intResult = confidence.getEvaluation(key: "\(resolveFlag).my-integer", defaultValue: 1)
let boolResult = confidence.getEvaluation(key: "\(resolveFlag).my-boolean", defaultValue: false)


Expand Down
38 changes: 38 additions & 0 deletions Tests/ConfidenceTests/ConfidenceTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,44 @@ class ConfidenceTest: XCTestCase {
}
}

func testTypeMismatch() async throws {
class FakeClient: ConfidenceResolveClient {
var resolveStats: Int = 0
var resolvedValues: [ResolvedValue] = []
func resolve(ctx: ConfidenceStruct) async throws -> ResolvesResult {
self.resolveStats += 1
return .init(resolvedValues: resolvedValues, resolveToken: "token")
}
}

let client = FakeClient()
client.resolvedValues = [
ResolvedValue(
variant: "control",
value: .init(structure: ["size": .init(boolean: true)]),
flag: "flag",
resolveReason: .match)
]

let confidence = Confidence.Builder(clientSecret: "test")
.withContext(initialContext: ["targeting_key": .init(string: "user1")])
.withFlagResolverClient(flagResolver: client)
.withFlagApplier(flagApplier: flagApplier)
.build()

try await confidence.fetchAndActivate()
let evaluation = confidence.getEvaluation(
key: "flag.size",
defaultValue: 1)

XCTAssertEqual(client.resolveStats, 1)
XCTAssertEqual(evaluation.value, 1)
XCTAssertEqual(evaluation.errorCode, .typeMismatch)
XCTAssertNil(evaluation.errorMessage, "")
XCTAssertEqual(evaluation.reason, .error)
XCTAssertEqual(evaluation.variant, nil)
}

func testConcurrentActivate() async {
for _ in 1...100 {
Task {
Expand Down

0 comments on commit 6a04cda

Please sign in to comment.