Skip to content

Commit 371e0a4

Browse files
authored
fix(storage): Only allow 1 batch to run at a time (#5704)
1 parent bc314f6 commit 371e0a4

File tree

2 files changed

+107
-0
lines changed

2 files changed

+107
-0
lines changed

packages/storage/amplify_storage_s3_dart/lib/src/storage_s3_service/service/task/s3_upload_task.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -547,11 +547,15 @@ class S3UploadTask {
547547
}
548548
}
549549

550+
bool _isNextBatchWaiting = false;
550551
Future<void> _startNextUploadPartsBatch({
551552
bool resumingFromPause = false,
552553
}) async {
553554
// await for previous batching to complete (if any)
555+
if (_isNextBatchWaiting) return;
556+
_isNextBatchWaiting = true;
554557
await _uploadPartBatchingCompleted;
558+
_isNextBatchWaiting = false;
555559

556560
if (_state != StorageTransferState.inProgress) {
557561
return;

packages/storage/amplify_storage_s3_dart/test/storage_s3_service/task/s3_upload_task_test.dart

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// SPDX-License-Identifier: Apache-2.0
33

44
import 'dart:async';
5+
import 'dart:math';
56
import 'dart:typed_data';
67

78
import 'package:amplify_core/amplify_core.dart';
@@ -1238,6 +1239,108 @@ void main() {
12381239
expect(finalState, StorageTransferState.failure);
12391240
});
12401241

1242+
test('should handle async gaps when reading from Multipart file',
1243+
() async {
1244+
late StorageTransferState finalState;
1245+
1246+
//completeMultipartUploadSmithyOperation
1247+
final testCompleteMultipartUploadOutput =
1248+
s3.CompleteMultipartUploadOutput();
1249+
final completeMultipartUploadSmithyOperation =
1250+
MockSmithyOperation<s3.CompleteMultipartUploadOutput>();
1251+
when(
1252+
() => completeMultipartUploadSmithyOperation.result,
1253+
).thenAnswer(
1254+
(_) async => testCompleteMultipartUploadOutput,
1255+
);
1256+
1257+
//uploadPartSmithyOperation
1258+
final testUploadPartOutput = s3.UploadPartOutput(eTag: 'eTag-part-1');
1259+
final uploadPartSmithyOperation =
1260+
MockSmithyOperation<s3.UploadPartOutput>();
1261+
when(
1262+
() => uploadPartSmithyOperation.result,
1263+
).thenAnswer(
1264+
(_) async => testUploadPartOutput,
1265+
);
1266+
1267+
//createMultipartUploadSmithyOperation
1268+
final testCreateMultipartUploadOutput = s3.CreateMultipartUploadOutput(
1269+
uploadId: 'uploadId', // response should always contain valid uploadId
1270+
);
1271+
final createMultipartUploadSmithyOperation =
1272+
MockSmithyOperation<s3.CreateMultipartUploadOutput>();
1273+
when(
1274+
() => createMultipartUploadSmithyOperation.result,
1275+
).thenAnswer(
1276+
(_) async => testCreateMultipartUploadOutput,
1277+
);
1278+
1279+
//s3Client
1280+
when(
1281+
() => s3Client.completeMultipartUpload(any()),
1282+
).thenAnswer((_) => completeMultipartUploadSmithyOperation);
1283+
when(
1284+
() => s3Client.uploadPart(
1285+
any(),
1286+
s3ClientConfig: any(named: 's3ClientConfig'),
1287+
),
1288+
).thenAnswer(
1289+
(_) => uploadPartSmithyOperation,
1290+
);
1291+
when(
1292+
() => s3Client.createMultipartUpload(any()),
1293+
).thenAnswer(
1294+
(_) => createMultipartUploadSmithyOperation,
1295+
);
1296+
1297+
//transferDatabase
1298+
when(
1299+
() => transferDatabase.insertTransferRecord(any<TransferRecord>()),
1300+
).thenAnswer(
1301+
(_) async => '1',
1302+
);
1303+
when(
1304+
() => transferDatabase.deleteTransferRecords(any()),
1305+
).thenAnswer(
1306+
(_) async => 1,
1307+
);
1308+
1309+
final bytes = List<int>.filled(
1310+
(32 * pow(2, 20)).toInt(),
1311+
0,
1312+
);
1313+
final mockFile = AWSFile.fromStream(
1314+
Stream.value(bytes),
1315+
size: bytes.length,
1316+
contentType: 'image/jpeg',
1317+
);
1318+
1319+
final uploadTask = S3UploadTask.fromAWSFile(
1320+
mockFile,
1321+
s3Client: s3Client,
1322+
defaultS3ClientConfig: defaultS3ClientConfig,
1323+
pathResolver: pathResolver,
1324+
bucket: testBucket,
1325+
path: const StoragePath.fromString(testKey),
1326+
options: testUploadDataOptions,
1327+
logger: logger,
1328+
transferDatabase: transferDatabase,
1329+
onProgress: (progress) {
1330+
finalState = progress.state;
1331+
},
1332+
);
1333+
1334+
unawaited(uploadTask.start());
1335+
1336+
await uploadTask.result;
1337+
1338+
expect(
1339+
finalState,
1340+
StorageTransferState.success,
1341+
);
1342+
});
1343+
12411344
test(
12421345
'should complete with StorageAccessDeniedException when CreateMultipartUploadRequest'
12431346
' returned UnknownSmithyHttpException with status code 403',

0 commit comments

Comments
 (0)