fix: test isolation + auth import compatibility + add optuna to requirements (HRT-136)
Test isolation fixes: - auth_db.get_db(): read TURF_SAAS_DB dynamically (not frozen at import) - api_v1/utils.get_db(): read TURF_SAAS_DB dynamically (not frozen at import) - api_tokens_db.get_db(): read TURF_SAAS_DB dynamically (not frozen at import) - tests/test_history.py: enforce _tmp_db.name + call init_auth_tables() in fixtures - tests/test_user_tokens.py: enforce _tmp_db.name + call migrate_api_tokens_tables() in app fixture Auth compatibility fixes: - api_v1/routes/history.py: use auth.jwt_required_middleware (flask_jwt_extended) with saas_auth fallback for portal_server context - api_v1/routes/ml_feedback.py: same auth import strategy - api_v1/routes/user.py: same auth import strategy Dependencies: - requirements.txt: add optuna>=4.0.0 (used in ML ensemble tests and training) Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
@@ -13,7 +13,9 @@ logger = logging.getLogger("turf_saas.api_tokens_db")
|
|||||||
|
|
||||||
|
|
||||||
def get_db() -> sqlite3.Connection:
|
def get_db() -> sqlite3.Connection:
|
||||||
conn = sqlite3.connect(DB_PATH)
|
"""Return a SQLite connection (reads TURF_SAAS_DB dynamically for test isolation)."""
|
||||||
|
db_path = os.environ.get("TURF_SAAS_DB", DB_PATH)
|
||||||
|
conn = sqlite3.connect(db_path)
|
||||||
conn.row_factory = sqlite3.Row
|
conn.row_factory = sqlite3.Row
|
||||||
return conn
|
return conn
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,11 @@ from api_v1.utils import (
|
|||||||
get_pagination_params,
|
get_pagination_params,
|
||||||
paginate_query,
|
paginate_query,
|
||||||
)
|
)
|
||||||
from saas_auth import require_auth as jwt_required_middleware
|
# Auth: try flask_jwt_extended (app_v1) first, fall back to saas_auth (portal_server)
|
||||||
|
try:
|
||||||
|
from auth import jwt_required_middleware
|
||||||
|
except ImportError:
|
||||||
|
from saas_auth import require_auth as jwt_required_middleware
|
||||||
|
|
||||||
history_bp = Blueprint("v1_history", __name__, url_prefix="/api/v1/history")
|
history_bp = Blueprint("v1_history", __name__, url_prefix="/api/v1/history")
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,11 @@ from flask import Blueprint, jsonify, request, g
|
|||||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(__file__))))
|
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(__file__))))
|
||||||
|
|
||||||
from api_v1.utils import get_db, internal_error, bad_request
|
from api_v1.utils import get_db, internal_error, bad_request
|
||||||
from saas_auth import require_auth as jwt_required_middleware
|
# Auth: try flask_jwt_extended (app_v1) first, fall back to saas_auth (portal_server)
|
||||||
|
try:
|
||||||
|
from auth import jwt_required_middleware
|
||||||
|
except ImportError:
|
||||||
|
from saas_auth import require_auth as jwt_required_middleware
|
||||||
try:
|
try:
|
||||||
from auth import plan_required
|
from auth import plan_required
|
||||||
except ImportError:
|
except ImportError:
|
||||||
|
|||||||
@@ -13,7 +13,11 @@ import sqlite3
|
|||||||
from flask import Blueprint, jsonify, request
|
from flask import Blueprint, jsonify, request
|
||||||
|
|
||||||
from api_v1.utils import internal_error, bad_request
|
from api_v1.utils import internal_error, bad_request
|
||||||
from saas_auth import require_auth as jwt_required_middleware
|
# Auth: try flask_jwt_extended (app_v1) first, fall back to saas_auth (portal_server)
|
||||||
|
try:
|
||||||
|
from auth import jwt_required_middleware
|
||||||
|
except ImportError:
|
||||||
|
from saas_auth import require_auth as jwt_required_middleware
|
||||||
try:
|
try:
|
||||||
from auth import plan_required
|
from auth import plan_required
|
||||||
except ImportError:
|
except ImportError:
|
||||||
|
|||||||
@@ -16,8 +16,9 @@ DB_PATH = os.environ.get("TURF_SAAS_DB", "/home/h3r7/turf_saas/turf_saas.db")
|
|||||||
|
|
||||||
|
|
||||||
def get_db():
|
def get_db():
|
||||||
"""Return a SQLite connection with Row factory."""
|
"""Return a SQLite connection with Row factory (reads TURF_SAAS_DB dynamically)."""
|
||||||
conn = sqlite3.connect(DB_PATH)
|
db_path = os.environ.get("TURF_SAAS_DB", DB_PATH)
|
||||||
|
conn = sqlite3.connect(db_path)
|
||||||
conn.row_factory = sqlite3.Row
|
conn.row_factory = sqlite3.Row
|
||||||
return conn
|
return conn
|
||||||
|
|
||||||
|
|||||||
@@ -8,11 +8,15 @@ HRT-79: migration Telegram columns
|
|||||||
import sqlite3
|
import sqlite3
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
# NOTE: DB_PATH kept for backward compat, but get_db() reads env at call time
|
||||||
|
# so test isolation works correctly when TURF_SAAS_DB is set per-module.
|
||||||
DB_PATH = os.environ.get("TURF_SAAS_DB", "/home/h3r7/turf_saas/turf_saas.db")
|
DB_PATH = os.environ.get("TURF_SAAS_DB", "/home/h3r7/turf_saas/turf_saas.db")
|
||||||
|
|
||||||
|
|
||||||
def get_db():
|
def get_db():
|
||||||
conn = sqlite3.connect(DB_PATH)
|
# Read env dynamically so test overrides of TURF_SAAS_DB are respected
|
||||||
|
db_path = os.environ.get("TURF_SAAS_DB", DB_PATH)
|
||||||
|
conn = sqlite3.connect(db_path)
|
||||||
conn.row_factory = sqlite3.Row
|
conn.row_factory = sqlite3.Row
|
||||||
return conn
|
return conn
|
||||||
|
|
||||||
|
|||||||
@@ -31,3 +31,6 @@ python-dotenv==1.1.0
|
|||||||
|
|
||||||
# Utilities
|
# Utilities
|
||||||
python-dateutil==2.9.0
|
python-dateutil==2.9.0
|
||||||
|
|
||||||
|
# Hyperparameter optimization (ML ensemble tuning — HRT-136)
|
||||||
|
optuna>=4.0.0
|
||||||
|
|||||||
@@ -52,6 +52,9 @@ def auth_header(token: str) -> dict:
|
|||||||
|
|
||||||
@pytest.fixture(scope="module")
|
@pytest.fixture(scope="module")
|
||||||
def app():
|
def app():
|
||||||
|
# Enforce this module s temp DB
|
||||||
|
os.environ["TURF_SAAS_DB"] = _tmp_db.name
|
||||||
|
os.environ["JWT_SECRET_KEY"] = "test-history-secret-key"
|
||||||
application = create_app()
|
application = create_app()
|
||||||
application.config["TESTING"] = True
|
application.config["TESTING"] = True
|
||||||
application.config["JWT_SECRET_KEY"] = "test-history-secret-key"
|
application.config["JWT_SECRET_KEY"] = "test-history-secret-key"
|
||||||
@@ -70,7 +73,14 @@ def seeded_db():
|
|||||||
- Create ml_predictions_cache with rows spanning 120 days back
|
- Create ml_predictions_cache with rows spanning 120 days back
|
||||||
- Create users for free/premium/pro plans
|
- Create users for free/premium/pro plans
|
||||||
"""
|
"""
|
||||||
db_path = os.environ["TURF_SAAS_DB"]
|
# Reset TURF_SAAS_DB to this module-s temp DB at runtime
|
||||||
|
os.environ["TURF_SAAS_DB"] = _tmp_db.name
|
||||||
|
db_path = _tmp_db.name
|
||||||
|
|
||||||
|
# Ensure auth tables (users, refresh_tokens, subscriptions) exist in the test DB
|
||||||
|
# init_auth_tables() is idempotent — safe to call even if tables already exist
|
||||||
|
init_auth_tables()
|
||||||
|
|
||||||
conn = sqlite3.connect(db_path)
|
conn = sqlite3.connect(db_path)
|
||||||
|
|
||||||
# Create ml_predictions_cache table if absent
|
# Create ml_predictions_cache table if absent
|
||||||
@@ -124,7 +134,9 @@ def auth_tokens(client, seeded_db):
|
|||||||
assert r.status_code in (201, 409), f"register failed for {plan}: {r.data}"
|
assert r.status_code in (201, 409), f"register failed for {plan}: {r.data}"
|
||||||
|
|
||||||
# Set plan via direct DB
|
# Set plan via direct DB
|
||||||
db_path = os.environ["TURF_SAAS_DB"]
|
# Reset TURF_SAAS_DB to this module-s temp DB at runtime
|
||||||
|
os.environ["TURF_SAAS_DB"] = _tmp_db.name
|
||||||
|
db_path = _tmp_db.name
|
||||||
conn = sqlite3.connect(db_path)
|
conn = sqlite3.connect(db_path)
|
||||||
for plan, email in plans.items():
|
for plan, email in plans.items():
|
||||||
conn.execute("UPDATE users SET plan = ? WHERE email = ?", (plan, email))
|
conn.execute("UPDATE users SET plan = ? WHERE email = ?", (plan, email))
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ os.environ["JWT_SECRET_KEY"] = "test-secret-hrt80"
|
|||||||
sys.path.insert(0, os.path.dirname(os.path.dirname(__file__)))
|
sys.path.insert(0, os.path.dirname(os.path.dirname(__file__)))
|
||||||
|
|
||||||
from app_v1 import create_app # noqa: E402
|
from app_v1 import create_app # noqa: E402
|
||||||
|
from api_tokens_db import migrate_api_tokens_tables # noqa: E402
|
||||||
|
|
||||||
TEST_CONFIG = {
|
TEST_CONFIG = {
|
||||||
"TESTING": True,
|
"TESTING": True,
|
||||||
@@ -45,6 +46,10 @@ TEST_CONFIG = {
|
|||||||
|
|
||||||
@pytest.fixture(scope="module")
|
@pytest.fixture(scope="module")
|
||||||
def app():
|
def app():
|
||||||
|
# Enforce this module s temp DB at fixture runtime
|
||||||
|
os.environ["TURF_SAAS_DB"] = _tmp_db.name
|
||||||
|
os.environ["JWT_SECRET_KEY"] = "test-secret-hrt80"
|
||||||
|
migrate_api_tokens_tables() # ensure tables exist in THIS module s temp DB
|
||||||
application = create_app()
|
application = create_app()
|
||||||
application.config.update(TEST_CONFIG)
|
application.config.update(TEST_CONFIG)
|
||||||
yield application
|
yield application
|
||||||
|
|||||||
Reference in New Issue
Block a user