Description
FirebaseStorage/Tests/Integration/StorageIntegration.swift#L879
testResumeGetFileInBackgroundQueue, Asynchronous wait failed: Exceeded timeout of 100 seconds, with unfulfilled expectations: "resume"
The reason testResumeGetFileInBackgroundQueue is flaky is due to a classic race condition between the blazing-fast network speeds on CI and the asynchronous dispatch of the pause() command.
Here is the exact sequence of events causing the timeout:
The Trigger: The test is downloading a 1MB file and waits for the progress to cross 256KB before triggering a pause.
The Asynchronous Dispatch: When completed > resumeAtBytes, unlike testResumeGetFile which pauses synchronously, this test dispatches task.pause() asynchronously to a background queue (DispatchQueue.global(qos: .background).async).
The Race: After dispatching, the progress observer immediately returns, allowing the NSURLSession download to continue at full speed. On a fast CI network, downloading the remaining ~750KB takes just a few milliseconds.
The Missed State: By the time the background thread is scheduled by the OS and actually executes task.pause(), the file download has already finished, and the task has transitioned to the .success state.
The Timeout: Because a completed task cannot be paused, task.pause() becomes a no-op. The .pause observer is never triggered, expectationResume is never fulfilled, and the test hangs for 100 seconds until it times out.
How to fix it:
To make this test robust, you need to guarantee that the task.pause() executes before the download completes.
Option 1 (Mock the network): Use updateTestBlock to mock the fetcher response and artificially delay the delivery of the data chunks. This is the most reliable way to guarantee the background thread has time to execute the pause.
Option 2 (Use a larger file): Switch the test payload from 1mb to something significantly larger (e.g., a 10MB or 20MB file). This artificially widens the race window, giving the background thread enough time to execute pause() before the download finishes.
Option 3 (Tolerate the race): If the .success observer fires before .pause, you could conditionally fulfill the expectationResume and expectationPause expectations to safely exit the test, though this technically defeats the purpose of the test on fast networks.
Reproducing the issue
Occasional integration test runs
Firebase SDK Version
12.16
Xcode Version
26.5
Installation Method
CocoaPods
Firebase Product(s)
Storage
Targeted Platforms
iOS
Relevant Log Output
If using Swift Package Manager, the project's Package.resolved
Expand Package.resolved snippet
Replace this line with the contents of your Package.resolved.
If using CocoaPods, the project's Podfile.lock
Expand Podfile.lock snippet
Replace this line with the contents of your Podfile.lock!
Description
FirebaseStorage/Tests/Integration/StorageIntegration.swift#L879
testResumeGetFileInBackgroundQueue, Asynchronous wait failed: Exceeded timeout of 100 seconds, with unfulfilled expectations: "resume"
The reason testResumeGetFileInBackgroundQueue is flaky is due to a classic race condition between the blazing-fast network speeds on CI and the asynchronous dispatch of the pause() command.
Here is the exact sequence of events causing the timeout:
The Trigger: The test is downloading a 1MB file and waits for the progress to cross 256KB before triggering a pause.
The Asynchronous Dispatch: When completed > resumeAtBytes, unlike testResumeGetFile which pauses synchronously, this test dispatches task.pause() asynchronously to a background queue (DispatchQueue.global(qos: .background).async).
The Race: After dispatching, the progress observer immediately returns, allowing the NSURLSession download to continue at full speed. On a fast CI network, downloading the remaining ~750KB takes just a few milliseconds.
The Missed State: By the time the background thread is scheduled by the OS and actually executes task.pause(), the file download has already finished, and the task has transitioned to the .success state.
The Timeout: Because a completed task cannot be paused, task.pause() becomes a no-op. The .pause observer is never triggered, expectationResume is never fulfilled, and the test hangs for 100 seconds until it times out.
How to fix it:
To make this test robust, you need to guarantee that the task.pause() executes before the download completes.
Option 1 (Mock the network): Use updateTestBlock to mock the fetcher response and artificially delay the delivery of the data chunks. This is the most reliable way to guarantee the background thread has time to execute the pause.
Option 2 (Use a larger file): Switch the test payload from 1mb to something significantly larger (e.g., a 10MB or 20MB file). This artificially widens the race window, giving the background thread enough time to execute pause() before the download finishes.
Option 3 (Tolerate the race): If the .success observer fires before .pause, you could conditionally fulfill the expectationResume and expectationPause expectations to safely exit the test, though this technically defeats the purpose of the test on fast networks.
Reproducing the issue
Occasional integration test runs
Firebase SDK Version
12.16
Xcode Version
26.5
Installation Method
CocoaPods
Firebase Product(s)
Storage
Targeted Platforms
iOS
Relevant Log Output
If using Swift Package Manager, the project's Package.resolved
Expand
Package.resolvedsnippetReplace this line with the contents of your Package.resolved.If using CocoaPods, the project's Podfile.lock
Expand
Podfile.locksnippetReplace this line with the contents of your Podfile.lock!