75 lines
3.1 KiB
Python
75 lines
3.1 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""merge_increment.py 计数契约: inserted 只计本连接写入(total_changes)。
|
|
|
|
2026-08-25 实锤: 03:00 合并窗口 bs_5m 并发写主库, after-before 把 5m 插的行
|
|
记成自己的 inserted → skipped(dup) 被挤成负数(-4881)。total_changes 只计本
|
|
连接 INSERT 生效行, 对并发写者天然免疫; skipped=inc-inserted 恢复真实含义。
|
|
"""
|
|
import importlib.util
|
|
import sqlite3
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
SCRIPT = Path(__file__).resolve().parents[2] / "scripts" / "nas_sync" / "merge_increment.py"
|
|
|
|
SCHEMA = (
|
|
"CREATE TABLE dbbardata(id INTEGER PRIMARY KEY AUTOINCREMENT, "
|
|
"symbol TEXT, exchange TEXT, datetime TEXT, interval TEXT, "
|
|
"volume REAL, turnover REAL, open_interest REAL, "
|
|
"open_price REAL, high_price REAL, low_price REAL, close_price REAL)")
|
|
|
|
|
|
def _run(monkeypatch, capsys, main_db, inc_db):
|
|
monkeypatch.setattr(sys, "argv", [
|
|
"merge_increment.py", "--db", str(main_db), "--inc", str(inc_db)])
|
|
spec = importlib.util.spec_from_file_location("merge_increment_mod", SCRIPT)
|
|
mod = importlib.util.module_from_spec(spec)
|
|
spec.loader.exec_module(mod)
|
|
mod.main()
|
|
return capsys.readouterr().out
|
|
|
|
|
|
def _mk_inc(path, rows):
|
|
c = sqlite3.connect(path)
|
|
c.execute(SCHEMA)
|
|
c.executemany(
|
|
"INSERT INTO dbbardata(symbol,exchange,datetime,interval,close_price) "
|
|
"VALUES(?,?,?,?,?)", rows)
|
|
c.commit()
|
|
c.close()
|
|
|
|
|
|
def test_merge_accounting_new_then_dup(tmp_path, monkeypatch, capsys):
|
|
main_db = tmp_path / "main.db"
|
|
inc1 = tmp_path / "inc1.db"
|
|
_mk_inc(inc1, [("600000", "SSE", "2026-08-21", "d", 10.0),
|
|
("600000", "SSE", "2026-08-22", "d", 11.0)])
|
|
out = _run(monkeypatch, capsys, main_db, inc1)
|
|
assert "inc=2 inserted=2 skipped(dup)=0" in out
|
|
# 同增量重跑: 全 dup, inserted=0(OR IGNORE 计数路径)
|
|
out = _run(monkeypatch, capsys, main_db, inc1)
|
|
assert "inc=2 inserted=0 skipped(dup)=2" in out
|
|
|
|
|
|
def test_merge_accounting_mixed_and_other_writer_rows(tmp_path, monkeypatch, capsys):
|
|
"""部分 dup 精确计数; 主库他源行(=bs_5m 并发写)不进 inserted/skipped。"""
|
|
main_db = tmp_path / "main.db"
|
|
inc1 = tmp_path / "inc1.db"
|
|
_mk_inc(inc1, [("600000", "SSE", "2026-08-21", "d", 10.0)])
|
|
_run(monkeypatch, capsys, main_db, inc1) # 建 schema + 首灌
|
|
# 模拟并发写者(另一连接)直接向主库插 3 行 —— 任何时刻都不该被算进 merge 计数
|
|
c = sqlite3.connect(main_db)
|
|
c.executemany(
|
|
"INSERT INTO dbbardata(symbol,exchange,datetime,interval,close_price) "
|
|
"VALUES(?,?,?,?,?)",
|
|
[("000001", "SZSE", "2026-08-22", "5m", 1.0),
|
|
("000001", "SZSE", "2026-08-22 09:35:00", "5m", 1.0),
|
|
("000002", "SZSE", "2026-08-22", "5m", 1.0)])
|
|
c.commit()
|
|
c.close()
|
|
inc2 = tmp_path / "inc2.db"
|
|
_mk_inc(inc2, [("600000", "SSE", "2026-08-21", "d", 10.0), # dup
|
|
("600000", "SSE", "2026-08-22", "d", 11.0)]) # 新
|
|
out = _run(monkeypatch, capsys, main_db, inc2)
|
|
assert "inc=2 inserted=1 skipped(dup)=1" in out
|