Skip to content

Add FailureInjector for in-app SDK failure simulation (1/3)#1698

Open
rahul-lohra wants to merge 6 commits into
developfrom
feature/rahullohra/faliure-injector
Open

Add FailureInjector for in-app SDK failure simulation (1/3)#1698
rahul-lohra wants to merge 6 commits into
developfrom
feature/rahullohra/faliure-injector

Conversation

@rahul-lohra
Copy link
Copy Markdown
Contributor

@rahul-lohra rahul-lohra commented May 26, 2026

Goal

Introduces a FailureInjector subsystem to the Stream Video Android SDK, allowing engineers to simulate specific SDK failure scenarios at runtime directly from the demo app — without network proxies or source code changes.

Implementation

Component Description
FailureKey Enum of all injectable failure points, grouped by subsystem (REST, WebSocket, Reconnect Strategy)
FailureInjector Public interface exposing enable, disable, setEnabled, isEnabled, clear, throwDebugFault, and sendFailResult
NoOpFailureInjector Default implementation where all methods are no-ops and isEnabled always returns false, resulting in zero production overhead
ClientState Exposes var failureInjector: FailureInjector, defaulting to NoOpFailureInjector
Call.kt Guards join() with FAIL_JOIN_CALL
StreamVideoClient.kt Guards location fetch with FAIL_LOCATION
SfuSocket.kt Guards WebSocket connect and reconnect strategies: FAIL_WS_CONNECT, FAIL_FAST_RECONNECT, FAIL_FULL_REJOIN, FAIL_MIGRATE

🎨 UI Changes

Screen 1 Detailed Screen
image image

Testing

  • Toggle FAIL_JOIN_CALL — verify call.join() returns an error
  • Toggle FAIL_LOCATION — verify location routing fails gracefully
  • Toggle FAIL_WS_CONNECT — verify WS connection error is handled
  • Toggle FAIL_FAST_RECONNECT / FAIL_FULL_REJOIN / FAIL_MIGRATE
    verify reconnect fallback behaviour
  • Clear all — verify all keys reset and normal flow resumes
  • Confirm no behaviour change in a clean build (no flags toggled)

Summary by CodeRabbit

  • New Features
    • Added a failure injection testing interface accessible through the demo app's settings menu, enabling simulation of various failure scenarios across API operations like joining calls and location retrieval
    • Provides a user-friendly UI for toggling individual failure cases with options to clear all or close the interface

Review Change Stack

@rahul-lohra rahul-lohra self-assigned this May 26, 2026
@rahul-lohra rahul-lohra requested a review from a team as a code owner May 26, 2026 11:36
@rahul-lohra rahul-lohra added the pr:internal Internal or infra-only changes label May 26, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 26, 2026

Walkthrough

This PR introduces a debug failure injection system to the Stream Video SDK. The core framework defines a FailureInjector interface and FailureKey enum, integrated into ClientState with a default no-op implementation. Failure injection points are wired into SDK methods (Call.joinRequest, location retrieval, WebSocket connection). A demo app implementation (FailureInjectorImpl) tracks enabled failures and provides a Compose UI (FailureInjectorUi) for toggling them via settings menu.

Changes

Failure Injection Framework & Demo Integration

Layer / File(s) Summary
Core failure injection contracts and framework
stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/failureinjector/FailureInjector.kt, FailureKey.kt, NoOpFailureInjector.kt, ClientState.kt
FailureInjector interface defines enable/disable/query/clear/throw/return-failure methods. FailureKey enum lists REST, WebSocket, and reconnect injection points. NoOpFailureInjector default implementation is inert. ClientState.failureInjector property wires injector into SDK state.
SDK integration at failure injection points
stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/Call.kt, StreamVideoClient.kt, socket/sfu/SfuSocket.kt
Call.joinRequest checks FAIL_JOIN_CALL before REST call. StreamVideoClient.getCachedLocation checks FAIL_LOCATION before location flow. SfuSocket.connectUser invokes debugFailureInjectors helper to conditionally throw faults based on reconnect strategy and enabled keys.
Demo app FailureInjectorImpl and initialization
demo-app/src/main/kotlin/io/getstream/video/android/App.kt, ui/FailureInjectorImpl.kt
FailureInjectorImpl maintains in-memory map of enabled faults; throwDebugFault throws HttpException for FAIL_LOCATION or RuntimeException for others; sendFailResult returns Result.Failure with GenericError. App.onCreate initializes injector via injectFault() helper.
Compose UI screen for fault injection control
demo-app/src/main/kotlin/io/getstream/video/android/ui/FailureInjectorUi.kt
FailureInjectorUi composable renders toggleable list of FailureKey entries with checkboxes and row clicks; syncs state with provided FailureInjector. Includes "Clear all" action and "OK" close button. FaultInjectorUiDemo preview wires UI to stubbed injector.
CallJoinScreen settings integration and UI wiring
demo-app/src/main/kotlin/io/getstream/video/android/ui/join/CallJoinScreen.kt, res/values/strings.xml
CallJoinScreen maintains state for fault-injector UI visibility; CallJoinHeader extended with onFaultInjectionClick callback and warning-icon button in settings menu. UI conditionally renders FailureInjectorUi when both state flag and failureInjector instance present. String resource "Fault Injector" added.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A framework for faults, both clever and spry,
Lets developers test when connections go dry.
With toggles and UI, inject failures with ease—
Debug integration flows, put the SDK to the test, please!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title accurately summarizes the main change: introducing a FailureInjector subsystem for SDK failure simulation in the demo app.
Description check ✅ Passed Pull request description is comprehensive and well-structured, covering Goal, Implementation, UI Changes with screenshots, and Testing checklist as per template.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/rahullohra/faliure-injector

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🧹 Nitpick comments (1)
stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/failureinjector/FailureInjector.kt (1)

21-37: ⚡ Quick win

Add KDoc for this public failure-injection contract.

FailureInjector exposes behavior that is easy to misapply (throwDebugFault vs sendFailResult). Please document expected semantics on the interface/methods.

As per coding guidelines, "Use KDoc (/** ... */) for public APIs and complex subsystems; link to Stream docs when relevant".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/failureinjector/FailureInjector.kt`
around lines 21 - 37, Add KDoc to the public FailureInjector interface
documenting its intended semantics and usage: describe the interface purpose
(failure-injection for tests/debugging), clarify the difference between
throwDebugFault(FailureKey) (throws an exception synchronously for debugging)
and sendFailResult(FailureKey) (returns an io.getstream.result.Result.Failure to
be used as a failure value), explain lifecycle methods
enable/disable/setEnabled/isEnabled/clear and thread-safety expectations, and
include a link to the Stream docs and any examples or recommended usage
patterns; apply the KDoc to the FailureInjector interface declaration and each
public method name (enable, disable, setEnabled, isEnabled, clear,
throwDebugFault, sendFailResult) so callers can’t misapply the API.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@demo-app/src/main/kotlin/io/getstream/video/android/App.kt`:
- Around line 87-90: injectFault() currently calls StreamVideo.instanceOrNull()
and silently does nothing if the SDK instance is not yet created; change it to
ensure the FailureInjectorImpl is attached even after a cold start by: if
StreamVideo.instanceOrNull() != null attach the injector to
StreamVideo.instanceOrNull()!!.state.failureInjector, otherwise persist the
FailureInjectorImpl (e.g., an App-level property) and attach it from the code
path that initializes StreamVideo (or subscribe to an SDK-initialized callback)
so that when StreamVideo is created you set state.failureInjector =
persistedFailureInjector; reference injectFault(), StreamVideo.instanceOrNull(),
FailureInjectorImpl, and state.failureInjector.

In
`@demo-app/src/main/kotlin/io/getstream/video/android/ui/FailureInjectorImpl.kt`:
- Around line 26-46: FailureInjectorImpl's enabledFaults uses mutableMapOf which
is not thread-safe; replace it with a thread-safe backing store (e.g.,
java.util.concurrent.ConcurrentHashMap or Collections.synchronizedMap) and keep
all access via the existing methods (enable, disable, setEnabled, isEnabled,
clear) so concurrent SDK/UI reads/writes can't race; ensure you update the
declaration of enabledFaults and leave the method signatures intact (no
global-scope coroutines) to maintain structured concurrency.
- Around line 51-55: The Retrofit Response.error call in FailureInjectorImpl
(the branch creating HttpException for FailureKey.FAIL_LOCATION) is using an
illegal status code 100 which causes Response.error to throw
IllegalArgumentException; change the status code to a value >= 400 (for example
500) while keeping the existing okhttp3.ResponseBody.create(null, "") so
Response.error<String>(500, ...) successfully constructs the error response and
the HttpException is created.

In `@demo-app/src/main/kotlin/io/getstream/video/android/ui/FailureInjectorUi.kt`:
- Around line 79-109: Replace hardcoded UI strings in FailureInjectorUi
composable with localized resources: change the Text(...) call that sets text =
"Failure Injection", the Text(...) with text = "Clear all", and any hardcoded
contentDescription like "Close" (and the string at line ~174) to use
stringResource(R.string.<name>) instead; add corresponding entries (e.g.,
failure_injection_title, failure_injection_clear_all, failure_injection_close)
to strings.xml and reference them via stringResource in the composable so all UI
text is localized.
- Around line 54-68: The root Column in FailureInjectorUi ignores the passed-in
modifier because it starts its chain with Modifier instead of the function
parameter; fix by replacing the leading Modifier with the function parameter
`modifier` in the Column's modifier chain (i.e., use
`modifier.fillMaxSize().background(...)`), so parent-provided modifiers applied
to FailureInjectorUi will be honored.

In
`@demo-app/src/main/kotlin/io/getstream/video/android/ui/join/CallJoinScreen.kt`:
- Around line 216-217: Remove the empty conditional block "if
(renderNetworkSettingsUi) { }" in CallJoinScreen (or, if it's intended as a
placeholder, replace the empty body with a clear TODO comment such as "// TODO:
render network settings UI here" so the intent is explicit); ensure you touch
the occurrence of the variable renderNetworkSettingsUi in CallJoinScreen.kt and
do not leave a no-op if statement lingering in the UI code.

In
`@stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/socket/sfu/SfuSocket.kt`:
- Around line 112-113: debugFailureInjectors can throw before the socket is
created so update connectUser to catch any exception thrown by
debugFailureInjectors and route it into the SfuSocket state machine (use the
existing sfuSocketStateService error/transition API, e.g. call the error
transition method with the caught exception) instead of letting it escape; after
sending the error transition return early to avoid continuing socket creation.
Apply the same try/catch+state-transition+return pattern to the other
debugFailureInjectors call site(s) in this class (the second block around the
streamWebSocket setup) so all injected faults consistently trigger
sfuSocketStateService error transitions rather than uncaught throws.

---

Nitpick comments:
In
`@stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/failureinjector/FailureInjector.kt`:
- Around line 21-37: Add KDoc to the public FailureInjector interface
documenting its intended semantics and usage: describe the interface purpose
(failure-injection for tests/debugging), clarify the difference between
throwDebugFault(FailureKey) (throws an exception synchronously for debugging)
and sendFailResult(FailureKey) (returns an io.getstream.result.Result.Failure to
be used as a failure value), explain lifecycle methods
enable/disable/setEnabled/isEnabled/clear and thread-safety expectations, and
include a link to the Stream docs and any examples or recommended usage
patterns; apply the KDoc to the FailureInjector interface declaration and each
public method name (enable, disable, setEnabled, isEnabled, clear,
throwDebugFault, sendFailResult) so callers can’t misapply the API.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 1d8a3d82-1166-499a-8395-d0bbc668c3c5

📥 Commits

Reviewing files that changed from the base of the PR and between 21203e5 and b8936a9.

📒 Files selected for processing (12)
  • demo-app/src/main/kotlin/io/getstream/video/android/App.kt
  • demo-app/src/main/kotlin/io/getstream/video/android/ui/FailureInjectorImpl.kt
  • demo-app/src/main/kotlin/io/getstream/video/android/ui/FailureInjectorUi.kt
  • demo-app/src/main/kotlin/io/getstream/video/android/ui/join/CallJoinScreen.kt
  • demo-app/src/main/res/values/strings.xml
  • stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/Call.kt
  • stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/ClientState.kt
  • stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/StreamVideoClient.kt
  • stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/failureinjector/FailureInjector.kt
  • stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/failureinjector/FailureKey.kt
  • stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/failureinjector/NoOpFailureInjector.kt
  • stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/socket/sfu/SfuSocket.kt

Comment thread demo-app/src/main/kotlin/io/getstream/video/android/App.kt
Comment thread demo-app/src/main/kotlin/io/getstream/video/android/ui/FailureInjectorUi.kt Outdated
Comment thread demo-app/src/main/kotlin/io/getstream/video/android/ui/join/CallJoinScreen.kt Outdated
@rahul-lohra rahul-lohra changed the title Add FailureInjector for in-app SDK failure simulation Add FailureInjector for in-app SDK failure simulation (1/3) May 26, 2026
@rahul-lohra rahul-lohra changed the title Add FailureInjector for in-app SDK failure simulation (1/3) [AND-1188] Add FailureInjector for in-app SDK failure simulation (1/3) May 26, 2026
@rahul-lohra rahul-lohra changed the title [AND-1188] Add FailureInjector for in-app SDK failure simulation (1/3) Add FailureInjector for in-app SDK failure simulation (1/3) May 26, 2026
@aleksandar-apostolov
Copy link
Copy Markdown
Contributor

We need to revise this approach, I fear having a testing code in the SDK is not the best approach. We need to find alternatives.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr:internal Internal or infra-only changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants