Files
pbf/tests/test_feature_identity_scope_audit.py

145 lines
7.5 KiB
Python

"""B2.5:不同 Provider 形态、Tile ID 作用域和 PRIMARY 审核门禁。"""
from __future__ import annotations
import importlib.util
from pathlib import Path
import tempfile
import unittest
from mapbox_vector_tile.Mapbox import vector_tile_pb2
BASE = Path(__file__).resolve().parents[1]
MODULE_FILE = BASE / "tools/provider-pipeline/feature_identity_scope_audit.py"
spec = importlib.util.spec_from_file_location("feature_identity_scope_audit", MODULE_FILE)
module = importlib.util.module_from_spec(spec)
assert spec and spec.loader
spec.loader.exec_module(module)
def write_tile(root: Path, tile: str, source_layer: str, feature_ids: list[int | None], *, property_value: str | None = None):
obj = vector_tile_pb2.tile()
layer = obj.layers.add()
layer.name = source_layer
layer.version = 2
layer.extent = 4096
if property_value is not None:
layer.keys.append("sampleLabel")
prop = layer.values.add()
prop.string_value = property_value
for fid in feature_ids:
feature = layer.features.add()
if fid is not None:
feature.id = fid
feature.type = 1
feature.geometry.extend([9, 0, 0])
if property_value is not None:
feature.tags.extend([0, 0])
target = root / f"{tile}.pbf"
target.parent.mkdir(parents=True, exist_ok=True)
target.write_bytes(obj.SerializeToString())
def visual_object(name: str, tile: str, source_layer: str, fid: int | None):
return {
"visual_object_id": name,
"provenance": {"source_layer": source_layer},
"example": {"tile": tile, "feature_id": fid},
"components": [{"style_layer_id": "shape", "style_index": 0, "role": "icon", "resource_key": "X"}],
}
class FeatureIdentityScopeTests(unittest.TestCase):
def test_two_provider_field_independent_tile_scoped_locator(self):
for source, layer, label in (("alpha", "points", "VO-A"), ("other-provider", "objects", "VO-B")):
with self.subTest(source=source), tempfile.TemporaryDirectory() as folder:
root = Path(folder)
write_tile(root, "1/0/0", layer, [7, 8])
style = {"layers": [{"id": "shape", "source": source, "source-layer": layer}]}
mapping = {"assignments": [{"visualObjectId": label, "status": "LAYER_ONLY", "standardLayer": "navigation_marks"}]}
audit = module.audit_scope(
{"visual_objects": [visual_object(label, "1/0/0", layer, 7)]},
style, root, provider_id=source, dataset_id="d1", mapping=mapping,
)
self.assertEqual(audit["exampleLocatorStatusCounts"], {"TILE_LOCAL_LOCATOR_CONFIRMED": 1})
self.assertEqual(audit["fidScope"], "unknown")
row = audit["reviewQueue"][0]
self.assertEqual(row["tileLocalFeatureLocator"]["sourceId"], source)
self.assertIsNone(row["stableEntityId"])
self.assertIsNone(row["primaryStyleComponentIndex"])
self.assertEqual(row["primaryReviewStatus"], "PENDING_REVIEW")
self.assertFalse(row["pickupDeduplicationAuthorized"])
self.assertEqual(row["assignmentStatus"], "LAYER_ONLY")
def test_reused_raw_id_across_tiles_not_global_claim(self):
with tempfile.TemporaryDirectory() as folder:
root = Path(folder)
write_tile(root, "1/0/0", "objects", [33], property_value="north")
write_tile(root, "1/1/0", "objects", [33], property_value="south")
style = {"layers": [{"id": "shape", "source": "beta", "source-layer": "objects"}]}
catalog = {"visual_objects": [
visual_object("VO-A", "1/0/0", "objects", 33),
visual_object("VO-B", "1/1/0", "objects", 33),
]}
out = module.audit_scope(catalog, style, root, provider_id="beta", dataset_id="d")
self.assertEqual(out["reusedRawFeatureIdAcrossExaminedTiles"], 1)
self.assertEqual(out["reusedRawFeatureIdWithDifferingProperties"], 1)
self.assertEqual(out["exampleLocatorStatusCounts"], {"TILE_LOCAL_LOCATOR_CONFIRMED": 2})
self.assertEqual(out["globalIdentityAuthorizedCount"], 0)
self.assertNotEqual(
out["reviewQueue"][0]["tileLocalFeatureLocator"]["x"],
out["reviewQueue"][1]["tileLocalFeatureLocator"]["x"],
)
def test_duplicate_raw_id_same_tile_blocked(self):
with tempfile.TemporaryDirectory() as folder:
root = Path(folder)
write_tile(root, "1/0/0", "objects", [12, 12])
catalog = {"visual_objects": [visual_object("VO-A", "1/0/0", "objects", 12)]}
style = {"layers": [{"id": "shape", "source": "beta", "source-layer": "objects"}]}
out = module.audit_scope(catalog, style, root, provider_id="beta", dataset_id="d")
self.assertEqual(out["exampleLocatorStatusCounts"], {"FEATURE_ID_AMBIGUOUS": 1})
self.assertEqual(out["examinedTileRawFeatureStats"]["duplicateFeatureIdValues"], 1)
self.assertIsNone(out["reviewQueue"][0]["tileLocalFeatureLocator"])
def test_missing_id_or_ambiguous_source_remains_unknown(self):
with tempfile.TemporaryDirectory() as folder:
root = Path(folder)
write_tile(root, "1/0/0", "objects", [None])
obj = visual_object("VO-A", "1/0/0", "objects", None)
style = {"layers": [{"id": "shape", "source": "beta", "source-layer": "objects"}]}
out = module.audit_scope({"visual_objects": [obj]}, style, root, provider_id="beta", dataset_id="d")
self.assertEqual(out["exampleLocatorStatusCounts"], {"FEATURE_ID_UNAVAILABLE": 1})
obj["example"]["feature_id"] = 7
style["layers"].append({"id": "other", "source": "gamma", "source-layer": "objects"})
out = module.audit_scope({"visual_objects": [obj]}, style, root, provider_id="beta", dataset_id="d")
self.assertEqual(out["exampleLocatorStatusCounts"], {"STYLE_SOURCE_SCOPE_UNPROVEN": 1})
def test_two_visual_types_claiming_same_raw_feature_block_both(self):
with tempfile.TemporaryDirectory() as folder:
root = Path(folder)
write_tile(root, "1/0/0", "objects", [42])
style = {"layers": [{"id": "shape", "source": "beta", "source-layer": "objects"}]}
catalog = {"visual_objects": [
visual_object("VO-A", "1/0/0", "objects", 42),
visual_object("VO-B", "1/0/0", "objects", 42),
]}
out = module.audit_scope(catalog, style, root, provider_id="beta", dataset_id="d")
self.assertEqual(
out["exampleLocatorStatusCounts"],
{"EXAMPLE_LOCATOR_SHARED_BY_VISUAL_TYPES": 2},
)
self.assertTrue(all(row["tileLocalFeatureLocator"] is None for row in out["reviewQueue"]))
self.assertTrue(all(row["identityScope"] == "UNVERIFIED" for row in out["reviewQueue"]))
def test_invalid_tile_and_duplicate_visual_type_rejected(self):
obj = visual_object("VO-A", "../1/0", "objects", 10)
with self.assertRaisesRegex(ValueError, "路径"):
module.audit_scope({"visual_objects": [obj]}, {"layers": []}, Path("/tmp"), provider_id="p", dataset_id="d")
obj["example"]["tile"] = "1/0/0"
with self.assertRaisesRegex(ValueError, "重复"):
module.audit_scope({"visual_objects": [obj, obj]}, {"layers": []}, Path("/tmp"), provider_id="p", dataset_id="d")
if __name__ == "__main__":
unittest.main()