# -*- coding: utf-8 -*- """ Schema 表定义迁移完整性属性测试 **Validates: Requirements 7.3, 7.6** Property 6: 对于任意现有数据库 schema(billiards_ods、billiards_dws)中的表, 新 schema(ods、dws)的 DDL 文件中应包含该表的 CREATE TABLE 定义。 """ import os import re from hypothesis import given, settings from hypothesis.strategies import sampled_from # ── 路径常量 ────────────────────────────────────────────── SCHEMAS_DIR = os.path.join(r"C:\NeoZQYY", "db", "etl_feiqiu", "schemas") # 旧 schema 文件(billiards_ods / billiards_dws) OLD_ODS_FILE = os.path.join(SCHEMAS_DIR, "schema_ODS_doc.sql") OLD_DWS_FILE = os.path.join(SCHEMAS_DIR, "schema_dws.sql") # 新 schema 文件(ods / dws) NEW_ODS_FILE = os.path.join(SCHEMAS_DIR, "ods.sql") NEW_DWS_FILE = os.path.join(SCHEMAS_DIR, "dws.sql") # ── 解析工具 ────────────────────────────────────────────── # 匹配 CREATE TABLE [IF NOT EXISTS] [schema.]table_name _CREATE_TABLE_RE = re.compile( r"CREATE\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?" r"(?:[\w]+\.)?(\w+)", re.IGNORECASE, ) def _extract_table_names(sql_path: str) -> set[str]: """从 SQL 文件中提取所有 CREATE TABLE 的表名(去掉 schema 前缀)。""" with open(sql_path, encoding="utf-8") as f: content = f.read() return {m.group(1).lower() for m in _CREATE_TABLE_RE.finditer(content)} # ── 预加载表名集合(模块级,只解析一次) ──────────────────── OLD_ODS_TABLES = sorted(_extract_table_names(OLD_ODS_FILE)) OLD_DWS_TABLES = sorted(_extract_table_names(OLD_DWS_FILE)) NEW_ODS_TABLES = _extract_table_names(NEW_ODS_FILE) NEW_DWS_TABLES = _extract_table_names(NEW_DWS_FILE) # 合并旧表名列表,附带来源标记,方便 hypothesis 采样 _OLD_ODS_TAGGED = [(t, "ods") for t in OLD_ODS_TABLES] _OLD_DWS_TAGGED = [(t, "dws") for t in OLD_DWS_TABLES] _ALL_OLD_TABLES = _OLD_ODS_TAGGED + _OLD_DWS_TAGGED # ── 属性测试 ────────────────────────────────────────────── @settings(max_examples=100) @given(table_info=sampled_from(_ALL_OLD_TABLES)) def test_old_table_exists_in_new_schema(table_info: tuple[str, str]) -> None: """ Property 6: Schema 表定义迁移完整性 **Validates: Requirements 7.3, 7.6** 对于旧 schema 中的任意表,新 schema DDL 中应包含同名 CREATE TABLE 定义。 """ table_name, source = table_info if source == "ods": assert table_name in NEW_ODS_TABLES, ( f"旧 billiards_ods 表 '{table_name}' 在新 ods.sql 中未找到 CREATE TABLE 定义。" f"\n新 ods.sql 包含的表: {sorted(NEW_ODS_TABLES)}" ) else: assert table_name in NEW_DWS_TABLES, ( f"旧 billiards_dws 表 '{table_name}' 在新 dws.sql 中未找到 CREATE TABLE 定义。" f"\n新 dws.sql 包含的表: {sorted(NEW_DWS_TABLES)}" )