Newer
Older
gnexus-creds / tests / test_extension.py
@Eugene Sukhodolskiy Eugene Sukhodolskiy 10 hours ago 3 KB Add in-app extension download page
"""Tests for extension distribution endpoints."""

import json
import zipfile
from unittest.mock import MagicMock, patch

import pytest
from httpx import ASGITransport, AsyncClient

from gnexus_creds import api as api_module


def _make_zip(path) -> None:
    with zipfile.ZipFile(path, "w") as zf:
        zf.writestr("manifest.json", "{}")


@pytest.fixture
def extension_dir(tmp_path):
    ext = tmp_path / "extensions"
    dist = ext / "dist"
    dist.mkdir(parents=True)
    chrome = dist / "gnexus-creds-extension-chrome-0.1.0.zip"
    firefox = dist / "gnexus-creds-extension-firefox-0.1.0.zip"
    for path in (chrome, firefox):
        _make_zip(path)
    manifest = {
        "version": "0.1.0",
        "released_at": "2026-08-24T00:00:00Z",
        "notes": "test build",
        "builds": [
            {
                "browser": "chrome",
                "filename": chrome.name,
                "sha256": "a" * 64,
                "size": chrome.stat().st_size,
            },
            {
                "browser": "firefox",
                "filename": firefox.name,
                "sha256": "b" * 64,
                "size": firefox.stat().st_size,
            },
        ],
    }
    (ext / "manifest.json").write_text(json.dumps(manifest))
    return ext


@pytest.fixture
def patched_settings(extension_dir):
    settings = MagicMock()
    settings.extension_dir = str(extension_dir)
    with patch.object(api_module, "get_settings", return_value=settings):
        yield


@pytest.mark.anyio
async def test_extension_info_lists_builds(app, patched_settings):
    async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as client:
        response = await client.get("/api/v1/extension")
        assert response.status_code == 200, response.text
        data = response.json()
        assert data["version"] == "0.1.0"
        assert data["notes"] == "test build"
        browsers = {build["browser"] for build in data["builds"]}
        assert browsers == {"chrome", "firefox"}
        for build in data["builds"]:
            assert build["download_url"].startswith("/api/v1/extension/download/")
            assert build["size"] > 0
            assert len(build["sha256"]) == 64


@pytest.mark.anyio
async def test_extension_download_returns_file(app, patched_settings, extension_dir):
    async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as client:
        filename = "gnexus-creds-extension-chrome-0.1.0.zip"
        response = await client.get(f"/api/v1/extension/download/{filename}")
        assert response.status_code == 200, response.text
        assert "attachment" in response.headers.get("content-disposition", "")
        assert filename in response.headers["content-disposition"]
        assert len(response.content) > 0


@pytest.mark.anyio
async def test_extension_download_unknown_returns_404(app, patched_settings):
    async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as client:
        response = await client.get("/api/v1/extension/download/does-not-exist.zip")
        assert response.status_code == 404


@pytest.mark.anyio
async def test_extension_info_requires_auth(auth_app, patched_settings):
    async with AsyncClient(transport=ASGITransport(app=auth_app), base_url="http://test") as client:
        response = await client.get("/api/v1/extension")
        assert response.status_code == 401