Skip to content

feat: add stateful/sequential mocks - #129

Open
MaxMichel2 wants to merge 1 commit into
feat/networkmock-failure-simulationfrom
feat/networkmock-sequential-mocks
Open

MaxMichel2 wants to merge 1 commit into
feat/networkmock-failure-simulationfrom
feat/networkmock-sequential-mocks

Conversation

@MaxMichel2

Copy link
Copy Markdown
Collaborator

Summary

Closes #96.

Stacked on #128 (PR chain: #123#124#127#128 → this) — merge in order.

Adds sequential/stateful mocks: an operation can advance through an ordered list of responses one step per matched request, sticking on the last step once exhausted. Fills the most common manual-testing gap static mocks can't — polling flows (order status, upload progress, async job completion) where the interesting behavior is the transition across repeated calls.

Design deviation from the issue's proposed shape

The issue suggested persisting the sequence position as a separate DataStore counter, keyed by OperationKey, alongside the existing Sequence state. I went with a simpler design: currentIndex lives inside OperationMockState.Sequence itself (matching the issue's own alternate suggestion, Sequence(responses, currentIndex)), not a second persisted key.

This is strictly simpler and gets the reset requirement for free: MockStateRepository.resetKnownOperationsToNetwork() and NetworkMockState.resetAllToNetwork() already replace the entire OperationMockState value with Network — with position embedded in the same object, it's discarded automatically. A separate counter key would need explicit clearing in both reset paths, which is exactly the trap the issue itself calls out.

What changed

  • OperationMockState.Sequence(responses: List<Mock>, currentIndex: Int = 0): a new sealed-interface variant. currentResponse: Mock? safely indexes the current step.
  • NetworkMockPlugin: a new Sequence branch — serves the current step, then persists the advanced (exhaustion-clamped) index via stateRepository.setOperationMockState before returning. Shares response-loading with the Mock branch via a new buildMockCall helper (reduces duplication rather than copy-pasting the try/catch). The x-devview.failureRate probabilistic roll from feat: probabilistic failure-rate injection #95 applies to Sequence the same way it does to Mock.
  • UI: a "SEQUENCE" section in the operation picker page. Building a sequence is a page-level mode, not a new icon on every response row — "Build a Sequence" changes what tapping a response row does (append to the in-progress list instead of selecting immediately); "Save Sequence" commits (≥2 steps required), "Cancel" discards. An active sequence shows its current step ("200 - default (2/3)") and offers "Reset Position".
  • Deliberate v1 scope cut: reordering is by clearing and rebuilding, not drag handles. A full reorder UI is a reasonable follow-up if users actually build sequences in the wrong order often enough to want it — not something to build speculatively now.
  • NetworkMockViewModel gains setOperationSequenceState(key, responses) and resetOperationSequencePosition(key).

Public API (breaking, per your call on 0.2.0 alphas)

OperationMockState gains another sealed subtype — the same exhaustive-when sites touched for Failure in #128 (EndpointCard, EndpointStateChip, the operation sheet's selected-response lookup, ModelUtils' icon/color extensions, NetworkMockScreen's Mocked/Network filter) needed a Sequence branch too (folded into "Mocked", same reasoning as Failure). api.txt regenerated for devview-networkmock-core and devview-networkmock.

Tests

  • MockStateRepositoryTest: Sequence round-trips through the real DataStore JSON path with its position intact; resetting to Network discards a previous sequence position.
  • NetworkMockPluginTest: a sequence advances across successive requests and sticks on the last step once exhausted (via a small mutableStateRepositoryMock backed by a real MutableStateFlow, so the plugin's own write-then-reread round-trips like it would against real DataStore); the probabilistic failure roll applies to Sequence states too.

Docs: networkmock-workflows.md (new workflow), networkmock-core.md (DataStore schema entry).

Verification

.\gradlew.bat detektFull -Pandroidx.baselineprofile.skipgeneration
.\gradlew.bat cleanTestAndroidHostTest testAndroidHostTest -Pandroidx.baselineprofile.skipgeneration
.\gradlew.bat :konsist:test -Pandroidx.baselineprofile.skipgeneration
.\gradlew.bat :devview-networkmock:compileAndroidDeviceTest -Pandroidx.baselineprofile.skipgeneration
.\gradlew.bat :sample:androidApp:assembleDebug -Pandroidx.baselineprofile.skipgeneration

All green (combined run, including a full repo-wide testAndroidHostTest).

🤖 Generated with Claude Code

@MaxMichel2 MaxMichel2 added this to the 0.2.0 milestone Sep 22, 2026
@MaxMichel2 MaxMichel2 self-assigned this Sep 22, 2026
@MaxMichel2
MaxMichel2 added this pull request to stack #130 September 22, 2026 12:07
Adds a Sequence operation state that advances through an ordered
list of responses one step per matched request, sticking on the
last step once exhausted. Fills the most common manual-testing gap
static mocks can't: polling flows (order status, upload progress,
async job completion) where the interesting behavior is the
transition across repeated calls, not any single response.

- OperationMockState.Sequence(responses: List<Mock>, currentIndex: Int):
  the position is persisted as part of this same state rather than a
  separate DataStore key/counter - simpler than the originally-proposed
  design, and it means resetting an operation to Network (or resetting
  all mocks) already discards the position along with everything else,
  with zero special-casing in the existing reset paths.
- NetworkMockPlugin: a new Sequence branch that serves the current step,
  then persists the advanced (or exhaustion-clamped) index back through
  the state repository before returning. Shares response-loading logic
  with the Mock branch via a new buildMockCall helper. The probabilistic
  x-devview.failureRate roll (see #95) applies to Sequence the same way
  it does to Mock.
- UI: a "SEQUENCE" section in the operation picker page. Building one is
  a page-level mode (not a new icon on every response row): "Build a
  Sequence" toggles tapping responses to append-to-sequence instead of
  select-immediately; "Save Sequence" commits (2+ steps required),
  "Cancel" discards. An active sequence shows its current step and a
  "Reset Position" action. Reordering is by clearing and rebuilding
  rather than drag handles - a deliberate v1 scope cut, not a gap in
  what's needed yet.

Breaking (fine during 0.2.0 alphas): OperationMockState gains another
new sealed subtype - the same exhaustive-when sites touched for
Failure (EndpointCard, EndpointStateChip, the operation sheet,
ModelUtils, the Mocked/Network list filter) needed a Sequence branch
too.

Closes #96.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

This branch has not been deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant