256 lines
9.0 KiB
Python
256 lines
9.0 KiB
Python
import uuid
|
|
import pytest
|
|
from fastapi.testclient import TestClient
|
|
|
|
|
|
@pytest.mark.integration
|
|
class TestConfigFoldersAPI:
|
|
"""Integration tests for config folders API."""
|
|
|
|
def test_list_config_folders_requires_authentication(self, test_client: TestClient) -> None:
|
|
"""Test that listing config folders requires authentication."""
|
|
response = test_client.get("/config-folders")
|
|
assert response.status_code == 401
|
|
|
|
def test_list_config_folders_returns_user_folders(self, authenticated_client: TestClient) -> None:
|
|
"""Test that authenticated users can list their folders."""
|
|
response = authenticated_client.get("/config-folders")
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert isinstance(data, dict)
|
|
assert "folders" in data
|
|
assert isinstance(data["folders"], list)
|
|
|
|
def test_create_config_folder_successfully(self, authenticated_client: TestClient) -> None:
|
|
"""Test creating a config folder."""
|
|
response = authenticated_client.post(
|
|
"/config-folders",
|
|
json={
|
|
"name": "test-folder",
|
|
"description": "Test folder",
|
|
"mount_path": "/home/user",
|
|
"files": {"test.txt": "hello world"},
|
|
},
|
|
)
|
|
assert response.status_code == 201
|
|
data = response.json()
|
|
assert data["name"] == "test-folder"
|
|
assert data["mount_path"] == "/home/user"
|
|
assert data["files"] == {"test.txt": "hello world"}
|
|
|
|
def test_create_config_folder_duplicate_name(self, authenticated_client: TestClient) -> None:
|
|
"""Test that duplicate folder names are rejected."""
|
|
# Create first folder
|
|
response = authenticated_client.post(
|
|
"/config-folders",
|
|
json={
|
|
"name": "duplicate-folder",
|
|
"mount_path": "/home/user",
|
|
"files": {},
|
|
},
|
|
)
|
|
assert response.status_code == 201
|
|
|
|
# Try to create second with same name
|
|
response = authenticated_client.post(
|
|
"/config-folders",
|
|
json={
|
|
"name": "duplicate-folder",
|
|
"mount_path": "/home/user",
|
|
"files": {},
|
|
},
|
|
)
|
|
assert response.status_code == 409
|
|
|
|
def test_create_config_folder_exceeds_size_limit(self, authenticated_client: TestClient) -> None:
|
|
"""Test that folders exceeding 10MB are rejected."""
|
|
large_content = "x" * (11 * 1024 * 1024) # 11MB
|
|
response = authenticated_client.post(
|
|
"/config-folders",
|
|
json={
|
|
"name": "large-folder",
|
|
"mount_path": "/home/user",
|
|
"files": {"large.txt": large_content},
|
|
},
|
|
)
|
|
assert response.status_code == 422
|
|
|
|
def test_create_config_folder_path_traversal_attack(self, authenticated_client: TestClient) -> None:
|
|
"""Test that path traversal in file paths is prevented."""
|
|
response = authenticated_client.post(
|
|
"/config-folders",
|
|
json={
|
|
"name": "bad-folder",
|
|
"mount_path": "/home/user",
|
|
"files": {"../../../etc/passwd": "malicious"},
|
|
},
|
|
)
|
|
assert response.status_code == 422
|
|
|
|
def test_get_config_folder_by_id(self, authenticated_client: TestClient) -> None:
|
|
"""Test getting a config folder by ID."""
|
|
# Create folder first
|
|
create_response = authenticated_client.post(
|
|
"/config-folders",
|
|
json={
|
|
"name": "get-test",
|
|
"mount_path": "/home/user",
|
|
"files": {},
|
|
},
|
|
)
|
|
folder_id = create_response.json()["id"]
|
|
|
|
# Get it back
|
|
response = authenticated_client.get(f"/config-folders/{folder_id}")
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["name"] == "get-test"
|
|
|
|
def test_get_config_folder_not_found(self, authenticated_client: TestClient) -> None:
|
|
"""Test getting a non-existent folder."""
|
|
response = authenticated_client.get(f"/config-folders/{uuid.uuid4()}")
|
|
assert response.status_code == 404
|
|
|
|
def test_update_config_folder_successfully(self, authenticated_client: TestClient) -> None:
|
|
"""Test updating a config folder."""
|
|
# Create folder first
|
|
create_response = authenticated_client.post(
|
|
"/config-folders",
|
|
json={
|
|
"name": "update-test",
|
|
"mount_path": "/home/user",
|
|
"files": {},
|
|
},
|
|
)
|
|
folder_id = create_response.json()["id"]
|
|
|
|
# Update it
|
|
response = authenticated_client.put(
|
|
f"/config-folders/{folder_id}",
|
|
json={
|
|
"name": "updated-name",
|
|
"mount_path": "/workspace",
|
|
"files": {"new.txt": "content"},
|
|
},
|
|
)
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["name"] == "updated-name"
|
|
assert data["mount_path"] == "/workspace"
|
|
|
|
def test_delete_config_folder_successfully(self, authenticated_client: TestClient) -> None:
|
|
"""Test deleting a config folder."""
|
|
# Create folder first
|
|
create_response = authenticated_client.post(
|
|
"/config-folders",
|
|
json={
|
|
"name": "delete-test",
|
|
"mount_path": "/home/user",
|
|
"files": {},
|
|
},
|
|
)
|
|
folder_id = create_response.json()["id"]
|
|
|
|
# Delete it
|
|
response = authenticated_client.delete(f"/config-folders/{folder_id}")
|
|
assert response.status_code == 204
|
|
|
|
# Verify it's gone
|
|
get_response = authenticated_client.get(f"/config-folders/{folder_id}")
|
|
assert get_response.status_code == 404
|
|
|
|
def test_add_project_override_successfully(self, authenticated_client: TestClient) -> None:
|
|
"""Test adding a project override."""
|
|
# Create folder first
|
|
create_response = authenticated_client.post(
|
|
"/config-folders",
|
|
json={
|
|
"name": "override-test",
|
|
"mount_path": "/home/user",
|
|
"files": {"global.txt": "global"},
|
|
},
|
|
)
|
|
folder_id = create_response.json()["id"]
|
|
project_id = str(uuid.uuid4())
|
|
|
|
# Add override
|
|
response = authenticated_client.post(
|
|
f"/config-folders/{folder_id}/overrides",
|
|
json={
|
|
"project_id": project_id,
|
|
"mount_path": "/workspace",
|
|
"files": {"project.txt": "project"},
|
|
},
|
|
)
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert project_id in data["project_overrides"]
|
|
|
|
def test_update_project_override_successfully(self, authenticated_client: TestClient) -> None:
|
|
"""Test updating a project override."""
|
|
# Create folder with override
|
|
create_response = authenticated_client.post(
|
|
"/config-folders",
|
|
json={
|
|
"name": "update-override-test",
|
|
"mount_path": "/home/user",
|
|
"files": {},
|
|
},
|
|
)
|
|
folder_id = create_response.json()["id"]
|
|
project_id = str(uuid.uuid4())
|
|
|
|
# Add override
|
|
authenticated_client.post(
|
|
f"/config-folders/{folder_id}/overrides",
|
|
json={
|
|
"project_id": project_id,
|
|
"mount_path": "/workspace",
|
|
"files": {"old.txt": "old"},
|
|
},
|
|
)
|
|
|
|
# Update override
|
|
response = authenticated_client.put(
|
|
f"/config-folders/{folder_id}/overrides/{project_id}",
|
|
json={
|
|
"mount_path": "/app",
|
|
"files": {"new.txt": "new"},
|
|
},
|
|
)
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["project_overrides"][project_id]["mount_path"] == "/app"
|
|
|
|
def test_delete_project_override_successfully(self, authenticated_client: TestClient) -> None:
|
|
"""Test deleting a project override."""
|
|
# Create folder with override
|
|
create_response = authenticated_client.post(
|
|
"/config-folders",
|
|
json={
|
|
"name": "delete-override-test",
|
|
"mount_path": "/home/user",
|
|
"files": {},
|
|
},
|
|
)
|
|
folder_id = create_response.json()["id"]
|
|
project_id = str(uuid.uuid4())
|
|
|
|
# Add override
|
|
authenticated_client.post(
|
|
f"/config-folders/{folder_id}/overrides",
|
|
json={
|
|
"project_id": project_id,
|
|
"mount_path": "/workspace",
|
|
"files": {},
|
|
},
|
|
)
|
|
|
|
# Delete override
|
|
response = authenticated_client.delete(
|
|
f"/config-folders/{folder_id}/overrides/{project_id}"
|
|
)
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert project_id not in data["project_overrides"]
|