feat(client): add guarded product link capture

This commit is contained in:
QiuSW
2026-08-04 09:26:37 +08:00
parent e7a4be1b9b
commit 7040bb61d8
11 changed files with 808 additions and 13 deletions
+93 -2
View File
@@ -16,11 +16,14 @@ from cmbuyer_client.device.adb import (
AdbClient,
CommandResult,
DeviceIdentityUnconfirmedError,
DeviceCommandError,
DeviceCommandTimeoutError,
DeviceNotFoundError,
DeviceOfflineError,
DeviceStateError,
DeviceUnauthorizedError,
DuplicatePhysicalDeviceError,
IntentLaunchUnconfirmedError,
SerialRequiredError,
)
@@ -176,7 +179,95 @@ class AdbClientTests(unittest.TestCase):
def run(self, arguments: Sequence[str], timeout_seconds: float) -> CommandResult:
raise subprocess.TimeoutExpired(arguments, timeout_seconds)
from cmbuyer_client.device.adb import DeviceCommandTimeoutError
with self.assertRaises(DeviceCommandTimeoutError):
AdbClient(TimeoutRunner()).inspect(USB_SERIAL)
def test_product_intent_is_fixed_to_action_view_and_pdd_package(self) -> None:
class IntentRunner:
def __init__(self) -> None:
self.calls: list[tuple[str, ...]] = []
def run(self, arguments: Sequence[str], timeout_seconds: float) -> CommandResult:
self.calls.append(tuple(arguments))
return CommandResult(stdout="Status: ok\n")
runner = IntentRunner()
summary = AdbClient(runner).start_pdd_view_intent(
USB_SERIAL,
"123",
)
self.assertEqual(summary.status, "ok")
self.assertEqual(
runner.calls,
[
(
"-s",
USB_SERIAL,
"shell",
"am",
"start",
"-W",
"-a",
"android.intent.action.VIEW",
"-d",
"https://mobile.yangkeduo.com/goods.html?goods_id=123",
"-p",
"com.xunmeng.pinduoduo",
)
],
)
def test_product_intent_without_explicit_success_is_rejected(self) -> None:
class UnknownIntentRunner:
def run(self, arguments: Sequence[str], timeout_seconds: float) -> CommandResult:
return CommandResult(stdout="Starting: Intent { ... }\n")
with self.assertRaises(IntentLaunchUnconfirmedError):
AdbClient(UnknownIntentRunner()).start_pdd_view_intent(
USB_SERIAL,
"123",
)
def test_product_intent_rejects_invalid_goods_id_before_runner(self) -> None:
class RecordingRunner:
def __init__(self) -> None:
self.calls: list[tuple[str, ...]] = []
def run(self, arguments: Sequence[str], timeout_seconds: float) -> CommandResult:
self.calls.append(tuple(arguments))
return CommandResult(stdout="Status: ok\n")
invalid_values: tuple[object, ...] = (
"",
"12a",
"123",
" 123",
"123 ",
"https://mobile.yangkeduo.com/goods.html?goods_id=123",
"am start -W -d anything",
123,
None,
)
for value in invalid_values:
with self.subTest(value=repr(value)):
runner = RecordingRunner()
with self.assertRaises(ValueError):
AdbClient(runner).start_pdd_view_intent(USB_SERIAL, value) # type: ignore[arg-type]
self.assertEqual(runner.calls, [])
def test_product_intent_nonzero_and_timeout_remain_distinct(self) -> None:
class FailedIntentRunner:
def run(self, arguments: Sequence[str], timeout_seconds: float) -> CommandResult:
return CommandResult(stdout="sensitive command output", returncode=1)
class TimeoutIntentRunner:
def run(self, arguments: Sequence[str], timeout_seconds: float) -> CommandResult:
raise subprocess.TimeoutExpired(arguments, timeout_seconds)
with self.assertRaises(DeviceCommandError) as command_error:
AdbClient(FailedIntentRunner()).start_pdd_view_intent(USB_SERIAL, "123")
self.assertNotIn("sensitive command output", str(command_error.exception))
with self.assertRaises(DeviceCommandTimeoutError):
AdbClient(TimeoutIntentRunner()).start_pdd_view_intent(USB_SERIAL, "123")