deploymate / tests /test_api.py
shakauthossain's picture
Version 1.0.3
f888e2a
"""
Comprehensive tests for the DevOps Toolkit API.
"""
import pytest
from fastapi.testclient import TestClient
from app.main import app
@pytest.fixture
def client():
"""Test client fixture."""
return TestClient(app)
class TestRootEndpoint:
"""Test cases for the root endpoint."""
def test_root_endpoint(self, client):
"""Test the root endpoint returns correct information."""
response = client.get("/")
assert response.status_code == 200
data = response.json()
assert "message" in data
assert "version" in data
assert "docs" in data
assert "redoc" in data
assert data["message"] == "DeployMate API"
assert data["version"] == "1.0.0"
class TestScriptGeneration:
"""Test cases for script generation endpoint."""
def test_generate_python_script(self, client):
"""Test generating a Python stack script."""
config = {
"stackType": "python",
"webServer": "nginx",
"database": "postgresql",
"dbName": "testdb",
"dbUsername": "testuser",
"dbPassword": "testpassword123",
"domain": "example.com",
"ssl": False,
"sslEmail": "",
"runtime": "3.11",
"processManager": "systemd",
}
response = client.post("/api/v1/generate-script", json=config)
assert response.status_code == 200
data = response.json()
assert "script_path" in data
assert "script_url" in data
assert "description" in data
assert "nginx_config_path" in data
assert "nginx_url" in data
assert "python" in data["description"].lower()
assert "nginx" in data["description"].lower()
def test_generate_nodejs_script(self, client):
"""Test generating a Node.js stack script."""
config = {
"stackType": "nodejs",
"webServer": "nginx",
"database": "mongodb",
"dbName": "testdb",
"dbUsername": "testuser",
"dbPassword": "testpassword123",
"domain": "example.com",
"ssl": True,
"sslEmail": "test@example.com",
"runtime": "20",
"processManager": "pm2",
}
response = client.post("/api/v1/generate-script", json=config)
assert response.status_code == 200
data = response.json()
assert "script_path" in data
assert "script_url" in data
assert "nodejs" in data["description"].lower()
def test_generate_react_script(self, client):
"""Test generating a React static site script."""
config = {
"stackType": "react",
"webServer": "nginx",
"database": "none",
"domain": "example.com",
"ssl": False,
"processManager": "none",
}
response = client.post("/api/v1/generate-script", json=config)
assert response.status_code == 200
data = response.json()
assert "script_path" in data
assert "script_url" in data
assert "react" in data["description"].lower()
def test_generate_script_without_webserver(self, client):
"""Test generating a script without web server."""
config = {
"stackType": "python",
"webServer": "none",
"database": "none",
"runtime": "3.11",
"processManager": "none",
}
response = client.post("/api/v1/generate-script", json=config)
assert response.status_code == 200
data = response.json()
assert "script_path" in data
assert "script_url" in data
# Should not have nginx config when no web server
assert data["nginx_config_path"] is None or data["nginx_config_path"] == ""
assert data["nginx_url"] is None or data["nginx_url"] == ""
def test_generate_script_validation_error(self, client):
"""Test script generation with invalid data."""
# Invalid stack type
config = {
"stackType": "invalid_stack",
"webServer": "nginx",
"database": "postgresql",
"dbName": "testdb",
"dbUsername": "testuser",
"dbPassword": "testpassword123",
}
response = client.post("/api/v1/generate-script", json=config)
assert response.status_code == 422 # Validation error
def test_generate_script_missing_required_fields(self, client):
"""Test script generation with missing required fields."""
config = {
"webServer": "nginx",
"database": "postgresql",
# Missing stackType
}
response = client.post("/api/v1/generate-script", json=config)
assert response.status_code == 422 # Validation error
class TestNginxGeneration:
"""Test cases for nginx configuration generation."""
def test_generate_nginx_python(self, client):
"""Test nginx config generation for Python."""
config = {
"stackType": "python",
"webServer": "nginx",
"database": "",
"dbName": "",
"dbUsername": "",
"dbPassword": "",
"domain": "example.com",
"ssl": False,
"sslEmail": "",
"runtime": "",
"processManager": "",
"security": {
"ufw": False,
"fail2ban": False,
"disableRoot": False,
"autoUpdates": False,
},
"advanced": {
"swap": False,
"swapSize": "",
"sshKey": "",
"backups": False,
"monitoring": False,
},
}
response = client.post("/api/v1/generate-nginx-config", json=config)
assert response.status_code == 200
data = response.json()
assert "nginx_config_path" in data
assert "nginx_url" in data
assert "description" in data
assert "python" in data["description"].lower()
def test_generate_nginx_nodejs(self, client):
"""Test nginx config generation for Node.js."""
config = {
"stackType": "nodejs",
"webServer": "nginx",
"database": "",
"dbName": "",
"dbUsername": "",
"dbPassword": "",
"domain": "example.com",
"ssl": True,
"sslEmail": "test@example.com",
"runtime": "",
"processManager": "",
"security": {
"ufw": False,
"fail2ban": False,
"disableRoot": False,
"autoUpdates": False,
},
"advanced": {
"swap": False,
"swapSize": "",
"sshKey": "",
"backups": False,
"monitoring": False,
},
}
response = client.post("/api/v1/generate-nginx-config", json=config)
assert response.status_code == 200
data = response.json()
assert "nginx_config_path" in data
assert "nginx_url" in data
assert "nodejs" in data["description"].lower()
def test_generate_nginx_react(self, client):
"""Test nginx config generation for React."""
config = {
"stackType": "react",
"webServer": "nginx",
"database": "",
"dbName": "",
"dbUsername": "",
"dbPassword": "",
"domain": "example.com",
"ssl": False,
"sslEmail": "",
"runtime": "",
"processManager": "",
"security": {
"ufw": False,
"fail2ban": False,
"disableRoot": False,
"autoUpdates": False,
},
"advanced": {
"swap": False,
"swapSize": "",
"sshKey": "",
"backups": False,
"monitoring": False,
},
}
response = client.post("/api/v1/generate-nginx-config", json=config)
assert response.status_code == 200
data = response.json()
assert "nginx_config_path" in data
assert "nginx_url" in data
def test_generate_nginx_validation_error(self, client):
"""Test nginx config generation with invalid data."""
config = {"stackType": "invalid_stack", "domain": "example.com"}
response = client.post("/api/v1/generate-nginx-config", json=config)
assert response.status_code == 422 # Validation error
class TestFileDownload:
"""Test cases for file download endpoint."""
def test_download_script_creates_file(self, client):
"""Test that script generation creates a downloadable file."""
# First generate a script
config = {
"stackType": "python",
"webServer": "nginx",
"database": "postgresql",
"dbName": "testdb",
"dbUsername": "testuser",
"dbPassword": "testpassword123",
"domain": "example.com",
"ssl": False,
"runtime": "3.11",
"processManager": "systemd",
}
gen_response = client.post("/api/v1/generate-script", json=config)
assert gen_response.status_code == 200
gen_data = gen_response.json()
# Check that the response contains file URLs
assert "script_url" in gen_data
assert "nginx_url" in gen_data
assert gen_data["script_url"].startswith("/download/")
assert gen_data["nginx_url"].startswith("/download/")
# Extract filename from URL
script_filename = gen_data["script_url"].split("/")[-1]
nginx_filename = gen_data["nginx_url"].split("/")[-1]
# Check that files exist (without actually downloading them
# due to test client issues)
from app.core.config import settings
script_path = settings.generated_dir / script_filename
nginx_path = settings.generated_dir / nginx_filename
assert script_path.exists(), f"Script file {script_filename} was not created"
assert nginx_path.exists(), f"Nginx file {nginx_filename} was not created"
class TestValidation:
"""Test cases for input validation."""
def test_invalid_domain_format(self, client):
"""Test validation of domain format."""
config = {
"stackType": "python",
"webServer": "nginx",
"database": "postgresql",
"dbName": "testdb",
"dbUsername": "testuser",
"dbPassword": "testpassword123",
"domain": "invalid-domain", # Invalid domain format
"ssl": False,
"runtime": "3.11",
"processManager": "systemd",
}
response = client.post("/api/v1/generate-script", json=config)
assert response.status_code == 422
def test_weak_database_password(self, client):
"""Test validation of database password strength."""
config = {
"stackType": "python",
"webServer": "nginx",
"database": "postgresql",
"dbName": "testdb",
"dbUsername": "testuser",
"dbPassword": "123", # Too short
"domain": "example.com",
"ssl": False,
"runtime": "3.11",
"processManager": "systemd",
}
response = client.post("/api/v1/generate-script", json=config)
assert response.status_code == 422
def test_invalid_web_server(self, client):
"""Test validation of web server type."""
config = {
"stackType": "python",
"webServer": "invalid_server",
"database": "postgresql",
"dbName": "testdb",
"dbUsername": "testuser",
"dbPassword": "testpassword123",
"domain": "example.com",
"ssl": False,
"runtime": "3.11",
"processManager": "systemd",
}
response = client.post("/api/v1/generate-script", json=config)
assert response.status_code == 422
def test_invalid_database_type(self, client):
"""Test validation of database type."""
config = {
"stackType": "python",
"webServer": "nginx",
"database": "invalid_db",
"dbName": "testdb",
"dbUsername": "testuser",
"dbPassword": "testpassword123",
"domain": "example.com",
"ssl": False,
"runtime": "3.11",
"processManager": "systemd",
}
response = client.post("/api/v1/generate-script", json=config)
assert response.status_code == 422
class TestEdgeCases:
"""Test cases for edge cases and error handling."""
def test_generate_script_with_all_features(self, client):
"""Test script generation with all security and advanced features enabled."""
config = {
"stackType": "python",
"webServer": "nginx",
"database": "postgresql",
"dbName": "testdb",
"dbUsername": "testuser",
"dbPassword": "testpassword123",
"domain": "example.com",
"ssl": True,
"sslEmail": "test@example.com",
"runtime": "3.11",
"processManager": "systemd",
"security": {
"ufw": True,
"fail2ban": True,
"disableRoot": True,
"autoUpdates": True,
},
"advanced": {
"swap": True,
"swapSize": "4G",
"sshKey": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQ...",
"backups": True,
"monitoring": True,
},
}
response = client.post("/api/v1/generate-script", json=config)
assert response.status_code == 200
data = response.json()
assert "script_path" in data
assert "script_url" in data
def test_generate_script_minimal_config(self, client):
"""Test script generation with minimal required configuration."""
config = {
"stackType": "python",
"webServer": "none",
"database": "none",
"processManager": "none",
}
response = client.post("/api/v1/generate-script", json=config)
assert response.status_code == 200
data = response.json()
assert "script_path" in data
assert "script_url" in data