Spaces:
Running
Running
| """ | |
| Comprehensive tests for the DevOps Toolkit API. | |
| """ | |
| import pytest | |
| from fastapi.testclient import TestClient | |
| from app.main import app | |
| 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 | |