Skip to content

Commit b181082

Browse files
committed
Add an integration test against followthemoney validate.
1 parent 4820462 commit b181082

1 file changed

Lines changed: 122 additions & 0 deletions

File tree

tests/test_validate.py

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
"""Integration test: generate entities and validate them with `uvx followthemoney validate`."""
2+
3+
import json
4+
import subprocess
5+
6+
from click.testing import CliRunner
7+
from followthemoney import model
8+
9+
from ftm_random.main import generate_entities
10+
11+
runner = CliRunner()
12+
13+
# All non-abstract schemas
14+
ALL_SCHEMAS = [name for name, s in model.schemata.items() if not s.abstract]
15+
16+
17+
def parse_output(result):
18+
return [json.loads(line) for line in result.output.strip().splitlines()]
19+
20+
21+
def validate_entities(entities):
22+
"""Run entities through `uvx followthemoney validate` and return parsed output."""
23+
input_lines = "\n".join(json.dumps(e) for e in entities)
24+
proc = subprocess.run(
25+
["uvx", "followthemoney", "validate"],
26+
input=input_lines,
27+
capture_output=True,
28+
text=True,
29+
timeout=120,
30+
)
31+
assert proc.returncode == 0, f"validate failed: {proc.stderr}"
32+
return [json.loads(line) for line in proc.stdout.strip().splitlines()]
33+
34+
35+
def normalize(entity):
36+
"""Add default fields that validate injects, for comparison."""
37+
out = dict(entity)
38+
out.setdefault("referents", [])
39+
out.setdefault("datasets", [])
40+
return out
41+
42+
43+
class TestValidateAllSchemas:
44+
"""Generate 5 entities per schema across all non-abstract schemas and validate."""
45+
46+
def test_all_schemas_validate_unchanged(self):
47+
args = []
48+
for name in ALL_SCHEMAS:
49+
args += ["--schema", name]
50+
args += ["--count-per-schema", "100"]
51+
52+
result = runner.invoke(generate_entities, args)
53+
assert result.exit_code == 0
54+
55+
entities = parse_output(result)
56+
assert len(entities) == 100 * len(ALL_SCHEMAS)
57+
58+
validated = validate_entities(entities)
59+
assert len(validated) == len(entities)
60+
61+
for original, after in zip(entities, validated):
62+
assert normalize(original) == after, (
63+
f"Mismatch for {original.get('schema')} entity {original.get('id')}"
64+
)
65+
66+
67+
class TestValidateConnected:
68+
"""Generate connected entities and validate them."""
69+
70+
def test_connected_entities_validate_unchanged(self):
71+
result = runner.invoke(
72+
generate_entities,
73+
[
74+
"--schema",
75+
"Person",
76+
"--schema",
77+
"Company",
78+
"--schema",
79+
"Directorship",
80+
"--schema",
81+
"Ownership",
82+
"--schema",
83+
"Associate",
84+
"--connected",
85+
"--count-per-schema",
86+
"10",
87+
],
88+
)
89+
assert result.exit_code == 0
90+
91+
entities = parse_output(result)
92+
assert len(entities) == 50
93+
94+
validated = validate_entities(entities)
95+
assert len(validated) == len(entities)
96+
97+
for original, after in zip(entities, validated):
98+
assert normalize(original) == after, (
99+
f"Mismatch for {original.get('schema')} entity {original.get('id')}"
100+
)
101+
102+
103+
class TestValidateRandomSchema:
104+
"""Generate entities with --random-schema and validate."""
105+
106+
def test_random_schema_entities_validate_unchanged(self):
107+
result = runner.invoke(
108+
generate_entities,
109+
["--random-schema", "--count", "1000"],
110+
)
111+
assert result.exit_code == 0
112+
113+
entities = parse_output(result)
114+
assert len(entities) == 1000
115+
116+
validated = validate_entities(entities)
117+
assert len(validated) == len(entities)
118+
119+
for original, after in zip(entities, validated):
120+
assert normalize(original) == after, (
121+
f"Mismatch for {original.get('schema')} entity {original.get('id')}"
122+
)

0 commit comments

Comments
 (0)