fix(client): reflect preselected SKU evidence states
This commit is contained in:
@@ -18,6 +18,7 @@ from xml.etree import ElementTree
|
||||
from PIL import Image, ImageDraw, UnidentifiedImageError
|
||||
|
||||
from ..pdd.product_url import ProductUrl, ProductUrlError, parse_product_url
|
||||
from ..pdd.sku_panel_state import HUMAN_DECLARED_STATES
|
||||
|
||||
|
||||
SANITIZER_VERSION = "t103-privacy-v1"
|
||||
@@ -27,9 +28,6 @@ EXPECTED_DEVICE_MODEL = "PKG110"
|
||||
EXPECTED_ANDROID_VERSION = "16"
|
||||
EXPECTED_WIDTH = 1080
|
||||
EXPECTED_HEIGHT = 2400
|
||||
HUMAN_DECLARED_STATES = frozenset(
|
||||
{"initial", "one-dimension-selected", "all-dimensions-selected"}
|
||||
)
|
||||
_ARTIFACT_FILES = ("screenshot.png", "hierarchy.xml")
|
||||
_SHA256_RE = re.compile(r"[0-9a-f]{64}\Z")
|
||||
_BOUNDS_RE = re.compile(r"\[(-?\d+),(-?\d+)\]\[(-?\d+),(-?\d+)\]\Z")
|
||||
|
||||
@@ -31,15 +31,7 @@ from ..device.baseline import (
|
||||
)
|
||||
from .product_open import EXPECTED_PDD_VERSION
|
||||
from .product_url import ProductUrl, parse_product_url
|
||||
|
||||
|
||||
HUMAN_DECLARED_STATES = frozenset(
|
||||
{
|
||||
"initial",
|
||||
"one-dimension-selected",
|
||||
"all-dimensions-selected",
|
||||
}
|
||||
)
|
||||
from .sku_panel_state import HUMAN_DECLARED_STATES
|
||||
|
||||
|
||||
class SkuPanelEvidenceError(RuntimeError):
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
"""T-103 的人工声明证据状态;不含任何页面识别或规格语义。"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
# 这些值由现场人员填写到 manifest,不能被解释为自动检测出的页面或选择状态。
|
||||
HUMAN_DECLARED_STATES = frozenset(
|
||||
{
|
||||
"panel-opened-target-preselected",
|
||||
"alternate-all-dimensions-selected",
|
||||
"target-selection-restored",
|
||||
}
|
||||
)
|
||||
@@ -54,7 +54,7 @@ def _default_xml() -> str:
|
||||
def _write_raw(
|
||||
root: Path,
|
||||
*,
|
||||
state: str = "initial",
|
||||
state: str = "panel-opened-target-preselected",
|
||||
goods_id: str = EXPECTED_GOODS_ID,
|
||||
model: str = "PKG110",
|
||||
android_version: str = "16",
|
||||
@@ -192,6 +192,14 @@ class SkuEvidenceSanitizerTests(unittest.TestCase):
|
||||
self.assertFalse((raw.parent / "derived").exists())
|
||||
self.assertEqual(list(raw.parent.glob(".derived.staging-*")), [])
|
||||
|
||||
def test_old_and_unknown_human_states_are_rejected(self) -> None:
|
||||
for state in ("initial", "one-dimension-selected", "all-dimensions-selected", "guessed"):
|
||||
with self.subTest(state=state), TemporaryDirectory() as temporary:
|
||||
raw = _write_raw(Path(temporary), state=state)
|
||||
with self.assertRaises(SkuEvidenceSanitizationError):
|
||||
sanitize_sku_panel_evidence(raw, raw.parent / "derived")
|
||||
self.assertFalse((raw.parent / "derived").exists())
|
||||
|
||||
def test_malformed_inputs_and_bounds_or_phone_residue_fail_closed(self) -> None:
|
||||
malformed = (
|
||||
("manifest", None),
|
||||
|
||||
@@ -124,14 +124,16 @@ class SkuPanelEvidenceTests(unittest.TestCase):
|
||||
|
||||
def test_invalid_state_and_url_fail_before_device_access(self) -> None:
|
||||
adb = FakeAdbClient()
|
||||
rejected_states = ("initial", "one-dimension-selected", "all-dimensions-selected", "guessed")
|
||||
with TemporaryDirectory() as temporary:
|
||||
with self.assertRaises(SkuPanelDeclaredStateError):
|
||||
self._capturer(adb, FakeUiDevice()).capture(SERIAL, URL, "guessed", Path(temporary) / "state")
|
||||
for state in rejected_states:
|
||||
with self.subTest(state=state), self.assertRaises(SkuPanelDeclaredStateError):
|
||||
self._capturer(adb, FakeUiDevice()).capture(SERIAL, URL, state, Path(temporary) / "state")
|
||||
with self.assertRaises(ProductUrlError):
|
||||
self._capturer(adb, FakeUiDevice()).capture(
|
||||
SERIAL,
|
||||
"https://mobile.yangkeduo.com/goods.html?goods_id=12x",
|
||||
"initial",
|
||||
"panel-opened-target-preselected",
|
||||
Path(temporary) / "url",
|
||||
)
|
||||
|
||||
@@ -146,7 +148,7 @@ class SkuPanelEvidenceTests(unittest.TestCase):
|
||||
with self.subTest(error_type=error_type.__name__), TemporaryDirectory() as temporary:
|
||||
target = Path(temporary) / "evidence"
|
||||
with self.assertRaises(error_type):
|
||||
self._capturer(FakeAdbClient(), device).capture(SERIAL, URL, "initial", target)
|
||||
self._capturer(FakeAdbClient(), device).capture(SERIAL, URL, "panel-opened-target-preselected", target)
|
||||
|
||||
self.assertEqual(device.calls, expected_calls)
|
||||
self.assertFalse(target.exists())
|
||||
@@ -160,7 +162,7 @@ class SkuPanelEvidenceTests(unittest.TestCase):
|
||||
with self.subTest(error_type=error_type.__name__), TemporaryDirectory() as temporary:
|
||||
target = Path(temporary) / "evidence"
|
||||
with self.assertRaises(error_type):
|
||||
self._capturer(FakeAdbClient(), device).capture(SERIAL, URL, "initial", target)
|
||||
self._capturer(FakeAdbClient(), device).capture(SERIAL, URL, "panel-opened-target-preselected", target)
|
||||
|
||||
self.assertFalse(target.exists())
|
||||
self.assertEqual(list(Path(temporary).glob(".evidence.staging-*")), [])
|
||||
@@ -176,7 +178,7 @@ class SkuPanelEvidenceTests(unittest.TestCase):
|
||||
with TemporaryDirectory() as temporary:
|
||||
target = Path(temporary) / "evidence"
|
||||
with self.assertRaises(SkuPanelEvidenceTimeoutError) as raised:
|
||||
self._capturer(FakeAdbClient(), TimeoutScreenshotDevice()).capture(SERIAL, URL, "initial", target)
|
||||
self._capturer(FakeAdbClient(), TimeoutScreenshotDevice()).capture(SERIAL, URL, "panel-opened-target-preselected", target)
|
||||
|
||||
self.assertNotIn(SERIAL, str(raised.exception))
|
||||
self.assertNotIn("adb", str(raised.exception).lower())
|
||||
@@ -193,7 +195,7 @@ class SkuPanelEvidenceTests(unittest.TestCase):
|
||||
sentinel.write_text("keep", encoding="utf-8")
|
||||
|
||||
with self.assertRaises(SkuPanelEvidenceError):
|
||||
self._capturer(adb, device).capture(SERIAL, URL, "initial", target)
|
||||
self._capturer(adb, device).capture(SERIAL, URL, "panel-opened-target-preselected", target)
|
||||
|
||||
self.assertEqual(adb.calls, [])
|
||||
self.assertEqual(device.calls, [])
|
||||
@@ -224,7 +226,7 @@ class SkuPanelSpikeCliTests(unittest.TestCase):
|
||||
"serial": SERIAL,
|
||||
"url": URL,
|
||||
"goods_id": None,
|
||||
"state": "initial",
|
||||
"state": "panel-opened-target-preselected",
|
||||
"output_dir": Path("evidence"),
|
||||
"timeout": 10.0,
|
||||
"adb": "adb",
|
||||
@@ -234,6 +236,9 @@ class SkuPanelSpikeCliTests(unittest.TestCase):
|
||||
("timeout", 0),
|
||||
("timeout", float("inf")),
|
||||
("state", "not-declared"),
|
||||
("state", "initial"),
|
||||
("state", "one-dimension-selected"),
|
||||
("state", "all-dimensions-selected"),
|
||||
("url", "https://mobile.yangkeduo.com/goods.html?goods_id=bad"),
|
||||
)
|
||||
for field, value in invalid_values:
|
||||
@@ -248,7 +253,7 @@ class SkuPanelSpikeCliTests(unittest.TestCase):
|
||||
serial=SERIAL,
|
||||
url=None,
|
||||
goods_id="00123",
|
||||
state="all-dimensions-selected",
|
||||
state="target-selection-restored",
|
||||
output_dir=Path("evidence"),
|
||||
timeout=10.0,
|
||||
adb="adb",
|
||||
|
||||
Reference in New Issue
Block a user