Source code for tests.sphinx.test_sphinx_linkcheck

# Copyright Kevin Deldycke <kevin@deldycke.com> and contributors.
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
"""Tests for the github.com authentication of the `linkcheck` builder."""

from __future__ import annotations

import re
from io import StringIO
from typing import Any

import pytest
from requests import PreparedRequest
from sphinx.application import Sphinx
from sphinx.util.docutils import docutils_namespace

from click_extra.sphinx.linkcheck import (
    GITHUB_TOKEN_ENV,
    GITHUB_URL_PATTERN,
    github_bearer_auth,
)

ORCHARD_AUTH = (r"https://orchard\.example\.com/", ("gardener", "spade"))
"""A `linkcheck_auth` entry a project declares in its own `conf.py`."""


[docs] def linkcheck_auth(tmp_path, entries: list[Any]) -> list[Any]: """Start a `linkcheck` build of a project declaring `entries`. :return: the `linkcheck_auth` the builder reads. """ srcdir = tmp_path / "source" srcdir.mkdir() (srcdir / "conf.py").write_text( f"extensions = ['click_extra.sphinx']\nlinkcheck_auth = {entries!r}\n", encoding="UTF-8", ) (srcdir / "index.rst").write_text("Orchard\n=======\n", encoding="UTF-8") outdir = tmp_path / "build" with docutils_namespace(): app = Sphinx( str(srcdir), str(srcdir), str(outdir), str(outdir / ".doctrees"), "linkcheck", status=None, warning=StringIO(), ) auth: list[Any] = app.config.linkcheck_auth return auth
[docs] def test_auth_entry_follows_the_project_ones(tmp_path, monkeypatch) -> None: """With a token, the github.com entry comes after the entries of `conf.py`. Sphinx signs a request with the first entry matching its URL, so a project entry keeps precedence. """ monkeypatch.setenv(GITHUB_TOKEN_ENV, "pear-token") assert linkcheck_auth(tmp_path, [ORCHARD_AUTH]) == [ ORCHARD_AUTH, (GITHUB_URL_PATTERN, github_bearer_auth), ]
[docs] @pytest.mark.parametrize("token", [None, ""], ids=["unset", "empty"]) def test_no_auth_entry_without_a_token(tmp_path, monkeypatch, token) -> None: """Without a token, `linkcheck_auth` holds the entries of `conf.py` alone.""" if token is None: monkeypatch.delenv(GITHUB_TOKEN_ENV, raising=False) else: monkeypatch.setenv(GITHUB_TOKEN_ENV, token) assert linkcheck_auth(tmp_path, [ORCHARD_AUTH]) == [ORCHARD_AUTH]
[docs] def test_bearer_auth_signs_with_the_token(monkeypatch) -> None: """The request carries the token the environment holds when it goes out.""" monkeypatch.setenv(GITHUB_TOKEN_ENV, "plum-token") request = PreparedRequest() request.prepare(method="GET", url="https://github.com/orchard/plums") assert github_bearer_auth(request) is request assert request.headers["Authorization"] == "Bearer plum-token"
[docs] @pytest.mark.parametrize( ("url", "signed"), [ ("https://github.com/orchard/plums", True), ("https://github.com/orchard/plums/releases/tag/v1.0.0", True), ("https://github.com/orchard/plums/releases/download/v1.0.0/jam.zip", False), ("https://github.com/orchard/plums/releases/latest/download/jam.zip", False), ("https://github.com.example.com/orchard/plums", False), ("https://gist.github.com/orchard", False), ], ) def test_github_url_pattern(url: str, signed: bool) -> None: """The token signs every page of github.com but a release download.""" assert bool(re.match(GITHUB_URL_PATTERN, url)) is signed