mirror of
https://github.com/immich-app/immich.git
synced 2026-06-29 17:54:35 -07:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1ee679f832 |
@@ -280,8 +280,7 @@ class SyncStreamService {
|
|||||||
return;
|
return;
|
||||||
// SyncCompleteV1 is used to signal the completion of the sync process. Cleanup stale assets and signal completion
|
// SyncCompleteV1 is used to signal the completion of the sync process. Cleanup stale assets and signal completion
|
||||||
case SyncEntityType.syncCompleteV1:
|
case SyncEntityType.syncCompleteV1:
|
||||||
return;
|
return _syncStreamRepository.pruneAssets();
|
||||||
// return _syncStreamRepository.pruneAssets();
|
|
||||||
// Request to reset the client state. Clear everything related to remote entities
|
// Request to reset the client state. Clear everything related to remote entities
|
||||||
case SyncEntityType.syncResetV1:
|
case SyncEntityType.syncResetV1:
|
||||||
return _syncStreamRepository.reset();
|
return _syncStreamRepository.reset();
|
||||||
|
|||||||
@@ -0,0 +1,64 @@
|
|||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:immich_mobile/infrastructure/repositories/sync_stream.repository.dart';
|
||||||
|
|
||||||
|
import '../repository_context.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
late MediumRepositoryContext ctx;
|
||||||
|
late SyncStreamRepository sut;
|
||||||
|
|
||||||
|
setUp(() {
|
||||||
|
ctx = MediumRepositoryContext();
|
||||||
|
sut = SyncStreamRepository(ctx.db);
|
||||||
|
});
|
||||||
|
|
||||||
|
tearDown(() async {
|
||||||
|
await ctx.dispose();
|
||||||
|
});
|
||||||
|
|
||||||
|
group('pruneAssets', () {
|
||||||
|
test('deletes foreign orphans and keeps owned, partner, and in-album assets', () async {
|
||||||
|
final me = await ctx.newUser();
|
||||||
|
final partner = await ctx.newUser();
|
||||||
|
final stranger = await ctx.newUser();
|
||||||
|
await ctx.newAuthUser(id: me.id);
|
||||||
|
await ctx.newPartner(sharedById: partner.id, sharedWithId: me.id);
|
||||||
|
|
||||||
|
final own = await ctx.newRemoteAsset(ownerId: me.id);
|
||||||
|
final fromPartner = await ctx.newRemoteAsset(ownerId: partner.id);
|
||||||
|
final shared = await ctx.newRemoteAsset(ownerId: stranger.id);
|
||||||
|
await ctx.newRemoteAsset(ownerId: stranger.id);
|
||||||
|
|
||||||
|
final album = await ctx.newRemoteAlbum(ownerId: me.id);
|
||||||
|
await ctx.newRemoteAlbumAsset(albumId: album.id, assetId: shared.id);
|
||||||
|
|
||||||
|
await sut.pruneAssets();
|
||||||
|
|
||||||
|
final remaining = await ctx.db.select(ctx.db.remoteAssetEntity).get();
|
||||||
|
expect(remaining.map((a) => a.id), unorderedEquals([own.id, fromPartner.id, shared.id]));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('does nothing when there is no authenticated user', () async {
|
||||||
|
final stranger = await ctx.newUser();
|
||||||
|
final orphan = await ctx.newRemoteAsset(ownerId: stranger.id);
|
||||||
|
|
||||||
|
await sut.pruneAssets();
|
||||||
|
|
||||||
|
final remaining = await ctx.db.select(ctx.db.remoteAssetEntity).get();
|
||||||
|
expect(remaining.map((a) => a.id), [orphan.id]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('prunes every stale foreign asset in a large data set', () async {
|
||||||
|
final stranger = await ctx.newUser();
|
||||||
|
await ctx.newAuthUser();
|
||||||
|
for (var i = 0; i < 600; i++) {
|
||||||
|
await ctx.newRemoteAsset(ownerId: stranger.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
await sut.pruneAssets();
|
||||||
|
|
||||||
|
final remaining = await ctx.db.select(ctx.db.remoteAssetEntity).get();
|
||||||
|
expect(remaining, isEmpty);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@ import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
|||||||
import 'package:immich_mobile/domain/models/memory.model.dart';
|
import 'package:immich_mobile/domain/models/memory.model.dart';
|
||||||
import 'package:immich_mobile/domain/models/user.model.dart';
|
import 'package:immich_mobile/domain/models/user.model.dart';
|
||||||
import 'package:immich_mobile/infrastructure/entities/asset_face.entity.drift.dart';
|
import 'package:immich_mobile/infrastructure/entities/asset_face.entity.drift.dart';
|
||||||
|
import 'package:immich_mobile/infrastructure/entities/auth_user.entity.drift.dart';
|
||||||
import 'package:immich_mobile/infrastructure/entities/local_album.entity.drift.dart';
|
import 'package:immich_mobile/infrastructure/entities/local_album.entity.drift.dart';
|
||||||
import 'package:immich_mobile/infrastructure/entities/local_album_asset.entity.drift.dart';
|
import 'package:immich_mobile/infrastructure/entities/local_album_asset.entity.drift.dart';
|
||||||
import 'package:immich_mobile/infrastructure/entities/local_asset.entity.drift.dart';
|
import 'package:immich_mobile/infrastructure/entities/local_asset.entity.drift.dart';
|
||||||
@@ -72,6 +73,20 @@ class MediumRepositoryContext {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<AuthUserEntityData> newAuthUser({String? id, String? email, AvatarColor? avatarColor}) async {
|
||||||
|
id ??= TestUtils.uuid();
|
||||||
|
return await db
|
||||||
|
.into(db.authUserEntity)
|
||||||
|
.insertReturning(
|
||||||
|
AuthUserEntityCompanion(
|
||||||
|
id: .new(id),
|
||||||
|
email: .new(email ?? '$id@test.com'),
|
||||||
|
name: .new('user_$id'),
|
||||||
|
avatarColor: .new(avatarColor ?? TestUtils.randElement(AvatarColor.values)),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> newPartner({required String sharedById, required String sharedWithId, bool? inTimeline}) {
|
Future<void> newPartner({required String sharedById, required String sharedWithId, bool? inTimeline}) {
|
||||||
return db
|
return db
|
||||||
.into(db.partnerEntity)
|
.into(db.partnerEntity)
|
||||||
|
|||||||
Reference in New Issue
Block a user