Files
0pt/services/api/tests/test_entity_resolution.py
admin 213294bc55
CI (SIAX Cloud) / security (push) Successful in 16s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 27s
CI (SIAX Cloud) / integration (push) Successful in 31s
CI (SIAX Cloud) / integration (pull_request) Successful in 32s
Security Scan (SIAX Cloud) / security (push) Successful in 43s
CI (SIAX Cloud) / security (pull_request) Successful in 43s
CI (SIAX Cloud) / quality (pull_request) Successful in 53s
CI (SIAX Cloud) / quality (push) Successful in 55s
fix: use services/api pytest import convention
2026-09-08 22:50:05 +02:00

94 lines
3.2 KiB
Python

from workers.entity_resolution import (
EntityCandidate,
ResolutionDecision,
rank_resolution_candidates,
resolve_entity_pair,
)
def organization(entity_id: str, **overrides):
values = {
"entity_id": entity_id,
"entity_type": "organization",
"name": "Example Technology AB",
"source_ref": f"source:{entity_id}",
"registration_country": "SE",
"registration_number": None,
"website": None,
"city": "Stockholm",
}
values.update(overrides)
return EntityCandidate(**values)
def person(entity_id: str, **overrides):
values = {
"entity_id": entity_id,
"entity_type": "person",
"name": "Anna Andersson",
"source_ref": f"source:{entity_id}",
"email": None,
"organization_id": None,
}
values.update(overrides)
return EntityCandidate(**values)
def test_registration_number_is_a_strong_organization_identifier():
result = resolve_entity_pair(
organization("left", registration_number="556123-4567"),
organization("right", registration_number="5561234567"),
)
assert result.decision is ResolutionDecision.EXACT_LINK
assert result.score == 1.0
assert result.requires_human_review is False
def test_conflicting_registration_numbers_fail_distinct_even_when_names_match():
result = resolve_entity_pair(
organization("left", registration_number="5561234567"),
organization("right", registration_number="5569999999"),
)
assert result.decision is ResolutionDecision.DISTINCT
assert result.score == 0.0
def test_same_person_email_is_exact_link():
result = resolve_entity_pair(
person("left", email="Anna@example.com"),
person("right", email=" anna@EXAMPLE.com "),
)
assert result.decision is ResolutionDecision.EXACT_LINK
assert result.requires_human_review is False
def test_fuzzy_organization_similarity_never_auto_merges():
result = resolve_entity_pair(
organization("left", name="Example Technology AB", website="example.se"),
organization("right", name="Example Technologies AB", website="https://www.example.se"),
)
assert result.score > 0.72
assert result.decision is ResolutionDecision.REVIEW
assert result.requires_human_review is True
def test_different_entity_types_are_distinct():
result = resolve_entity_pair(
organization("org"),
person("person"),
)
assert result.decision is ResolutionDecision.DISTINCT
def test_candidate_ranking_prefers_exact_then_review_and_is_stable():
query = organization("query", registration_number="5561234567", website="example.se")
candidates = [
organization("weak", name="Completely Different Company", registration_country="NO", city="Oslo"),
organization("review", name="Example Technologies AB", website="example.se"),
organization("exact", registration_number="556123-4567"),
]
ranked = rank_resolution_candidates(query, candidates)
assert [result.right_id for result in ranked] == ["exact", "review", "weak"]
assert ranked[0].decision is ResolutionDecision.EXACT_LINK
assert ranked[1].decision is ResolutionDecision.REVIEW