feat(mobile): upload engine with preparation, batching states and retries
Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -31,6 +31,22 @@ final Map<String, dynamic> initResponseFixture = <String, dynamic>{
|
||||
'credential': credentialFixture,
|
||||
};
|
||||
|
||||
/// UploadSessionRecord 最小形状(sourceDeviceId 测试基底)。
|
||||
const Map<String, dynamic> _recordFixture = <String, dynamic>{
|
||||
'uploadId': 'upl0000002',
|
||||
'albumId': 'cktragt000001',
|
||||
'clientTaskId': 'task-uuid-0002',
|
||||
'state': 'confirmed',
|
||||
'expectedBytes': 8192000,
|
||||
'contentType': 'image/png',
|
||||
'createdAt': '2026-09-19T09:15:30.000Z',
|
||||
'photo': {
|
||||
'photoId': 'pho0000002',
|
||||
'processingState': 'uploaded',
|
||||
'visibility': 'unpublished',
|
||||
},
|
||||
};
|
||||
|
||||
void main() {
|
||||
test('UploadCredential fromJson/toJson 往返(e2e 凭证形状)', () {
|
||||
final model = UploadCredential.fromJson(credentialFixture);
|
||||
@@ -76,6 +92,27 @@ void main() {
|
||||
expect(withCategory.toJson()['categoryId'], 'ckucat0000001');
|
||||
});
|
||||
|
||||
test('UploadInitRequest sourceDeviceId(P3 Task 3 契约增补):'
|
||||
'提供时下发、缺省不下发', () {
|
||||
const withDevice = UploadInitRequest(
|
||||
albumId: 'cktragt000001',
|
||||
clientTaskId: 'task-uuid-0003',
|
||||
filename: 'IMG_20260919_0003.jpg',
|
||||
bytes: 1024,
|
||||
contentType: 'image/jpeg',
|
||||
sourceDeviceId: '0123456789abcdef0123456789abcdef',
|
||||
);
|
||||
expect(withDevice.toJson()['sourceDeviceId'], isNotNull);
|
||||
const withoutDevice = UploadInitRequest(
|
||||
albumId: 'cktragt000001',
|
||||
clientTaskId: 'task-uuid-0004',
|
||||
filename: 'IMG_20260919_0004.jpg',
|
||||
bytes: 1024,
|
||||
contentType: 'image/jpeg',
|
||||
);
|
||||
expect(withoutDevice.toJson().containsKey('sourceDeviceId'), isFalse);
|
||||
});
|
||||
|
||||
test('UploadCompleteResponse fromJson/toJson 往返', () {
|
||||
final fixture = <String, dynamic>{
|
||||
'photoId': 'pho0000001',
|
||||
@@ -108,6 +145,19 @@ void main() {
|
||||
expect(model.toJson(), equals(fixture));
|
||||
});
|
||||
|
||||
test('UploadSessionRecord sourceDeviceId:可空回显(A19 设备来源)', () {
|
||||
final withDevice = UploadSessionRecord.fromJson({
|
||||
..._recordFixture,
|
||||
'sourceDeviceId': '0123456789abcdef0123456789abcdef',
|
||||
});
|
||||
expect(withDevice.sourceDeviceId, '0123456789abcdef0123456789abcdef');
|
||||
expect(withDevice.toJson()['sourceDeviceId'], isNotNull);
|
||||
// init 未携带时为 null(契约 type: [string, 'null'])。
|
||||
final withoutDevice = UploadSessionRecord.fromJson(_recordFixture);
|
||||
expect(withoutDevice.sourceDeviceId, isNull);
|
||||
expect(withoutDevice.toJson().containsKey('sourceDeviceId'), isFalse);
|
||||
});
|
||||
|
||||
test('UploadSessionState 全枚举解析(pending/confirmed/cancelled/expired)',
|
||||
() {
|
||||
for (final value in const ['pending', 'confirmed', 'cancelled', 'expired']) {
|
||||
|
||||
Reference in New Issue
Block a user