fix: add Gitea Actions CI workflow for automated testing

This commit is contained in:
CI Bot
2026-02-06 06:37:08 +00:00
parent 40a6a4f7d4
commit 839317c44b
24 changed files with 3115 additions and 0 deletions

1
tests/unit/__init__.py Normal file
View File

@@ -0,0 +1 @@
"""Unit tests for API TestGen."""

182
tests/unit/test_auth.py Normal file
View File

@@ -0,0 +1,182 @@
"""Unit tests for the auth configuration module."""
import pytest
import tempfile
from pathlib import Path
from api_testgen.core.auth import AuthConfig, AuthType
from api_testgen.core.exceptions import AuthConfigError, MissingSecuritySchemeError
class TestAuthConfig:
"""Tests for AuthConfig class."""
def test_add_api_key(self):
"""Test adding API key authentication."""
auth = AuthConfig()
auth.add_api_key("test_api_key", header_name="X-API-Key", api_key="test123")
method = auth.get_auth_method("test_api_key")
assert method is not None
assert method["type"] == AuthType.API_KEY
assert method["header_name"] == "X-API-Key"
assert method["api_key"] == "test123"
def test_add_bearer_token(self):
"""Test adding Bearer token authentication."""
auth = AuthConfig()
auth.add_bearer("test_bearer", token="abc123", token_prefix="Bearer")
method = auth.get_auth_method("test_bearer")
assert method is not None
assert method["type"] == AuthType.BEARER
assert method["token"] == "abc123"
assert method["token_prefix"] == "Bearer"
def test_add_basic_auth(self):
"""Test adding Basic authentication."""
auth = AuthConfig()
auth.add_basic("test_basic", username="user", password="pass")
method = auth.get_auth_method("test_basic")
assert method is not None
assert method["type"] == AuthType.BASIC
assert method["username"] == "user"
assert method["password"] == "pass"
def test_method_chaining(self):
"""Test that add methods return self for chaining."""
auth = AuthConfig()
result = auth.add_api_key("key1")
assert result is auth
result = auth.add_bearer("key2")
assert result is auth
result = auth.add_basic("key3")
assert result is auth
def test_get_all_methods(self):
"""Test getting all configured auth methods."""
auth = AuthConfig()
auth.add_api_key("api_key")
auth.add_bearer("bearer")
methods = auth.get_all_methods()
assert len(methods) == 2
assert "api_key" in methods
assert "bearer" in methods
def test_get_headers_api_key(self):
"""Test getting headers for API key auth."""
auth = AuthConfig()
auth.add_api_key("test", header_name="X-Custom-Key", api_key="mykey")
headers = auth.get_headers("test")
assert headers["X-Custom-Key"] == "mykey"
def test_get_headers_bearer(self):
"""Test getting headers for Bearer auth."""
auth = AuthConfig()
auth.add_bearer("test", token="mytoken", token_prefix="Bearer")
headers = auth.get_headers("test")
assert headers["Authorization"] == "Bearer mytoken"
def test_get_headers_basic(self):
"""Test getting headers for Basic auth."""
import base64
auth = AuthConfig()
auth.add_basic("test", username="user", password="pass")
headers = auth.get_headers("test")
expected = base64.b64encode(b"user:pass").decode()
assert headers["Authorization"] == f"Basic {expected}"
def test_get_headers_unconfigured_scheme_raises_error(self):
"""Test that getting headers for unconfigured scheme raises error."""
auth = AuthConfig()
with pytest.raises(AuthConfigError):
auth.get_headers("nonexistent")
def test_build_from_spec(self):
"""Test building auth config from OpenAPI security schemes."""
auth = AuthConfig()
security_schemes = {
"ApiKeyAuth": {"type": "apiKey", "name": "X-API-Key", "in": "header"},
"BearerAuth": {"type": "http", "scheme": "bearer"},
"BasicAuth": {"type": "http", "scheme": "basic"},
}
security_requirements = [
{"ApiKeyAuth": []},
{"BearerAuth": []},
]
auth.build_from_spec(security_schemes, security_requirements)
assert auth.get_auth_method("ApiKeyAuth") is not None
assert auth.get_auth_method("BearerAuth") is not None
assert auth.get_auth_method("BasicAuth") is None
def test_build_from_spec_missing_scheme_raises_error(self):
"""Test that missing security scheme raises error."""
auth = AuthConfig()
security_schemes = {
"ApiKeyAuth": {"type": "apiKey", "name": "X-API-Key", "in": "header"},
}
security_requirements = [
{"MissingScheme": []},
]
with pytest.raises(MissingSecuritySchemeError):
auth.build_from_spec(security_schemes, security_requirements)
def test_generate_pytest_auth_code(self):
"""Test generating pytest authentication code."""
auth = AuthConfig()
auth.add_api_key("test_key", header_name="X-Api-Key", api_key="key123")
code = auth.generate_auth_code("test_key", "pytest")
assert "X-Api-Key" in code
assert "key123" in code
def test_generate_jest_auth_code(self):
"""Test generating Jest authentication code."""
auth = AuthConfig()
auth.add_bearer("test_bearer", token="token123")
code = auth.generate_auth_code("test_bearer", "jest")
assert "Authorization" in code
assert "token123" in code
def test_generate_go_auth_code(self):
"""Test generating Go authentication code."""
auth = AuthConfig()
auth.add_api_key("test_key", header_name="X-Api-Key")
code = auth.generate_auth_code("test_key", "go")
assert "X-Api-Key" in code
def test_generate_auth_code_unconfigured_scheme(self):
"""Test generating auth code for unconfigured scheme returns empty."""
auth = AuthConfig()
code = auth.generate_auth_code("nonexistent", "pytest")
assert code == ""

View File

@@ -0,0 +1,223 @@
"""Unit tests for the generator modules."""
import pytest
import tempfile
import os
from pathlib import Path
from api_testgen.core import SpecParser
from api_testgen.generators import PytestGenerator, JestGenerator, GoGenerator
from api_testgen.mocks import MockServerGenerator
class TestPytestGenerator:
"""Tests for PytestGenerator class."""
@pytest.fixture
def parser(self, sample_openapi_spec):
"""Create a spec parser with sample spec."""
with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f:
import yaml
yaml.dump(sample_openapi_spec, f)
parser = SpecParser(Path(f.name))
parser.load()
return parser
def test_generate_creates_file(self, parser, tmp_path):
"""Test that generate creates a test file."""
generator = PytestGenerator(parser, output_dir=str(tmp_path))
files = generator.generate()
assert len(files) == 1
assert files[0].exists()
assert files[0].suffix == ".py"
def test_generate_content_contains_tests(self, parser, tmp_path):
"""Test that generated file contains test functions."""
generator = PytestGenerator(parser, output_dir=str(tmp_path))
files = generator.generate()
content = files[0].read_text()
assert "test_" in content
assert "BASE_URL" in content
assert "def test_" in content
def test_generate_with_custom_output_file(self, parser, tmp_path):
"""Test generating to a specific file path."""
generator = PytestGenerator(parser, output_dir=str(tmp_path))
files = generator.generate(output_file=str(tmp_path / "custom_test.py"))
assert len(files) == 1
assert files[0].name == "custom_test.py"
def test_generate_endpoint_test(self, parser):
"""Test generating a single endpoint test."""
generator = PytestGenerator(parser)
test_code = generator.generate_endpoint_tests("/pets", "get")
assert "test_" in test_code
assert "requests.get" in test_code
def test_generate_test_name(self, parser):
"""Test test name generation."""
generator = PytestGenerator(parser)
name = generator._generate_test_name({
"path": "/pets",
"method": "get",
"summary": "List all pets",
})
assert name == "get_pets" or "pets" in name
class TestJestGenerator:
"""Tests for JestGenerator class."""
@pytest.fixture
def parser(self, sample_openapi_spec):
"""Create a spec parser with sample spec."""
with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f:
import yaml
yaml.dump(sample_openapi_spec, f)
parser = SpecParser(Path(f.name))
parser.load()
return parser
def test_generate_creates_file(self, parser, tmp_path):
"""Test that generate creates a test file."""
generator = JestGenerator(parser, output_dir=str(tmp_path))
files = generator.generate()
assert len(files) == 1
assert files[0].exists()
assert files[0].suffix == ".js"
def test_generate_content_contains_describe(self, parser, tmp_path):
"""Test that generated file contains describe blocks."""
generator = JestGenerator(parser, output_dir=str(tmp_path))
files = generator.generate()
content = files[0].read_text()
assert "describe" in content
expect_in = "expect" in content or "toContain" in content or "toBe" in content
assert expect_in
def test_generate_endpoint_test(self, parser):
"""Test generating a single endpoint test."""
generator = JestGenerator(parser)
test_code = generator.generate_endpoint_tests("/pets", "get")
assert "describe" in test_code or "it(" in test_code
class TestGoGenerator:
"""Tests for GoGenerator class."""
@pytest.fixture
def parser(self, sample_openapi_spec):
"""Create a spec parser with sample spec."""
with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f:
import yaml
yaml.dump(sample_openapi_spec, f)
parser = SpecParser(Path(f.name))
parser.load()
return parser
def test_generate_creates_file(self, parser, tmp_path):
"""Test that generate creates a test file."""
generator = GoGenerator(parser, output_dir=str(tmp_path))
files = generator.generate()
assert len(files) == 1
assert files[0].exists()
assert files[0].name.endswith("_test.go")
def test_generate_content_contains_tests(self, parser, tmp_path):
"""Test that generated file contains test functions."""
generator = GoGenerator(parser, output_dir=str(tmp_path))
files = generator.generate()
content = files[0].read_text()
assert "func Test" in content
assert "http.Client" in content or "http.NewRequest" in content
def test_generate_with_custom_package(self, parser, tmp_path):
"""Test generating with custom package name."""
generator = GoGenerator(parser, output_dir=str(tmp_path), package_name="custompkg")
files = generator.generate()
content = files[0].read_text()
assert "package custompkg" in content
class TestMockServerGenerator:
"""Tests for MockServerGenerator class."""
@pytest.fixture
def parser(self, sample_openapi_spec):
"""Create a spec parser with sample spec."""
with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f:
import yaml
yaml.dump(sample_openapi_spec, f)
parser = SpecParser(Path(f.name))
parser.load()
return parser
def test_generate_prism_config(self, parser, tmp_path):
"""Test generating Prism configuration."""
generator = MockServerGenerator(parser, output_dir=str(tmp_path))
file = generator.generate_prism_config()
assert file.exists()
assert file.name == "prism-config.json"
content = file.read_text()
import json
config = json.loads(content)
assert "mock" in config
assert "port" in config["mock"]
def test_generate_docker_compose(self, parser, tmp_path):
"""Test generating Docker Compose configuration."""
generator = MockServerGenerator(parser, output_dir=str(tmp_path))
file = generator.generate_docker_compose()
assert file.exists()
assert file.name == "docker-compose.yml"
content = file.read_text()
assert "services" in content
assert "mock-server" in content
def test_generate_dockerfile(self, parser, tmp_path):
"""Test generating Dockerfile."""
generator = MockServerGenerator(parser, output_dir=str(tmp_path))
file = generator.generate_dockerfile()
assert file.exists()
assert file.name == "Dockerfile"
content = file.read_text()
assert "FROM" in content
assert "prism" in content.lower()
def test_generate_all(self, parser, tmp_path):
"""Test generating all mock server files."""
generator = MockServerGenerator(parser, output_dir=str(tmp_path))
files = generator.generate()
assert len(files) == 3
file_names = [f.name for f in files]
assert "prism-config.json" in file_names
assert "docker-compose.yml" in file_names
assert "Dockerfile" in file_names

View File

@@ -0,0 +1,173 @@
"""Unit tests for the spec parser module."""
import pytest
import tempfile
import json
from pathlib import Path
from api_testgen.core import SpecParser
from api_testgen.core.exceptions import InvalidOpenAPISpecError, UnsupportedVersionError
class TestSpecParser:
"""Tests for SpecParser class."""
def test_load_valid_openapi_30_spec(self, temp_spec_file):
"""Test loading a valid OpenAPI 3.0 specification."""
parser = SpecParser(temp_spec_file)
spec = parser.load()
assert spec is not None
assert parser.version == "3.0.0"
assert parser.base_path == ""
assert len(parser.servers) == 1
def test_load_valid_json_spec(self, temp_json_spec_file):
"""Test loading a valid JSON OpenAPI specification."""
parser = SpecParser(temp_json_spec_file)
spec = parser.load()
assert spec is not None
assert parser.version == "3.0.0"
def test_get_info(self, temp_spec_file):
"""Test extracting API info from spec."""
parser = SpecParser(temp_spec_file)
parser.load()
info = parser.get_info()
assert info["title"] == "Test Pet Store API"
assert info["version"] == "1.0.0"
assert "sample" in info["description"].lower()
def test_get_paths(self, temp_spec_file):
"""Test extracting paths from spec."""
parser = SpecParser(temp_spec_file)
parser.load()
paths = parser.get_paths()
assert "/pets" in paths
assert "/pets/{petId}" in paths
def test_get_endpoints(self, temp_spec_file):
"""Test extracting endpoints from spec."""
parser = SpecParser(temp_spec_file)
parser.load()
endpoints = parser.get_endpoints()
assert len(endpoints) == 4
assert any(e["method"] == "get" and e["path"] == "/pets" for e in endpoints)
assert any(e["method"] == "post" and e["path"] == "/pets" for e in endpoints)
assert any(e["method"] == "get" and e["path"] == "/pets/{petId}" for e in endpoints)
assert any(e["method"] == "delete" and e["path"] == "/pets/{petId}" for e in endpoints)
def test_get_security_schemes(self, temp_spec_file):
"""Test extracting security schemes from spec."""
parser = SpecParser(temp_spec_file)
parser.load()
schemes = parser.get_security_schemes()
assert "ApiKeyAuth" in schemes
assert "BearerAuth" in schemes
assert schemes["ApiKeyAuth"]["type"] == "apiKey"
assert schemes["BearerAuth"]["type"] == "http"
assert schemes["BearerAuth"]["scheme"] == "bearer"
def test_get_definitions(self, temp_spec_file):
"""Test extracting schema definitions from spec."""
parser = SpecParser(temp_spec_file)
parser.load()
definitions = parser.get_definitions()
assert "Pet" in definitions
assert definitions["Pet"]["type"] == "object"
def test_endpoint_with_parameters(self, temp_spec_file):
"""Test endpoint parameter extraction."""
parser = SpecParser(temp_spec_file)
parser.load()
endpoints = parser.get_endpoints()
pets_endpoint = next(e for e in endpoints if e["path"] == "/pets" and e["method"] == "get")
assert len(pets_endpoint["parameters"]) == 2
assert any(p["name"] == "limit" and p["in"] == "query" for p in pets_endpoint["parameters"])
assert any(p["name"] == "status" and p["in"] == "query" for p in pets_endpoint["parameters"])
def test_endpoint_with_path_parameters(self, temp_spec_file):
"""Test path parameter extraction."""
parser = SpecParser(temp_spec_file)
parser.load()
endpoints = parser.get_endpoints()
pet_endpoint = next(e for e in endpoints if e["path"] == "/pets/{petId}" and e["method"] == "get")
assert len(pet_endpoint["parameters"]) == 1
param = pet_endpoint["parameters"][0]
assert param["name"] == "petId"
assert param["in"] == "path"
assert param["required"] is True
def test_endpoint_with_request_body(self, temp_spec_file):
"""Test request body extraction for OpenAPI 3.0."""
parser = SpecParser(temp_spec_file)
parser.load()
endpoints = parser.get_endpoints()
create_endpoint = next(e for e in endpoints if e["path"] == "/pets" and e["method"] == "post")
assert create_endpoint["request_body"] is not None
assert create_endpoint["request_body"]["required"] is True
def test_endpoint_with_responses(self, temp_spec_file):
"""Test response extraction."""
parser = SpecParser(temp_spec_file)
parser.load()
endpoints = parser.get_endpoints()
pets_endpoint = next(e for e in endpoints if e["path"] == "/pets" and e["method"] == "get")
assert "200" in pets_endpoint["responses"]
assert pets_endpoint["responses"]["200"]["description"] == "A list of pets"
def test_to_dict(self, temp_spec_file):
"""Test dictionary representation of parsed spec."""
parser = SpecParser(temp_spec_file)
parser.load()
spec_dict = parser.to_dict()
assert "version" in spec_dict
assert "info" in spec_dict
assert "paths" in spec_dict
assert "endpoints" in spec_dict
assert "security_schemes" in spec_dict
assert "definitions" in spec_dict
def test_nonexistent_file_raises_error(self):
"""Test that nonexistent file raises InvalidOpenAPISpecError."""
parser = SpecParser("/nonexistent/path/spec.yaml")
with pytest.raises(InvalidOpenAPISpecError):
parser.load()
def test_invalid_yaml_raises_error(self):
"""Test that invalid YAML raises InvalidOpenAPISpecError."""
with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f:
f.write("invalid: yaml: content: [[[")
f.flush()
parser = SpecParser(Path(f.name))
with pytest.raises(InvalidOpenAPISpecError):
parser.load()
Path(f.name).unlink()