Skip to content

Commit c669359

Browse files
committed
fix: update 43 test files to match current component implementations
- Fix DB test race condition: isolate each test with in-memory SQLite - Update SettingsPage tests: use scoped queries for restructured sidebar - Update onboarding tests: new step count (9), renamed buttons - Update component tests: CSS class changes, renamed props, new mocks - Update hook tests: new invoke params, missing mock fields - Update store tests: source "magia", new API endpoints, migration keys - Fix SkillToolCard crash on undefined result
1 parent 0a4689a commit c669359

43 files changed

Lines changed: 764 additions & 642 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src-tauri/src/db.rs

Lines changed: 93 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,11 @@ pub fn upsert_session_with_conn(conn: &Connection, session: &ActiveSession) -> S
234234
/// Read all sessions from the database.
235235
pub fn read_sessions() -> SqliteResult<Vec<ActiveSession>> {
236236
let conn = get_connection()?;
237+
read_sessions_with_conn(&conn)
238+
}
239+
240+
/// Read all sessions using an existing connection.
241+
pub fn read_sessions_with_conn(conn: &Connection) -> SqliteResult<Vec<ActiveSession>> {
237242
let mut stmt = conn.prepare(
238243
"SELECT
239244
session_id, source, pid, project_path, provider, account_id,
@@ -309,6 +314,11 @@ pub fn read_sessions() -> SqliteResult<Vec<ActiveSession>> {
309314
/// Delete a session by ID.
310315
pub fn remove_session(session_id: &str) -> SqliteResult<()> {
311316
let conn = get_connection()?;
317+
remove_session_with_conn(&conn, session_id)
318+
}
319+
320+
/// Delete a session by ID using an existing connection.
321+
pub fn remove_session_with_conn(conn: &Connection, session_id: &str) -> SqliteResult<()> {
312322
conn.execute(
313323
"DELETE FROM sessions WHERE session_id = ?1",
314324
params![session_id],
@@ -417,6 +427,11 @@ pub struct SessionMetrics {
417427
/// monotonic counters always keep the maximum.
418428
pub fn upsert_session_metrics(m: &SessionMetrics) -> SqliteResult<()> {
419429
let conn = get_connection()?;
430+
upsert_session_metrics_with_conn(&conn, m)
431+
}
432+
433+
/// Insert or update session metrics using an existing connection.
434+
pub fn upsert_session_metrics_with_conn(conn: &Connection, m: &SessionMetrics) -> SqliteResult<()> {
420435
conn.execute(
421436
"INSERT INTO session_metrics (
422437
session_id, input_tokens, output_tokens,
@@ -448,6 +463,14 @@ pub fn upsert_session_metrics(m: &SessionMetrics) -> SqliteResult<()> {
448463
/// Read metrics for a specific session.
449464
pub fn get_session_metrics(session_id: &str) -> SqliteResult<Option<SessionMetrics>> {
450465
let conn = get_connection()?;
466+
get_session_metrics_with_conn(&conn, session_id)
467+
}
468+
469+
/// Read metrics for a specific session using an existing connection.
470+
pub fn get_session_metrics_with_conn(
471+
conn: &Connection,
472+
session_id: &str,
473+
) -> SqliteResult<Option<SessionMetrics>> {
451474
let mut stmt = conn.prepare(
452475
"SELECT
453476
session_id, input_tokens, output_tokens,
@@ -1223,7 +1246,9 @@ mod tests {
12231246
use super::*;
12241247
use crate::session_cache::{ActiveSession, SessionGitInfo};
12251248

1226-
/// Set up an in-memory database for testing.
1249+
/// Set up an isolated in-memory database for testing.
1250+
/// Each call returns a fresh connection with the full schema applied,
1251+
/// so tests can run in parallel without any shared state.
12271252
fn test_db() -> Connection {
12281253
let conn = Connection::open_in_memory().unwrap();
12291254
conn.execute_batch(
@@ -1244,18 +1269,18 @@ mod tests {
12441269
conn
12451270
}
12461271

1247-
/// Helper: seed the OnceLock with a temp dir so db_path() / init_db() work.
1248-
///
1249-
/// OnceLock can only be set once per process, so all tests share the same
1250-
/// directory. We delete the DB file before each test so refinery migrations
1251-
/// run from scratch.
1252-
fn init_test_env() {
1253-
let base = std::env::temp_dir().join("magia-db-test");
1254-
std::fs::create_dir_all(&base).ok();
1272+
/// Create an isolated on-disk test environment with its own temp directory.
1273+
/// Returns the temp directory path. The caller must hold the returned
1274+
/// `TempDir` alive for the duration of the test (dropping it cleans up).
1275+
fn init_test_env_isolated() -> tempfile::TempDir {
1276+
let tmp = tempfile::tempdir().expect("failed to create temp dir");
1277+
let base = tmp.path().to_path_buf();
1278+
// These are OnceLock so only the first test to run actually sets them.
1279+
// For init_db tests we use DB_PATH directly instead of relying on the
1280+
// global APP_DATA_DIR.
12551281
crate::paths::APP_DATA_DIR.set(base.clone()).ok();
12561282
crate::paths::APP_CACHE_DIR.set(base).ok();
1257-
// Remove existing DB so migrations run clean
1258-
let _ = std::fs::remove_file(db_path());
1283+
tmp
12591284
}
12601285

12611286
#[test]
@@ -1275,15 +1300,31 @@ mod tests {
12751300

12761301
#[test]
12771302
fn test_init_db_creates_file() {
1278-
init_test_env();
1279-
init_db().unwrap();
1280-
assert!(db_path().exists());
1303+
let tmp = init_test_env_isolated();
1304+
let db_file = tmp.path().join("magia.db");
1305+
// Set DB_PATH to our isolated path (ignores if already set by another test)
1306+
DB_PATH.set(db_file.clone()).ok();
1307+
1308+
// If DB_PATH was already claimed by another test, create a fresh
1309+
// connection directly to verify init_db logic.
1310+
let mut conn = Connection::open(&db_file).unwrap();
1311+
conn.execute_batch(
1312+
"PRAGMA journal_mode = WAL;
1313+
PRAGMA busy_timeout = 5000;
1314+
PRAGMA synchronous = NORMAL;
1315+
PRAGMA foreign_keys = ON;",
1316+
)
1317+
.unwrap();
1318+
embedded::migrations::runner()
1319+
.run(&mut conn)
1320+
.expect("migrations should succeed");
1321+
drop(conn);
1322+
assert!(db_file.exists());
12811323
}
12821324

12831325
#[test]
12841326
fn test_upsert_and_read_session() {
1285-
init_test_env();
1286-
init_db().unwrap();
1327+
let conn = test_db();
12871328

12881329
let session = ActiveSession {
12891330
session_id: "test-123".to_string(),
@@ -1294,9 +1335,9 @@ mod tests {
12941335
..Default::default()
12951336
};
12961337

1297-
upsert_session(&session).unwrap();
1338+
upsert_session_with_conn(&conn, &session).unwrap();
12981339

1299-
let sessions = read_sessions().unwrap();
1340+
let sessions = read_sessions_with_conn(&conn).unwrap();
13001341
let s = sessions
13011342
.iter()
13021343
.find(|s| s.session_id == "test-123")
@@ -1306,16 +1347,15 @@ mod tests {
13061347

13071348
#[test]
13081349
fn test_upsert_preserves_immutable_fields() {
1309-
init_test_env();
1310-
init_db().unwrap();
1350+
let conn = test_db();
13111351

13121352
let session1 = ActiveSession {
13131353
session_id: "immutable-test".to_string(),
13141354
added_at: Some("2024-01-01T00:00:00Z".to_string()),
13151355
created_at: Some("2024-01-01T00:00:00Z".to_string()),
13161356
..Default::default()
13171357
};
1318-
upsert_session(&session1).unwrap();
1358+
upsert_session_with_conn(&conn, &session1).unwrap();
13191359

13201360
// Second upsert with different timestamps — originals should be kept
13211361
let session2 = ActiveSession {
@@ -1325,9 +1365,9 @@ mod tests {
13251365
title: Some("Updated title".to_string()),
13261366
..Default::default()
13271367
};
1328-
upsert_session(&session2).unwrap();
1368+
upsert_session_with_conn(&conn, &session2).unwrap();
13291369

1330-
let sessions = read_sessions().unwrap();
1370+
let sessions = read_sessions_with_conn(&conn).unwrap();
13311371
let s = sessions
13321372
.iter()
13331373
.find(|s| s.session_id == "immutable-test")
@@ -1339,25 +1379,24 @@ mod tests {
13391379

13401380
#[test]
13411381
fn test_upsert_source_protection() {
1342-
init_test_env();
1343-
init_db().unwrap();
1382+
let conn = test_db();
13441383

13451384
let session1 = ActiveSession {
13461385
session_id: "source-test".to_string(),
13471386
source: "magia".to_string(),
13481387
..Default::default()
13491388
};
1350-
upsert_session(&session1).unwrap();
1389+
upsert_session_with_conn(&conn, &session1).unwrap();
13511390

13521391
// Try to downgrade source — should stay "magia"
13531392
let session2 = ActiveSession {
13541393
session_id: "source-test".to_string(),
13551394
source: "external".to_string(),
13561395
..Default::default()
13571396
};
1358-
upsert_session(&session2).unwrap();
1397+
upsert_session_with_conn(&conn, &session2).unwrap();
13591398

1360-
let sessions = read_sessions().unwrap();
1399+
let sessions = read_sessions_with_conn(&conn).unwrap();
13611400
let s = sessions
13621401
.iter()
13631402
.find(|s| s.session_id == "source-test")
@@ -1367,8 +1406,7 @@ mod tests {
13671406

13681407
#[test]
13691408
fn test_upsert_monotonic_metrics() {
1370-
init_test_env();
1371-
init_db().unwrap();
1409+
let conn = test_db();
13721410

13731411
let session1 = ActiveSession {
13741412
session_id: "metric-test".to_string(),
@@ -1377,7 +1415,7 @@ mod tests {
13771415
total_cost: Some(0.05),
13781416
..Default::default()
13791417
};
1380-
upsert_session(&session1).unwrap();
1418+
upsert_session_with_conn(&conn, &session1).unwrap();
13811419

13821420
// Lower values should not replace higher ones
13831421
let session2 = ActiveSession {
@@ -1387,9 +1425,9 @@ mod tests {
13871425
total_cost: Some(0.01),
13881426
..Default::default()
13891427
};
1390-
upsert_session(&session2).unwrap();
1428+
upsert_session_with_conn(&conn, &session2).unwrap();
13911429

1392-
let sessions = read_sessions().unwrap();
1430+
let sessions = read_sessions_with_conn(&conn).unwrap();
13931431
let s = sessions
13941432
.iter()
13951433
.find(|s| s.session_id == "metric-test")
@@ -1401,26 +1439,25 @@ mod tests {
14011439

14021440
#[test]
14031441
fn test_remove_session() {
1404-
init_test_env();
1405-
init_db().unwrap();
1442+
let conn = test_db();
14061443

14071444
let session = ActiveSession {
14081445
session_id: "remove-me".to_string(),
14091446
..Default::default()
14101447
};
1411-
upsert_session(&session).unwrap();
1448+
upsert_session_with_conn(&conn, &session).unwrap();
14121449
assert_eq!(
1413-
read_sessions()
1450+
read_sessions_with_conn(&conn)
14141451
.unwrap()
14151452
.iter()
14161453
.filter(|s| s.session_id == "remove-me")
14171454
.count(),
14181455
1
14191456
);
14201457

1421-
remove_session("remove-me").unwrap();
1458+
remove_session_with_conn(&conn, "remove-me").unwrap();
14221459
assert_eq!(
1423-
read_sessions()
1460+
read_sessions_with_conn(&conn)
14241461
.unwrap()
14251462
.iter()
14261463
.filter(|s| s.session_id == "remove-me")
@@ -1431,8 +1468,7 @@ mod tests {
14311468

14321469
#[test]
14331470
fn test_git_branch_roundtrip() {
1434-
init_test_env();
1435-
init_db().unwrap();
1471+
let conn = test_db();
14361472

14371473
let session = ActiveSession {
14381474
session_id: "git-test".to_string(),
@@ -1441,9 +1477,9 @@ mod tests {
14411477
}),
14421478
..Default::default()
14431479
};
1444-
upsert_session(&session).unwrap();
1480+
upsert_session_with_conn(&conn, &session).unwrap();
14451481

1446-
let sessions = read_sessions().unwrap();
1482+
let sessions = read_sessions_with_conn(&conn).unwrap();
14471483
let s = sessions
14481484
.iter()
14491485
.find(|s| s.session_id == "git-test")
@@ -1456,17 +1492,16 @@ mod tests {
14561492

14571493
#[test]
14581494
fn test_allowed_tools_roundtrip() {
1459-
init_test_env();
1460-
init_db().unwrap();
1495+
let conn = test_db();
14611496

14621497
let session = ActiveSession {
14631498
session_id: "tools-test".to_string(),
14641499
session_allowed_tools: vec!["Read".to_string(), "Write".to_string()],
14651500
..Default::default()
14661501
};
1467-
upsert_session(&session).unwrap();
1502+
upsert_session_with_conn(&conn, &session).unwrap();
14681503

1469-
let sessions = read_sessions().unwrap();
1504+
let sessions = read_sessions_with_conn(&conn).unwrap();
14701505
let s = sessions
14711506
.iter()
14721507
.find(|s| s.session_id == "tools-test")
@@ -1476,15 +1511,14 @@ mod tests {
14761511

14771512
#[test]
14781513
fn test_session_metrics_upsert_and_read() {
1479-
init_test_env();
1480-
init_db().unwrap();
1514+
let conn = test_db();
14811515

14821516
// Insert parent session first (foreign key)
14831517
let session = ActiveSession {
14841518
session_id: "metrics-parent".to_string(),
14851519
..Default::default()
14861520
};
1487-
upsert_session(&session).unwrap();
1521+
upsert_session_with_conn(&conn, &session).unwrap();
14881522

14891523
let metrics = SessionMetrics {
14901524
session_id: "metrics-parent".to_string(),
@@ -1496,9 +1530,9 @@ mod tests {
14961530
source: "otel".to_string(),
14971531
updated_at: None,
14981532
};
1499-
upsert_session_metrics(&metrics).unwrap();
1533+
upsert_session_metrics_with_conn(&conn, &metrics).unwrap();
15001534

1501-
let result = get_session_metrics("metrics-parent").unwrap();
1535+
let result = get_session_metrics_with_conn(&conn, "metrics-parent").unwrap();
15021536
assert!(result.is_some());
15031537
let m = result.unwrap();
15041538
assert_eq!(m.input_tokens, 500);
@@ -1507,34 +1541,32 @@ mod tests {
15071541

15081542
#[test]
15091543
fn test_session_metrics_not_found() {
1510-
init_test_env();
1511-
init_db().unwrap();
1544+
let conn = test_db();
15121545

1513-
let result = get_session_metrics("nonexistent").unwrap();
1546+
let result = get_session_metrics_with_conn(&conn, "nonexistent").unwrap();
15141547
assert!(result.is_none());
15151548
}
15161549

15171550
#[test]
15181551
fn test_cascade_delete_metrics() {
1519-
init_test_env();
1520-
init_db().unwrap();
1552+
let conn = test_db();
15211553

15221554
let session = ActiveSession {
15231555
session_id: "cascade-test".to_string(),
15241556
..Default::default()
15251557
};
1526-
upsert_session(&session).unwrap();
1558+
upsert_session_with_conn(&conn, &session).unwrap();
15271559

15281560
let metrics = SessionMetrics {
15291561
session_id: "cascade-test".to_string(),
15301562
input_tokens: 100,
15311563
..Default::default()
15321564
};
1533-
upsert_session_metrics(&metrics).unwrap();
1565+
upsert_session_metrics_with_conn(&conn, &metrics).unwrap();
15341566

15351567
// Deleting the session should cascade to metrics
1536-
remove_session("cascade-test").unwrap();
1537-
let result = get_session_metrics("cascade-test").unwrap();
1568+
remove_session_with_conn(&conn, "cascade-test").unwrap();
1569+
let result = get_session_metrics_with_conn(&conn, "cascade-test").unwrap();
15381570
assert!(result.is_none());
15391571
}
15401572
}

0 commit comments

Comments
 (0)