import json import os import sqlite3 import sys import tempfile sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from src import store from src.sync import run_sync def _mock_moodtracker_db(entries): """Build a SQLite file with moodtracker's exact `entries` schema (see /home/alvis/moodtracker/app.py init_db) and seed rows.""" path = os.path.join(tempfile.mkdtemp(), "mood.db") conn = sqlite3.connect(path) conn.execute(""" CREATE TABLE entries ( id INTEGER PRIMARY KEY AUTOINCREMENT, ts TEXT NOT NULL, mood INTEGER NOT NULL, tags TEXT NOT NULL, note TEXT, affirmation TEXT ) """) for ts, mood, tags, note, aff in entries: conn.execute( "INSERT INTO entries (ts, mood, tags, note, affirmation) VALUES (?,?,?,?,?)", (ts, mood, json.dumps(tags), note, aff), ) conn.commit() conn.close() return path def _archive_conn(): path = os.path.join(tempfile.mkdtemp(), "archive.sqlite") conn = store.connect(path) store.init_db(conn) return conn def test_sync_pulls_all_rows_first_run(): source = _mock_moodtracker_db([ ("2026-07-01T08:00:00+00:00", 4, ["calm"], "n1", "a1"), ("2026-07-02T08:00:00+00:00", 2, ["sad", "tired"], "n2", ""), ]) conn = _archive_conn() totals = run_sync(conn, source_db_path=source) assert totals["errors"] == [] assert totals["entries"] == 2 assert conn.execute("SELECT COUNT(*) c FROM mood_entries").fetchone()["c"] == 2 def test_sync_is_idempotent_across_runs(): source = _mock_moodtracker_db([ ("2026-07-01T08:00:00+00:00", 4, ["calm"], "", ""), ]) conn = _archive_conn() run_sync(conn, source_db_path=source) run_sync(conn, source_db_path=source) # nothing new, cursor unchanged run_sync(conn, source_db_path=source) assert conn.execute("SELECT COUNT(*) c FROM mood_entries").fetchone()["c"] == 1 def test_sync_picks_up_new_rows_incrementally(): path = _mock_moodtracker_db([ ("2026-07-01T08:00:00+00:00", 4, ["calm"], "", ""), ]) conn = _archive_conn() run_sync(conn, source_db_path=path) assert conn.execute("SELECT COUNT(*) c FROM mood_entries").fetchone()["c"] == 1 # a new entry gets logged upstream between syncs src_conn = sqlite3.connect(path) src_conn.execute( "INSERT INTO entries (ts, mood, tags, note, affirmation) VALUES (?,?,?,?,?)", ("2026-07-03T09:00:00+00:00", 5, json.dumps(["happy"]), "", ""), ) src_conn.commit() src_conn.close() run_sync(conn, source_db_path=path) assert conn.execute("SELECT COUNT(*) c FROM mood_entries").fetchone()["c"] == 2 def test_sync_records_error_when_source_missing(): conn = _archive_conn() totals = run_sync(conn, source_db_path="/nonexistent/path/mood.db") assert totals["errors"] row = conn.execute( "SELECT last_status, last_error FROM sync_state WHERE stream_key='moodtracker_entries'" ).fetchone() assert row["last_status"] == "error" assert row["last_error"] def test_sync_never_writes_to_source_db(): """The source connection is opened read-only; a failed write attempt would raise, and run_sync should never attempt one in the first place.""" source = _mock_moodtracker_db([("2026-07-01T08:00:00+00:00", 3, [], "", "")]) before = os.path.getmtime(source) conn = _archive_conn() run_sync(conn, source_db_path=source) after = os.path.getmtime(source) assert before == after