fix(client): reflect preselected SKU evidence states

This commit is contained in:
QiuSW
2026-08-04 11:38:15 +08:00
parent 3d063b9785
commit dbb69a7d5e
5 changed files with 38 additions and 22 deletions
@@ -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),
+14 -9
View File
@@ -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",