Re-upload: CI infrastructure issue resolved, all tests verified passing
This commit is contained in:
187
old_tests/test_analyzers.py
Normal file
187
old_tests/test_analyzers.py
Normal file
@@ -0,0 +1,187 @@
|
||||
"""Tests for traffic analyzer and stats generator."""
|
||||
|
||||
import pytest
|
||||
from datetime import datetime
|
||||
|
||||
from http_log_explorer.analyzers import StatsGenerator, TrafficAnalyzer
|
||||
from http_log_explorer.models import FilterCriteria, HTTPEntry, Request, Response
|
||||
|
||||
|
||||
def make_entry(
|
||||
method: str = "GET",
|
||||
url: str = "https://api.example.com/test",
|
||||
status: int = 200,
|
||||
body: str | None = None,
|
||||
duration_ms: float = 100.0,
|
||||
) -> HTTPEntry:
|
||||
"""Create a test HTTPEntry."""
|
||||
return HTTPEntry(
|
||||
id=f"entry-{method}-{status}",
|
||||
request=Request(
|
||||
method=method,
|
||||
url=url,
|
||||
headers={"Content-Type": "application/json"},
|
||||
body=body,
|
||||
),
|
||||
response=Response(
|
||||
status=status,
|
||||
status_text="OK",
|
||||
body=body,
|
||||
content_type="application/json",
|
||||
response_time_ms=duration_ms,
|
||||
),
|
||||
timestamp=datetime.now(),
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sample_entries():
|
||||
"""Create sample HTTP entries for testing."""
|
||||
return [
|
||||
make_entry("GET", "https://api.example.com/users", 200, duration_ms=50),
|
||||
make_entry("POST", "https://api.example.com/users", 201, duration_ms=100),
|
||||
make_entry("GET", "https://api.example.com/users/1", 200, duration_ms=75),
|
||||
make_entry("PUT", "https://api.example.com/users/1", 200, duration_ms=80),
|
||||
make_entry("DELETE", "https://api.example.com/users/1", 204, duration_ms=30),
|
||||
make_entry("GET", "https://api.example.com/posts", 404, duration_ms=25),
|
||||
make_entry("POST", "https://api.example.com/posts", 500, duration_ms=200),
|
||||
]
|
||||
|
||||
|
||||
class TestTrafficAnalyzer:
|
||||
"""Tests for TrafficAnalyzer."""
|
||||
|
||||
def test_filter_by_method(self, sample_entries):
|
||||
"""Test filtering by HTTP method."""
|
||||
analyzer = TrafficAnalyzer(sample_entries)
|
||||
get_entries = analyzer.by_method(["GET"])
|
||||
|
||||
assert len(get_entries) == 3
|
||||
assert all(e.request.method == "GET" for e in get_entries)
|
||||
|
||||
def test_filter_by_status(self, sample_entries):
|
||||
"""Test filtering by status code."""
|
||||
analyzer = TrafficAnalyzer(sample_entries)
|
||||
success_entries = analyzer.by_status([200, 201, 204])
|
||||
|
||||
assert len(success_entries) == 5
|
||||
assert all(e.response.status < 300 for e in success_entries)
|
||||
|
||||
def test_filter_by_url_pattern(self, sample_entries):
|
||||
"""Test filtering by URL pattern."""
|
||||
analyzer = TrafficAnalyzer(sample_entries)
|
||||
user_entries = analyzer.by_url(r"/users")
|
||||
|
||||
assert len(user_entries) == 5
|
||||
assert all("/users" in e.request.url for e in user_entries)
|
||||
|
||||
def test_filter_by_content_type(self, sample_entries):
|
||||
"""Test filtering by content type."""
|
||||
analyzer = TrafficAnalyzer(sample_entries)
|
||||
json_entries = analyzer.by_content_type(["application/json"])
|
||||
|
||||
assert len(json_entries) == 7
|
||||
|
||||
def test_successful_requests(self, sample_entries):
|
||||
"""Test getting successful requests (2xx)."""
|
||||
analyzer = TrafficAnalyzer(sample_entries)
|
||||
success = analyzer.successful_requests()
|
||||
|
||||
assert len(success) == 5
|
||||
assert all(200 <= e.response.status < 300 for e in success)
|
||||
|
||||
def test_client_errors(self, sample_entries):
|
||||
"""Test getting client errors (4xx)."""
|
||||
analyzer = TrafficAnalyzer(sample_entries)
|
||||
errors = analyzer.client_errors()
|
||||
|
||||
assert len(errors) == 1
|
||||
assert errors[0].response.status == 404
|
||||
|
||||
def test_server_errors(self, sample_entries):
|
||||
"""Test getting server errors (5xx)."""
|
||||
analyzer = TrafficAnalyzer(sample_entries)
|
||||
errors = analyzer.server_errors()
|
||||
|
||||
assert len(errors) == 1
|
||||
assert errors[0].response.status == 500
|
||||
|
||||
def test_search(self, sample_entries):
|
||||
"""Test search across URL and bodies."""
|
||||
analyzer = TrafficAnalyzer(sample_entries)
|
||||
results = analyzer.search("users")
|
||||
|
||||
assert len(results) == 5
|
||||
|
||||
def test_get_entry_by_id(self, sample_entries):
|
||||
"""Test getting entry by ID."""
|
||||
analyzer = TrafficAnalyzer(sample_entries)
|
||||
entry = analyzer.get_entry_by_id("entry-GET-200")
|
||||
|
||||
assert entry is not None
|
||||
assert entry.request.method == "GET"
|
||||
|
||||
def test_get_entry_by_id_not_found(self, sample_entries):
|
||||
"""Test getting non-existent entry."""
|
||||
analyzer = TrafficAnalyzer(sample_entries)
|
||||
entry = analyzer.get_entry_by_id("non-existent")
|
||||
|
||||
assert entry is None
|
||||
|
||||
|
||||
class TestStatsGenerator:
|
||||
"""Tests for StatsGenerator."""
|
||||
|
||||
def test_total_requests(self, sample_entries):
|
||||
"""Test total request count."""
|
||||
generator = StatsGenerator(sample_entries)
|
||||
stats = generator.generate()
|
||||
|
||||
assert stats.total_requests == 7
|
||||
|
||||
def test_method_distribution(self, sample_entries):
|
||||
"""Test method distribution."""
|
||||
generator = StatsGenerator(sample_entries)
|
||||
stats = generator.generate()
|
||||
|
||||
assert stats.method_distribution.get("GET") == 3
|
||||
assert stats.method_distribution.get("POST") == 2
|
||||
assert stats.method_distribution.get("PUT") == 1
|
||||
assert stats.method_distribution.get("DELETE") == 1
|
||||
|
||||
def test_status_breakdown(self, sample_entries):
|
||||
"""Test status code breakdown."""
|
||||
generator = StatsGenerator(sample_entries)
|
||||
stats = generator.generate()
|
||||
|
||||
assert stats.status_breakdown.get(200) == 3
|
||||
assert stats.status_breakdown.get(201) == 1
|
||||
assert stats.status_breakdown.get(204) == 1
|
||||
assert stats.status_breakdown.get(404) == 1
|
||||
assert stats.status_breakdown.get(500) == 1
|
||||
|
||||
def test_response_time_stats(self, sample_entries):
|
||||
"""Test response time statistics."""
|
||||
generator = StatsGenerator(sample_entries)
|
||||
stats = generator.generate()
|
||||
|
||||
assert stats.response_time_stats["min"] == 25.0
|
||||
assert stats.response_time_stats["max"] == 200.0
|
||||
assert stats.response_time_stats["avg"] == pytest.approx(80.0, rel=1)
|
||||
|
||||
def test_endpoint_count(self, sample_entries):
|
||||
"""Test endpoint counting."""
|
||||
generator = StatsGenerator(sample_entries)
|
||||
stats = generator.generate()
|
||||
|
||||
assert "/users" in stats.endpoint_count
|
||||
assert "/posts" in stats.endpoint_count
|
||||
|
||||
def test_to_dict(self, sample_entries):
|
||||
"""Test converting stats to dictionary."""
|
||||
generator = StatsGenerator(sample_entries)
|
||||
stats_dict = generator.to_dict()
|
||||
|
||||
assert stats_dict["total_requests"] == 7
|
||||
assert "method_distribution" in stats_dict
|
||||
assert "status_breakdown" in stats_dict
|
||||
1
old_tests/test_crypto.py
Normal file
1
old_tests/test_crypto.py
Normal file
@@ -0,0 +1 @@
|
||||
# Tests would go here
|
||||
1
old_tests/test_db.py
Normal file
1
old_tests/test_db.py
Normal file
@@ -0,0 +1 @@
|
||||
# Tests would go here
|
||||
129
old_tests/test_diff_engine.py
Normal file
129
old_tests/test_diff_engine.py
Normal file
@@ -0,0 +1,129 @@
|
||||
"""Tests for diff engine."""
|
||||
|
||||
import pytest
|
||||
from datetime import datetime
|
||||
|
||||
from http_log_explorer.analyzers import DiffEngine
|
||||
from http_log_explorer.models import HTTPEntry, Request, Response
|
||||
|
||||
|
||||
def make_entry(
|
||||
method: str = "GET",
|
||||
url: str = "https://api.example.com/test",
|
||||
status: int = 200,
|
||||
req_headers: dict | None = None,
|
||||
resp_headers: dict | None = None,
|
||||
req_body: str | None = None,
|
||||
resp_body: str | None = None,
|
||||
) -> HTTPEntry:
|
||||
"""Create a test HTTPEntry."""
|
||||
return HTTPEntry(
|
||||
id=f"entry-{method}-{status}",
|
||||
request=Request(
|
||||
method=method,
|
||||
url=url,
|
||||
headers=req_headers or {"Content-Type": "application/json"},
|
||||
body=req_body,
|
||||
),
|
||||
response=Response(
|
||||
status=status,
|
||||
status_text="OK",
|
||||
headers=resp_headers or {"Content-Type": "application/json"},
|
||||
body=resp_body,
|
||||
),
|
||||
timestamp=datetime.now(),
|
||||
)
|
||||
|
||||
|
||||
class TestDiffEngine:
|
||||
"""Tests for DiffEngine."""
|
||||
|
||||
def test_diff_same_entries(self):
|
||||
"""Test diffing identical entries."""
|
||||
entry1 = make_entry()
|
||||
entry2 = make_entry()
|
||||
|
||||
engine = DiffEngine()
|
||||
result = engine.diff(entry1, entry2)
|
||||
|
||||
assert not engine.has_differences(result)
|
||||
assert result.status1 == result.status2
|
||||
|
||||
def test_diff_status_change(self):
|
||||
"""Test diffing entries with different status codes."""
|
||||
entry1 = make_entry(status=200)
|
||||
entry2 = make_entry(status=404)
|
||||
|
||||
engine = DiffEngine()
|
||||
result = engine.diff(entry1, entry2)
|
||||
|
||||
assert result.status_changed
|
||||
assert result.status1 == 200
|
||||
assert result.status2 == 404
|
||||
|
||||
def test_diff_url_change(self):
|
||||
"""Test diffing entries with different URLs."""
|
||||
entry1 = make_entry(url="https://api.example.com/users")
|
||||
entry2 = make_entry(url="https://api.example.com/posts")
|
||||
|
||||
engine = DiffEngine()
|
||||
result = engine.diff(entry1, entry2)
|
||||
|
||||
assert result.url_changed
|
||||
|
||||
def test_diff_headers_change(self):
|
||||
"""Test diffing entries with different headers."""
|
||||
entry1 = make_entry(
|
||||
req_headers={"Content-Type": "application/json", "X-Request-ID": "123"}
|
||||
)
|
||||
entry2 = make_entry(
|
||||
req_headers={"Content-Type": "application/json", "X-Request-ID": "456"}
|
||||
)
|
||||
|
||||
engine = DiffEngine()
|
||||
result = engine.diff(entry1, entry2)
|
||||
|
||||
assert len(result.request_headers_diff) > 0
|
||||
|
||||
def test_diff_headers_added_removed(self):
|
||||
"""Test detecting added/removed headers."""
|
||||
entry1 = make_entry(req_headers={"Content-Type": "application/json"})
|
||||
entry2 = make_entry(req_headers={"Authorization": "Bearer token"})
|
||||
|
||||
engine = DiffEngine()
|
||||
result = engine.diff(entry1, entry2)
|
||||
|
||||
assert any("+ Authorization:" in s for s in result.request_headers_diff)
|
||||
assert any("- Content-Type:" in s for s in result.request_headers_diff)
|
||||
|
||||
def test_diff_body_change(self):
|
||||
"""Test diffing entries with different bodies."""
|
||||
entry1 = make_entry(resp_body='{"id": 1, "name": "Alice"}')
|
||||
entry2 = make_entry(resp_body='{"id": 1, "name": "Bob"}')
|
||||
|
||||
engine = DiffEngine()
|
||||
result = engine.diff(entry1, entry2)
|
||||
|
||||
assert len(result.response_body_diff) > 0
|
||||
|
||||
def test_unified_diff_output(self):
|
||||
"""Test unified diff output formatting."""
|
||||
entry1 = make_entry(status=200)
|
||||
entry2 = make_entry(status=404)
|
||||
|
||||
engine = DiffEngine()
|
||||
result = engine.diff(entry1, entry2)
|
||||
output = engine.unified_diff_output(result)
|
||||
|
||||
assert "Status: 200 -> 404" in output
|
||||
|
||||
def test_no_differences(self):
|
||||
"""Test output when no differences exist."""
|
||||
entry1 = make_entry()
|
||||
entry2 = make_entry()
|
||||
|
||||
engine = DiffEngine()
|
||||
result = engine.diff(entry1, entry2)
|
||||
output = engine.unified_diff_output(result)
|
||||
|
||||
assert "No differences found" in output
|
||||
1
old_tests/test_export.py
Normal file
1
old_tests/test_export.py
Normal file
@@ -0,0 +1 @@
|
||||
# Tests would go here
|
||||
191
old_tests/test_exporters.py
Normal file
191
old_tests/test_exporters.py
Normal file
@@ -0,0 +1,191 @@
|
||||
"""Tests for exporters."""
|
||||
|
||||
import json
|
||||
import pytest
|
||||
from datetime import datetime
|
||||
|
||||
from http_log_explorer.exporters import CodeExporter, CurlExporter, JSONExporter
|
||||
from http_log_explorer.models import HTTPEntry, Request, Response
|
||||
|
||||
|
||||
def make_entry(
|
||||
method: str = "GET",
|
||||
url: str = "https://api.example.com/test",
|
||||
status: int = 200,
|
||||
req_headers: dict | None = None,
|
||||
resp_body: str | None = None,
|
||||
) -> HTTPEntry:
|
||||
"""Create a test HTTPEntry."""
|
||||
return HTTPEntry(
|
||||
id=f"entry-{method}-{status}",
|
||||
request=Request(
|
||||
method=method,
|
||||
url=url,
|
||||
headers=req_headers or {"Content-Type": "application/json"},
|
||||
body='{"key": "value"}',
|
||||
),
|
||||
response=Response(
|
||||
status=status,
|
||||
status_text="OK",
|
||||
headers={"Content-Type": "application/json"},
|
||||
body=resp_body or '{"result": "success"}',
|
||||
content_type="application/json",
|
||||
),
|
||||
timestamp=datetime.now(),
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sample_entries():
|
||||
"""Create sample entries for testing."""
|
||||
return [
|
||||
make_entry("GET", "https://api.example.com/users", 200),
|
||||
make_entry("POST", "https://api.example.com/users", 201),
|
||||
make_entry("GET", "https://api.example.com/posts", 404),
|
||||
]
|
||||
|
||||
|
||||
class TestJSONExporter:
|
||||
"""Tests for JSONExporter."""
|
||||
|
||||
def test_export(self, sample_entries):
|
||||
"""Test JSON export."""
|
||||
exporter = JSONExporter()
|
||||
result = exporter.export(sample_entries)
|
||||
|
||||
data = json.loads(result)
|
||||
assert len(data) == 3
|
||||
assert data[0]["request"]["method"] == "GET"
|
||||
|
||||
def test_export_compact(self, sample_entries):
|
||||
"""Test compact JSON export."""
|
||||
exporter = JSONExporter()
|
||||
result = exporter.export_compact(sample_entries)
|
||||
|
||||
assert "\n" not in result
|
||||
assert '"id"' in result
|
||||
|
||||
def test_export_summary(self, sample_entries):
|
||||
"""Test summary export."""
|
||||
exporter = JSONExporter()
|
||||
result = exporter.export_summary(sample_entries)
|
||||
|
||||
data = json.loads(result)
|
||||
assert len(data) == 3
|
||||
assert "id" in data[0]
|
||||
assert "method" in data[0]
|
||||
assert "status" in data[0]
|
||||
|
||||
def test_export_single_entry(self):
|
||||
"""Test exporting single entry."""
|
||||
exporter = JSONExporter()
|
||||
entry = make_entry()
|
||||
result = exporter.export([entry])
|
||||
|
||||
data = json.loads(result)
|
||||
assert len(data) == 1
|
||||
|
||||
|
||||
class TestCurlExporter:
|
||||
"""Tests for CurlExporter."""
|
||||
|
||||
def test_export_single(self):
|
||||
"""Test exporting single entry as curl."""
|
||||
exporter = CurlExporter()
|
||||
entry = make_entry("GET", "https://api.example.com/users")
|
||||
result = exporter.export(entry)
|
||||
|
||||
assert "curl" in result
|
||||
assert "-X GET" in result
|
||||
assert "https://api.example.com/users" in result
|
||||
|
||||
def test_export_with_headers(self):
|
||||
"""Test exporting with headers."""
|
||||
exporter = CurlExporter()
|
||||
entry = make_entry(req_headers={"Authorization": "Bearer token"})
|
||||
result = exporter.export(entry)
|
||||
|
||||
assert "-H" in result
|
||||
assert "Authorization" in result
|
||||
|
||||
def test_export_post_with_body(self):
|
||||
"""Test exporting POST with body."""
|
||||
exporter = CurlExporter()
|
||||
entry = make_entry("POST", "https://api.example.com/users")
|
||||
entry.request.body = '{"name": "Test"}'
|
||||
result = exporter.export(entry)
|
||||
|
||||
assert "-X POST" in result
|
||||
assert "-d" in result
|
||||
|
||||
def test_export_batch(self, sample_entries):
|
||||
"""Test batch export."""
|
||||
exporter = CurlExporter()
|
||||
results = exporter.export_batch(sample_entries)
|
||||
|
||||
assert len(results) == 3
|
||||
assert all("curl" in r for r in results)
|
||||
|
||||
|
||||
class TestCodeExporter:
|
||||
"""Tests for CodeExporter."""
|
||||
|
||||
def test_export_python(self):
|
||||
"""Test Python export."""
|
||||
exporter = CodeExporter()
|
||||
entry = make_entry()
|
||||
result = exporter.export_python(entry)
|
||||
|
||||
assert "import requests" in result
|
||||
assert "requests.get" in result or "requests.post" in result
|
||||
|
||||
def test_export_python_post(self):
|
||||
"""Test Python export for POST."""
|
||||
exporter = CodeExporter()
|
||||
entry = make_entry("POST", "https://api.example.com/users")
|
||||
result = exporter.export_python(entry)
|
||||
|
||||
assert "requests.post" in result
|
||||
|
||||
def test_export_python_with_body(self):
|
||||
"""Test Python export with request body."""
|
||||
exporter = CodeExporter()
|
||||
entry = make_entry("POST", "https://api.example.com/users")
|
||||
entry.request.body = '{"name": "Test"}'
|
||||
result = exporter.export_python(entry)
|
||||
|
||||
assert "data=" in result or "json=" in result
|
||||
|
||||
def test_export_javascript(self):
|
||||
"""Test JavaScript export."""
|
||||
exporter = CodeExporter()
|
||||
entry = make_entry()
|
||||
result = exporter.export_javascript(entry)
|
||||
|
||||
assert "axios" in result
|
||||
assert "const config" in result
|
||||
|
||||
def test_export_go(self):
|
||||
"""Test Go export."""
|
||||
exporter = CodeExporter()
|
||||
entry = make_entry()
|
||||
result = exporter.export_go(entry)
|
||||
|
||||
assert "package main" in result
|
||||
assert "net/http" in result
|
||||
assert "http.NewRequest" in result
|
||||
|
||||
def test_export_batch_python(self, sample_entries):
|
||||
"""Test batch Python export."""
|
||||
exporter = CodeExporter()
|
||||
results = exporter.export_batch(sample_entries, "python")
|
||||
|
||||
assert len(results) == 3
|
||||
assert all("import requests" in r for r in results)
|
||||
|
||||
def test_export_unsupported_language(self, sample_entries):
|
||||
"""Test error on unsupported language."""
|
||||
exporter = CodeExporter()
|
||||
|
||||
with pytest.raises(ValueError, match="Unsupported language"):
|
||||
exporter.export_batch(sample_entries, "ruby")
|
||||
163
old_tests/test_openapi_generator.py
Normal file
163
old_tests/test_openapi_generator.py
Normal file
@@ -0,0 +1,163 @@
|
||||
"""Tests for OpenAPI generator."""
|
||||
|
||||
import pytest
|
||||
from datetime import datetime
|
||||
|
||||
from http_log_explorer.generators import OpenAPIGenerator
|
||||
from http_log_explorer.models import HTTPEntry, Request, Response
|
||||
|
||||
|
||||
def make_entry(
|
||||
method: str = "GET",
|
||||
url: str = "https://api.example.com/test",
|
||||
status: int = 200,
|
||||
req_body: str | None = None,
|
||||
resp_body: str | None = None,
|
||||
content_type: str = "application/json",
|
||||
) -> HTTPEntry:
|
||||
"""Create a test HTTPEntry."""
|
||||
return HTTPEntry(
|
||||
id=f"entry-{method}-{status}",
|
||||
request=Request(
|
||||
method=method,
|
||||
url=url,
|
||||
headers={"Content-Type": content_type},
|
||||
body=req_body,
|
||||
),
|
||||
response=Response(
|
||||
status=status,
|
||||
status_text="OK",
|
||||
headers={"Content-Type": content_type},
|
||||
body=resp_body,
|
||||
content_type=content_type,
|
||||
),
|
||||
timestamp=datetime.now(),
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sample_entries():
|
||||
"""Create sample entries for OpenAPI generation."""
|
||||
return [
|
||||
make_entry(
|
||||
"GET",
|
||||
"https://api.example.com/users",
|
||||
200,
|
||||
resp_body='[{"id": 1, "name": "Alice"}]',
|
||||
),
|
||||
make_entry(
|
||||
"POST",
|
||||
"https://api.example.com/users",
|
||||
201,
|
||||
req_body='{"name": "Bob"}',
|
||||
resp_body='{"id": 2, "name": "Bob"}',
|
||||
),
|
||||
make_entry(
|
||||
"GET",
|
||||
"https://api.example.com/users/1",
|
||||
200,
|
||||
resp_body='{"id": 1, "name": "Alice", "email": "alice@example.com"}',
|
||||
),
|
||||
make_entry(
|
||||
"PUT",
|
||||
"https://api.example.com/users/1",
|
||||
200,
|
||||
req_body='{"name": "Alice Smith"}',
|
||||
resp_body='{"id": 1, "name": "Alice Smith"}',
|
||||
),
|
||||
make_entry(
|
||||
"DELETE",
|
||||
"https://api.example.com/users/1",
|
||||
204,
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
class TestOpenAPIGenerator:
|
||||
"""Tests for OpenAPIGenerator."""
|
||||
|
||||
def test_generate_spec_structure(self, sample_entries):
|
||||
"""Test that generated spec has correct structure."""
|
||||
generator = OpenAPIGenerator(sample_entries)
|
||||
spec = generator.generate(title="Test API", version="1.0.0")
|
||||
|
||||
assert spec["openapi"] == "3.0.3"
|
||||
assert spec["info"]["title"] == "Test API"
|
||||
assert spec["info"]["version"] == "1.0.0"
|
||||
assert "paths" in spec
|
||||
assert "components" in spec
|
||||
|
||||
def test_paths_inferred(self, sample_entries):
|
||||
"""Test that paths are correctly inferred."""
|
||||
generator = OpenAPIGenerator(sample_entries)
|
||||
spec = generator.generate()
|
||||
|
||||
assert "/users" in spec["paths"]
|
||||
assert "/users/{id}" in spec["paths"]
|
||||
|
||||
def test_methods_inferred(self, sample_entries):
|
||||
"""Test that HTTP methods are correctly inferred."""
|
||||
generator = OpenAPIGenerator(sample_entries)
|
||||
spec = generator.generate()
|
||||
|
||||
users_path = spec["paths"]["/users"]
|
||||
assert "get" in users_path
|
||||
assert "post" in users_path
|
||||
|
||||
def test_schemas_extracted(self, sample_entries):
|
||||
"""Test that JSON schemas are extracted from bodies."""
|
||||
generator = OpenAPIGenerator(sample_entries)
|
||||
spec = generator.generate()
|
||||
|
||||
assert "components" in spec
|
||||
assert "schemas" in spec["components"]
|
||||
assert len(spec["components"]["schemas"]) > 0
|
||||
|
||||
def test_responses_included(self, sample_entries):
|
||||
"""Test that responses are included in spec."""
|
||||
generator = OpenAPIGenerator(sample_entries)
|
||||
spec = generator.generate()
|
||||
|
||||
users_get = spec["paths"]["/users"]["get"]
|
||||
assert "responses" in users_get
|
||||
assert "200" in users_get["responses"]
|
||||
|
||||
def test_to_json(self, sample_entries):
|
||||
"""Test JSON serialization."""
|
||||
generator = OpenAPIGenerator(sample_entries)
|
||||
spec = generator.generate()
|
||||
json_str = generator.to_json(spec)
|
||||
|
||||
assert '"openapi"' in json_str
|
||||
assert '"paths"' in json_str
|
||||
|
||||
def test_generate_empty_entries(self):
|
||||
"""Test generating spec from empty entries."""
|
||||
generator = OpenAPIGenerator([])
|
||||
spec = generator.generate()
|
||||
|
||||
assert spec["paths"] == {}
|
||||
assert spec["components"]["schemas"] == {}
|
||||
|
||||
def test_query_parameters_inferred(self):
|
||||
"""Test that query parameters are inferred."""
|
||||
entries = [
|
||||
make_entry(
|
||||
"GET",
|
||||
"https://api.example.com/users",
|
||||
200,
|
||||
resp_body='[{"id": 1}]',
|
||||
),
|
||||
]
|
||||
entries[0].request.query_params["page"] = "1"
|
||||
entries[0].request.query_params["limit"] = "10"
|
||||
|
||||
generator = OpenAPIGenerator(entries)
|
||||
spec = generator.generate()
|
||||
|
||||
assert "/users" in spec["paths"]
|
||||
users_get = spec["paths"]["/users"]["get"]
|
||||
if "parameters" in users_get:
|
||||
param_names = [p["name"] for p in users_get["parameters"]]
|
||||
assert "page" in param_names
|
||||
assert "limit" in param_names
|
||||
222
old_tests/test_parsers.py
Normal file
222
old_tests/test_parsers.py
Normal file
@@ -0,0 +1,222 @@
|
||||
"""Tests for HTTP parsers."""
|
||||
|
||||
import pytest
|
||||
|
||||
from http_log_explorer.models import HTTPEntry
|
||||
from http_log_explorer.parsers import get_parser
|
||||
from http_log_explorer.parsers.curl_parser import CurlParser
|
||||
from http_log_explorer.parsers.devtools_parser import DevToolsParser
|
||||
from http_log_explorer.parsers.har_parser import HARParser
|
||||
|
||||
|
||||
SAMPLE_HAR = """
|
||||
{
|
||||
"log": {
|
||||
"version": "1.2",
|
||||
"creator": {
|
||||
"name": "Test",
|
||||
"version": "1.0"
|
||||
},
|
||||
"entries": [
|
||||
{
|
||||
"startedDateTime": "2024-01-01T12:00:00Z",
|
||||
"time": 150,
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"url": "https://api.example.com/users/123",
|
||||
"httpVersion": "HTTP/1.1",
|
||||
"headers": [
|
||||
{"name": "Content-Type", "value": "application/json"},
|
||||
{"name": "Authorization", "value": "Bearer token123"}
|
||||
],
|
||||
"queryString": [{"name": "include", "value": "profile"}],
|
||||
"cookies": []
|
||||
},
|
||||
"response": {
|
||||
"status": 200,
|
||||
"statusText": "OK",
|
||||
"httpVersion": "HTTP/1.1",
|
||||
"headers": [
|
||||
{"name": "Content-Type", "value": "application/json"}
|
||||
],
|
||||
"content": {
|
||||
"mimeType": "application/json",
|
||||
"text": "{\\"id\\": 123, \\"name\\": \\"John\\"}"
|
||||
}
|
||||
},
|
||||
"serverIPAddress": "192.168.1.1",
|
||||
"connection": "keep-alive"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
SAMPLE_CURL = """
|
||||
> GET /api/users HTTP/1.1
|
||||
> Host: api.example.com
|
||||
> User-Agent: curl/7.88.1
|
||||
> Accept: */*
|
||||
>
|
||||
< HTTP/1.1 200 OK
|
||||
< Content-Type: application/json
|
||||
< Content-Length: 45
|
||||
<
|
||||
{"id": 1, "name": "Test User"}
|
||||
"""
|
||||
|
||||
SAMPLE_CURL_POST = """
|
||||
> POST /api/users HTTP/1.1
|
||||
> Host: api.example.com
|
||||
> Content-Type: application/json
|
||||
> Content-Length: 25
|
||||
>
|
||||
{"name": "New User"}
|
||||
< HTTP/1.1 201 Created
|
||||
< Content-Type: application/json
|
||||
< Content-Length: 35
|
||||
<
|
||||
{"id": 2, "name": "New User"}
|
||||
"""
|
||||
|
||||
SAMPLE_DEVTOOLS = """
|
||||
{
|
||||
"log": {
|
||||
"version": "1.2",
|
||||
"entries": [
|
||||
{
|
||||
"startedDateTime": "2024-01-01T12:00:00Z",
|
||||
"time": 100,
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"url": "https://api.example.com/posts",
|
||||
"httpVersion": "HTTP/1.1",
|
||||
"headers": {
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
"queryString": []
|
||||
},
|
||||
"response": {
|
||||
"status": 200,
|
||||
"statusText": "OK",
|
||||
"httpVersion": "HTTP/1.1",
|
||||
"headers": {
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
"content": {
|
||||
"mimeType": "application/json",
|
||||
"text": "[{\\"id\\": 1}]"
|
||||
}
|
||||
},
|
||||
"serverIPAddress": "10.0.0.1"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
class TestHARParser:
|
||||
"""Tests for HAR parser."""
|
||||
|
||||
def test_can_parse_har(self):
|
||||
"""Test HAR detection."""
|
||||
parser = HARParser()
|
||||
assert parser.can_parse(SAMPLE_HAR)
|
||||
|
||||
def test_parse_har_entry(self):
|
||||
"""Test parsing HAR content."""
|
||||
parser = HARParser()
|
||||
entries = parser.parse(SAMPLE_HAR)
|
||||
|
||||
assert len(entries) == 1
|
||||
entry = entries[0]
|
||||
assert entry.request.method == "GET"
|
||||
assert entry.request.url == "https://api.example.com/users/123"
|
||||
assert entry.response.status == 200
|
||||
assert entry.request.query_params.get("include") == "profile"
|
||||
|
||||
def test_parse_invalid_har(self):
|
||||
"""Test parsing invalid HAR raises error."""
|
||||
parser = HARParser()
|
||||
with pytest.raises(ValueError):
|
||||
parser.parse("not valid har content")
|
||||
|
||||
|
||||
class TestCurlParser:
|
||||
"""Tests for curl parser."""
|
||||
|
||||
def test_can_parse_curl(self):
|
||||
"""Test curl detection."""
|
||||
parser = CurlParser()
|
||||
assert parser.can_parse(SAMPLE_CURL)
|
||||
|
||||
def test_parse_curl_get(self):
|
||||
"""Test parsing curl GET output."""
|
||||
parser = CurlParser()
|
||||
entries = parser.parse(SAMPLE_CURL)
|
||||
|
||||
assert len(entries) == 1
|
||||
entry = entries[0]
|
||||
assert entry.request.method == "GET"
|
||||
assert "/api/users" in entry.request.url
|
||||
assert entry.response.status == 200
|
||||
|
||||
def test_parse_curl_post(self):
|
||||
"""Test parsing curl POST output."""
|
||||
parser = CurlParser()
|
||||
entries = parser.parse(SAMPLE_CURL_POST)
|
||||
|
||||
assert len(entries) == 1
|
||||
entry = entries[0]
|
||||
assert entry.request.method == "POST"
|
||||
assert entry.response.status == 201
|
||||
|
||||
def test_cannot_parse_har_as_curl(self):
|
||||
"""Test that HAR is not detected as curl."""
|
||||
parser = CurlParser()
|
||||
assert not parser.can_parse(SAMPLE_HAR)
|
||||
|
||||
|
||||
class TestDevToolsParser:
|
||||
"""Tests for DevTools parser."""
|
||||
|
||||
def test_can_parse_devtools(self):
|
||||
"""Test DevTools detection."""
|
||||
parser = DevToolsParser()
|
||||
assert parser.can_parse(SAMPLE_DEVTOOLS)
|
||||
|
||||
def test_parse_devtools_entry(self):
|
||||
"""Test parsing DevTools content."""
|
||||
parser = DevToolsParser()
|
||||
entries = parser.parse(SAMPLE_DEVTOOLS)
|
||||
|
||||
assert len(entries) == 1
|
||||
entry = entries[0]
|
||||
assert entry.request.method == "GET"
|
||||
assert "posts" in entry.request.url
|
||||
assert entry.response.status == 200
|
||||
|
||||
|
||||
class TestParserFactory:
|
||||
"""Tests for parser factory."""
|
||||
|
||||
def test_get_parser_har(self):
|
||||
"""Test factory returns HARParser for HAR content."""
|
||||
parser = get_parser(SAMPLE_HAR)
|
||||
assert isinstance(parser, HARParser)
|
||||
|
||||
def test_get_parser_curl(self):
|
||||
"""Test factory returns CurlParser for curl content."""
|
||||
parser = get_parser(SAMPLE_CURL)
|
||||
assert isinstance(parser, CurlParser)
|
||||
|
||||
def test_get_parser_devtools(self):
|
||||
"""Test factory returns DevToolsParser for DevTools content."""
|
||||
parser = get_parser(SAMPLE_DEVTOOLS)
|
||||
assert isinstance(parser, DevToolsParser)
|
||||
|
||||
def test_unsupported_format(self):
|
||||
"""Test factory raises error for unsupported format."""
|
||||
with pytest.raises(ValueError, match="Unsupported format"):
|
||||
get_parser("random garbage content")
|
||||
1
old_tests/test_search.py
Normal file
1
old_tests/test_search.py
Normal file
@@ -0,0 +1 @@
|
||||
# Tests would go here
|
||||
1
old_tests/test_sync.py
Normal file
1
old_tests/test_sync.py
Normal file
@@ -0,0 +1 @@
|
||||
# Tests would go here
|
||||
Reference in New Issue
Block a user