From c306fb6e19ffd7354775a8a105b9244edb3546d6 Mon Sep 17 00:00:00 2001 From: OoO Date: Wed, 13 May 2026 11:51:45 +0800 Subject: [PATCH] =?UTF-8?q?=E9=9A=94=E9=9B=A2=20PG=20sync=20=E6=95=B4?= =?UTF-8?q?=E5=90=88=E6=B8=AC=E8=A9=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../claude_inventory_validation_20260513.md | 1 + tests/test_pg_sync.py | 19 ++++++++++++++----- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/docs/memory/claude_inventory_validation_20260513.md b/docs/memory/claude_inventory_validation_20260513.md index c5730e2..4f61f7e 100644 --- a/docs/memory/claude_inventory_validation_20260513.md +++ b/docs/memory/claude_inventory_validation_20260513.md @@ -47,6 +47,7 @@ - `tests/test_requirements_pinning.py` 已鎖住上述被 V2 誤列的 runtime dependencies:套件需留在 `requirements.txt`,且至少一個 runtime import 證據仍存在。 - `paramiko` 已確認沒有 runtime import;ADR-013 現行實作改以 `utils/ssh_helper.py` 組 CLI `ssh`,因此已從 `requirements.txt` 移除並補測試防止依賴殘影回來。 - `pgvector` Python package 與 `matplotlib-inline` 已確認不是 runtime 依賴:pgvector 走 PostgreSQL extension + 本地 SQLAlchemy `Vector` type,Jupyter inline backend 不屬 production path;兩者已從 `requirements.txt` 移除並補測試。 +- `tests/test_pg_sync.py` 已改為 opt-in integration test:預設不再連 localhost PostgreSQL 或建立/刪除測試表,需 `RUN_PG_SYNC_INTEGRATION=1` 且提供 `POSTGRES_PASSWORD` 才執行。 - Telegram `momo:eig:` callback 已在 `routes/openclaw_bot_routes.py` 與 `services/telegram_bot_service.py` 實作並有 webhook 測試覆蓋,不是未實作缺口。 - Telegram `date_*` / `goal_*` 不是死 callback handler:按鈕先送 `await:*` 進入輸入等待狀態,使用者下一則文字才由 pending action 消費;`tests/test_openclaw_bot_menu_keyboards.py` 與 `tests/test_openclaw_bot_routes_webhook.py` 已覆蓋。 - `services/ai_automation_smoke_service.py` 不是死 service:`run_scheduler.py` 每日 09:10 掛 `run_ai_smoke_daily_summary_task()`,該 task 會呼叫 `send_smoke_daily_summary()`;`tests/test_ai_automation_smoke_service.py` 與 `tests/test_ai_automation_metrics.py` 已覆蓋。 diff --git a/tests/test_pg_sync.py b/tests/test_pg_sync.py index 531c6e7..5346252 100644 --- a/tests/test_pg_sync.py +++ b/tests/test_pg_sync.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -"""測試完整 76 欄位同步""" +"""Opt-in integration smoke for the legacy SQLite → PostgreSQL sync script.""" import os import sqlite3 @@ -8,9 +8,18 @@ import pytest psycopg2 = pytest.importorskip("psycopg2") +pytestmark = pytest.mark.skipif( + os.environ.get("RUN_PG_SYNC_INTEGRATION") != "1", + reason="PG sync integration touches a local PostgreSQL database; set RUN_PG_SYNC_INTEGRATION=1 to run.", +) + def test_pg_sync(): + if not os.environ.get("POSTGRES_PASSWORD"): + pytest.skip("POSTGRES_PASSWORD is required for PG sync integration") + sqlite_conn = sqlite3.connect("data/momo_database.db") + test_table = "test_full76" try: cursor = sqlite_conn.cursor() cursor.execute("PRAGMA table_info(realtime_sales_monthly)") @@ -30,14 +39,14 @@ def test_pg_sync(): ) try: pg_cursor = pg_conn.cursor() - pg_cursor.execute("DROP TABLE IF EXISTS test_full76 CASCADE") + pg_cursor.execute(f'DROP TABLE IF EXISTS "{test_table}" CASCADE') cols_def = ", ".join([f'"{c}" TEXT' for c in columns]) - pg_cursor.execute(f"CREATE TABLE test_full76 (id SERIAL PRIMARY KEY, {cols_def})") + pg_cursor.execute(f'CREATE TABLE "{test_table}" (id SERIAL PRIMARY KEY, {cols_def})') pg_conn.commit() cols_sql = ", ".join([f'"{c}"' for c in columns]) placeholders = ", ".join(["%s"] * len(columns)) - sql = f"INSERT INTO test_full76 ({cols_sql}) VALUES ({placeholders})" + sql = f'INSERT INTO "{test_table}" ({cols_sql}) VALUES ({placeholders})' success_count = 0 for row in rows: @@ -49,7 +58,7 @@ def test_pg_sync(): pg_conn.commit() assert success_count >= 0 - pg_cursor.execute("DROP TABLE test_full76 CASCADE") + pg_cursor.execute(f'DROP TABLE IF EXISTS "{test_table}" CASCADE') pg_conn.commit() finally: pg_conn.close()