diff --git a/lib/services/app_state_database.dart b/lib/services/app_state_database.dart index 054f96ac..d16978c1 100644 --- a/lib/services/app_state_database.dart +++ b/lib/services/app_state_database.dart @@ -103,8 +103,11 @@ class AppStateDatabase { } static Future _createPlaybackSessionTable(Database db) { + // Keep this idempotent so an interrupted migration or a database restored + // from an intermediate build can resume v1 -> v2 without losing queue + // state merely because the table was already created. return db.execute(''' - CREATE TABLE $_playbackSessionTable ( + CREATE TABLE IF NOT EXISTS $_playbackSessionTable ( id INTEGER PRIMARY KEY CHECK (id = 1), session_json TEXT NOT NULL, updated_at TEXT NOT NULL diff --git a/test/models_and_utils_test.dart b/test/models_and_utils_test.dart index a8c570a9..72fd3aa7 100644 --- a/test/models_and_utils_test.dart +++ b/test/models_and_utils_test.dart @@ -139,6 +139,26 @@ void main() { }); }); + group('app state database migrations', () { + final source = File( + 'lib/services/app_state_database.dart', + ).readAsStringSync(); + + test('v1 to v2 tolerates an existing playback session table', () { + expect( + source, + contains('CREATE TABLE IF NOT EXISTS \$_playbackSessionTable'), + ); + expect( + RegExp( + r'if \(oldVersion < 2\)\s*\{\s*' + r'await _createPlaybackSessionTable\(db\);', + ).hasMatch(source), + isTrue, + ); + }); + }); + group('native worker contracts', () { final finalizerSource = File( 'android/app/src/main/kotlin/com/zarz/spotiflac/'