feat: add static file serving with ETag caching
This commit is contained in:
@@ -23,10 +23,11 @@ def get_free_port():
|
||||
class PipelineServer:
|
||||
"""Manages a pipeline-runner server instance for tests."""
|
||||
|
||||
def __init__(self, port, work_dir, verbose=False):
|
||||
def __init__(self, port, work_dir, verbose=False, web_root=None):
|
||||
self.port = port
|
||||
self.work_dir = work_dir
|
||||
self.verbose = verbose
|
||||
self.web_root = web_root
|
||||
|
||||
test_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
project_root = os.path.dirname(test_dir)
|
||||
@@ -37,6 +38,8 @@ class PipelineServer:
|
||||
"pipelines_dir": os.path.join(work_dir, "pipelines") + "/",
|
||||
"logs_dir": os.path.join(work_dir, "logs") + "/",
|
||||
}
|
||||
if web_root:
|
||||
config["web_root"] = web_root
|
||||
self.config_path = os.path.join(work_dir, "pipeline-runner.conf")
|
||||
with open(self.config_path, "w") as f:
|
||||
json.dump(config, f)
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
"""Smoke tests for pipeline-runner REST API endpoints."""
|
||||
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
import socket
|
||||
import subprocess
|
||||
import tempfile
|
||||
import time
|
||||
|
||||
import pytest
|
||||
import requests
|
||||
|
||||
@@ -24,3 +32,110 @@ def test_cors_headers(pipeline_server):
|
||||
"""Check that CORS headers are present on responses."""
|
||||
response = requests.get(f"{pipeline_server.base_url}/api/pipelines")
|
||||
assert response.headers.get("Access-Control-Allow-Origin") == "*"
|
||||
|
||||
|
||||
def _get_free_port():
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
s.bind(("", 0))
|
||||
port = s.getsockname()[1]
|
||||
s.close()
|
||||
return port
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def static_file_server():
|
||||
"""Fixture that starts a server with web_root configured for static file tests."""
|
||||
project_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
build_script = os.path.join(project_dir, "build.sh")
|
||||
subprocess.check_call([build_script, "--fake"], cwd=project_dir)
|
||||
|
||||
work_dir = tempfile.mkdtemp(prefix="pipeline-static-test-")
|
||||
|
||||
web_root = os.path.join(work_dir, "web")
|
||||
os.makedirs(web_root)
|
||||
os.makedirs(os.path.join(web_root, "subdir"))
|
||||
|
||||
html_content = "<html><body><h1>Hello Static</h1></body></html>"
|
||||
with open(os.path.join(web_root, "index.html"), "w") as f:
|
||||
f.write(html_content)
|
||||
|
||||
css_content = "body { color: red; }"
|
||||
with open(os.path.join(web_root, "style.css"), "w") as f:
|
||||
f.write(css_content)
|
||||
|
||||
js_content = "console.log('hello');"
|
||||
with open(os.path.join(web_root, "app.js"), "w") as f:
|
||||
f.write(js_content)
|
||||
|
||||
nested_content = "nested file content"
|
||||
with open(os.path.join(web_root, "subdir", "nested.txt"), "w") as f:
|
||||
f.write(nested_content)
|
||||
|
||||
port = _get_free_port()
|
||||
|
||||
test_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
from conftest import PipelineServer
|
||||
server = PipelineServer(port, work_dir, web_root=web_root)
|
||||
if not server.start():
|
||||
pytest.fail("Could not start pipeline-runner server with static files")
|
||||
|
||||
yield server, web_root
|
||||
|
||||
server.stop()
|
||||
shutil.rmtree(work_dir, ignore_errors=True)
|
||||
|
||||
|
||||
class TestStaticFiles:
|
||||
def test_serve_html(self, static_file_server):
|
||||
server, _ = static_file_server
|
||||
resp = requests.get(f"{server.base_url}/index.html")
|
||||
assert resp.status_code == 200
|
||||
assert "text/html" in resp.headers.get("Content-Type", "")
|
||||
assert "<h1>Hello Static</h1>" in resp.text
|
||||
assert "ETag" in resp.headers
|
||||
|
||||
def test_serve_css(self, static_file_server):
|
||||
server, _ = static_file_server
|
||||
resp = requests.get(f"{server.base_url}/style.css")
|
||||
assert resp.status_code == 200
|
||||
assert "text/css" in resp.headers.get("Content-Type", "")
|
||||
assert resp.text == "body { color: red; }"
|
||||
|
||||
def test_serve_js(self, static_file_server):
|
||||
server, _ = static_file_server
|
||||
resp = requests.get(f"{server.base_url}/app.js")
|
||||
assert resp.status_code == 200
|
||||
assert "text/javascript" in resp.headers.get("Content-Type", "")
|
||||
assert resp.text == "console.log('hello');"
|
||||
|
||||
def test_serve_nested_file(self, static_file_server):
|
||||
server, _ = static_file_server
|
||||
resp = requests.get(f"{server.base_url}/subdir/nested.txt")
|
||||
assert resp.status_code == 200
|
||||
assert "text/plain" in resp.headers.get("Content-Type", "")
|
||||
assert resp.text == "nested file content"
|
||||
|
||||
def test_etag_304(self, static_file_server):
|
||||
server, _ = static_file_server
|
||||
resp1 = requests.get(f"{server.base_url}/index.html")
|
||||
assert resp1.status_code == 200
|
||||
etag = resp1.headers.get("ETag")
|
||||
assert etag is not None
|
||||
|
||||
resp2 = requests.get(
|
||||
f"{server.base_url}/index.html",
|
||||
headers={"If-None-Match": etag},
|
||||
)
|
||||
assert resp2.status_code == 304
|
||||
assert resp2.text == ""
|
||||
|
||||
def test_cache_control_header(self, static_file_server):
|
||||
server, _ = static_file_server
|
||||
resp = requests.get(f"{server.base_url}/index.html")
|
||||
assert resp.status_code == 200
|
||||
assert "max-age" in resp.headers.get("Cache-Control", "")
|
||||
|
||||
def test_static_404(self, static_file_server):
|
||||
server, _ = static_file_server
|
||||
resp = requests.get(f"{server.base_url}/nonexistent.html")
|
||||
assert resp.status_code == 404
|
||||
|
||||
Reference in New Issue
Block a user