Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions DemoSwiftApp/Samples/SamplesForAPI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,7 @@ class SamplesForAPI {
userId: "USER_123",
attributes: ["country": "us"]
)
let options: [OptimizelyDecideOption] = [.ignoreCmabCache, .ignoreUserProfileService]
let options: [OptimizelyDecideOption] = [.ignoreCmabCache]
let decision = await user.decideAsync(key: FLAG_KEY, options: options)
print("CMAB decision: \(decision)")
}
Expand All @@ -462,7 +462,7 @@ class SamplesForAPI {
userId: "USER_123",
attributes: ["country": "us"]
)
let options: [OptimizelyDecideOption] = [.ignoreCmabCache, .ignoreUserProfileService]
let options: [OptimizelyDecideOption] = [.ignoreCmabCache]
user.decideAsync(key: FLAG_KEY, options: options, completion: { decision in
print("CMAB decision: \(decision)")
})
Expand Down Expand Up @@ -494,7 +494,7 @@ class SamplesForAPI {
userId: "USER_123",
attributes: ["country": "us"]
)
let options: [OptimizelyDecideOption] = [.ignoreCmabCache, .ignoreUserProfileService]
let options: [OptimizelyDecideOption] = [.ignoreCmabCache]
let decision = await user.decideAsync(key: FLAG_KEY, options: options)
print("CMAB decision: \(decision)")
}
Expand All @@ -512,7 +512,7 @@ class SamplesForAPI {
userId: "USER_123",
attributes: ["country": "us"]
)
let options: [OptimizelyDecideOption] = [.ignoreCmabCache, .ignoreUserProfileService]
let options: [OptimizelyDecideOption] = [.ignoreCmabCache]
user.decideAsync(key: FLAG_KEY, options: options, completion: { decision in
print("CMAB decision: \(decision)")
})
Expand Down
10 changes: 9 additions & 1 deletion Sources/Implementation/DefaultDecisionService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,8 @@ class DefaultDecisionService: OPTDecisionService {
user: user)
reasons.merge(audienceResponse.reasons)

var ignoreUPS = false

if audienceResponse.result ?? false {
// Acquire bucketingId
let bucketingId = getBucketingId(userId: userId, attributes: attributes)
Expand All @@ -262,6 +264,9 @@ class DefaultDecisionService: OPTDecisionService {
options: options)
reasons.merge(cmabDecisionResponse.reasons)
variationDecision = cmabDecisionResponse.result

// CMAB decision shouldn't be in the UPS
ignoreUPS = cmabDecisionResponse.result?.variation != nil
} else {
// bucket user into a variation
let decisionResponse = bucketer.bucketExperiment(config: config,
Expand All @@ -277,7 +282,10 @@ class DefaultDecisionService: OPTDecisionService {
let info = LogMessage.userBucketedIntoVariationInExperiment(userId, experiment.key, variation.key)
logger.i(info)
reasons.addInfo(info)
userProfileTracker?.updateProfile(experiment: experiment, variation: variation)
if !ignoreUPS {
userProfileTracker?.updateProfile(experiment: experiment, variation: variation)
}

} else {
let info = LogMessage.userNotBucketedIntoVariation(userId)
logger.i(info)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ class OptimizelyUserContextTests_Decide_CMAB: XCTestCase {
let user = optimizely.createUserContext(userId: kUserId, attributes: ["gender": "f"])

// Test multiple decisions with decideAsync
user.decideAsync(keys: featureKeys, options: [.ignoreUserProfileService]) { decisions in
user.decideAsync(keys: featureKeys) { decisions in

// Verify correct number of decisions were returned
XCTAssertEqual(decisions.count, 2)
Expand Down Expand Up @@ -175,7 +175,7 @@ class OptimizelyUserContextTests_Decide_CMAB: XCTestCase {
wait(for: [expectation], timeout: 5) // Increased timeout for reliability
}

func testDecideAsync_cmabWithUserProfileCahing() {
func testDecideAsync_cmabIgnoreUPSCacheing() {
let expectation1 = XCTestExpectation(description: "First CMAB decision")
let expectation2 = XCTestExpectation(description: "Second CMAB decision")

Expand All @@ -192,17 +192,17 @@ class OptimizelyUserContextTests_Decide_CMAB: XCTestCase {
attributes: ["gender": "f", "age": 25]
)

// First decision cache into user profile

user.decideAsync(key: "feature_1") { decision in
XCTAssertEqual(decision.variationKey, "a")
XCTAssertEqual(self.mockCmabService.decisionCallCount, 1)
expectation1.fulfill()

// Second decision (should use cache)
// Second decision, ignore UPS, fetch decision again
user.decideAsync(key: "feature_1") { decision in
XCTAssertEqual(decision.variationKey, "a")
// Call count should still be 1 (cached)
XCTAssertEqual(self.mockCmabService.decisionCallCount, 1)
// Call count should be increased by 1
XCTAssertEqual(self.mockCmabService.decisionCallCount, 2)
expectation2.fulfill()
}
}
Expand All @@ -228,17 +228,17 @@ class OptimizelyUserContextTests_Decide_CMAB: XCTestCase {
userId: kUserId,
attributes: ["gender": "f", "age": 25]
)
user.decideAsync(key: "feature_1", options: [.ignoreUserProfileService, .ignoreCmabCache]) { decision in
user.decideAsync(key: "feature_1", options: [.ignoreCmabCache]) { decision in
XCTAssertEqual(decision.variationKey, "a")
XCTAssertTrue(self.mockCmabService.ignoreCacheUsed)
exp1.fulfill()
}
user.decideAsync(key: "feature_1", options: [.ignoreUserProfileService, .resetCmabCache]) { decision in
user.decideAsync(key: "feature_1", options: [.resetCmabCache]) { decision in
XCTAssertEqual(decision.variationKey, "a")
XCTAssertTrue(self.mockCmabService.resetCacheCache)
exp2.fulfill()
}
user.decideAsync(key: "feature_1", options: [.ignoreUserProfileService, .invalidateUserCmabCache]) { decision in
user.decideAsync(key: "feature_1", options: [.invalidateUserCmabCache]) { decision in
XCTAssertEqual(decision.variationKey, "a")
XCTAssertTrue(self.mockCmabService.invalidateUserCmabCache)
exp3.fulfill()
Expand All @@ -263,7 +263,7 @@ class OptimizelyUserContextTests_Decide_CMAB: XCTestCase {
attributes: ["gender": "f", "age": 25]
)

user.decideAsync(key: "feature_1", options: [.ignoreUserProfileService, .includeReasons]) { decision in
user.decideAsync(key: "feature_1", options: [.includeReasons]) { decision in
XCTAssertTrue(decision.reasons.contains(LogMessage.cmabFetchFailed("exp_with_audience").reason))
expectation.fulfill()
}
Expand Down
Loading