133 lines
4.2 KiB
Python
133 lines
4.2 KiB
Python
|
|
"""Tests for the AI deploy script (scripts/ai_deploy.py)."""
|
||
|
|
|
||
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
import json
|
||
|
|
import os
|
||
|
|
import sys
|
||
|
|
from unittest.mock import patch
|
||
|
|
|
||
|
|
import pytest
|
||
|
|
|
||
|
|
# Add scripts dir to path
|
||
|
|
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "scripts"))
|
||
|
|
|
||
|
|
|
||
|
|
def test_phase_result_to_dict():
|
||
|
|
"""PhaseResult.to_dict should serialize correctly."""
|
||
|
|
from ai_deploy import PhaseResult
|
||
|
|
|
||
|
|
result = PhaseResult(name="build", success=True, duration_s=1.5, output="ok")
|
||
|
|
d = result.to_dict()
|
||
|
|
assert d["phase"] == "build"
|
||
|
|
assert d["success"] is True
|
||
|
|
assert d["duration_s"] == 1.5
|
||
|
|
assert d["output"] == "ok"
|
||
|
|
|
||
|
|
|
||
|
|
def test_deploy_report_to_dict():
|
||
|
|
"""DeployReport.to_dict should include phases and rollback info."""
|
||
|
|
from ai_deploy import DeployReport, PhaseResult
|
||
|
|
|
||
|
|
report = DeployReport(
|
||
|
|
started_at="2026-01-01T00:00:00Z",
|
||
|
|
finished_at="2026-01-01T00:05:00Z",
|
||
|
|
overall_success=True,
|
||
|
|
)
|
||
|
|
report.phases.append(PhaseResult(name="build", success=True))
|
||
|
|
d = report.to_dict()
|
||
|
|
assert d["overall_success"] is True
|
||
|
|
assert len(d["phases"]) == 1
|
||
|
|
assert d["rollback_performed"] is False
|
||
|
|
|
||
|
|
|
||
|
|
def test_phase_build_skip():
|
||
|
|
"""phase_build should skip when --skip-build is set."""
|
||
|
|
from ai_deploy import phase_build
|
||
|
|
|
||
|
|
result = phase_build(skip_build=True, dry_run=False)
|
||
|
|
assert result.success is True
|
||
|
|
assert "skipped" in result.output.lower()
|
||
|
|
|
||
|
|
|
||
|
|
def test_phase_build_dry_run():
|
||
|
|
"""phase_build should return dry-run message in dry-run mode."""
|
||
|
|
from ai_deploy import phase_build
|
||
|
|
|
||
|
|
result = phase_build(skip_build=False, dry_run=True)
|
||
|
|
assert result.success is True
|
||
|
|
assert "DRY-RUN" in result.output
|
||
|
|
|
||
|
|
|
||
|
|
def test_phase_tests_skip():
|
||
|
|
"""phase_tests should skip when --skip-tests is set."""
|
||
|
|
from ai_deploy import phase_tests
|
||
|
|
|
||
|
|
result = phase_tests(skip_tests=True, dry_run=False)
|
||
|
|
assert result.success is True
|
||
|
|
assert "skipped" in result.output.lower()
|
||
|
|
|
||
|
|
|
||
|
|
def test_phase_tests_dry_run():
|
||
|
|
"""phase_tests should return dry-run message in dry-run mode."""
|
||
|
|
from ai_deploy import phase_tests
|
||
|
|
|
||
|
|
result = phase_tests(skip_tests=False, dry_run=True)
|
||
|
|
assert result.success is True
|
||
|
|
assert "DRY-RUN" in result.output
|
||
|
|
|
||
|
|
|
||
|
|
def test_phase_deploy_missing_env():
|
||
|
|
"""phase_deploy should fail when env vars are missing."""
|
||
|
|
from ai_deploy import phase_deploy
|
||
|
|
|
||
|
|
# Ensure env vars are not set
|
||
|
|
with patch.dict(os.environ, {}, clear=True):
|
||
|
|
result = phase_deploy(dry_run=False)
|
||
|
|
assert result.success is False
|
||
|
|
assert "COOLIFY" in result.error
|
||
|
|
|
||
|
|
|
||
|
|
def test_phase_deploy_dry_run_with_env():
|
||
|
|
"""phase_deploy should succeed in dry-run mode with env vars set."""
|
||
|
|
from ai_deploy import phase_deploy
|
||
|
|
|
||
|
|
with patch.dict(os.environ, {"COOLIFY_API_TOKEN": "test", "COOLIFY_APP_UUID": "uuid-123"}):
|
||
|
|
result = phase_deploy(dry_run=True)
|
||
|
|
assert result.success is True
|
||
|
|
assert "DRY-RUN" in result.output
|
||
|
|
assert "uuid-123" in result.output
|
||
|
|
|
||
|
|
|
||
|
|
def test_phase_rollback_missing_env():
|
||
|
|
"""phase_rollback should fail when env vars are missing."""
|
||
|
|
from ai_deploy import phase_rollback
|
||
|
|
|
||
|
|
with patch.dict(os.environ, {}, clear=True):
|
||
|
|
result = phase_rollback(dry_run=False)
|
||
|
|
assert result.success is False
|
||
|
|
assert "COOLIFY" in result.error
|
||
|
|
|
||
|
|
|
||
|
|
def test_run_pipeline_dry_run_all_skip():
|
||
|
|
"""Full pipeline in dry-run with all skips should succeed with env vars."""
|
||
|
|
from ai_deploy import run_pipeline
|
||
|
|
|
||
|
|
with patch.dict(os.environ, {"COOLIFY_API_TOKEN": "test", "COOLIFY_APP_UUID": "uuid-123"}):
|
||
|
|
report = run_pipeline(skip_build=True, skip_tests=True, dry_run=True)
|
||
|
|
assert report.overall_success is True
|
||
|
|
assert len(report.phases) == 3 # build, tests, deploy
|
||
|
|
assert all(p.success for p in report.phases)
|
||
|
|
assert report.rollback_performed is False
|
||
|
|
|
||
|
|
|
||
|
|
def test_run_pipeline_deploy_fail_triggers_rollback():
|
||
|
|
"""Pipeline should trigger rollback when deploy fails."""
|
||
|
|
from ai_deploy import run_pipeline
|
||
|
|
|
||
|
|
with patch.dict(os.environ, {}, clear=True):
|
||
|
|
report = run_pipeline(skip_build=True, skip_tests=True, dry_run=False)
|
||
|
|
assert report.overall_success is False
|
||
|
|
assert report.rollback_performed is True
|
||
|
|
assert len(report.phases) == 4 # build, tests, deploy, rollback
|