145 lines
7.5 KiB
Python
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()
|