Skip to content

chore: kickoff release - #4210

Merged
harsh62 merged 3 commits into
releasefrom
main
May 5, 2026
Merged

chore: kickoff release#4210
harsh62 merged 3 commits into
releasefrom
main

Conversation

@github-actions

@github-actions github-actions Bot commented May 5, 2026

Copy link
Copy Markdown
Contributor

kickoff release

burak-pensa and others added 3 commits April 22, 2026 13:53
* feat(storage): add progress stall timeout for S3 uploads

- Add progressStallTimeoutInterval to StorageConfiguration and AWSS3StoragePluginConfiguration
- Single upload: stall timer in StorageServiceSessionDelegate, resets on didSendBodyData
- Multipart upload: stall timer in StorageMultipartUploadSession
- New error: AWSS3TransferUtilityErrorDomain, code 10 (makeProgressStallTimeoutError)
- Dispatch .failed events on main thread for faster UI feedback
- Unit tests: StorageErrorConstants, StorageConfiguration, PluginConfiguration,
  StorageServiceSessionDelegate, StorageMultipartUploadSession
- Default: 0 (disabled), opt-in via configuration

Made-with: Cursor

* docs: add progress stall timeout documentation

- Storage plugin README with configuration and error handling
- Enhanced doc comments for AWSS3StoragePluginConfiguration
- StorageErrorConstants documentation for stall timeout error
- CHANGELOG entry
- .gitignore for local changelog

Made-with: Cursor

* refactor(storage): ProgressStallTimeout type and per-operation override

Introduce ProgressStallTimeout (.disabled, .interval) to replace raw
TimeInterval naming. Plugin configuration uses progressStallTimeout;
upload options can override per operation. Update tests, README, and
CHANGELOG.

Made-with: Cursor

* test(storage): serialize Amplify reset/configure in operation unit tests

Route reset and configure through a shared actor so concurrent test
setUp/tearDown cannot leave Hub in pendingConfiguration when operations
use Amplify.Hub. Update UploadFileOperationTests2 for async setUp.

* fix(storage): address stall timeout review (errors, tests, Hub lifecycle)

- Use StorageError.unknown for stall timeouts; remove NSError helper constants
- Resolve stall interval on StorageTransferTask (-1 defers to StorageConfiguration)
- Stall path: fail, unregister, then cancel; reset timer on multipart part progress
- Restore upload operation failure dispatch threading; rename tests per review
- Add integration tests for progressStallTimeout on small and multipart uploads
- Fix OperationTestBase vs XCTest async ordering (Hub pendingConfiguration)
- Reset Amplify in BaseConfigTests setUp when add() requires clean framework

Made-with: Cursor

* test(storage): rename progress stall timeout config test to camelCase

Made-with: Cursor

* Revert Storage README and .gitignore per review

Made-with: Cursor

* chore: revert Unreleased CHANGELOG entry; rename multipart stall test

Made-with: Cursor

* test(storage): add integration test for multipart stall timeout failure

Made-with: Cursor

* test(storage): stabilize stall timeout test on slow simulators

Increase the stall interval and fulfillment timeout so the GCD timer
has enough slack to fire reliably on watchOS/tvOS/iOS simulators in CI.

Made-with: Cursor

* refactor(storage): remove redundant StorageConfiguration init

Drop the single-arg init(forBucket:) overload; the init(forBucket:progressStallTimeout:)
variant already provides the same behavior via the default progressStallTimeout value.

Made-with: Cursor

* test(storage): rename stall tests to camelCase and stabilize mock session

- Rename progress stall unit and integration tests from snake_case to
  camelCase to match review feedback and the rest of the suite.
- Retain ARC ownership of the mock service/delegate in the async stall
  test so the delegate's weak reference to the service survives until
  the stall timer fires on slow simulators.
- Configure the storage service mock with URLSessionConfiguration.default
  so the underlying URLSession initializes cleanly on iOS/watchOS/tvOS
  simulators that lack the application-identifier entitlement required
  for background sessions.

Made-with: Cursor

* refactor(storage): use optional TimeInterval for stall timeout sentinel

Replace the -1 sentinel in StorageTransferTask.progressStallTimeoutSeconds
with an optional TimeInterval. `nil` now signals "resolve from
StorageConfiguration" (used for tasks restored from persistence), and
resolvedProgressStallTimeoutSeconds falls back to the configuration value
via nil-coalescing.

Made-with: Cursor

* style(storage): apply swiftformat to StorageMultipartUploadSession

Drop redundant self. references inside the stall-timer closure to satisfy
SwiftFormat 0.60.1 rules used by CI.

Made-with: Cursor

* test(storage): remove flaky multipart stall timeout failure test

The sub-second interval used to force a stall during multipart uploads is
too timing-sensitive for CI. Per reviewer feedback, drop the test and its
associated error-chain helper; the unit-level coverage in
StorageServiceSessionDelegateTests is sufficient to exercise the stall
path without relying on network timing.

Made-with: Cursor

---------

Co-authored-by: Harsh <6162866+harsh62@users.noreply.github.com>
Co-authored-by: Abhash Kumar Singh <thisisabhash@gmail.com>
…th change (#4202)

* fix(api): recycle WebSocket and resubscribe on same-online network path change

Resolve zombie subscription state after iOS recycles the TCP route while
NWPathMonitor continues reporting path.status == .satisfied (e.g. during a
scenePhase inactive -> active transition on the same Wi-Fi network).

Two layered bugs were addressed:

1. WebSocketClient.onNetworkStateChange dropped (.online, .online)
   transitions through `default: break`. NWPathMonitor's pathUpdateHandler
   only fires on real path changes, so a second .satisfied emission while
   already online means the underlying path was swapped and the existing
   URLSessionWebSocketTask is bound to a stale route. The task's state
   stays .running but reads/writes silently fail, leaving the cached
   client zombied. Added an explicit (.online, .online) case that cancels
   the stale task and re-establishes the connection. Guarded by
   connection?.state == .running so we don't recycle a torn-down
   connection.

2. AppSyncRealTimeSubscription.subscribe() early-returned when local
   state was already .subscribed, so after the WebSocket recycled and
   resumeExistingSubscriptions() fired, no .start request was resent to
   the server. The server had already forgotten the subscription, so the
   subscription was silently broken. Added prepareForResubscribe() which
   resets local state to .none, and call it from
   resumeExistingSubscriptions() before re-invoking subscribe().

Fixes #3976

* test(websocket): tolerate spontaneous NWPathMonitor fires in integration test

`testWebSocketClient_withRealNetworkMonitor_whenPathChangesWhileOnline_shouldRecycle`
was failing deterministically on watchOS CI (watchOS 26.x on Apple Watch
Series 10). Reproduced locally on watchOS 26.1 with the same 5-second
timeout signature.

Root cause: the test used `verifyConnected()` which XCTFails on any
event other than `.connected`. On watchOS, the real `NWPathMonitor`
inside `AmplifyNetworkMonitor` fires `pathUpdateHandler` spontaneously
during startup — often multiple times — which either (a) delivers an
`.online` before the WebSocketClient's Combine sink attaches, causing
the scan to miss the priming event and never reach `(.online, .online)`,
or (b) fires an extra `.satisfied` after the client is connected,
triggering a recycle that `verifyConnected` sees as an unexpected
`.disconnected`.

Rewrote the test to:
- Subscribe to the WebSocket publisher before calling `connect()`, so
  no events can be missed during sink-attach.
- Count `.connected` events with a thread-safe counter and expect two
  (initial connect + post-recycle reconnect) rather than asserting
  exact event sequences.
- Tolerate `.disconnected`/`.error`/`.string`/`.data` events so
  NWPathMonitor-driven noise doesn't fail the test.

Verified on watchOS 26.1 (Apple Watch Series 11 simulator) — passes
8/8 WebSocketClientTests, 1325/1325 AWSPluginsCoreTests. iOS 26.1
still passes 8/8.

* docs(tests): apply Given/When/Then doc comments to new regression tests

The four regression tests added for issue #3976 were written with plain
comment blocks instead of the project-standard Given/When/Then doc
comments. Retrofit them to match the convention documented in AGENTS.md.

Also strengthen the testing-conventions section in AGENTS.md to mark
Given/When/Then doc comments as mandatory for all new or modified tests,
so future contributors and automated agents follow the rule.

Tests updated:
- testWebSocketClient_whenNetworkPathChangesWhileOnline_shouldRecycleConnection
- testWebSocketClient_withRealNetworkMonitor_whenPathChangesWhileOnline_shouldRecycle
- testAmplifyNetworkMonitor_whenOnlineEmittedTwice_publishesOnlineOnlineTuple
- testSubscribe_afterOnlineToOnlinePathChange_shouldRecycleAndResubscribe

No behavioral change — doc comments only. All 8 WebSocketClientTests
pass on iOS 26.1 and watchOS 26.1.

* test(api): address PR #4202 review nits on E2E regression test

- Drop the obsolete config-location note from the doc comment; every
  test in the file has the same requirement, enforced in setUp.
- Replace the plain `var subscribedCount = 0` with an AtomicInt helper
  matching the unit-test pattern. The counter is mutated from a
  Combine sink closure, which can fire on any scheduler — theoretical
  data race that AtomicInt closes cleanly.
…refresh (#4208)

* fix(auth): Use inputUsername for device metadata lookup during token refresh

* fix(auth): Use inputUsername for device metadata lookup during token refresh
@github-actions
github-actions Bot requested a review from a team as a code owner May 5, 2026 15:09
@harsh62
harsh62 merged commit c285e64 into release May 5, 2026
173 of 176 checks passed
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.

3 participants