Skip to content

Commit 2ce85b3

Browse files
committed
Merge build/fensu-0.29.3 (5104dd9): fensu 0.29.3
2 parents ff6bf51 + 5104dd9 commit 2ce85b3

5 files changed

Lines changed: 119 additions & 48 deletions

File tree

‎pyproject.toml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ dev = [
1111
"duckdb==2.0.0",
1212
# DuckDB's Python functions need numpy; the guard measurement's raise hook is one.
1313
"numpy==2.5.4",
14-
"fensu>=0.28.0",
14+
"fensu>=0.29.3",
1515
# The BigQuery referee's authenticated transport to the BigQuery API.
1616
"google-auth[requests]==2.62.1",
1717
# The DuckShop measure reads the Arrow files recorded from Snowflake.

‎tests/unit/scripts/fensu_policy/_test_types.py‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,3 +132,12 @@ class ConversionFieldRuleTestCase:
132132
path: str
133133
source: str
134134
expected_fault_count: int
135+
136+
137+
@dataclass(frozen=True)
138+
class MixedCheckTestCase:
139+
description: str
140+
path: str
141+
expected_returncode: int
142+
expected_summary: str
143+
absent_summary: str
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
"""Write a one-crate workspace with the repository's fensu policy rules, and run fensu over it."""
2+
3+
from __future__ import annotations
4+
5+
import os
6+
import shutil
7+
import subprocess
8+
import sys
9+
from pathlib import Path
10+
11+
REPOSITORY: Path = Path(__file__).resolve().parents[4]
12+
WORKSPACE_MANIFEST: str = '[workspace]\nmembers = ["crates/sqlquack-semantics"]\nresolver = "2"\n'
13+
CRATE_MANIFEST: str = (
14+
'[package]\nname = "sqlquack-semantics"\nversion = "0.1.0"\nedition = "2021"\n\n'
15+
"[features]\ndefault = []\nsnowflake = []\n"
16+
)
17+
LIB: str = '#[cfg(feature = "snowflake")]\nmod snowflake;\nmod schemas;\n'
18+
19+
20+
def write_semantics_crate(root: Path, config: str) -> None:
21+
"""Write the semantics crate, fensu.toml from `config` and the policy rules under `root`."""
22+
crate: Path = root / "crates" / "sqlquack-semantics"
23+
for folder in ("snowflake", "schemas"):
24+
(crate / "src" / folder).mkdir(parents=True)
25+
(crate / "src" / folder / "mod.rs").write_text("pub fn column() {}\n")
26+
(root / "Cargo.toml").write_text(WORKSPACE_MANIFEST)
27+
(crate / "Cargo.toml").write_text(CRATE_MANIFEST)
28+
(crate / "src" / "lib.rs").write_text(LIB)
29+
(root / "fensu.toml").write_text(config)
30+
shutil.copytree(
31+
REPOSITORY / "scripts" / "fensu_policy",
32+
root / "scripts" / "fensu_policy",
33+
ignore=shutil.ignore_patterns("__pycache__"),
34+
)
35+
(root / "scripts" / "__init__.py").write_text("")
36+
37+
38+
def run_fensu_check(root: Path, path: str) -> subprocess.CompletedProcess[str]:
39+
"""Run `fensu check` in `root` with `path` as PATH."""
40+
return subprocess.run(
41+
[str(Path(sys.executable).with_name("fensu")), "check", "--no-cache"],
42+
cwd=root,
43+
env={**os.environ, "PATH": path, "PYTHONPATH": str(root)},
44+
capture_output=True,
45+
text=True,
46+
check=False,
47+
)

‎tests/unit/scripts/fensu_policy/test_conversion_fields.py‎

Lines changed: 47 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
from __future__ import annotations
44

55
import os
6-
import shutil
76
import subprocess
87
import sys
98
from pathlib import Path
@@ -15,19 +14,20 @@
1514
from tests.unit.scripts.fensu_policy._test_types import (
1615
ConversionFieldLinesTestCase,
1716
ConversionFieldRuleTestCase,
17+
MixedCheckTestCase,
1818
)
19+
from tests.unit.scripts.fensu_policy.helpers import run_fensu_check, write_semantics_crate
1920

20-
REPOSITORY: Path = Path(__file__).resolve().parents[4]
21-
WORKSPACE_MANIFEST: str = '[workspace]\nmembers = ["crates/sqlquack-semantics"]\nresolver = "2"\n'
22-
CRATE_MANIFEST: str = (
23-
'[package]\nname = "sqlquack-semantics"\nversion = "0.1.0"\nedition = "2021"\n\n'
24-
"[features]\ndefault = []\nsnowflake = []\n"
25-
)
26-
LIB: str = '#[cfg(feature = "snowflake")]\nmod snowflake;\nmod schemas;\n'
2721
FIELD_RULE_CONFIG: str = (
2822
'[targets.rust]\nanalyzer = "rust"\nroots = ["crates"]\ntests = []\n'
2923
'rule_modules = ["scripts.fensu_policy.rules.conversion_fields"]\nselect = ["XSQ009"]\n'
3024
)
25+
# A Python target with a custom rule beside the Rust one, as the repository's own fensu.toml has.
26+
MIXED_CONFIG: str = (
27+
'[targets.python]\nanalyzer = "python"\nroots = ["tooling"]\ntests = []\n'
28+
'rule_modules = ["scripts.fensu_policy.rules.script_names"]\nselect = ["XSQ005"]\n\n'
29+
+ FIELD_RULE_CONFIG
30+
)
3131

3232

3333
@pytest.mark.parametrize(
@@ -125,31 +125,46 @@ def test_given_source_when_checking_then_lists_conversion_field_reads(
125125
def test_given_crate_when_running_fensu_then_reports_shared_conversion_field_reads(
126126
test_case: ConversionFieldRuleTestCase, tmp_path: Path
127127
) -> None:
128-
crate: Path = tmp_path / "crates" / "sqlquack-semantics"
129-
for folder in ("snowflake", "schemas"):
130-
(crate / "src" / folder).mkdir(parents=True)
131-
(crate / "src" / folder / "mod.rs").write_text("pub fn column() {}\n")
132-
(tmp_path / "Cargo.toml").write_text(WORKSPACE_MANIFEST)
133-
(crate / "Cargo.toml").write_text(CRATE_MANIFEST)
134-
(crate / "src" / "lib.rs").write_text(LIB)
135-
(crate / test_case.path).write_text(test_case.source)
136-
(tmp_path / "fensu.toml").write_text(FIELD_RULE_CONFIG)
137-
shutil.copytree(
138-
REPOSITORY / "scripts" / "fensu_policy",
139-
tmp_path / "scripts" / "fensu_policy",
140-
ignore=shutil.ignore_patterns("__pycache__"),
141-
)
142-
(tmp_path / "scripts" / "__init__.py").write_text("")
143-
144-
completed: subprocess.CompletedProcess[str] = subprocess.run(
145-
[str(Path(sys.executable).with_name("fensu")), "check", "--no-cache"],
146-
cwd=tmp_path,
147-
env={**os.environ, "PYTHONPATH": str(tmp_path)},
148-
capture_output=True,
149-
text=True,
150-
check=False,
151-
)
128+
write_semantics_crate(tmp_path, FIELD_RULE_CONFIG)
129+
(tmp_path / "crates" / "sqlquack-semantics" / test_case.path).write_text(test_case.source)
130+
131+
completed: subprocess.CompletedProcess[str] = run_fensu_check(tmp_path, os.environ["PATH"])
152132

153133
output: str = completed.stdout + completed.stderr
154134
assert completed.returncode == min(test_case.expected_fault_count, 1), output
155135
assert output.count("XSQ009") == test_case.expected_fault_count, output
136+
137+
138+
@pytest.mark.parametrize(
139+
"test_case",
140+
[
141+
MixedCheckTestCase(
142+
"with cargo, the check is complete",
143+
os.environ["PATH"],
144+
0,
145+
"Found 0 faults",
146+
"Check incomplete",
147+
),
148+
MixedCheckTestCase(
149+
"without cargo, the check says it is incomplete",
150+
str(Path(sys.executable).parent),
151+
2,
152+
"Check incomplete",
153+
"Found ",
154+
),
155+
],
156+
ids=lambda case: case.description,
157+
)
158+
def test_given_python_and_rust_targets_when_running_fensu_then_summary_says_whether_all_ran(
159+
test_case: MixedCheckTestCase, tmp_path: Path
160+
) -> None:
161+
write_semantics_crate(tmp_path, MIXED_CONFIG)
162+
(tmp_path / "tooling").mkdir()
163+
(tmp_path / "tooling" / "__init__.py").write_text("")
164+
165+
completed: subprocess.CompletedProcess[str] = run_fensu_check(tmp_path, test_case.path)
166+
167+
output: str = completed.stdout + completed.stderr
168+
assert completed.returncode == test_case.expected_returncode, output
169+
assert test_case.expected_summary in output, output
170+
assert test_case.absent_summary not in output, output

‎uv.lock‎

Lines changed: 15 additions & 15 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)