SDK-300 Add OnSuccess/OnFailure handlers to logoutUser#1069
Conversation
Adds a public `IterableAPI.logoutUser(withOnSuccess:onFailure:)` overload for observability around the logout sequence. logoutUser/logoutPreviousUser are local-only operations -- the only network side-effect is the disableDeviceForCurrentUser triggered when autoPushRegistration is on, and that already auto-retries offline via SDK-297. The handlers signal that the local sequence completed and surface the triggered disableDevice's result; they are not a retry mechanism. - Public: new `logoutUser(withOnSuccess:onFailure:)` on IterableAPI; the existing parameterless `logoutUser()` delegates to it with nil/nil handlers, preserving Obj-C and source compatibility. Mirrors the precedent set by disableDeviceForCurrentUser's two-overload shape. - Internal: new InternalIterableAPI.logoutUser(withOnSuccess:onFailure:). Not-initialized -> onFailure. autoPushRegistration on -> handlers piped through the existing disableDeviceForCurrentUser(withOnSuccess:onFailure:) *before* clearing identity (so the disable request goes out with the still-set userId/email), then local cleanup runs. autoPushRegistration off -> local cleanup, then onSuccess(nil) synchronously. - logoutPreviousUser() left untouched -- still used on internal user-switch paths with its existing fire-and-forget contract. - Tests in AuthTests cover: autoPush-on success, autoPush-on failure (local cleanup STILL happens despite network error), autoPush-off synchronous success with no network, not-initialized failure, and the parameterless overload regression. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #1069 +/- ##
==========================================
+ Coverage 71.27% 71.31% +0.03%
==========================================
Files 112 112
Lines 9369 9389 +20
==========================================
+ Hits 6678 6696 +18
- Misses 2691 2693 +2 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
| } | ||
|
|
||
| func logoutUser() { | ||
| logoutPreviousUser() |
There was a problem hiding this comment.
Before this PR, logoutUser() delegated to logoutPreviousUser() (line 251 on master), keeping a single source of truth for the eight-step logout cleanup sequence. After this PR, that body lives in two places:
- logoutPreviousUser() (line 877), used by setEmail/setUserId user-switch paths.
- logoutUser(withOnSuccess:onFailure:) (line 254), used by both public entry points.
There was a problem hiding this comment.
@franco-zalamena-iterable Good catch and appreciate the attention to detail. This is fixed in c0193b7. logoutPreviousUser() now delegates to logoutUser(withOnSuccess:onFailure:) with nil handlers instead of carrying its own copy of the eight-step cleanup, so the sequence has a single source of truth again.
Behavior is unchanged for the setEmail/setUserId user-switch paths: a nil onFailure keeps the not-initialized guard a silent no-op, and a nil onSuccess makes the auto-push-off completion a no-op — exactly matching the old logoutPreviousUser() body.
Verified: build green, AuthTests 42/0, and UserMergeScenariosTests 21/0 (which exercises the user-switch paths through logoutPreviousUser).
Per Franco's review, collapse the duplicated logout cleanup sequence. logoutPreviousUser() now delegates to logoutUser(withOnSuccess:onFailure:) with nil handlers instead of carrying its own copy of the eight-step cleanup. The full sequence lives in exactly one place. Behavior is unchanged for the setEmail/setUserId user-switch paths: a nil onFailure keeps the not-initialized guard a silent no-op, and a nil onSuccess makes the auto-push-off completion a no-op. Verified: ./agent_build.sh green; AuthTests 42/0; UserMergeScenariosTests 21/0 (exercises the user-switch paths through logoutPreviousUser). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
franco-zalamena-iterable
left a comment
There was a problem hiding this comment.
Just one thing to address but non blocker anymore
Per Franco's review follow-up: now that logoutPreviousUser() delegates to logoutUser(withOnSuccess:onFailure:), the parameterless logoutUser() can keep calling logoutPreviousUser() as it did on master instead of calling the handler overload directly. Minimizes the diff and preserves the original delegation; behavior is unchanged (logoutUser() -> logoutPreviousUser() -> logoutUser(withOnSuccess:nil,onFailure:nil)). Build green; AuthTests 42/0. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Following a detailed handler-correctness review (no functional bug found), clarify the observability contract and close the one test gap: - Doc comment on the public logoutUser(withOnSuccess:onFailure:) spelling out that logout is local-only and the handlers reflect the triggered disableDevice result when autoPushRegistration is on. Notably, an onFailure (e.g. "no token present", or a failed disable request) does NOT mean the local logout failed. Also documents that handlers are in-process only (not persisted across app termination) and not guaranteed to be delivered on the main thread. - Test: autoPush ON with no registered token now asserts onFailure fires with "no token present", that local cleanup STILL completes, and that no disableDevice request is sent. Build green; AuthTests 43/0. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…success-failure-handlers * origin/master: SDK-493: Prepare for Release 6.7.2 (#1070)
There was a problem hiding this comment.
Should this be updated with the same level of error as we have on logoutUser?
There was a problem hiding this comment.
Good catch, addressed in 7708de1. Both disableDeviceForCurrentUser and disableDeviceForAllUsers completion overloads now fire onFailure("Iterable SDK is not initialized", nil) on the not-initialized guard, matching logoutUser. The parameterless overloads pass nil handlers, so they are unchanged. Added a test, AuthTests 44/0.
Per Joao's review, make the disableDeviceForCurrentUser and
disableDeviceForAllUsers completion overloads call
onFailure("Iterable SDK is not initialized", nil) on the not-initialized
guard, matching logoutUser. The parameterless overloads pass nil handlers,
so they are unchanged.
AuthTests 44/0.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…success-failure-handlers * origin/master: SDK-469 Fix CodeQL string length conflation in deep link check (#1071)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
What
Adds a public
IterableAPI.logoutUser(withOnSuccess:onFailure:)overload so SDK consumers can observe the logout sequence. The handlers signal that the local logout sequence completed and surface the triggereddisableDeviceForCurrentUserresult — they are an observability primitive, not a retry mechanism (the disable already auto-retries offline via SDK-297). Ticket: SDK-300.Changes
IterableAPI.swift): NewlogoutUser(withOnSuccess:onFailure:)overload. ParameterlesslogoutUser()now delegates withnil/nilhandlers, preserving Obj-C and source compatibility. MirrorsdisableDeviceForCurrentUser's two-overload precedent.InternalIterableAPI.swift): NewlogoutUser(withOnSuccess:onFailure:). Not-initialized →onFailure.autoPushRegistrationon → handlers piped through the existingdisableDeviceForCurrentUser(withOnSuccess:onFailure:)before identity cleanup (so the disable request goes out with the still-set userId/email), then local cleanup runs.autoPushRegistrationoff → local cleanup, thenonSuccess(nil)synchronously.logoutPreviousUser()untouched — internal user-switch paths keep their existing fire-and-forget contract.AuthTests.swift): 5 new tests covering autoPush-on success, autoPush-on failure (verifies local cleanup STILL happens despite network error), autoPush-off synchronous success with no network, not-initialized failure, and the parameterless overload regression.Impact
logoutUser()is unchanged; only adds a new overload.Testing
How to test:
./agent_test.sh AuthTests— all 42 tests pass (5 new).IterableAPI.logoutUser(withOnSuccess:onFailure:)from a sample app withautoPushRegistration = trueand a logged-in user; verifyonSuccessfires after the disable network call returns.autoPushRegistration = false, verifyonSuccessfires synchronously and no network request is made.onFailurefires withIterable SDK is not initialized.logoutUser()still logs out without regression.