use std::path::PathBuf;
fn unique_dir() -> PathBuf {
static SEQ: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
let seq = SEQ.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
let nanos = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_nanos();
let pid = std::process::id();
let dir = std::env::temp_dir().join(format!("kopuz-migrate-{pid}-{nanos}-{seq}"));
std::fs::create_dir_all(&dir).unwrap();
dir
}
const LEGACY_CONFIG: &str = r#"{
"servers": [
{"id":"s1","name":"Yt","url":"https://music.youtube.com","service":"YtMusic"},
{"id":"s2","name":"Jelly","url":"https://jelly.lan","service":"Jellyfin"}
],
"server": {"id":"s1","name":"Yt","url":"https://music.youtube.com","service":"YtMusic","access_token":"tok"},
"active_source": "Server",
"active_server_id": "s1",
"recently_played": ["/m/a.flac", "/m/b.flac"],
"recently_played_server": ["VID1", "VID2", "VID3"]
}"#;
async fn import(config_json: &str) -> (db::Db, PathBuf) {
let dir = unique_dir();
std::fs::write(dir.join("config.json"), config_json).unwrap();
let db = db::init(&dir.join("kopuz.db")).await.unwrap();
db.import_legacy_json(&dir).await.unwrap();
(db, dir)
}
#[tokio::test]
async fn migration_imports_recently_played_per_source() {
let (db, dir) = import(LEGACY_CONFIG).await;
assert_eq!(
db.recently_played(&db::Source::Local, 50).await.unwrap(),
vec!["/m/a.flac", "/m/b.flac"]
);
assert_eq!(
db.recently_played(&db::Source::Server("s1".into()), 50)
.await
.unwrap(),
vec!["VID1", "VID2", "VID3"]
);
assert!(
db.recently_played(&db::Source::Server("s2".into()), 50)
.await
.unwrap()
.is_empty()
);
let _ = std::fs::remove_dir_all(dir);
}
#[tokio::test]
async fn migration_is_idempotent() {
let (db, dir) = import(LEGACY_CONFIG).await;
db.import_legacy_json(&dir).await.unwrap();
assert_eq!(
db.recently_played(&db::Source::Server("s1".into()), 50)
.await
.unwrap(),
vec!["VID1", "VID2", "VID3"]
);
let _ = std::fs::remove_dir_all(dir);
}
#[tokio::test]
async fn migration_imports_servers_and_active_source() {
let (db, dir) = import(LEGACY_CONFIG).await;
let cfg = db.load_config().await.unwrap().expect("config present");
assert_eq!(cfg.servers.len(), 2);
assert_eq!(cfg.active_source.server_id(), Some("s1"));
assert_eq!(
cfg.server.as_ref().and_then(|s| s.access_token.as_deref()),
Some("tok")
);
let _ = std::fs::remove_dir_all(dir);
}