Skip to content

Commit b88693d

Browse files
test(storage, apple): fix consistently failing storage e2e cancel() test (#17596)
1 parent a4db26e commit b88693d

File tree

7 files changed

+145
-21
lines changed

7 files changed

+145
-21
lines changed

.github/workflows/all_plugins.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ jobs:
124124
"flutter build web"
125125
swift-integration:
126126
runs-on: macos-15
127-
timeout-minutes: 30
127+
timeout-minutes: 45
128128
env:
129129
FLUTTER_DEPENDENCIES: "cloud_firestore firebase_remote_config cloud_functions firebase_database firebase_auth firebase_storage firebase_analytics firebase_messaging firebase_app_check firebase_in_app_messaging firebase_performance firebase_crashlytics firebase_ml_model_downloader firebase_app_installations"
130130
PR_HEAD_REPO: ${{ github.event.pull_request.head.repo.full_name }}

packages/firebase_storage/firebase_storage/example/ios/Runner.xcodeproj/project.pbxproj

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@
157157
97C146EC1CF9000F007C117D /* Resources */,
158158
9705A1C41CF9048500538489 /* Embed Frameworks */,
159159
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
160+
545E69528F1478FA4BB537F8 /* [CP] Embed Pods Frameworks */,
160161
);
161162
buildRules = (
162163
);
@@ -240,6 +241,40 @@
240241
shellPath = /bin/sh;
241242
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
242243
};
244+
545E69528F1478FA4BB537F8 /* [CP] Embed Pods Frameworks */ = {
245+
isa = PBXShellScriptBuildPhase;
246+
buildActionMask = 2147483647;
247+
files = (
248+
);
249+
inputPaths = (
250+
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh",
251+
"${BUILT_PRODUCTS_DIR}/FirebaseAppCheckInterop/FirebaseAppCheckInterop.framework",
252+
"${BUILT_PRODUCTS_DIR}/FirebaseAuthInterop/FirebaseAuthInterop.framework",
253+
"${BUILT_PRODUCTS_DIR}/FirebaseCore/FirebaseCore.framework",
254+
"${BUILT_PRODUCTS_DIR}/FirebaseCoreExtension/FirebaseCoreExtension.framework",
255+
"${BUILT_PRODUCTS_DIR}/FirebaseCoreInternal/FirebaseCoreInternal.framework",
256+
"${BUILT_PRODUCTS_DIR}/FirebaseStorage/FirebaseStorage.framework",
257+
"${BUILT_PRODUCTS_DIR}/GTMSessionFetcher/GTMSessionFetcher.framework",
258+
"${BUILT_PRODUCTS_DIR}/GoogleUtilities/GoogleUtilities.framework",
259+
"${BUILT_PRODUCTS_DIR}/image_picker_ios/image_picker_ios.framework",
260+
);
261+
name = "[CP] Embed Pods Frameworks";
262+
outputPaths = (
263+
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseAppCheckInterop.framework",
264+
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseAuthInterop.framework",
265+
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseCore.framework",
266+
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseCoreExtension.framework",
267+
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseCoreInternal.framework",
268+
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseStorage.framework",
269+
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GTMSessionFetcher.framework",
270+
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleUtilities.framework",
271+
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/image_picker_ios.framework",
272+
);
273+
runOnlyForDeploymentPostprocessing = 0;
274+
shellPath = /bin/sh;
275+
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
276+
showEnvVarsInLog = 0;
277+
};
243278
9740EEB61CF901F6004384FC /* Run Script */ = {
244279
isa = PBXShellScriptBuildPhase;
245280
alwaysOutOfDate = 1;

packages/firebase_storage/firebase_storage/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
buildConfiguration = "Debug"
4545
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
4646
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
47+
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
4748
shouldUseLaunchSchemeArgsEnv = "YES">
4849
<Testables>
4950
</Testables>
@@ -63,11 +64,13 @@
6364
buildConfiguration = "Debug"
6465
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
6566
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
67+
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
6668
launchStyle = "0"
6769
useCustomWorkingDirectory = "NO"
6870
ignoresPersistentStateOnLaunch = "NO"
6971
debugDocumentVersioning = "YES"
7072
debugServiceExtension = "internal"
73+
enableGPUValidationMode = "1"
7174
allowLocationSimulation = "YES">
7275
<BuildableProductRunnable
7376
runnableDebuggingMode = "0">

tests/integration_test/firebase_storage/reference_e2e.dart

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,10 @@ void setupReferenceTests() {
344344
test(
345345
'uploads a file',
346346
() async {
347-
final File file = await createFile('flt-ok.txt');
347+
final File file = await createFile(
348+
'flt-ok.txt',
349+
string: kTestString,
350+
);
348351

349352
final Reference ref =
350353
storage.ref('flutter-tests').child('flt-ok.txt');
@@ -381,7 +384,7 @@ void setupReferenceTests() {
381384
'put file some text to compare with uploaded and downloaded';
382385
final File file = await createFile(
383386
'read-and-write.txt',
384-
largeString: text,
387+
string: text,
385388
);
386389

387390
final Reference ref =

tests/integration_test/firebase_storage/task_e2e.dart

Lines changed: 59 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -235,53 +235,85 @@ void setupTaskTests() {
235235
() {
236236
late Task task;
237237

238-
Future<void> _testCancelTask() async {
238+
Future<void> _testCancelTaskSnapshotEvents(Task task) async {
239239
List<TaskSnapshot> snapshots = [];
240240
expect(task.snapshot.state, TaskState.running);
241241
final Completer<FirebaseException> errorReceived =
242242
Completer<FirebaseException>();
243+
final Completer<bool> started = Completer<bool>();
243244

244245
task.snapshotEvents.listen(
245246
(TaskSnapshot snapshot) {
247+
if (!started.isCompleted) {
248+
started.complete(true);
249+
}
246250
snapshots.add(snapshot);
247251
},
248252
onError: (error) {
249253
errorReceived.complete(error);
250254
},
251255
);
252256

257+
await started.future;
258+
253259
bool canceled = await task.cancel();
254260
expect(canceled, isTrue);
255261
expect(task.snapshot.state, TaskState.canceled);
256262

263+
final streamError = await errorReceived.future;
264+
265+
expect(streamError, isNotNull);
266+
expect(streamError.code, 'canceled');
267+
// Expecting there to only be running states, canceled should not get sent as an event.
268+
expect(
269+
snapshots.every((snapshot) => snapshot.state == TaskState.running),
270+
isTrue,
271+
);
272+
257273
await expectLater(
258274
task,
259275
throwsA(
260276
isA<FirebaseException>()
261277
.having((e) => e.code, 'code', 'canceled'),
262278
),
263279
);
280+
}
264281

282+
Future<void> _testCancelTaskLastEvent(Task task) async {
283+
expect(task.snapshot.state, TaskState.running);
284+
285+
bool canceled = await task.cancel();
286+
expect(canceled, isTrue);
265287
expect(task.snapshot.state, TaskState.canceled);
288+
}
266289

267-
// Need to wait for error to be received before checking
268-
final streamError = await errorReceived.future;
290+
test(
291+
'successfully cancels download task using snapshotEvents',
292+
() async {
293+
file = await createFile('ok.txt');
294+
// Need to put a large file in emulator first to test cancel.
295+
final initialPut = downloadRef.putFile(file);
269296

270-
expect(streamError, isNotNull);
271-
expect(streamError.code, 'canceled');
272-
// Expecting there to only be running states, canceled should not get sent as an event.
273-
expect(
274-
snapshots.every((snapshot) => snapshot.state == TaskState.running),
275-
isTrue,
276-
);
277-
}
297+
await initialPut;
298+
task = downloadRef.writeToFile(file);
299+
300+
await _testCancelTaskSnapshotEvents(task);
301+
},
302+
// There's no DownloadTask on web.
303+
// Windows `task.cancel()` is returning "false", same code on example app works as intended
304+
skip: kIsWeb || defaultTargetPlatform == TargetPlatform.windows,
305+
retry: 2,
306+
);
278307

279308
test(
280-
'successfully cancels download task',
309+
'successfully cancels download task and provides the last `canceled` event',
281310
() async {
282-
file = await createFile('ok.jpeg', largeString: 'A' * 20000000);
311+
file = await createFile('ok.txt');
312+
final initialPut = downloadRef.putFile(file);
313+
314+
await initialPut;
283315
task = downloadRef.writeToFile(file);
284-
await _testCancelTask();
316+
await _testCancelTaskLastEvent(task);
285317
},
286318
// There's no DownloadTask on web.
287319
// Windows `task.cancel()` is returning "false", same code on example app works as intended
@@ -290,10 +322,21 @@ void setupTaskTests() {
290322
);
291323

292324
test(
293-
'successfully cancels upload task',
325+
'successfully cancels upload task using snapshotEvents',
326+
() async {
327+
task = uploadRef.putString('A' * 20000000);
328+
await _testCancelTaskSnapshotEvents(task);
329+
},
330+
retry: 2,
331+
// Windows `task.cancel()` is returning "false", same code on example app works as intended
332+
skip: defaultTargetPlatform == TargetPlatform.windows,
333+
);
334+
335+
test(
336+
'successfully cancels upload task and provides the last `canceled` event',
294337
() async {
295338
task = uploadRef.putString('A' * 20000000);
296-
await _testCancelTask();
339+
await _testCancelTaskLastEvent(task);
297340
},
298341
retry: 2,
299342
// Windows `task.cancel()` is returning "false", same code on example app works as intended

tests/integration_test/firebase_storage/test_utils.dart

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,47 @@ const int testEmulatorPort = 9199;
3333

3434
// Creates a test file with a specified name to
3535
// a locally directory
36-
Future<File> createFile(String name, {String? largeString}) async {
36+
Future<File> createFile(
37+
String name, {
38+
String? string,
39+
int sizeInBytes = 209715200,
40+
}) async {
3741
final Directory systemTempDir = Directory.systemTemp;
3842
final File file = await File('${systemTempDir.path}/$name').create();
39-
await file.writeAsString(largeString ?? kTestString);
43+
44+
if (string != null) {
45+
await file.writeAsString(string);
46+
return file;
47+
}
48+
49+
// Create a 200MB file by writing data in chunks to avoid memory issues
50+
const chunkSize = 1024 * 1024; // 1MB chunks
51+
final chunk = Uint8List(chunkSize);
52+
53+
// Fill chunk with random-ish data to prevent compression
54+
for (int i = 0; i < chunkSize; i++) {
55+
chunk[i] = i % 256; // Creates a pattern from 0-255
56+
}
57+
58+
final sink = file.openWrite();
59+
final totalChunks = (sizeInBytes / chunkSize).ceil();
60+
61+
for (int i = 0; i < totalChunks; i++) {
62+
if (i == totalChunks - 1) {
63+
// Last chunk might be smaller
64+
final remainingBytes = sizeInBytes % chunkSize;
65+
if (remainingBytes > 0) {
66+
sink.add(chunk.sublist(0, remainingBytes));
67+
} else {
68+
sink.add(chunk);
69+
}
70+
} else {
71+
sink.add(chunk);
72+
}
73+
}
74+
75+
await sink.close();
76+
4077
return file;
4178
}
4279

tests/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
buildConfiguration = "Debug"
2727
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
2828
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
29+
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
2930
shouldUseLaunchSchemeArgsEnv = "YES">
3031
<MacroExpansion>
3132
<BuildableReference
@@ -43,11 +44,13 @@
4344
buildConfiguration = "Debug"
4445
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
4546
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
47+
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
4648
launchStyle = "0"
4749
useCustomWorkingDirectory = "NO"
4850
ignoresPersistentStateOnLaunch = "NO"
4951
debugDocumentVersioning = "YES"
5052
debugServiceExtension = "internal"
53+
enableGPUValidationMode = "1"
5154
allowLocationSimulation = "YES">
5255
<BuildableProductRunnable
5356
runnableDebuggingMode = "0">

0 commit comments

Comments
 (0)