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 PIL import Image, ImageDraw, UnidentifiedImageError
|
||||||
|
|
||||||
from ..pdd.product_url import ProductUrl, ProductUrlError, parse_product_url
|
from ..pdd.product_url import ProductUrl, ProductUrlError, parse_product_url
|
||||||
|
from ..pdd.sku_panel_state import HUMAN_DECLARED_STATES
|
||||||
|
|
||||||
|
|
||||||
SANITIZER_VERSION = "t103-privacy-v1"
|
SANITIZER_VERSION = "t103-privacy-v1"
|
||||||
@@ -27,9 +28,6 @@ EXPECTED_DEVICE_MODEL = "PKG110"
|
|||||||
EXPECTED_ANDROID_VERSION = "16"
|
EXPECTED_ANDROID_VERSION = "16"
|
||||||
EXPECTED_WIDTH = 1080
|
EXPECTED_WIDTH = 1080
|
||||||
EXPECTED_HEIGHT = 2400
|
EXPECTED_HEIGHT = 2400
|
||||||
HUMAN_DECLARED_STATES = frozenset(
|
|
||||||
{"initial", "one-dimension-selected", "all-dimensions-selected"}
|
|
||||||
)
|
|
||||||
_ARTIFACT_FILES = ("screenshot.png", "hierarchy.xml")
|
_ARTIFACT_FILES = ("screenshot.png", "hierarchy.xml")
|
||||||
_SHA256_RE = re.compile(r"[0-9a-f]{64}\Z")
|
_SHA256_RE = re.compile(r"[0-9a-f]{64}\Z")
|
||||||
_BOUNDS_RE = re.compile(r"\[(-?\d+),(-?\d+)\]\[(-?\d+),(-?\d+)\]\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_open import EXPECTED_PDD_VERSION
|
||||||
from .product_url import ProductUrl, parse_product_url
|
from .product_url import ProductUrl, parse_product_url
|
||||||
|
from .sku_panel_state import HUMAN_DECLARED_STATES
|
||||||
|
|
||||||
HUMAN_DECLARED_STATES = frozenset(
|
|
||||||
{
|
|
||||||
"initial",
|
|
||||||
"one-dimension-selected",
|
|
||||||
"all-dimensions-selected",
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class SkuPanelEvidenceError(RuntimeError):
|
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(
|
def _write_raw(
|
||||||
root: Path,
|
root: Path,
|
||||||
*,
|
*,
|
||||||
state: str = "initial",
|
state: str = "panel-opened-target-preselected",
|
||||||
goods_id: str = EXPECTED_GOODS_ID,
|
goods_id: str = EXPECTED_GOODS_ID,
|
||||||
model: str = "PKG110",
|
model: str = "PKG110",
|
||||||
android_version: str = "16",
|
android_version: str = "16",
|
||||||
@@ -192,6 +192,14 @@ class SkuEvidenceSanitizerTests(unittest.TestCase):
|
|||||||
self.assertFalse((raw.parent / "derived").exists())
|
self.assertFalse((raw.parent / "derived").exists())
|
||||||
self.assertEqual(list(raw.parent.glob(".derived.staging-*")), [])
|
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:
|
def test_malformed_inputs_and_bounds_or_phone_residue_fail_closed(self) -> None:
|
||||||
malformed = (
|
malformed = (
|
||||||
("manifest", None),
|
("manifest", None),
|
||||||
|
|||||||
@@ -124,14 +124,16 @@ class SkuPanelEvidenceTests(unittest.TestCase):
|
|||||||
|
|
||||||
def test_invalid_state_and_url_fail_before_device_access(self) -> None:
|
def test_invalid_state_and_url_fail_before_device_access(self) -> None:
|
||||||
adb = FakeAdbClient()
|
adb = FakeAdbClient()
|
||||||
|
rejected_states = ("initial", "one-dimension-selected", "all-dimensions-selected", "guessed")
|
||||||
with TemporaryDirectory() as temporary:
|
with TemporaryDirectory() as temporary:
|
||||||
with self.assertRaises(SkuPanelDeclaredStateError):
|
for state in rejected_states:
|
||||||
self._capturer(adb, FakeUiDevice()).capture(SERIAL, URL, "guessed", Path(temporary) / "state")
|
with self.subTest(state=state), self.assertRaises(SkuPanelDeclaredStateError):
|
||||||
|
self._capturer(adb, FakeUiDevice()).capture(SERIAL, URL, state, Path(temporary) / "state")
|
||||||
with self.assertRaises(ProductUrlError):
|
with self.assertRaises(ProductUrlError):
|
||||||
self._capturer(adb, FakeUiDevice()).capture(
|
self._capturer(adb, FakeUiDevice()).capture(
|
||||||
SERIAL,
|
SERIAL,
|
||||||
"https://mobile.yangkeduo.com/goods.html?goods_id=12x",
|
"https://mobile.yangkeduo.com/goods.html?goods_id=12x",
|
||||||
"initial",
|
"panel-opened-target-preselected",
|
||||||
Path(temporary) / "url",
|
Path(temporary) / "url",
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -146,7 +148,7 @@ class SkuPanelEvidenceTests(unittest.TestCase):
|
|||||||
with self.subTest(error_type=error_type.__name__), TemporaryDirectory() as temporary:
|
with self.subTest(error_type=error_type.__name__), TemporaryDirectory() as temporary:
|
||||||
target = Path(temporary) / "evidence"
|
target = Path(temporary) / "evidence"
|
||||||
with self.assertRaises(error_type):
|
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.assertEqual(device.calls, expected_calls)
|
||||||
self.assertFalse(target.exists())
|
self.assertFalse(target.exists())
|
||||||
@@ -160,7 +162,7 @@ class SkuPanelEvidenceTests(unittest.TestCase):
|
|||||||
with self.subTest(error_type=error_type.__name__), TemporaryDirectory() as temporary:
|
with self.subTest(error_type=error_type.__name__), TemporaryDirectory() as temporary:
|
||||||
target = Path(temporary) / "evidence"
|
target = Path(temporary) / "evidence"
|
||||||
with self.assertRaises(error_type):
|
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.assertFalse(target.exists())
|
||||||
self.assertEqual(list(Path(temporary).glob(".evidence.staging-*")), [])
|
self.assertEqual(list(Path(temporary).glob(".evidence.staging-*")), [])
|
||||||
@@ -176,7 +178,7 @@ class SkuPanelEvidenceTests(unittest.TestCase):
|
|||||||
with TemporaryDirectory() as temporary:
|
with TemporaryDirectory() as temporary:
|
||||||
target = Path(temporary) / "evidence"
|
target = Path(temporary) / "evidence"
|
||||||
with self.assertRaises(SkuPanelEvidenceTimeoutError) as raised:
|
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(SERIAL, str(raised.exception))
|
||||||
self.assertNotIn("adb", str(raised.exception).lower())
|
self.assertNotIn("adb", str(raised.exception).lower())
|
||||||
@@ -193,7 +195,7 @@ class SkuPanelEvidenceTests(unittest.TestCase):
|
|||||||
sentinel.write_text("keep", encoding="utf-8")
|
sentinel.write_text("keep", encoding="utf-8")
|
||||||
|
|
||||||
with self.assertRaises(SkuPanelEvidenceError):
|
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(adb.calls, [])
|
||||||
self.assertEqual(device.calls, [])
|
self.assertEqual(device.calls, [])
|
||||||
@@ -224,7 +226,7 @@ class SkuPanelSpikeCliTests(unittest.TestCase):
|
|||||||
"serial": SERIAL,
|
"serial": SERIAL,
|
||||||
"url": URL,
|
"url": URL,
|
||||||
"goods_id": None,
|
"goods_id": None,
|
||||||
"state": "initial",
|
"state": "panel-opened-target-preselected",
|
||||||
"output_dir": Path("evidence"),
|
"output_dir": Path("evidence"),
|
||||||
"timeout": 10.0,
|
"timeout": 10.0,
|
||||||
"adb": "adb",
|
"adb": "adb",
|
||||||
@@ -234,6 +236,9 @@ class SkuPanelSpikeCliTests(unittest.TestCase):
|
|||||||
("timeout", 0),
|
("timeout", 0),
|
||||||
("timeout", float("inf")),
|
("timeout", float("inf")),
|
||||||
("state", "not-declared"),
|
("state", "not-declared"),
|
||||||
|
("state", "initial"),
|
||||||
|
("state", "one-dimension-selected"),
|
||||||
|
("state", "all-dimensions-selected"),
|
||||||
("url", "https://mobile.yangkeduo.com/goods.html?goods_id=bad"),
|
("url", "https://mobile.yangkeduo.com/goods.html?goods_id=bad"),
|
||||||
)
|
)
|
||||||
for field, value in invalid_values:
|
for field, value in invalid_values:
|
||||||
@@ -248,7 +253,7 @@ class SkuPanelSpikeCliTests(unittest.TestCase):
|
|||||||
serial=SERIAL,
|
serial=SERIAL,
|
||||||
url=None,
|
url=None,
|
||||||
goods_id="00123",
|
goods_id="00123",
|
||||||
state="all-dimensions-selected",
|
state="target-selection-restored",
|
||||||
output_dir=Path("evidence"),
|
output_dir=Path("evidence"),
|
||||||
timeout=10.0,
|
timeout=10.0,
|
||||||
adb="adb",
|
adb="adb",
|
||||||
|
|||||||
Reference in New Issue
Block a user