feat: 移除 Client 真实采购手工授权 (#114)
This commit is contained in:
@@ -1,87 +0,0 @@
|
||||
"""真实下单授权服务测试;不连接 Admin 或手机。"""
|
||||
|
||||
import os
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
from src.live_purchase_authorization import (
|
||||
LIVE_CONFIRMATION_TEXT,
|
||||
LIVE_ENABLED_KEY,
|
||||
LivePurchaseAuthorizationService,
|
||||
)
|
||||
from src.settings_repository import SettingsRepository
|
||||
|
||||
|
||||
class LivePurchaseAuthorizationTest(unittest.TestCase):
|
||||
def setUp(self) -> None:
|
||||
self.temporary_directory = tempfile.TemporaryDirectory()
|
||||
repository = SettingsRepository(
|
||||
Path(self.temporary_directory.name) / "client.db"
|
||||
)
|
||||
self.repository = repository
|
||||
self.service = LivePurchaseAuthorizationService(repository)
|
||||
|
||||
def tearDown(self) -> None:
|
||||
self.temporary_directory.cleanup()
|
||||
|
||||
def test_missing_setting_and_environment_always_default_to_dry_run(self):
|
||||
os.environ["CMAUTOBUY_PURCHASE_MODE"] = "live"
|
||||
try:
|
||||
self.assertFalse(self.service.load().enabled)
|
||||
self.assertEqual(
|
||||
self.service.purchase_mode_for(
|
||||
"CLIENT-1", "USB-1", live_adapter_ready=True
|
||||
),
|
||||
"dry_run",
|
||||
)
|
||||
finally:
|
||||
os.environ.pop("CMAUTOBUY_PURCHASE_MODE", None)
|
||||
|
||||
def test_enable_requires_exact_confirmation_and_binds_identity(self):
|
||||
with self.assertRaisesRegex(ValueError, LIVE_CONFIRMATION_TEXT):
|
||||
self.service.enable("CLIENT-1", "USB-1", "确认")
|
||||
self.assertIsNone(self.repository.get(LIVE_ENABLED_KEY))
|
||||
|
||||
authorization = self.service.enable(
|
||||
"CLIENT-1", "USB-1", LIVE_CONFIRMATION_TEXT
|
||||
)
|
||||
|
||||
self.assertTrue(authorization.enabled)
|
||||
self.assertTrue(authorization.matches("CLIENT-1", "USB-1"))
|
||||
self.assertEqual(
|
||||
self.service.purchase_mode_for(
|
||||
"CLIENT-1", "USB-1", live_adapter_ready=True
|
||||
),
|
||||
"live",
|
||||
)
|
||||
|
||||
def test_binding_mismatch_or_missing_adapter_stays_dry_run(self):
|
||||
self.service.enable("CLIENT-1", "USB-1", LIVE_CONFIRMATION_TEXT)
|
||||
|
||||
self.assertEqual(
|
||||
self.service.purchase_mode_for(
|
||||
"CLIENT-2", "USB-1", live_adapter_ready=True
|
||||
),
|
||||
"dry_run",
|
||||
)
|
||||
self.assertEqual(
|
||||
self.service.purchase_mode_for(
|
||||
"CLIENT-1", "USB-2", live_adapter_ready=True
|
||||
),
|
||||
"dry_run",
|
||||
)
|
||||
self.assertEqual(
|
||||
self.service.purchase_mode_for(
|
||||
"CLIENT-1", "USB-1", live_adapter_ready=False
|
||||
),
|
||||
"dry_run",
|
||||
)
|
||||
|
||||
def test_disable_is_immediate_and_does_not_require_confirmation(self):
|
||||
self.service.enable("CLIENT-1", "USB-1", LIVE_CONFIRMATION_TEXT)
|
||||
|
||||
authorization = self.service.disable()
|
||||
|
||||
self.assertFalse(authorization.enabled)
|
||||
self.assertFalse(self.service.load().enabled)
|
||||
@@ -1249,6 +1249,27 @@ class PDDTaskPageEventTest(unittest.TestCase):
|
||||
events.shutdown()
|
||||
page.deleteLater()
|
||||
|
||||
def test_ready_runtime_automatically_declares_live_capability(self):
|
||||
gateway = RecordingClaimGateway(None)
|
||||
page = PDDTaskPage()
|
||||
events = PDDTaskPageEvent(
|
||||
page,
|
||||
self.repository,
|
||||
claim_gateway=gateway,
|
||||
settings_repository=self._saved_settings(),
|
||||
purchase_adapter_factory=fake_purchase_factory,
|
||||
live_purchase_adapter_factory=lambda *_args: None,
|
||||
)
|
||||
|
||||
page.autoFetchRequested.emit()
|
||||
|
||||
self.assertTrue(wait_until(self.app, lambda: not events._claim_busy))
|
||||
_, capabilities = gateway.calls[0]
|
||||
self.assertEqual(capabilities.purchase_mode, "live")
|
||||
self.assertIn(TaskType.PURCHASE, capabilities.supported_types)
|
||||
events.shutdown()
|
||||
page.deleteLater()
|
||||
|
||||
def test_no_task_schedules_next_claim_and_stop_cancels_timer(self):
|
||||
gateway = RecordingClaimGateway(None)
|
||||
page = PDDTaskPage()
|
||||
|
||||
@@ -19,13 +19,10 @@ from src.android_device_service import (
|
||||
AndroidWifiConversionResult,
|
||||
)
|
||||
from src.mock_admin_gateway import MockAdminGateway
|
||||
from src.live_purchase_authorization import (
|
||||
LIVE_CONFIRMATION_TEXT,
|
||||
LIVE_ENABLED_KEY,
|
||||
)
|
||||
from src.selected_android_device_service import SELECTED_ANDROID_SERIAL_KEY
|
||||
from src.settings_repository import SettingsRepository
|
||||
from src.settings_ui import AndroidDeviceRow, SettingsPage
|
||||
from src.task_models import TaskType
|
||||
|
||||
|
||||
class SlowMockAdminGateway(MockAdminGateway):
|
||||
@@ -219,23 +216,20 @@ class SettingsPageEventTest(unittest.TestCase):
|
||||
page.eventBinder.shutdown()
|
||||
page.deleteLater()
|
||||
|
||||
def test_live_purchase_defaults_off_and_requires_exact_confirmation(self):
|
||||
def test_settings_page_has_no_manual_live_purchase_authorization(self):
|
||||
page = SettingsPage(
|
||||
settings_repository=self.repository,
|
||||
admin_gateway=MockAdminGateway(),
|
||||
live_purchase_adapter_ready=True,
|
||||
)
|
||||
|
||||
self.assertIn("已关闭", page.livePurchaseStatusLabel.text())
|
||||
self.assertFalse(page.livePurchaseEnableButton.isEnabled())
|
||||
page.livePurchaseConfirmationInput.setText("确认")
|
||||
self.assertFalse(page.livePurchaseEnableButton.isEnabled())
|
||||
page.livePurchaseConfirmationInput.setText(LIVE_CONFIRMATION_TEXT)
|
||||
self.assertTrue(page.livePurchaseEnableButton.isEnabled())
|
||||
self.assertFalse(hasattr(page, "livePurchaseCard"))
|
||||
self.assertFalse(hasattr(page, "livePurchaseEnableButton"))
|
||||
self.assertFalse(hasattr(page, "livePurchaseConfirmationInput"))
|
||||
page.eventBinder.shutdown()
|
||||
page.deleteLater()
|
||||
|
||||
def test_enable_and_disable_live_purchase_updates_admin_capability(self):
|
||||
def test_ready_client_automatically_registers_live_capability(self):
|
||||
self.repository.set_many(
|
||||
{
|
||||
"admin.client_id": "CLIENT-LIVE",
|
||||
@@ -252,27 +246,12 @@ class SettingsPageEventTest(unittest.TestCase):
|
||||
live_purchase_adapter_ready=True,
|
||||
)
|
||||
self._wait_until(lambda: page.eventBinder._search_thread is None)
|
||||
page.livePurchaseConfirmationInput.setText(LIVE_CONFIRMATION_TEXT)
|
||||
|
||||
page.livePurchaseEnableButton.click()
|
||||
self._wait_until(
|
||||
lambda: page.eventBinder._live_purchase_thread is None
|
||||
)
|
||||
|
||||
self.assertIs(self.repository.get(LIVE_ENABLED_KEY), True)
|
||||
self.assertIn("已启用", page.livePurchaseStatusLabel.text())
|
||||
page.currentDeviceSaveButton.click()
|
||||
self._wait_until(lambda: gateway.registration_count == 1)
|
||||
self._wait_until(lambda: page.eventBinder._thread is None)
|
||||
registered = gateway.registered_client("CLIENT-LIVE")
|
||||
self.assertEqual(registered[1].purchase_mode, "live")
|
||||
|
||||
page.livePurchaseDisableButton.click()
|
||||
self._wait_until(
|
||||
lambda: page.eventBinder._live_purchase_thread is None
|
||||
)
|
||||
|
||||
self.assertIs(self.repository.get(LIVE_ENABLED_KEY), False)
|
||||
self.assertIn("已关闭", page.livePurchaseStatusLabel.text())
|
||||
registered = gateway.registered_client("CLIENT-LIVE")
|
||||
self.assertEqual(registered[1].purchase_mode, "dry_run")
|
||||
self.assertIn(TaskType.PURCHASE, registered[1].supported_types)
|
||||
page.eventBinder.shutdown()
|
||||
page.deleteLater()
|
||||
|
||||
|
||||
@@ -220,11 +220,11 @@ class TaskDispatcherTest(unittest.TestCase):
|
||||
authorized.claim_capabilities().purchase_mode, "live"
|
||||
)
|
||||
|
||||
def test_local_live_task_never_runs_after_authorization_is_disabled(self):
|
||||
def test_local_live_task_never_runs_when_runtime_is_not_ready(self):
|
||||
task = purchase_task(execution_mode="live")
|
||||
self.repository.add_claimed_task(admin_task_to_new_claimed_task(task))
|
||||
|
||||
with self.assertRaisesRegex(RuntimeError, "授权已关闭"):
|
||||
with self.assertRaisesRegex(RuntimeError, "设备或真实采购执行器未就绪"):
|
||||
self._dispatcher(
|
||||
purchase_ready=True,
|
||||
live_ready=True,
|
||||
|
||||
Reference in New Issue
Block a user