//! Integration tests for SqliteWeeklyReviewRepository. //! //! Focus: upsert idempotency (the `ON CONFLICT(user_id, week_start_date)` path) //! and vacation-day round-trips, the review-repo atomicity the audit flagged as //! untested. mod common; use chrono::{Datelike, NaiveDate}; use goingson_core::WeeklyReviewRepository; use goingson_db_sqlite::SqliteWeeklyReviewRepository; fn monday() -> NaiveDate { NaiveDate::from_ymd_opt(2026, 6, 15).unwrap() } #[tokio::test] async fn test_upsert_creates_then_updates_in_place() { let pool = common::setup_test_db().await; let user_id = common::create_test_user(&pool).await; let repo = SqliteWeeklyReviewRepository::new(pool); let week = monday(); let first = repo.upsert(user_id, week, "initial notes").await.unwrap(); assert_eq!(first.notes, "initial notes"); assert_eq!(first.week_start_date, week); // Second upsert for the same (user, week) must UPDATE the same row, not insert a duplicate. let second = repo.upsert(user_id, week, "revised notes").await.unwrap(); assert_eq!(second.id, first.id, "upsert must reuse the existing row id"); assert_eq!(second.notes, "revised notes"); let all = repo.list_all(user_id).await.unwrap(); assert_eq!( all.len(), 1, "repeated upsert must not create duplicate weeks" ); assert_eq!(all[0].notes, "revised notes"); } #[tokio::test] async fn test_upsert_is_idempotent_under_repeated_writes() { let pool = common::setup_test_db().await; let user_id = common::create_test_user(&pool).await; let repo = SqliteWeeklyReviewRepository::new(pool); let week = monday(); for i in 0..5 { repo.upsert(user_id, week, &format!("pass {i}")) .await .unwrap(); } let all = repo.list_all(user_id).await.unwrap(); assert_eq!(all.len(), 1); assert_eq!(all[0].notes, "pass 4"); } #[tokio::test] async fn test_set_vacation_days_round_trip_and_overwrite() { let pool = common::setup_test_db().await; let user_id = common::create_test_user(&pool).await; let repo = SqliteWeeklyReviewRepository::new(pool); let week = monday(); repo.upsert(user_id, week, "notes").await.unwrap(); repo.set_vacation_days(user_id, week, &[0, 2, 4]) .await .unwrap(); let review = repo.get_for_week(user_id, week).await.unwrap().unwrap(); assert_eq!(review.vacation_days, vec![0, 2, 4]); // Overwriting vacation days must replace, not append or duplicate the row. repo.set_vacation_days(user_id, week, &[6]).await.unwrap(); let review = repo.get_for_week(user_id, week).await.unwrap().unwrap(); assert_eq!(review.vacation_days, vec![6]); assert_eq!(repo.list_all(user_id).await.unwrap().len(), 1); } #[tokio::test] async fn test_is_current_week_completed_reflects_upsert() { let pool = common::setup_test_db().await; let user_id = common::create_test_user(&pool).await; let repo = SqliteWeeklyReviewRepository::new(pool); assert!(!repo.is_current_week_completed(user_id).await.unwrap()); // Complete the current calendar week's review. let today = chrono::Utc::now().date_naive(); let days_since_monday = today.weekday().num_days_from_monday() as i64; let this_monday = today - chrono::Duration::days(days_since_monday); repo.upsert(user_id, this_monday, "done").await.unwrap(); assert!(repo.is_current_week_completed(user_id).await.unwrap()); }