feat: sql writer with dedup insert and apply call
Adds SqlWriter: a pyodbc-backed writer that dedup-inserts into dbo.SyncQueue (IF NOT EXISTS guarded by UX_SyncQueue_Dedup), invokes dbo.usp_SyncApply, and reports applied SourceLogIDs. Connection is opened with autocommit=True per the controller revision: usp_SyncApply manages its own transaction internally (BEGIN/ROLLBACK), and an outer pyodbc transaction would conflict on ROLLBACK (SQL error 266). The dedup IF NOT EXISTS...INSERT is a single atomic statement. Integration test self-cleans via SourceFile='sqlw_test.accdb' marker; conn_str comes from the gitignored config.yaml (no hardcoded creds). Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
55
tests/test_sql_writer.py
Normal file
55
tests/test_sql_writer.py
Normal file
@@ -0,0 +1,55 @@
|
||||
"""Integration test for sync.sql_writer.SqlWriter.
|
||||
|
||||
Validates the dedup INSERT (same SourceLogID is only ever enqueued once), the
|
||||
``applied_log_ids`` query (rows flipped to ``applied`` come back in order), and
|
||||
that ``call_apply`` invokes the proc without raising.
|
||||
|
||||
conn_str is read from the gitignored ``config.yaml`` via ``load_config``; no
|
||||
credentials are hardcoded here. The test self-cleans using a throwaway
|
||||
``SourceFile='sqlw_test.accdb'`` marker so no residue is left on SyncQueue.
|
||||
"""
|
||||
import os
|
||||
import pytest
|
||||
|
||||
from sync.sql_writer import SqlWriter, QueueRow
|
||||
from sync.config import load_config
|
||||
|
||||
|
||||
@pytest.mark.integration
|
||||
def test_insert_dedup_and_applied_ids():
|
||||
if not os.environ.get("RUN_INTEGRATION"):
|
||||
pytest.skip("integration")
|
||||
cfg = load_config("config.yaml")
|
||||
w = SqlWriter(cfg.sql_server.conn_str, "dbo.SyncQueue")
|
||||
try:
|
||||
cur = w._conn.cursor()
|
||||
cur.execute("DELETE dbo.SyncQueue WHERE SourceFile='sqlw_test.accdb'")
|
||||
qr = QueueRow(
|
||||
source_file="sqlw_test.accdb",
|
||||
source_table="T",
|
||||
record_id="7",
|
||||
target_schema="sync_test",
|
||||
target_table="T_YEAR2026",
|
||||
source_log_id=100,
|
||||
operate_type="Insert",
|
||||
row_data='{"ID":7}',
|
||||
)
|
||||
w.insert_queue_row(qr)
|
||||
w.insert_queue_row(qr) # duplicate must be deduped (ignored)
|
||||
cur.execute(
|
||||
"SELECT COUNT(*) FROM dbo.SyncQueue "
|
||||
"WHERE SourceFile='sqlw_test.accdb' AND SourceLogID=100"
|
||||
)
|
||||
assert cur.fetchone()[0] == 1
|
||||
|
||||
# call_apply must run without error (proc logic validated elsewhere).
|
||||
w.call_apply(max_retries=5)
|
||||
|
||||
cur.execute(
|
||||
"UPDATE dbo.SyncQueue SET Status='applied' "
|
||||
"WHERE SourceFile='sqlw_test.accdb'"
|
||||
)
|
||||
assert w.applied_log_ids("sqlw_test.accdb") == [100]
|
||||
finally:
|
||||
cur.execute("DELETE dbo.SyncQueue WHERE SourceFile='sqlw_test.accdb'")
|
||||
w.close()
|
||||
Reference in New Issue
Block a user