mews.page/tests/test_resources.py

167 lines
5.8 KiB
Python
Raw Permalink Normal View History

"""The checks that read a page's stylesheet and images from a live server."""
from pathlib import Path
import zlib
import pytest
from mews.fetch import Fetcher
from mews.lint import validate_bytes
CANONICAL = (Path(__file__).resolve().parent.parent / "mews-0.1.css").read_bytes()
FONT_FACE = b"""@font-face {
font-family: "Atkinson Hyperlegible";
src: url(/fonts/atkinson.woff2) format("woff2");
}
"""
PNG = (
b"\x89PNG\r\n\x1a\n"
b"\x00\x00\x00\rIHDR\x00\x00\x00\x01\x00\x00\x00\x01\x08\x06\x00\x00\x00"
b"\x1f\x15\xc4\x89"
b"\x00\x00\x00\x00IEND\xaeB`\x82"
)
@pytest.fixture
def check(site):
"""Validate a page served by the local server, reading its sub-resources."""
def run(page: bytes, path: str = "/index.html"):
url = site.add(path, page, headers={"ETag": '"v1"'})
with Fetcher(allow_loopback=True) as fetcher:
return validate_bytes(page, url=url, fetcher=fetcher)
return run
def codes(report):
return [finding.code for finding in report.findings]
def test_an_unmodified_stylesheet_copy_passes(site, check, conforming):
site.add("/mews-0.1.css", CANONICAL)
report = check(conforming())
assert "stylesheet-modified" not in codes(report)
def test_an_added_font_face_passes(site, check, conforming):
site.add("/mews-0.1.css", FONT_FACE + CANONICAL)
site.add("/fonts/atkinson.woff2", b"font")
report = check(conforming())
assert "stylesheet-modified" not in codes(report)
assert "font-offsite" not in codes(report)
def test_a_changed_stylesheet_fails(site, check, conforming):
site.add("/mews-0.1.css", CANONICAL.replace(b"#faf8f3", b"#ffffff"))
report = check(conforming())
failure = [f for f in report.findings if f.code == "stylesheet-modified"]
assert failure and failure[0].section == "5.2"
assert not report.conforms
def test_a_font_from_another_site_fails(site, check, conforming):
off = FONT_FACE.replace(b"/fonts/atkinson.woff2", b"https://fonts.example.net/a")
site.add("/mews-0.1.css", off + CANONICAL)
report = check(conforming())
assert "font-offsite" in codes(report)
assert not report.conforms
def test_an_import_in_the_stylesheet_fails(site, check, conforming):
site.add("/mews-0.1.css", b'@import url("x.css");\n' + CANONICAL)
report = check(conforming())
assert "stylesheet-import" in codes(report)
def test_a_missing_stylesheet_only_warns(site, check, conforming):
report = check(conforming())
warning = [f for f in report.findings if f.code == "stylesheet-unreachable"]
assert warning and warning[0].level == "should"
def test_a_stylesheet_on_another_site_fails(site, check, conforming):
site.add("/mews-0.1.css", CANONICAL)
report = check(conforming(stylesheet="https://cdn.example.net/mews-0.1.css"))
assert "stylesheet-offsite" in codes(report)
assert not report.conforms
def test_the_central_stylesheet_only_warns(site, check, conforming):
"""Linking mews.page's own copy is discouraged, not a failure."""
report = check(conforming(stylesheet="https://mews.page/mews-0.1.css"))
assert "stylesheet-offsite" not in codes(report)
canonical = [f for f in report.findings if f.code == "stylesheet-canonical"]
assert canonical and canonical[0].level == "should"
def test_a_cookie_on_the_stylesheet_fails(site, check, conforming):
site.add("/mews-0.1.css", CANONICAL, headers={"Set-Cookie": "a=1"})
report = check(conforming())
assert "cookie" in codes(report)
assert not report.conforms
# --- images ------------------------------------------------------------
def test_a_small_png_passes(site, check, conforming):
site.add("/mews-0.1.css", CANONICAL)
site.add("/a.png", PNG, headers={"Content-Type": "image/png"})
report = check(conforming(body='<p><img src="a.png" alt="A dot" /></p>'))
assert report.conforms
assert not report.warnings
def test_an_image_that_is_not_an_image_warns(site, check, conforming):
site.add("/mews-0.1.css", CANONICAL)
site.add("/a.png", b"<svg/>")
report = check(conforming(body='<p><img src="a.png" alt="x" /></p>'))
warning = [f for f in report.findings if f.code == "image-format"]
assert warning and warning[0].level == "should"
assert report.conforms
def test_a_large_image_warns(site, check, conforming):
site.add("/mews-0.1.css", CANONICAL)
site.add("/a.png", PNG + b"\x00" * 60_000)
report = check(conforming(body='<p><img src="a.png" alt="x" /></p>'))
assert "image-size" in codes(report)
def test_camera_metadata_warns(site, check, conforming):
site.add("/mews-0.1.css", CANONICAL)
site.add("/a.jpg", b"\xff\xd8\xff\xe1\x00\x16Exif\x00\x00" + b"\x00" * 100)
report = check(conforming(body='<p><img src="a.jpg" alt="x" /></p>'))
assert "image-metadata" in codes(report)
def test_a_missing_image_warns(site, check, conforming):
site.add("/mews-0.1.css", CANONICAL)
report = check(conforming(body='<p><img src="gone.png" alt="x" /></p>'))
assert "image-unreachable" in codes(report)
def test_only_the_first_twenty_images_are_read(site, check, conforming):
site.add("/mews-0.1.css", CANONICAL)
site.add("/a.png", PNG)
body = "".join(f'<p><img src="a.png?{i}" alt="x" /></p>' for i in range(25))
report = check(conforming(body=body))
assert "images-not-checked" in codes(report)
assert len([r for r in site.requests if r[0].startswith("/a.png")]) == 20
def test_a_compression_bomb_is_refused(site, conforming):
"""A short download that expands enormously is not a page."""
body = zlib.compress(b"x" * 10_000_000)
url = site.add(
"/big.html",
body,
headers={"Content-Encoding": "deflate", "Content-Type": "text/html"},
declare_length=False,
)
with Fetcher(allow_loopback=True) as fetcher:
response = fetcher.get(url)
assert response.truncated