223 lines
5.9 KiB
Python
223 lines
5.9 KiB
Python
"""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")
|