Files
immich/mobile/test/services/foreground_upload.service_test.dart
T
99883096d6 fix: still part of live photo hidden on bg upload (#29884)
* fix: still part of live photo hidden on bg upload

* add foreground tests

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2026-07-13 14:50:06 -05:00

129 lines
5.4 KiB
Dart

import 'dart:io';
import 'package:drift/drift.dart' hide isNull, isNotNull;
import 'package:drift/native.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:immich_mobile/domain/models/store.model.dart';
import 'package:immich_mobile/domain/services/store.service.dart';
import 'package:immich_mobile/entities/store.entity.dart';
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
import 'package:immich_mobile/infrastructure/repositories/settings.repository.dart';
import 'package:immich_mobile/infrastructure/repositories/store.repository.dart';
import 'package:immich_mobile/repositories/upload.repository.dart';
import 'package:immich_mobile/services/foreground_upload.service.dart';
import 'package:mocktail/mocktail.dart';
import '../api.mocks.dart';
import '../fixtures/asset.stub.dart';
import '../infrastructure/repository.mock.dart';
import '../mocks/asset_entity.mock.dart';
import '../repository.mocks.dart';
void main() {
late ForegroundUploadService sut;
late MockUploadRepository mockUploadRepository;
late MockStorageRepository mockStorageRepository;
late MockDriftBackupRepository mockBackupRepository;
late MockConnectivityApi mockConnectivityApi;
late MockAssetMediaRepository mockAssetMediaRepository;
late Drift db;
setUpAll(() async {
TestWidgetsFlutterBinding.ensureInitialized();
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler(
const MethodChannel('plugins.flutter.io/path_provider'),
(MethodCall methodCall) async => 'test',
);
db = Drift(DatabaseConnection(NativeDatabase.memory(), closeStreamsSynchronously: true));
await StoreService.init(storeRepository: DriftStoreRepository(db));
await SettingsRepository.ensureInitialized(db);
await Store.put(StoreKey.serverEndpoint, 'http://demo.immich.app');
await Store.put(StoreKey.deviceId, 'device-id');
registerFallbackValue(File('file'));
registerFallbackValue(<String, String>{});
});
setUp(() {
mockUploadRepository = MockUploadRepository();
mockStorageRepository = MockStorageRepository();
mockBackupRepository = MockDriftBackupRepository();
mockConnectivityApi = MockConnectivityApi();
mockAssetMediaRepository = MockAssetMediaRepository();
sut = ForegroundUploadService(
mockUploadRepository,
mockStorageRepository,
mockBackupRepository,
mockConnectivityApi,
mockAssetMediaRepository,
);
});
List<Map<String, String>> captureFields() {
final captured = <Map<String, String>>[];
when(
() => mockUploadRepository.uploadFile(
file: any(named: 'file'),
originalFileName: any(named: 'originalFileName'),
fields: any(named: 'fields'),
cancelToken: any(named: 'cancelToken'),
onProgress: any(named: 'onProgress'),
logContext: any(named: 'logContext'),
),
).thenAnswer((invocation) async {
final fields = invocation.namedArguments[#fields] as Map<String, String>;
captured.add(Map.of(fields));
return UploadResult.success(remoteAssetId: 'remote-${captured.length}');
});
return captured;
}
group('uploadSingleAsset', () {
test('should upload the motion part hidden and keep the still image visible', () async {
final asset = LocalAssetStub.image1;
final mockEntity = MockAssetEntity();
final stillFile = File('/path/to/still.heic');
final videoFile = File('/path/to/motion.mov');
when(() => mockEntity.isLivePhoto).thenReturn(true);
when(() => mockStorageRepository.getAssetEntityForAsset(asset)).thenAnswer((_) async => mockEntity);
when(() => mockStorageRepository.isAssetAvailableLocally(asset.id)).thenAnswer((_) async => true);
when(() => mockStorageRepository.getFileForAsset(asset.id)).thenAnswer((_) async => stillFile);
when(() => mockStorageRepository.getMotionFileForAsset(asset)).thenAnswer((_) async => videoFile);
when(() => mockAssetMediaRepository.getOriginalFilename(asset.id)).thenAnswer((_) async => 'live.heic');
final captured = captureFields();
await sut.uploadSingleAsset(asset, null, callbacks: const UploadCallbacks());
expect(captured, hasLength(2));
expect(captured[0]['visibility'], equals('hidden'));
expect(captured[0].containsKey('livePhotoVideoId'), isFalse);
expect(captured[1].containsKey('visibility'), isFalse);
expect(captured[1]['livePhotoVideoId'], equals('remote-1'));
});
test('should not set visibility for a regular photo', () async {
final asset = LocalAssetStub.image1;
final mockEntity = MockAssetEntity();
final stillFile = File('/path/to/photo.jpg');
when(() => mockEntity.isLivePhoto).thenReturn(false);
when(() => mockStorageRepository.getAssetEntityForAsset(asset)).thenAnswer((_) async => mockEntity);
when(() => mockStorageRepository.isAssetAvailableLocally(asset.id)).thenAnswer((_) async => true);
when(() => mockStorageRepository.getFileForAsset(asset.id)).thenAnswer((_) async => stillFile);
when(() => mockAssetMediaRepository.getOriginalFilename(asset.id)).thenAnswer((_) async => 'photo.jpg');
final captured = captureFields();
await sut.uploadSingleAsset(asset, null, callbacks: const UploadCallbacks());
expect(captured, hasLength(1));
expect(captured[0].containsKey('visibility'), isFalse);
});
});
}