Files
metabuilder/dbal/tools/conformance/run_all.py
johndoe6345789 49f40177b5 Generated by Spark: I was thinking more like this, you can replace python with ts if you like: dbal/
README.md
  LICENSE
  AGENTS.md

  api/                          # Language-agnostic contract (source of truth)
    schema/
      entities/                 # Entity definitions (conceptual models)
        user.yaml
        session.yaml
        ...
      operations/               # CRUD + domain operations (semantic, not SQL)
        user.ops.yaml
        ...
      errors.yaml               # Standard error codes (conflict, not_found, etc.)
      capabilities.yaml         # Feature flags per backend (tx, joins, ttl, etc.)
    idl/
      dbal.proto                # Optional: RPC/IPC contract if needed
      dbal.fbs                  # Optional: FlatBuffers schema if you prefer
    versioning/
      compat.md                 # Compatibility rules across TS/C++

  common/                       # Shared test vectors + fixtures + golden results
    fixtures/
      seed/
      datasets/
    golden/
      query_results/
    contracts/
      conformance_cases.yaml

  ts/                           # Development implementation in TypeScript
    package.json
    tsconfig.json
    src/
      index.ts                  # Public entrypoint (creates client)
      core/
        client.ts               # DBAL client facade
        types.ts                # TS types mirroring api/schema
        errors.ts               # Error mapping to api/errors.yaml
        validation/             # Runtime validation (zod/io-ts/etc.)
          input.ts
          output.ts
        capabilities.ts         # Capability negotiation
        telemetry/
          logger.ts
          metrics.ts
          tracing.ts
      adapters/                 # Backend implementations (TS)
        prisma/
          index.ts
          prisma_client.ts      # Wraps Prisma client (server-side only)
          mapping.ts            # DB <-> entity mapping, select shaping
          migrations/           # Optional: Prisma migration helpers
        sqlite/
          index.ts
          sqlite_driver.ts
          schema.ts
          migrations/
        mongodb/
          index.ts
          mongo_driver.ts
          schema.ts
      query/                    # Query builder / AST (no backend leakage)
        ast.ts
        builder.ts
        normalize.ts
        optimize.ts
      runtime/
        config.ts               # DBAL config (env, URLs, pool sizes)
        secrets.ts              # Secret loading boundary (server-only)
      util/
        assert.ts
        retry.ts
        backoff.ts
        time.ts
    tests/
      unit/
      integration/
      conformance/              # Runs common/contract vectors on TS adapters
      harness/
        setup.ts

  cpp/                          # Production implementation in C++
    CMakeLists.txt
    include/
      dbal/
        dbal.hpp                # Public API
        client.hpp              # Facade
        types.hpp               # Entity/DTO types
        errors.hpp
        capabilities.hpp
        telemetry.hpp
        query/
          ast.hpp
          builder.hpp
          normalize.hpp
        adapters/
          adapter.hpp           # Adapter interface
          sqlite/
            sqlite_adapter.hpp
          mongodb/
            mongodb_adapter.hpp
          prisma/
            prisma_adapter.hpp  # Usually NOT direct; see note below
        util/
          expected.hpp
          result.hpp
          uuid.hpp
    src/
      client.cpp
      errors.cpp
      capabilities.cpp
      telemetry.cpp
      query/
        ast.cpp
        builder.cpp
        normalize.cpp
      adapters/
        sqlite/
          sqlite_adapter.cpp
          sqlite_pool.cpp
          sqlite_migrations.cpp
        mongodb/
          mongodb_adapter.cpp
          mongo_pool.cpp
        prisma/
          prisma_adapter.cpp    # See note below (often an RPC bridge)
      util/
        uuid.cpp
        backoff.cpp
    tests/
      unit/
      integration/
      conformance/              # Runs common/contract vectors on C++ adapters
      harness/
        main.cpp

  backends/                     # Backend-specific assets not tied to one lang
    sqlite/
      schema.sql
      migrations/
    mongodb/
      indexes.json
    prisma/
      schema.prisma
      migrations/

  tools/                        # Codegen + build helpers (prefer Python)
    codegen/
      gen_types.py              # api/schema -> ts/core/types.ts and cpp/types.hpp
      gen_errors.py
      gen_capabilities.py
    conformance/
      run_all.py                # runs TS + C++ conformance suites
    dev/
      lint.py
      format.py

  scripts/                      # Cross-platform entrypoints (Python per your pref)
    build.py
    test.py
    conformance.py
    package.py

  dist/                         # Build outputs (gitignored)
  .github/
    workflows/
      ci.yml

  .gitignore
  .editorconfig
2025-12-24 20:13:18 +00:00

168 lines
5.5 KiB
Python

#!/usr/bin/env python3
"""
Conformance test runner
Runs the same test vectors against both TypeScript and C++ implementations
"""
import subprocess
import json
import yaml
from pathlib import Path
from typing import Dict, Any, List
import sys
class ConformanceRunner:
def __init__(self, root_dir: Path):
self.root_dir = root_dir
self.test_dir = root_dir / 'common' / 'contracts'
self.results = {'ts': {}, 'cpp': {}}
def load_test_cases(self) -> List[Dict[str, Any]]:
"""Load all conformance test cases"""
test_cases = []
for yaml_file in self.test_dir.glob('*_tests.yaml'):
with open(yaml_file) as f:
cases = yaml.safe_load(f)
if isinstance(cases, list):
test_cases.extend(cases)
return test_cases
def run_typescript_tests(self) -> bool:
"""Run TypeScript conformance tests"""
print("\n=== Running TypeScript Conformance Tests ===")
ts_dir = self.root_dir / 'ts'
try:
result = subprocess.run(
['npm', 'run', 'test:conformance'],
cwd=ts_dir,
capture_output=True,
text=True,
timeout=300
)
print(result.stdout)
if result.returncode != 0:
print(f"TypeScript tests failed:\n{result.stderr}", file=sys.stderr)
return False
self.results['ts'] = self.parse_test_output(result.stdout)
return True
except subprocess.TimeoutExpired:
print("TypeScript tests timed out", file=sys.stderr)
return False
except Exception as e:
print(f"Error running TypeScript tests: {e}", file=sys.stderr)
return False
def run_cpp_tests(self) -> bool:
"""Run C++ conformance tests"""
print("\n=== Running C++ Conformance Tests ===")
cpp_build_dir = self.root_dir / 'cpp' / 'build'
if not cpp_build_dir.exists():
print("C++ build directory not found. Run: cd cpp && cmake -B build && make",
file=sys.stderr)
return False
try:
result = subprocess.run(
['./conformance_tests'],
cwd=cpp_build_dir,
capture_output=True,
text=True,
timeout=300
)
print(result.stdout)
if result.returncode != 0:
print(f"C++ tests failed:\n{result.stderr}", file=sys.stderr)
return False
self.results['cpp'] = self.parse_test_output(result.stdout)
return True
except subprocess.TimeoutExpired:
print("C++ tests timed out", file=sys.stderr)
return False
except Exception as e:
print(f"Error running C++ tests: {e}", file=sys.stderr)
return False
def parse_test_output(self, output: str) -> Dict[str, Any]:
"""Parse test output to structured results"""
results = {}
for line in output.split('\n'):
if 'PASS' in line or 'FAIL' in line:
parts = line.split()
if len(parts) >= 2:
test_name = parts[0]
status = 'pass' if 'PASS' in line else 'fail'
results[test_name] = status
return results
def compare_results(self) -> bool:
"""Compare TypeScript and C++ test results"""
print("\n=== Comparing Results ===")
ts_results = self.results['ts']
cpp_results = self.results['cpp']
all_tests = set(ts_results.keys()) | set(cpp_results.keys())
mismatches = []
for test_name in sorted(all_tests):
ts_status = ts_results.get(test_name, 'missing')
cpp_status = cpp_results.get(test_name, 'missing')
if ts_status != cpp_status:
mismatches.append({
'test': test_name,
'ts': ts_status,
'cpp': cpp_status
})
if mismatches:
print("\n❌ Implementation Mismatch Detected!")
print(f"Found {len(mismatches)} test(s) with different results:\n")
for mismatch in mismatches:
print(f" {mismatch['test']}:")
print(f" TypeScript: {mismatch['ts']}")
print(f" C++: {mismatch['cpp']}")
return False
else:
print("\n✓ All tests passed consistently across both implementations!")
print(f" Total tests: {len(all_tests)}")
return True
def run_all(self) -> bool:
"""Run all conformance tests"""
print("DBAL Conformance Test Runner")
print("=" * 60)
test_cases = self.load_test_cases()
print(f"Loaded {len(test_cases)} test cases")
ts_success = self.run_typescript_tests()
cpp_success = self.run_cpp_tests()
if not (ts_success and cpp_success):
print("\n❌ Conformance tests failed", file=sys.stderr)
return False
return self.compare_results()
def main():
root_dir = Path(__file__).parent.parent.parent
runner = ConformanceRunner(root_dir)
success = runner.run_all()
sys.exit(0 if success else 1)
if __name__ == '__main__':
main()