Migrate sync queue persistence to store adapters
This commit is contained in:
@@ -4,6 +4,8 @@ import 'package:relationship_saver/features/local/local_models.dart';
|
||||
import 'package:relationship_saver/features/local/local_repository.dart';
|
||||
import 'package:relationship_saver/features/local/storage/local_data_store_in_memory.dart';
|
||||
import 'package:relationship_saver/features/local/storage/local_data_store_provider.dart';
|
||||
import 'package:relationship_saver/features/sync/storage/sync_state_store_in_memory.dart';
|
||||
import 'package:relationship_saver/features/sync/storage/sync_state_store_provider.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
void main() {
|
||||
@@ -179,6 +181,7 @@ ProviderContainer _createContainer() {
|
||||
return ProviderContainer(
|
||||
overrides: [
|
||||
localDataStoreProvider.overrideWithValue(InMemoryLocalDataStore()),
|
||||
syncStateStoreProvider.overrideWithValue(InMemorySyncStateStore()),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -14,6 +14,8 @@ import 'package:relationship_saver/features/people/people_view.dart';
|
||||
import 'package:relationship_saver/features/reminders/reminders_view.dart';
|
||||
import 'package:relationship_saver/features/settings/settings_view.dart';
|
||||
import 'package:relationship_saver/features/signals/signals_view.dart';
|
||||
import 'package:relationship_saver/features/sync/storage/sync_state_store_in_memory.dart';
|
||||
import 'package:relationship_saver/features/sync/storage/sync_state_store_provider.dart';
|
||||
import 'package:relationship_saver/features/sync/sync_view.dart';
|
||||
import 'package:relationship_saver/integrations/backend/backend_gateway_fake.dart';
|
||||
import 'package:relationship_saver/integrations/backend/backend_gateway_provider.dart';
|
||||
@@ -102,6 +104,7 @@ Future<void> pumpResponsive(
|
||||
tokenStoreProvider.overrideWithValue(InMemoryTokenStore()),
|
||||
backendGatewayProvider.overrideWithValue(BackendGatewayFake()),
|
||||
localDataStoreProvider.overrideWithValue(InMemoryLocalDataStore()),
|
||||
syncStateStoreProvider.overrideWithValue(InMemorySyncStateStore()),
|
||||
],
|
||||
child: MaterialApp(theme: AppTheme.light(), home: home),
|
||||
),
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:relationship_saver/features/sync/storage/sync_state_store.dart';
|
||||
import 'package:relationship_saver/features/sync/storage/sync_state_store_hive.dart';
|
||||
import 'package:relationship_saver/features/sync/storage/sync_state_store_provider.dart';
|
||||
import 'package:relationship_saver/features/sync/storage/sync_state_store_shared_prefs.dart';
|
||||
import 'package:relationship_saver/features/sync/sync_queue_repository.dart';
|
||||
import 'package:relationship_saver/integrations/backend/models/backend_models.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
void main() {
|
||||
setUp(() {
|
||||
SharedPreferences.setMockInitialValues(<String, Object>{});
|
||||
});
|
||||
|
||||
test(
|
||||
'migrates legacy shared prefs sync queue payload into hive store',
|
||||
() async {
|
||||
final SyncStateRecord legacyRecord = SyncStateRecord(
|
||||
rawState: jsonEncode(<String, dynamic>{
|
||||
'cursor': 'legacy-cursor',
|
||||
'pendingChanges': <Map<String, dynamic>>[
|
||||
ChangeEnvelope(
|
||||
schemaVersion: 1,
|
||||
entityType: 'person',
|
||||
entityId: 'legacy-person',
|
||||
op: ChangeOperation.upsert,
|
||||
modifiedAt: DateTime(2026, 2, 15, 10).toUtc(),
|
||||
clientMutationId: 'legacy-cm-1',
|
||||
payload: const <String, dynamic>{'name': 'Legacy'},
|
||||
).toJson(),
|
||||
],
|
||||
'lastSyncAt': null,
|
||||
'lastAttemptAt': null,
|
||||
'lastError': null,
|
||||
'lastRejected': <Map<String, dynamic>>[],
|
||||
}),
|
||||
);
|
||||
|
||||
final SharedPrefsSyncStateStore legacyStore = SharedPrefsSyncStateStore();
|
||||
await legacyStore.write(rawState: legacyRecord.rawState);
|
||||
|
||||
final _FakeHiveSyncStore hiveStore = _FakeHiveSyncStore();
|
||||
final ProviderContainer container = ProviderContainer(
|
||||
overrides: [syncStateStoreProvider.overrideWithValue(hiveStore)],
|
||||
);
|
||||
addTearDown(container.dispose);
|
||||
|
||||
final state = await container.read(syncQueueRepositoryProvider.future);
|
||||
|
||||
expect(state.cursor, 'legacy-cursor');
|
||||
expect(state.pendingChanges.length, 1);
|
||||
expect(state.pendingChanges.first.clientMutationId, 'legacy-cm-1');
|
||||
|
||||
final SyncStateRecord? migrated = await hiveStore.read();
|
||||
expect(migrated, isNotNull);
|
||||
|
||||
final SyncStateRecord? legacyAfter = await legacyStore.read();
|
||||
expect(legacyAfter, isNull);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
class _FakeHiveSyncStore extends HiveSyncStateStore {
|
||||
SyncStateRecord? _record;
|
||||
|
||||
@override
|
||||
Future<void> clear() async {
|
||||
_record = null;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<SyncStateRecord?> read() async => _record;
|
||||
|
||||
@override
|
||||
Future<void> write({required String rawState}) async {
|
||||
_record = SyncStateRecord(rawState: rawState);
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,8 @@ import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:relationship_saver/features/local/local_repository.dart';
|
||||
import 'package:relationship_saver/features/local/storage/local_data_store_in_memory.dart';
|
||||
import 'package:relationship_saver/features/local/storage/local_data_store_provider.dart';
|
||||
import 'package:relationship_saver/features/sync/storage/sync_state_store_in_memory.dart';
|
||||
import 'package:relationship_saver/features/sync/storage/sync_state_store_provider.dart';
|
||||
import 'package:relationship_saver/features/sync/sync_coordinator.dart';
|
||||
import 'package:relationship_saver/features/sync/sync_queue_repository.dart';
|
||||
import 'package:relationship_saver/features/sync/sync_state.dart';
|
||||
@@ -21,6 +23,7 @@ void main() {
|
||||
overrides: [
|
||||
backendGatewayProvider.overrideWithValue(_TestGateway()),
|
||||
localDataStoreProvider.overrideWithValue(InMemoryLocalDataStore()),
|
||||
syncStateStoreProvider.overrideWithValue(InMemorySyncStateStore()),
|
||||
],
|
||||
);
|
||||
addTearDown(container.dispose);
|
||||
@@ -83,6 +86,7 @@ void main() {
|
||||
_TestGateway(pullResult: pullResult),
|
||||
),
|
||||
localDataStoreProvider.overrideWithValue(InMemoryLocalDataStore()),
|
||||
syncStateStoreProvider.overrideWithValue(InMemorySyncStateStore()),
|
||||
],
|
||||
);
|
||||
addTearDown(container.dispose);
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:relationship_saver/features/sync/storage/sync_state_store_in_memory.dart';
|
||||
import 'package:relationship_saver/features/sync/storage/sync_state_store_provider.dart';
|
||||
import 'package:relationship_saver/features/sync/sync_queue_repository.dart';
|
||||
import 'package:relationship_saver/integrations/backend/models/backend_models.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
void main() {
|
||||
setUp(() {
|
||||
SharedPreferences.setMockInitialValues(<String, Object>{});
|
||||
});
|
||||
|
||||
test('enqueue persists and can be reloaded', () async {
|
||||
final ProviderContainer container = ProviderContainer();
|
||||
final InMemorySyncStateStore store = InMemorySyncStateStore();
|
||||
final ProviderContainer container = ProviderContainer(
|
||||
overrides: [syncStateStoreProvider.overrideWithValue(store)],
|
||||
);
|
||||
|
||||
await container
|
||||
.read(syncQueueRepositoryProvider.notifier)
|
||||
@@ -20,7 +20,9 @@ void main() {
|
||||
|
||||
container.dispose();
|
||||
|
||||
final ProviderContainer reloaded = ProviderContainer();
|
||||
final ProviderContainer reloaded = ProviderContainer(
|
||||
overrides: [syncStateStoreProvider.overrideWithValue(store)],
|
||||
);
|
||||
addTearDown(reloaded.dispose);
|
||||
final SyncStateData reloadedState = await _readState(reloaded);
|
||||
expect(reloadedState.pending.length, 1);
|
||||
@@ -30,7 +32,11 @@ void main() {
|
||||
test(
|
||||
'applyPushResult removes completed mutation ids and tracks rejections',
|
||||
() async {
|
||||
final ProviderContainer container = ProviderContainer();
|
||||
final ProviderContainer container = ProviderContainer(
|
||||
overrides: [
|
||||
syncStateStoreProvider.overrideWithValue(InMemorySyncStateStore()),
|
||||
],
|
||||
);
|
||||
addTearDown(container.dispose);
|
||||
|
||||
final SyncQueueRepository notifier = container.read(
|
||||
|
||||
Reference in New Issue
Block a user