codeflash-internal/django/aiservice/tests/optimizer/test_javascript_api.py
2026-01-14 22:15:27 -08:00

366 lines
13 KiB
Python

"""
Integration tests for JavaScript optimization API endpoints.
These tests call the actual API endpoints to verify end-to-end functionality.
NOTE: These tests require authentication mocking which is complex due to Django
middleware being instantiated at startup. The tests are marked to skip by default.
Run with: pytest -m integration tests/optimizer/test_javascript_api.py
For actual API testing, use curl or httpie against a running dev server with a valid
API key.
"""
import json
import uuid
from unittest.mock import patch
import pytest
from django.test import AsyncClient
# Mark all tests in this module as integration tests that skip by default
pytestmark = [
pytest.mark.integration,
pytest.mark.skip(reason="Integration tests require running server - run with -m integration --runintegration"),
]
@pytest.fixture
def api_client():
"""Create an async test client."""
return AsyncClient()
@pytest.fixture
def valid_trace_id():
"""Generate a valid UUIDv4 trace ID."""
return str(uuid.uuid4())
@pytest.fixture
def mock_auth(settings):
"""Mock authentication by patching the AuthBearer class method.
Note: This mock is applied but Django middleware is instantiated at startup,
so the mock may not take effect unless the server is restarted after patching.
"""
from authapp.auth import AuthBearer
# Store original authenticate method
original_authenticate = AuthBearer.authenticate
async def fake_authenticate(self, request, token):
request.user = "test-user-123"
request.tier = "pro"
request.api_key_id = 1
request.organization_id = "test-org"
request.should_log_features = False
return token
# Create a mock subscription
class FakeSubscription:
subscription_status = "active"
optimizations_used = 0
optimizations_limit = 1000
total_lifetime_optimizations = 0
plan_type = "pro"
async def asave(self, *args, **kwargs):
return None
class FakeFilter:
async def afirst(self):
return FakeSubscription()
async def aupdate(self, **kwargs):
return 1
# Patch the method on the class (affects all instances)
AuthBearer.authenticate = fake_authenticate
with patch(
"aiservice.middleware.track_usage_middleware.Subscriptions.objects.filter",
return_value=FakeFilter()
):
yield
# Restore original method
AuthBearer.authenticate = original_authenticate
@pytest.fixture
def auth_headers():
"""Headers with authentication token."""
return {"HTTP_AUTHORIZATION": "Bearer test-token-123"}
class TestOptimizeJavaScriptRouting:
"""Test that JavaScript optimization requests are properly routed."""
@pytest.mark.asyncio
@pytest.mark.django_db
async def test_javascript_language_routes_correctly(self, api_client, valid_trace_id, mock_auth, auth_headers):
"""Test that language=javascript routes to JavaScript optimizer."""
response = await api_client.post(
"/ai/optimize/",
data=json.dumps({
"source_code": "function add(a, b) { return a + b; }",
"dependency_code": None,
"trace_id": valid_trace_id,
"language": "javascript",
"language_version": "ES2022",
"n_candidates": 1,
}),
content_type="application/json",
**auth_headers,
)
# The request should be processed (may fail due to LLM mocking,
# but should not fail due to routing)
assert response.status_code in [200, 400, 500]
# If it fails, check that it's not a "not implemented" error
if response.status_code != 200:
data = response.json()
assert "not yet implemented" not in data.get("error", "").lower()
@pytest.mark.asyncio
@pytest.mark.django_db
async def test_typescript_language_routes_correctly(self, api_client, valid_trace_id, mock_auth, auth_headers):
"""Test that language=typescript routes to JavaScript optimizer."""
response = await api_client.post(
"/ai/optimize/",
data=json.dumps({
"source_code": "function add(a: number, b: number): number { return a + b; }",
"dependency_code": None,
"trace_id": valid_trace_id,
"language": "typescript",
"language_version": "ES2022",
"n_candidates": 1,
}),
content_type="application/json",
**auth_headers,
)
assert response.status_code in [200, 400, 500]
if response.status_code != 200:
data = response.json()
assert "not yet implemented" not in data.get("error", "").lower()
@pytest.mark.asyncio
@pytest.mark.django_db
async def test_python_still_works(self, api_client, valid_trace_id, mock_auth, auth_headers):
"""Test that Python optimization still works (backward compatibility)."""
response = await api_client.post(
"/ai/optimize/",
data=json.dumps({
"source_code": "def add(a, b): return a + b",
"dependency_code": None,
"trace_id": valid_trace_id,
"language": "python",
"python_version": "3.11",
"n_candidates": 1,
}),
content_type="application/json",
**auth_headers,
)
assert response.status_code in [200, 400, 500]
@pytest.mark.asyncio
@pytest.mark.django_db
async def test_default_language_is_python(self, api_client, valid_trace_id, mock_auth, auth_headers):
"""Test that omitting language defaults to Python."""
response = await api_client.post(
"/ai/optimize/",
data=json.dumps({
"source_code": "def add(a, b): return a + b",
"dependency_code": None,
"trace_id": valid_trace_id,
"python_version": "3.11",
"n_candidates": 1,
}),
content_type="application/json",
**auth_headers,
)
# Should work as Python (the default)
assert response.status_code in [200, 400, 500]
class TestOptimizeJavaScriptValidation:
"""Test JavaScript-specific validation in the API."""
@pytest.mark.asyncio
@pytest.mark.django_db
async def test_invalid_javascript_syntax_rejected(self, api_client, valid_trace_id, mock_auth, auth_headers):
"""Test that invalid JavaScript syntax is rejected."""
response = await api_client.post(
"/ai/optimize/",
data=json.dumps({
"source_code": "function broken( { return; }", # Invalid syntax
"dependency_code": None,
"trace_id": valid_trace_id,
"language": "javascript",
"n_candidates": 1,
}),
content_type="application/json",
**auth_headers,
)
assert response.status_code == 400
data = response.json()
assert "error" in data
@pytest.mark.asyncio
@pytest.mark.django_db
async def test_empty_source_code_rejected(self, api_client, valid_trace_id, mock_auth, auth_headers):
"""Test that empty source code is rejected."""
response = await api_client.post(
"/ai/optimize/",
data=json.dumps({
"source_code": "",
"dependency_code": None,
"trace_id": valid_trace_id,
"language": "javascript",
"n_candidates": 1,
}),
content_type="application/json",
**auth_headers,
)
assert response.status_code == 400
@pytest.mark.asyncio
@pytest.mark.django_db
async def test_invalid_trace_id_rejected(self, api_client, mock_auth, auth_headers):
"""Test that invalid trace ID is rejected."""
response = await api_client.post(
"/ai/optimize/",
data=json.dumps({
"source_code": "function add(a, b) { return a + b; }",
"dependency_code": None,
"trace_id": "not-a-valid-uuid",
"language": "javascript",
"n_candidates": 1,
}),
content_type="application/json",
**auth_headers,
)
assert response.status_code == 400
data = response.json()
assert "trace" in data.get("error", "").lower() or "uuid" in data.get("error", "").lower()
class TestTestGenJavaScriptRouting:
"""Test that JavaScript test generation requests are properly routed."""
@pytest.mark.asyncio
@pytest.mark.django_db
async def test_javascript_testgen_routes_correctly(self, api_client, valid_trace_id, mock_auth, auth_headers):
"""Test that language=javascript routes to JavaScript testgen."""
response = await api_client.post(
"/ai/testgen/",
data=json.dumps({
"source_code_being_tested": "function add(a, b) { return a + b; }",
"function_to_optimize": {
"function_name": "add",
"file_path": "/test.js",
"parents": [],
"starting_line": 1,
"ending_line": 1,
},
"module_path": "./math",
"test_module_path": "./math.test",
"test_framework": "jest",
"test_timeout": 30,
"trace_id": valid_trace_id,
"language": "javascript",
}),
content_type="application/json",
**auth_headers,
)
assert response.status_code in [200, 400, 500]
if response.status_code != 200:
data = response.json()
assert "not yet implemented" not in data.get("error", "").lower()
@pytest.mark.asyncio
@pytest.mark.django_db
async def test_invalid_test_framework_rejected(self, api_client, valid_trace_id, mock_auth, auth_headers):
"""Test that invalid test framework is rejected for JavaScript."""
response = await api_client.post(
"/ai/testgen/",
data=json.dumps({
"source_code_being_tested": "function add(a, b) { return a + b; }",
"function_to_optimize": {
"function_name": "add",
"file_path": "/test.js",
"parents": [],
"starting_line": 1,
"ending_line": 1,
},
"module_path": "./math",
"test_module_path": "./math.test",
"test_framework": "pytest", # Wrong framework for JS
"test_timeout": 30,
"trace_id": valid_trace_id,
"language": "javascript",
}),
content_type="application/json",
**auth_headers,
)
assert response.status_code == 400
data = response.json()
assert "framework" in data.get("error", "").lower()
class TestSchemaValidation:
"""Test that API schema validation works correctly."""
@pytest.mark.asyncio
@pytest.mark.django_db
async def test_language_field_accepted(self, api_client, valid_trace_id, mock_auth, auth_headers):
"""Test that the language field is accepted in the API."""
response = await api_client.post(
"/ai/optimize/",
data=json.dumps({
"source_code": "const x = 1;",
"dependency_code": None,
"trace_id": valid_trace_id,
"language": "javascript",
"language_version": "ES2022",
"n_candidates": 0, # 0 candidates to avoid LLM call
}),
content_type="application/json",
**auth_headers,
)
# Should not fail schema validation (may fail elsewhere)
assert response.status_code != 422 # 422 = schema validation error
@pytest.mark.asyncio
@pytest.mark.django_db
async def test_language_version_field_accepted(self, api_client, valid_trace_id, mock_auth, auth_headers):
"""Test that the language_version field is accepted in the API."""
response = await api_client.post(
"/ai/optimize/",
data=json.dumps({
"source_code": "const x = 1;",
"dependency_code": None,
"trace_id": valid_trace_id,
"language": "javascript",
"language_version": "ES2020",
"n_candidates": 0,
}),
content_type="application/json",
**auth_headers,
)
assert response.status_code != 422