691 lines
26 KiB
Python
691 lines
26 KiB
Python
"""Integration tests for deployment API endpoints using direct view calls."""
|
|
|
|
import pytest
|
|
from unittest.mock import Mock, patch
|
|
from fastapi import HTTPException
|
|
|
|
from agentops.deploy.models import HostingProjectModel
|
|
from agentops.opsboard.models import ProjectModel
|
|
from agentops.deploy.views.deploy import (
|
|
CreateUpdateSecretView,
|
|
ListSecretsView,
|
|
InitiateDeploymentView,
|
|
DeploymentStatusView,
|
|
DeploymentHistoryView,
|
|
)
|
|
from agentops.deploy.schemas import CreateSecretRequest
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_hosting_project():
|
|
"""Mock hosting project model."""
|
|
hosting_project = Mock(spec=HostingProjectModel)
|
|
hosting_project.id = "project-123"
|
|
hosting_project.namespace = "test-namespace"
|
|
hosting_project.app_name = "test-app"
|
|
hosting_project.git_url = "https://github.com/test/repo"
|
|
hosting_project.git_branch = "main"
|
|
hosting_project.entrypoint = "main.py"
|
|
hosting_project.github_oath_access_token = "token123"
|
|
hosting_project.pack_name = "FASTAPI" # Default pack for tests
|
|
return hosting_project
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_project():
|
|
"""Mock project model."""
|
|
project = Mock(spec=ProjectModel)
|
|
project.id = "project-123"
|
|
project.name = "Test Project"
|
|
project.org = Mock()
|
|
project.org.is_user_member.return_value = True
|
|
return project
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
def mock_request():
|
|
"""Create a mock request with a session user_id."""
|
|
from unittest.mock import MagicMock
|
|
from fastapi import Request
|
|
|
|
request = MagicMock(spec=Request)
|
|
request.state.session.user_id = "00000000-0000-0000-0000-000000000001"
|
|
return request
|
|
|
|
|
|
class TestDeploymentSecretsAPI:
|
|
"""Test the deployment secrets API endpoints."""
|
|
|
|
@patch('agentops.deploy.views.deploy.delete_secret')
|
|
@patch('agentops.deploy.views.deploy.create_secret')
|
|
async def test_create_secret_success(
|
|
self,
|
|
mock_create,
|
|
mock_delete,
|
|
mock_request,
|
|
orm_session,
|
|
mock_hosting_project,
|
|
mock_project,
|
|
):
|
|
"""Test creating a secret via view function."""
|
|
# Setup mocks
|
|
mock_delete.return_value = True
|
|
mock_create.return_value = Mock()
|
|
|
|
with (
|
|
patch.object(HostingProjectModel, 'get_by_id', return_value=mock_hosting_project),
|
|
patch.object(ProjectModel, 'get_by_id', return_value=mock_project),
|
|
):
|
|
# Create the view and call it directly
|
|
view = CreateUpdateSecretView(mock_request)
|
|
body = CreateSecretRequest(name="DATABASE_URL", value="postgresql://localhost:5432/test")
|
|
|
|
response = await view(
|
|
project_id="project-123",
|
|
body=body,
|
|
orm=orm_session,
|
|
)
|
|
|
|
assert response.success is True
|
|
assert response.message == "Successfully created secret"
|
|
|
|
@patch('agentops.deploy.views.deploy.list_secrets')
|
|
async def test_list_secrets_success(
|
|
self, mock_list_secrets, mock_request, orm_session, mock_hosting_project, mock_project
|
|
):
|
|
"""Test listing secrets via view function."""
|
|
# Setup mocks
|
|
mock_list_secrets.return_value = ["DATABASE_URL", "API_KEY"]
|
|
|
|
with (
|
|
patch.object(HostingProjectModel, 'get_by_id', return_value=mock_hosting_project),
|
|
patch.object(ProjectModel, 'get_by_id', return_value=mock_project),
|
|
):
|
|
# Create the view and call it directly
|
|
view = ListSecretsView(mock_request)
|
|
|
|
response = await view(
|
|
project_id="project-123",
|
|
orm=orm_session,
|
|
)
|
|
|
|
assert len(response.secrets) == 2
|
|
secret_names = [secret.name for secret in response.secrets]
|
|
assert "DATABASE_URL" in secret_names
|
|
assert "API_KEY" in secret_names
|
|
|
|
async def test_deployment_not_found(self, mock_request, orm_session):
|
|
"""Test view response when deployment doesn't exist."""
|
|
with patch.object(ProjectModel, 'get_by_id', return_value=None):
|
|
# Create the view and call it directly
|
|
view = ListSecretsView(mock_request)
|
|
|
|
with pytest.raises(HTTPException) as exc_info:
|
|
await view(
|
|
project_id="00000000-0000-0000-0000-000000000000",
|
|
orm=orm_session,
|
|
)
|
|
|
|
assert exc_info.value.status_code == 404
|
|
assert "Project not found" in str(exc_info.value.detail)
|
|
|
|
|
|
class TestDeploymentManagementAPI:
|
|
"""Test the deployment management API endpoints."""
|
|
|
|
@patch('agentops.deploy.views.deploy.queue_task')
|
|
@patch('agentops.deploy.views.deploy.list_secrets')
|
|
async def test_initiate_deployment_success(
|
|
self,
|
|
mock_list_secrets,
|
|
mock_queue,
|
|
mock_request,
|
|
orm_session,
|
|
mock_hosting_project,
|
|
mock_project,
|
|
):
|
|
"""Test initiating a deployment via view function."""
|
|
# Setup mocks
|
|
mock_list_secrets.return_value = ["DATABASE_URL"]
|
|
mock_queue.return_value = "job-456"
|
|
|
|
with (
|
|
patch.object(HostingProjectModel, 'get_by_id', return_value=mock_hosting_project),
|
|
patch.object(ProjectModel, 'get_by_id', return_value=mock_project),
|
|
):
|
|
# Create the view and call it directly
|
|
view = InitiateDeploymentView(mock_request)
|
|
|
|
response = await view(
|
|
project_id="project-123",
|
|
orm=orm_session,
|
|
)
|
|
|
|
assert response.success is True
|
|
assert response.message == "Deployment initiated successfully"
|
|
assert response.job_id == "job-456"
|
|
|
|
@patch('agentops.deploy.views.deploy.get_task_events')
|
|
async def test_deployment_status_success(
|
|
self, mock_get_events, mock_request, orm_session, mock_hosting_project, mock_project
|
|
):
|
|
"""Test getting deployment status via view function."""
|
|
from datetime import datetime
|
|
from enum import Enum
|
|
|
|
class MockStatus(Enum):
|
|
SUCCESS = "success"
|
|
|
|
# Setup mocks
|
|
mock_events = [
|
|
Mock(
|
|
event_type="build",
|
|
status=MockStatus.SUCCESS,
|
|
message="Build completed",
|
|
timestamp=datetime.fromisoformat("2024-01-01T00:00:00"),
|
|
),
|
|
]
|
|
mock_get_events.return_value = mock_events
|
|
|
|
with (
|
|
patch.object(HostingProjectModel, 'get_by_id', return_value=mock_hosting_project),
|
|
patch.object(ProjectModel, 'get_by_id', return_value=mock_project),
|
|
):
|
|
# Create the view and call it directly
|
|
view = DeploymentStatusView(mock_request)
|
|
|
|
response = await view(
|
|
project_id="project-123",
|
|
job_id="test-job-123",
|
|
orm=orm_session,
|
|
)
|
|
|
|
assert len(response.events) == 1
|
|
assert response.events[0].type == "build"
|
|
assert response.events[0].status == "success"
|
|
assert response.events[0].message == "Build completed"
|
|
|
|
@patch('agentops.deploy.views.deploy.get_task_events')
|
|
async def test_deployment_status_with_start_date(
|
|
self, mock_get_events, mock_request, orm_session, mock_hosting_project, mock_project
|
|
):
|
|
"""Test getting deployment status with start date filter via view function."""
|
|
from datetime import datetime
|
|
|
|
# Setup mocks
|
|
mock_get_events.return_value = []
|
|
|
|
with (
|
|
patch.object(HostingProjectModel, 'get_by_id', return_value=mock_hosting_project),
|
|
patch.object(ProjectModel, 'get_by_id', return_value=mock_project),
|
|
):
|
|
# Create the view and call it directly
|
|
view = DeploymentStatusView(mock_request)
|
|
start_date = datetime.fromisoformat("2024-01-01T12:00:00")
|
|
|
|
response = await view(
|
|
project_id="project-123",
|
|
job_id="test-job-456",
|
|
start_date=start_date,
|
|
orm=orm_session,
|
|
)
|
|
|
|
assert len(response.events) == 0
|
|
|
|
|
|
class TestViewValidation:
|
|
"""Test view validation and error handling."""
|
|
|
|
@patch('agentops.deploy.views.deploy.create_secret')
|
|
@patch('agentops.deploy.views.deploy.delete_secret')
|
|
async def test_create_secret_kubernetes_error(
|
|
self,
|
|
mock_delete,
|
|
mock_create,
|
|
mock_request,
|
|
orm_session,
|
|
mock_hosting_project,
|
|
mock_project,
|
|
):
|
|
"""Test creating a secret when Kubernetes operations fail."""
|
|
# Setup mocks
|
|
mock_delete.return_value = True
|
|
mock_create.side_effect = Exception("Kubernetes API error")
|
|
|
|
with (
|
|
patch.object(HostingProjectModel, 'get_by_id', return_value=mock_hosting_project),
|
|
patch.object(ProjectModel, 'get_by_id', return_value=mock_project),
|
|
):
|
|
# Create the view and call it directly
|
|
view = CreateUpdateSecretView(mock_request)
|
|
body = CreateSecretRequest(name="DATABASE_URL", value="postgresql://localhost:5432/test")
|
|
|
|
# The view should let the exception bubble up
|
|
with pytest.raises(Exception) as exc_info:
|
|
await view(
|
|
project_id="project-123",
|
|
body=body,
|
|
orm=orm_session,
|
|
)
|
|
|
|
assert "Kubernetes API error" in str(exc_info.value)
|
|
|
|
|
|
class TestDeploymentHistoryAPI:
|
|
"""Test the deployment history API endpoint."""
|
|
|
|
@patch('agentops.deploy.views.deploy.get_task_status')
|
|
@patch('agentops.deploy.views.deploy.get_tasks')
|
|
async def test_deployment_history_success(
|
|
self,
|
|
mock_get_tasks,
|
|
mock_get_status,
|
|
mock_request,
|
|
orm_session,
|
|
mock_hosting_project,
|
|
mock_project,
|
|
):
|
|
"""Test getting deployment history via view function."""
|
|
from enum import Enum
|
|
|
|
class MockStatus(Enum):
|
|
SUCCESS = "success"
|
|
RUNNING = "running"
|
|
|
|
# Setup mock jobs
|
|
mock_jobs = [
|
|
{
|
|
"job_id": "job-123",
|
|
"project_id": "project-123",
|
|
"namespace": "test-namespace",
|
|
"queued_at": "2024-01-01T10:00:00",
|
|
"config": {},
|
|
},
|
|
{
|
|
"job_id": "job-456",
|
|
"project_id": "project-123",
|
|
"namespace": "test-namespace",
|
|
"queued_at": "2024-01-01T11:00:00",
|
|
"config": {},
|
|
},
|
|
]
|
|
mock_get_tasks.return_value = mock_jobs
|
|
|
|
# Setup mock status for each job (get_task_status returns BaseEvent)
|
|
def mock_status_side_effect(job_id):
|
|
if job_id == "job-123":
|
|
return Mock(
|
|
status=MockStatus.SUCCESS,
|
|
message="Deployment completed successfully",
|
|
)
|
|
elif job_id == "job-456":
|
|
return Mock(
|
|
status=MockStatus.RUNNING,
|
|
message="Deployment in progress",
|
|
)
|
|
return None
|
|
|
|
mock_get_status.side_effect = mock_status_side_effect
|
|
|
|
with (
|
|
patch.object(HostingProjectModel, 'get_by_id', return_value=mock_hosting_project),
|
|
patch.object(ProjectModel, 'get_by_id', return_value=mock_project),
|
|
):
|
|
# Create the view and call it directly
|
|
view = DeploymentHistoryView(mock_request)
|
|
|
|
response = await view(
|
|
project_id="project-123",
|
|
orm=orm_session,
|
|
)
|
|
|
|
# Verify response
|
|
assert len(response.jobs) == 2
|
|
|
|
# Check first job
|
|
job1 = response.jobs[0]
|
|
assert job1.id == "job-123"
|
|
assert job1.queued_at == "2024-01-01T10:00:00"
|
|
assert job1.status == "success"
|
|
assert job1.message == "Deployment completed successfully"
|
|
|
|
# Check second job
|
|
job2 = response.jobs[1]
|
|
assert job2.id == "job-456"
|
|
assert job2.queued_at == "2024-01-01T11:00:00"
|
|
assert job2.status == "running"
|
|
assert job2.message == "Deployment in progress"
|
|
|
|
@patch('agentops.deploy.views.deploy.get_task_status')
|
|
@patch('agentops.deploy.views.deploy.get_tasks')
|
|
async def test_deployment_history_no_events(
|
|
self,
|
|
mock_get_tasks,
|
|
mock_get_status,
|
|
mock_request,
|
|
orm_session,
|
|
mock_hosting_project,
|
|
mock_project,
|
|
):
|
|
"""Test deployment history when jobs have no events."""
|
|
# Setup mock jobs
|
|
mock_jobs = [
|
|
{
|
|
"job_id": "job-789",
|
|
"project_id": "project-123",
|
|
"namespace": "test-namespace",
|
|
"queued_at": "2024-01-01T12:00:00",
|
|
"config": {},
|
|
},
|
|
]
|
|
mock_get_tasks.return_value = mock_jobs
|
|
mock_get_status.return_value = None # No events
|
|
|
|
with (
|
|
patch.object(HostingProjectModel, 'get_by_id', return_value=mock_hosting_project),
|
|
patch.object(ProjectModel, 'get_by_id', return_value=mock_project),
|
|
):
|
|
# Create the view and call it directly
|
|
view = DeploymentHistoryView(mock_request)
|
|
|
|
response = await view(
|
|
project_id="project-123",
|
|
orm=orm_session,
|
|
)
|
|
|
|
# Verify response
|
|
assert len(response.jobs) == 1
|
|
job = response.jobs[0]
|
|
assert job.id == "job-789"
|
|
assert job.queued_at == "2024-01-01T12:00:00"
|
|
assert job.status == "unknown"
|
|
assert job.message == ""
|
|
|
|
@patch('agentops.deploy.views.deploy.get_tasks')
|
|
async def test_deployment_history_empty_jobs(
|
|
self,
|
|
mock_get_tasks,
|
|
mock_request,
|
|
orm_session,
|
|
mock_hosting_project,
|
|
mock_project,
|
|
):
|
|
"""Test deployment history when no jobs exist."""
|
|
mock_get_tasks.return_value = [] # No jobs
|
|
|
|
with (
|
|
patch.object(HostingProjectModel, 'get_by_id', return_value=mock_hosting_project),
|
|
patch.object(ProjectModel, 'get_by_id', return_value=mock_project),
|
|
):
|
|
# Create the view and call it directly
|
|
view = DeploymentHistoryView(mock_request)
|
|
|
|
response = await view(
|
|
project_id="project-123",
|
|
orm=orm_session,
|
|
)
|
|
|
|
# Verify response
|
|
assert len(response.jobs) == 0
|
|
|
|
|
|
class TestDeploymentPacksAPI:
|
|
"""Test deployment pack functionality in API endpoints."""
|
|
|
|
@pytest.fixture
|
|
def mock_project_with_api_key(self):
|
|
"""Mock project model with API key."""
|
|
project = Mock(spec=ProjectModel)
|
|
project.id = "project-123"
|
|
project.name = "Test Project"
|
|
project.api_key = "test-api-key-123"
|
|
project.org = Mock()
|
|
project.org.is_user_member.return_value = True
|
|
return project
|
|
|
|
def test_hosting_project_deployment_config_with_fastapi_pack(self, mock_project_with_api_key):
|
|
"""Test that FASTAPI pack creates correct deployment config."""
|
|
from jockey import DeploymentConfig
|
|
from agentops.deploy.models import HostingProjectModel
|
|
|
|
# Create hosting project with FASTAPI pack
|
|
hosting_project = HostingProjectModel()
|
|
hosting_project.id = "project-123"
|
|
hosting_project.pack_name = "FASTAPI"
|
|
hosting_project.git_url = "https://github.com/test/repo"
|
|
hosting_project.git_branch = "main"
|
|
hosting_project.entrypoint = "main.py"
|
|
hosting_project.github_oath_access_token = "token123"
|
|
hosting_project.watch_path = None
|
|
hosting_project.user_callback_url = None
|
|
hosting_project.project = mock_project_with_api_key
|
|
|
|
# Mock list_secrets to return empty list
|
|
with patch('jockey.list_secrets', return_value=[]):
|
|
config = hosting_project.deployment_config
|
|
|
|
# Verify FASTAPI pack defaults are applied
|
|
assert config.dockerfile_template == "fastapi-agent"
|
|
assert config.ports == [8000]
|
|
assert config.build_files == {}
|
|
assert config.namespace == "project-123" # namespace property returns str(id)
|
|
assert config.project_id == "project-123"
|
|
|
|
def test_hosting_project_deployment_config_with_crewai_pack(self, mock_project_with_api_key):
|
|
"""Test that CREWAI pack creates correct deployment config."""
|
|
from jockey import DeploymentConfig
|
|
from agentops.deploy.models import HostingProjectModel
|
|
|
|
# Create hosting project with CREWAI pack
|
|
hosting_project = HostingProjectModel()
|
|
hosting_project.id = "project-123"
|
|
hosting_project.pack_name = "CREWAI"
|
|
hosting_project.git_url = "https://github.com/test/repo"
|
|
hosting_project.git_branch = "main"
|
|
hosting_project.entrypoint = "main.py"
|
|
hosting_project.github_oath_access_token = "token123"
|
|
hosting_project.watch_path = "src/"
|
|
hosting_project.user_callback_url = None
|
|
hosting_project.project = mock_project_with_api_key
|
|
|
|
# Mock list_secrets to return empty list
|
|
with patch('jockey.list_secrets', return_value=[]):
|
|
config = hosting_project.deployment_config
|
|
|
|
# Verify CREWAI pack defaults are applied
|
|
assert config.dockerfile_template == "crewai-agent"
|
|
assert config.ports == [8080]
|
|
assert isinstance(config.build_files, dict) # Should have build files
|
|
assert config.namespace == "project-123" # namespace property returns str(id)
|
|
assert config.project_id == "project-123"
|
|
assert config.watch_path == "src/"
|
|
|
|
def test_hosting_project_deployment_config_with_crewai_job_pack(self, mock_project_with_api_key):
|
|
"""Test that CREWAI_JOB pack creates correct deployment config."""
|
|
from jockey import DeploymentConfig
|
|
from agentops.deploy.models import HostingProjectModel
|
|
|
|
# Create hosting project with CREWAI_JOB pack
|
|
hosting_project = HostingProjectModel()
|
|
hosting_project.id = "project-123"
|
|
hosting_project.pack_name = "CREWAI_JOB"
|
|
hosting_project.git_url = "https://github.com/test/repo"
|
|
hosting_project.git_branch = "main"
|
|
hosting_project.entrypoint = "main.py"
|
|
hosting_project.github_oath_access_token = "token123"
|
|
hosting_project.watch_path = "src/"
|
|
hosting_project.user_callback_url = None
|
|
hosting_project.project = mock_project_with_api_key
|
|
|
|
# Mock list_secrets to return empty list
|
|
with patch('jockey.list_secrets', return_value=[]):
|
|
config = hosting_project.deployment_config
|
|
|
|
# Verify CREWAI_JOB pack defaults are applied
|
|
assert config.dockerfile_template == "crewai-job"
|
|
assert config.ports == [] # No ports for job execution
|
|
assert isinstance(config.build_files, dict) # Should have build files
|
|
assert config.namespace == "project-123" # namespace property returns str(id)
|
|
assert config.project_id == "project-123"
|
|
|
|
def test_hosting_project_deployment_config_with_none_pack_fallback(self, mock_project_with_api_key):
|
|
"""Test that None pack_name falls back to FASTAPI."""
|
|
from jockey import DeploymentConfig
|
|
from agentops.deploy.models import HostingProjectModel
|
|
|
|
# Create hosting project with None pack_name
|
|
hosting_project = HostingProjectModel()
|
|
hosting_project.id = "project-123"
|
|
hosting_project.pack_name = None
|
|
hosting_project.git_url = "https://github.com/test/repo"
|
|
hosting_project.git_branch = "main"
|
|
hosting_project.entrypoint = "main.py"
|
|
hosting_project.github_oath_access_token = "token123"
|
|
hosting_project.watch_path = None
|
|
hosting_project.user_callback_url = None
|
|
hosting_project.project = mock_project_with_api_key
|
|
|
|
# Mock list_secrets to return empty list
|
|
with patch('jockey.list_secrets', return_value=[]):
|
|
config = hosting_project.deployment_config
|
|
|
|
# Should fall back to FASTAPI defaults
|
|
assert config.dockerfile_template == "fastapi-agent"
|
|
assert config.ports == [8000]
|
|
assert config.build_files == {}
|
|
|
|
def test_hosting_project_deployment_config_with_invalid_pack_raises_error(self, mock_project_with_api_key):
|
|
"""Test that invalid pack_name raises ValueError."""
|
|
from jockey import DeploymentConfig
|
|
from agentops.deploy.models import HostingProjectModel
|
|
|
|
# Create hosting project with invalid pack_name
|
|
hosting_project = HostingProjectModel()
|
|
hosting_project.id = "project-123"
|
|
hosting_project.pack_name = "INVALID_PACK"
|
|
hosting_project.git_url = "https://github.com/test/repo"
|
|
hosting_project.git_branch = "main"
|
|
hosting_project.entrypoint = "main.py"
|
|
hosting_project.github_oath_access_token = "token123"
|
|
hosting_project.watch_path = None
|
|
hosting_project.user_callback_url = None
|
|
hosting_project.project = mock_project_with_api_key
|
|
|
|
# Mock list_secrets to return empty list
|
|
with patch('jockey.list_secrets', return_value=[]):
|
|
with pytest.raises(ValueError, match="Invalid deployment pack name: INVALID_PACK"):
|
|
config = hosting_project.deployment_config
|
|
|
|
@patch('agentops.deploy.views.deploy.queue_task')
|
|
async def test_initiate_deployment_with_crewai_pack(
|
|
self,
|
|
mock_queue,
|
|
mock_request,
|
|
orm_session,
|
|
mock_project_with_api_key,
|
|
):
|
|
"""Test that deployment uses correct pack configuration."""
|
|
# Setup hosting project with CREWAI pack
|
|
hosting_project = HostingProjectModel()
|
|
hosting_project.id = "project-123"
|
|
hosting_project.pack_name = "CREWAI"
|
|
hosting_project.git_url = "https://github.com/test/repo"
|
|
hosting_project.git_branch = "main"
|
|
hosting_project.entrypoint = "main.py"
|
|
hosting_project.github_oath_access_token = "token123"
|
|
hosting_project.watch_path = "src/"
|
|
hosting_project.user_callback_url = None
|
|
hosting_project.project = mock_project_with_api_key
|
|
|
|
# Setup mocks
|
|
mock_queue.return_value = "job-456"
|
|
|
|
with (
|
|
patch.object(HostingProjectModel, 'get_by_id', return_value=hosting_project),
|
|
patch.object(ProjectModel, 'get_by_id', return_value=mock_project_with_api_key),
|
|
patch('jockey.list_secrets', return_value=["DATABASE_URL"]),
|
|
):
|
|
# Create the view and call it directly
|
|
view = InitiateDeploymentView(mock_request)
|
|
|
|
response = await view(
|
|
project_id="project-123",
|
|
orm=orm_session,
|
|
)
|
|
|
|
# Verify response
|
|
assert response.success is True
|
|
assert response.message == "Deployment initiated successfully"
|
|
assert response.job_id == "job-456"
|
|
|
|
# Verify queue_task was called with correct config
|
|
mock_queue.assert_called_once()
|
|
call_args = mock_queue.call_args
|
|
config = call_args[1]["config"] # Get config from kwargs
|
|
|
|
# Should have CREWAI pack defaults
|
|
assert config.dockerfile_template == "crewai-agent"
|
|
assert config.ports == [8080]
|
|
assert isinstance(config.build_files, dict)
|
|
assert len(config.build_files) > 0 # CREWAI should have build files
|
|
|
|
@patch('agentops.deploy.views.deploy.queue_task')
|
|
async def test_initiate_deployment_preserves_user_overrides(
|
|
self,
|
|
mock_queue,
|
|
mock_request,
|
|
orm_session,
|
|
mock_project_with_api_key,
|
|
):
|
|
"""Test that user-provided fields override pack defaults."""
|
|
# Setup hosting project with custom settings
|
|
hosting_project = HostingProjectModel()
|
|
hosting_project.id = "project-123"
|
|
hosting_project.pack_name = "FASTAPI"
|
|
hosting_project.git_url = "https://github.com/test/custom-repo"
|
|
hosting_project.git_branch = "feature-branch"
|
|
hosting_project.entrypoint = "custom_main.py"
|
|
hosting_project.github_oath_access_token = "custom-token"
|
|
hosting_project.watch_path = "custom/path/"
|
|
hosting_project.user_callback_url = "https://custom-callback.com"
|
|
hosting_project.project = mock_project_with_api_key
|
|
|
|
# Setup mocks
|
|
mock_queue.return_value = "job-789"
|
|
|
|
with (
|
|
patch.object(HostingProjectModel, 'get_by_id', return_value=hosting_project),
|
|
patch.object(ProjectModel, 'get_by_id', return_value=mock_project_with_api_key),
|
|
patch('jockey.list_secrets', return_value=["API_KEY"]),
|
|
):
|
|
# Create the view and call it directly
|
|
view = InitiateDeploymentView(mock_request)
|
|
|
|
response = await view(
|
|
project_id="project-123",
|
|
orm=orm_session,
|
|
)
|
|
|
|
# Verify response
|
|
assert response.success is True
|
|
|
|
# Verify config has pack defaults but user overrides
|
|
mock_queue.assert_called_once()
|
|
call_args = mock_queue.call_args
|
|
config = call_args[1]["config"] # Get config from kwargs
|
|
|
|
# Pack defaults
|
|
assert config.dockerfile_template == "fastapi-agent"
|
|
assert config.ports == [8000]
|
|
assert config.build_files == {}
|
|
|
|
# User overrides
|
|
assert config.repository_url == "https://github.com/test/custom-repo"
|
|
assert config.branch == "feature-branch"
|
|
assert config.entrypoint == "custom_main.py"
|
|
assert config.github_access_token == "custom-token"
|
|
assert config.watch_path == "custom/path/"
|
|
assert config.callback_url == "https://custom-callback.com"
|
|
assert config.secret_names == ["API_KEY"]
|
|
assert config.agentops_api_key == "test-api-key-123"
|