Skip to content

Commit 7a4c05b

Browse files
add tests for doc links
1 parent f91ba0f commit 7a4c05b

File tree

3 files changed

+132
-49
lines changed

3 files changed

+132
-49
lines changed

doc/conf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@
8080
}
8181
# -- Configure link checking behavior ----------------------------------------
8282
linkcheck_rate_limit_timeout = 40
83-
linkcheck_timeout = 5
83+
linkcheck_timeout = 10
8484
linkcheck_delay = 20
8585
linkcheck_retries = 2
8686
linkcheck_anchors = False

exasol/toolbox/nox/_documentation.py

Lines changed: 43 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,14 @@
22

33
import argparse
44
import json
5-
import os
6-
import re
75
import shutil
86
import subprocess
97
import sys
108
import tempfile
119
import webbrowser
12-
from collections.abc import (
13-
Container,
14-
Iterable,
15-
)
16-
from itertools import repeat
1710
from pathlib import Path
18-
from typing import (
19-
Optional,
20-
Tuple,
21-
)
2211

2312
import nox
24-
import requests # type: ignore
2513
from nox import Session
2614

2715
from exasol.toolbox.nox._shared import DOCS_OUTPUT_DIR
@@ -100,26 +88,24 @@ def clean_docs(_session: Session) -> None:
10088
shutil.rmtree(docs_folder)
10189

10290

103-
@nox.session(name="docs:links", python=False)
104-
def docs_list_links(session: Session) -> None:
105-
"""List all the links within the documentation."""
91+
def _docs_list_links(doc_config: Path):
10692
with tempfile.TemporaryDirectory() as path:
10793
tmpdir = Path(path)
108-
sp = subprocess.run(
94+
sp = subprocess.run( # nosec
10995
[
11096
"sphinx-build",
11197
"-b",
11298
"linkcheck",
11399
"-D",
114100
"linkcheck_ignore=.*",
115-
PROJECT_CONFIG.root / "doc",
101+
doc_config,
116102
tmpdir,
117103
],
104+
capture_output= True,
105+
text= True
118106
)
119-
print(sp.returncode)
120107
if sp.returncode >= 2:
121-
print(sp.stderr)
122-
session.error(2)
108+
return sp.returncode, sp.stderr
123109
output = tmpdir / "output.json"
124110
links = output.read_text().split("\n")
125111
file_links = []
@@ -129,51 +115,60 @@ def docs_list_links(session: Session) -> None:
129115
if not line["uri"].startswith("#"):
130116
file_links.append(line)
131117
file_links.sort(key=lambda file: file["filename"])
132-
print(
133-
"\n".join(
134-
f"filename: {fl['filename']} -> uri: {fl['uri']}" for fl in file_links
118+
return 0, "\n".join(
119+
f"filename: {fl['filename']}:{fl['lineno']} -> uri: {fl['uri']}" for fl in file_links
135120
)
136-
)
137121

138122

139-
@nox.session(name="docs:links:check", python=False)
140-
def docs_links_check(session: Session) -> None:
141-
"""Checks whether all links in the documentation are accessible."""
142-
parser = argparse.ArgumentParser(
143-
prog="nox -s release:prepare",
144-
usage="nox -s release:prepare -- [-h] [-o |--output]",
145-
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
146-
)
147-
parser.add_argument(
148-
"-o", "--output", type=Path, help="path to output file", default=None
149-
)
150-
args = parser.parse_args(session.posargs)
123+
@nox.session(name="docs:links", python=False)
124+
def docs_list_links(session: Session) -> None:
125+
"""List all the links within the documentation."""
126+
r_code, text = _docs_list_links(PROJECT_CONFIG.doc)
127+
print(text)
128+
if r_code != 0:
129+
session.error()
130+
131+
132+
def _docs_links_check(doc_config: Path, args):
151133
with tempfile.TemporaryDirectory() as path:
152134
tmpdir = Path(path)
153135
sp = subprocess.run(
154136
[
155137
"sphinx-build",
156138
"-b",
157139
"linkcheck",
158-
PROJECT_CONFIG.root / "doc",
140+
doc_config,
159141
tmpdir,
160142
],
161143
)
162-
print(sp.returncode)
163-
if sp.returncode >= 2:
164-
print(sp.stderr)
165-
session.error(2)
166-
if args.output:
144+
if args.output and sp.returncode <= 1:
167145
result_json = tmpdir / "output.json"
168146
dst = Path(args.output) / "link-check-output.json"
169147
shutil.copyfile(result_json, dst)
170148
print(f"file generated at path: {result_json.resolve()}")
171-
result_txt = tmpdir / "output.txt"
172-
if sp.returncode == 1 or result_txt.read_text() != "":
173-
escape_rot = "\033[31m"
174-
print(escape_rot + "errors:")
175-
print(result_txt.read_text())
176-
session.error(1)
149+
return sp.returncode, None if sp.returncode >= 2 else (tmpdir / "output.txt").read_text()
150+
151+
152+
@nox.session(name="docs:links:check", python=False)
153+
def docs_links_check(session: Session) -> None:
154+
"""Checks whether all links in the documentation are accessible."""
155+
parser = argparse.ArgumentParser(
156+
prog="nox -s docs:links:check",
157+
usage="nox -s docs:links:check -- [-h] [-o |--output]",
158+
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
159+
)
160+
parser.add_argument(
161+
"-o", "--output", type=Path, help="path to output file", default=None
162+
)
163+
args = parser.parse_args(session.posargs)
164+
r_code, problems = _docs_links_check(PROJECT_CONFIG.doc, args)
165+
if r_code >= 2:
166+
session.error(2)
167+
if r_code == 1 or problems != "":
168+
escape_rot = "\033[31m"
169+
print(escape_rot + "errors:")
170+
print(problems)
171+
session.error(1)
177172

178173

179174
@nox.session(name="changelog:updated", python=False)

test/unit/documentation_test.py

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import pytest
2+
from unittest.mock import patch, MagicMock
3+
import exasol.toolbox.nox._documentation
4+
from exasol.toolbox.nox._documentation import (
5+
_docs_list_links,
6+
_docs_links_check
7+
)
8+
import shutil
9+
from noxconfig import Config
10+
11+
12+
@pytest.fixture()
13+
def file1():
14+
return """
15+
https://examle.invalid
16+
:ref:`Test`"""
17+
18+
19+
@pytest.fixture()
20+
def index():
21+
return """.. _Test:
22+
Test
23+
____
24+
25+
.. toctree::
26+
:maxdepth: 1
27+
:hidden:
28+
29+
file"""
30+
31+
@pytest.fixture()
32+
def expected1():
33+
return """filename: file.rst:2 -> uri: https://examle.invalid"""
34+
35+
36+
def config(index, file, tmp_path):
37+
test_doc = tmp_path / "doc"
38+
test_doc.mkdir()
39+
(test_doc / "_static").mkdir()
40+
shutil.copyfile(Config.doc / "conf.py", test_doc / "conf.py")
41+
rst_index = test_doc / "index.rst"
42+
rst_file1 = test_doc / "file.rst"
43+
rst_index.touch()
44+
rst_file1.touch()
45+
rst_index.write_text(index)
46+
rst_file1.write_text(file)
47+
48+
49+
def test_docs_links(index, file1, expected1, tmp_path):
50+
config(index, file1, tmp_path)
51+
r_code, text = _docs_list_links(tmp_path / "doc")
52+
assert (text == expected1) and not r_code
53+
54+
55+
@pytest.mark.parametrize(
56+
"file2, expected2",
57+
[
58+
(
59+
"https://httpbin.org/status/200",
60+
(0, "")
61+
),
62+
(
63+
"https://httpbin.org/status/301",
64+
(0, "file.rst:1: [redirected with Found] https://httpbin.org/status/301 to https://httpbin.org/get\n")
65+
),
66+
(
67+
"https://httpbin.org/status/302",
68+
(0, "file.rst:1: [redirected with Found] https://httpbin.org/status/302 to https://httpbin.org/get\n")
69+
),
70+
(
71+
"https://httpbin.org/status/303",
72+
(0, "file.rst:1: [redirected with Found] https://httpbin.org/status/303 to https://httpbin.org/get\n")
73+
),
74+
(
75+
"https://httpbin.org/status/404",
76+
(1, "file.rst:1: [broken] https://httpbin.org/status/404: 404 Client Error: NOT FOUND for url: https://httpbin.org/status/404\n")
77+
)
78+
]
79+
)
80+
def test_docs_links_check(index, file2, expected2, tmp_path):
81+
config(index, file2, tmp_path)
82+
args = MagicMock
83+
args.output = None
84+
actual = _docs_links_check(tmp_path / "doc", args)
85+
print("______________________")
86+
print(actual)
87+
print("______________________")
88+
assert actual == expected2

0 commit comments

Comments
 (0)