功能:隔离五类测试业务链路

This commit is contained in:
焦龙言
2026-09-23 08:27:14 +08:00
parent 43fe17cc70
commit f5df2150d8
18 changed files with 1206 additions and 831 deletions
@@ -31,6 +31,7 @@ from module_business.dao.inventory_dao import InventoryDao
from module_business.dao.master_dao import MasterDao
from module_business.dao.operation_dao import OperationDao
from module_business.domain.enums import PalletEventType, PalletFlowState
from module_business.domain.test_batch_scope import TestBatchScope
from module_business.entity.do.master_do import BizCustomerSite, BizPallet, BizProductionLine
from module_business.entity.do.operation_do import (
BizFillingRecord,
@@ -48,6 +49,7 @@ from module_business.entity.vo.operation_vo import (
UsageSuccessResponseModel,
)
from module_business.service.access_service import AccessService
from tests.module_business.test_batch_fixtures import make_test_scope
SERVICE_SPEC = importlib.util.find_spec('module_business.service.usage_service')
CONTROLLER_SPEC = importlib.util.find_spec('module_business.controller.usage_controller')
@@ -223,6 +225,17 @@ class TestUsageBootstrap(unittest.TestCase):
@unittest.skipUnless(UsageService is not None, 'UsageService 尚未实现')
class TestUsagePublicContract(unittest.TestCase):
def test_public_business_methods_require_explicit_test_scope(self) -> None:
for method_name in (
'get_usage_list_services',
'usage_detail_services',
'get_line_options_services',
'scan_usage_pallet_services',
'record_usage_services',
):
with self.subTest(method=method_name):
self.assertIn('test_scope', inspect.signature(getattr(UsageService, method_name)).parameters)
def test_service_exposes_complete_usage_workflow(self) -> None:
expected = {
'get_usage_list_services',
@@ -235,11 +248,12 @@ class TestUsagePublicContract(unittest.TestCase):
def test_record_signature_and_types_are_exact(self) -> None:
signature = inspect.signature(UsageService.record_usage_services)
self.assertEqual(('query_db', 'page_object', 'current_user'), tuple(signature.parameters))
self.assertEqual(('query_db', 'page_object', 'current_user', 'test_scope'), tuple(signature.parameters))
hints = get_type_hints(UsageService.record_usage_services)
self.assertIs(AsyncSession, hints['query_db'])
self.assertIs(UsageCreateModel, hints['page_object'])
self.assertIs(CurrentUserModel, hints['current_user'])
self.assertIs(TestBatchScope, hints['test_scope'])
self.assertIs(CrudResponseModel, hints['return'])
def test_request_hash_is_stable_normalized_and_excludes_idempotency_key(self) -> None:
@@ -319,9 +333,15 @@ class TestUsageReadServices(unittest.IsolatedAsyncioTestCase):
patch.object(AccessDao, 'list_user_site_ids', new=AsyncMock(return_value=[11, 9, 9])),
patch.object(OperationDao, 'get_usage_list', new=get_list),
):
result = await UsageService.get_usage_list_services(self.db, query, self.user)
result = await UsageService.get_usage_list_services(self.db, query, self.user, TestBatchScope.formal())
get_list.assert_awaited_once_with(self.db, query, True, site_ids=[9, 11])
get_list.assert_awaited_once_with(
self.db,
query,
site_ids=[9, 11],
scope=TestBatchScope.formal(),
is_page=True,
)
self.assertEqual(1, result.total)
self.assertIsInstance(result.rows[0], UsageModel)
@@ -337,6 +357,7 @@ class TestUsageReadServices(unittest.IsolatedAsyncioTestCase):
self.db,
UsagePageQueryModel(pageNum=2, pageSize=7),
self.user,
TestBatchScope.formal(),
is_page=is_page,
)
@@ -360,6 +381,7 @@ class TestUsageReadServices(unittest.IsolatedAsyncioTestCase):
self.db,
UsagePageQueryModel(siteId=10),
self.user,
TestBatchScope.formal(),
)
self.assertEqual('无权访问该客户现场', raised.exception.message)
@@ -377,11 +399,18 @@ class TestUsageReadServices(unittest.IsolatedAsyncioTestCase):
self.db,
query,
make_user(1),
TestBatchScope.formal(),
is_page=False,
)
get_scope.assert_not_awaited()
get_list.assert_awaited_once_with(self.db, query, False, site_ids=None)
get_list.assert_awaited_once_with(
self.db,
query,
site_ids=None,
scope=TestBatchScope.formal(),
is_page=False,
)
self.assertEqual([], result)
async def test_detail_is_scoped_and_hides_missing_but_admin_gets_precise_error(self) -> None:
@@ -396,9 +425,14 @@ class TestUsageReadServices(unittest.IsolatedAsyncioTestCase):
patch.object(OperationDao, 'get_usage_by_id', new=get_detail),
self.assertRaises(expected_exception) as raised,
):
await UsageService.usage_detail_services(self.db, 61, user)
await UsageService.usage_detail_services(self.db, 61, user, TestBatchScope.formal())
get_detail.assert_awaited_once_with(self.db, 61, site_ids=expected_scope)
get_detail.assert_awaited_once_with(
self.db,
61,
TestBatchScope.formal(),
site_ids=expected_scope,
)
self.assertEqual(expected_message, raised.exception.message)
async def test_line_options_require_site_access_and_only_return_enabled_lines_for_site(self) -> None:
@@ -415,14 +449,15 @@ class TestUsageReadServices(unittest.IsolatedAsyncioTestCase):
patch.object(MasterDao, 'get_site', new=AsyncMock(return_value=make_site())),
patch.object(MasterDao, 'list_line', new=list_line),
):
result = await UsageService.get_line_options_services(self.db, 9, self.user)
result = await UsageService.get_line_options_services(self.db, 9, self.user, TestBatchScope.formal())
access.assert_awaited_once_with(self.db, self.user, 9)
query = list_line.await_args.args[1]
self.assertIsInstance(query, LinePageQueryModel)
self.assertEqual(9, query.site_id)
self.assertEqual('0', query.status)
self.assertFalse(list_line.await_args.args[2])
self.assertEqual(TestBatchScope.formal(), list_line.await_args.args[2])
self.assertFalse(list_line.await_args.args[3])
self.assertEqual([3, 6], [option.id for option in result])
self.assertTrue(all(isinstance(option, BusinessOptionModel) for option in result))
@@ -439,7 +474,7 @@ class TestUsageReadServices(unittest.IsolatedAsyncioTestCase):
patch.object(MasterDao, 'list_line', new=list_line),
self.assertRaises(PermissionException),
):
await UsageService.get_line_options_services(self.db, 9, self.user)
await UsageService.get_line_options_services(self.db, 9, self.user, TestBatchScope.formal())
get_site.assert_not_awaited()
list_line.assert_not_awaited()
@@ -466,10 +501,10 @@ class TestUsageReadServices(unittest.IsolatedAsyncioTestCase):
patch.object(InventoryDao, 'get_pallets_by_ids', new=pallet_lock),
patch.object(OperationDao, 'get_active_filling_for_update', new=filling_lock),
):
result = await UsageService.scan_usage_pallet_services(self.db, 'qr-2', self.user)
result = await UsageService.scan_usage_pallet_services(self.db, 'qr-2', self.user, TestBatchScope.formal())
access.assert_awaited_once_with(self.db, self.user, 9)
get_filling.assert_awaited_once_with(self.db, 31)
get_filling.assert_awaited_once_with(self.db, 31, TestBatchScope.formal())
inventory_lock.assert_not_awaited()
pallet_lock.assert_not_awaited()
filling_lock.assert_not_awaited()
@@ -489,7 +524,7 @@ class TestUsageReadServices(unittest.IsolatedAsyncioTestCase):
patch.object(InventoryDao, 'get_pallet_by_qr_token', new=AsyncMock(return_value=None)),
self.assertRaises(PermissionException) as missing,
):
await UsageService.scan_usage_pallet_services(self.db, 'missing', self.user)
await UsageService.scan_usage_pallet_services(self.db, 'missing', self.user, TestBatchScope.formal())
self.assertEqual('无权访问该托盘', missing.exception.message)
with (
@@ -497,7 +532,7 @@ class TestUsageReadServices(unittest.IsolatedAsyncioTestCase):
patch.object(MasterDao, 'get_pallet_inventory', new=AsyncMock(return_value=make_inventory(site_id=None))),
self.assertRaises(PermissionException) as non_site,
):
await UsageService.scan_usage_pallet_services(self.db, 'qr-2', self.user)
await UsageService.scan_usage_pallet_services(self.db, 'qr-2', self.user, TestBatchScope.formal())
self.assertEqual('无权访问该托盘', non_site.exception.message)
with (
@@ -510,7 +545,7 @@ class TestUsageReadServices(unittest.IsolatedAsyncioTestCase):
),
self.assertRaises(PermissionException) as unauthorized,
):
await UsageService.scan_usage_pallet_services(self.db, 'qr-2', self.user)
await UsageService.scan_usage_pallet_services(self.db, 'qr-2', self.user, TestBatchScope.formal())
self.assertEqual('无权访问该托盘', unauthorized.exception.message)
async def test_scan_admin_keeps_precise_missing_error(self) -> None:
@@ -518,7 +553,7 @@ class TestUsageReadServices(unittest.IsolatedAsyncioTestCase):
patch.object(InventoryDao, 'get_pallet_by_qr_token', new=AsyncMock(return_value=None)),
self.assertRaises(ServiceException) as raised,
):
await UsageService.scan_usage_pallet_services(self.db, 'missing', make_user(1))
await UsageService.scan_usage_pallet_services(self.db, 'missing', make_user(1), TestBatchScope.formal())
self.assertEqual('托盘不存在', raised.exception.message)
@@ -644,6 +679,7 @@ class TestUsageControllerResponse(unittest.IsolatedAsyncioTestCase):
db = MagicMock(spec=AsyncSession)
user = make_user()
page = make_page()
test_scope = make_test_scope(9)
service = AsyncMock(
return_value=CrudResponseModel(
is_success=True,
@@ -661,9 +697,10 @@ class TestUsageControllerResponse(unittest.IsolatedAsyncioTestCase):
add_usage=page,
query_db=db,
current_user=user,
test_scope=test_scope,
)
service.assert_awaited_once_with(db, page, user)
service.assert_awaited_once_with(db, page, user, test_scope)
payload = json.loads(response.body)
self.assertEqual('使用成功', payload['msg'])
self.assertIn('data', payload)
@@ -738,12 +775,13 @@ class TestRecordUsageCore(unittest.IsolatedAsyncioTestCase):
async def read_line(
db: AsyncSession,
line_id: int,
scope: TestBatchScope,
*,
for_update: bool = False,
) -> BizProductionLine | None:
if for_update:
return await line_lock(db, line_id, for_update=True)
return await preflight_line_read(db, line_id)
return await line_lock(db, line_id, scope, for_update=True)
return await preflight_line_read(db, line_id, scope)
stack.enter_context(patch.object(AccessDao, 'list_user_site_ids', new=scope_read))
stack.enter_context(patch.object(AccessService, 'assert_site_access', new=site_access))
@@ -884,7 +922,7 @@ class TestRecordUsageCore(unittest.IsolatedAsyncioTestCase):
patch('module_business.service.usage_service.datetime') as mocked_datetime,
):
mocked_datetime.now.return_value = self.fixed_time
result = await UsageService.record_usage_services(self.db, self.page, self.user)
result = await UsageService.record_usage_services(self.db, self.page, self.user, TestBatchScope.formal())
self.assertEqual(
[
@@ -987,6 +1025,7 @@ class TestRecordUsageCore(unittest.IsolatedAsyncioTestCase):
self.db,
make_page(used_packages=3),
self.user,
TestBatchScope.formal(),
)
self.assertTrue(result.is_success)
@@ -1028,6 +1067,7 @@ class TestRecordUsageCore(unittest.IsolatedAsyncioTestCase):
self.db,
make_page(used_packages=2),
self.user,
TestBatchScope.formal(),
)
self.assertTrue(result.is_success)
self.assertEqual(4, same_inventory.current_line_id)
@@ -1040,7 +1080,7 @@ class TestRecordUsageCore(unittest.IsolatedAsyncioTestCase):
)
stack, mocks = self._patch_record_path(inventory=other_inventory)
with stack, self.assertRaises(ServiceException) as raised:
await UsageService.record_usage_services(self.db, self.page, self.user)
await UsageService.record_usage_services(self.db, self.page, self.user, TestBatchScope.formal())
self.assertIn('已绑定其他产线', raised.exception.message)
mocks['add_usage'].assert_not_awaited()
mocks['add_event'].assert_not_awaited()
@@ -1060,7 +1100,7 @@ class TestRecordUsageCore(unittest.IsolatedAsyncioTestCase):
mocks['preflight_line_read'].return_value = None
mocks['line_lock'].return_value = None
with stack, self.assertRaises(ServiceException) as raised:
await UsageService.record_usage_services(self.db, self.page, self.user)
await UsageService.record_usage_services(self.db, self.page, self.user, TestBatchScope.formal())
self.assertEqual(message, raised.exception.message)
mocks['add_usage'].assert_not_awaited()
mocks['add_event'].assert_not_awaited()
@@ -1091,7 +1131,7 @@ class TestRecordUsageCore(unittest.IsolatedAsyncioTestCase):
self.db.reset_mock()
stack, mocks = self._patch_record_path(inventory=inventory)
with stack, self.assertRaises(ServiceException) as raised:
await UsageService.record_usage_services(self.db, page, self.user)
await UsageService.record_usage_services(self.db, page, self.user, TestBatchScope.formal())
self.assertEqual(message, raised.exception.message)
mocks['add_usage'].assert_not_awaited()
mocks['add_event'].assert_not_awaited()
@@ -1102,7 +1142,7 @@ class TestRecordUsageCore(unittest.IsolatedAsyncioTestCase):
access = AsyncMock(side_effect=PermissionException(data='', message='无权访问该客户现场'))
stack, mocks = self._patch_record_path(access=access)
with stack, self.assertRaises(PermissionException) as raised:
await UsageService.record_usage_services(self.db, self.page, self.user)
await UsageService.record_usage_services(self.db, self.page, self.user, TestBatchScope.formal())
self.assertEqual('无权访问该托盘', raised.exception.message)
mocks['inventory_lock'].assert_awaited_once()
@@ -1127,10 +1167,15 @@ class TestRecordUsageCore(unittest.IsolatedAsyncioTestCase):
access = AsyncMock(side_effect=access_check)
stack, mocks = self._patch_record_path(site=make_site(status='1'), access=access)
with stack, self.assertRaises(PermissionException) as raised:
await UsageService.record_usage_services(self.db, self.page, self.user)
await UsageService.record_usage_services(self.db, self.page, self.user, TestBatchScope.formal())
self.assertEqual('无权访问该托盘', raised.exception.message)
mocks['site_lock'].assert_awaited_once_with(self.db, 9, for_update=True)
mocks['site_lock'].assert_awaited_once_with(
self.db,
9,
TestBatchScope.formal(),
for_update=True,
)
access.assert_awaited_with(self.db, self.user, 9, for_update=True)
mocks['line_lock'].assert_not_awaited()
mocks['add_usage'].assert_not_awaited()
@@ -1144,7 +1189,7 @@ class TestRecordUsageCore(unittest.IsolatedAsyncioTestCase):
if site is None:
mocks['site_lock'].return_value = None
with stack, self.assertRaises(ServiceException) as raised:
await UsageService.record_usage_services(self.db, self.page, make_user(1))
await UsageService.record_usage_services(self.db, self.page, make_user(1), TestBatchScope.formal())
self.assertEqual(message, raised.exception.message)
mocks['add_usage'].assert_not_awaited()
self.assertEqual(2, self.db.rollback.await_count)
@@ -1162,7 +1207,7 @@ class TestRecordUsageCore(unittest.IsolatedAsyncioTestCase):
self.db.reset_mock()
stack, mocks = self._patch_record_path(**overrides)
with stack, self.assertRaises(ServiceException):
await UsageService.record_usage_services(self.db, self.page, self.user)
await UsageService.record_usage_services(self.db, self.page, self.user, TestBatchScope.formal())
mocks['add_usage'].assert_not_awaited()
mocks['update_filling'].assert_not_awaited()
mocks['add_event'].assert_not_awaited()
@@ -1173,7 +1218,7 @@ class TestRecordUsageCore(unittest.IsolatedAsyncioTestCase):
inventory = make_inventory(version=-1)
stack, mocks = self._patch_record_path(inventory=inventory)
with stack, self.assertRaises(ServiceException) as raised:
await UsageService.record_usage_services(self.db, self.page, self.user)
await UsageService.record_usage_services(self.db, self.page, self.user, TestBatchScope.formal())
self.assertEqual('托盘库存版本无效', raised.exception.message)
mocks['add_usage'].assert_not_awaited()
@@ -1188,7 +1233,7 @@ class TestRecordUsageCore(unittest.IsolatedAsyncioTestCase):
patch.object(InventoryDao, 'get_pallet_by_qr_token', new=AsyncMock(return_value=None)),
self.assertRaises(PermissionException) as normal_missing,
):
await UsageService.record_usage_services(self.db, self.page, self.user)
await UsageService.record_usage_services(self.db, self.page, self.user, TestBatchScope.formal())
self.assertEqual('无权访问该托盘', normal_missing.exception.message)
self.db.rollback.assert_awaited_once()
@@ -1199,14 +1244,14 @@ class TestRecordUsageCore(unittest.IsolatedAsyncioTestCase):
patch.object(InventoryDao, 'get_pallet_by_qr_token', new=AsyncMock(return_value=None)),
self.assertRaises(ServiceException) as admin_missing,
):
await UsageService.record_usage_services(self.db, self.page, make_user(1))
await UsageService.record_usage_services(self.db, self.page, make_user(1), TestBatchScope.formal())
self.assertEqual('托盘不存在', admin_missing.exception.message)
self.db.rollback.assert_awaited_once()
self.db.reset_mock()
stack, mocks = self._patch_record_path(inventory=make_inventory(site_id=None))
with stack, self.assertRaises(PermissionException) as non_site:
await UsageService.record_usage_services(self.db, self.page, self.user)
await UsageService.record_usage_services(self.db, self.page, self.user, TestBatchScope.formal())
self.assertEqual('无权访问该托盘', non_site.exception.message)
mocks['pallet_lock'].assert_not_awaited()
self.assertEqual(2, self.db.rollback.await_count)
@@ -1329,14 +1374,15 @@ class TestUsageIdempotency(unittest.IsolatedAsyncioTestCase):
patch.object(InventoryDao, 'get_inventory_for_update', new=inventory_lock),
patch.object(OperationDao, 'add_usage_record', new=AsyncMock()) as add_usage,
):
result = await UsageService.record_usage_services(self.db, self.page, self.user)
result = await UsageService.record_usage_services(self.db, self.page, self.user, TestBatchScope.formal())
get_key.assert_awaited_once_with(
self.db,
'usage-key',
TestBatchScope.formal(),
site_ids=[9],
)
site_lock.assert_awaited_once_with(self.db, 9, for_update=True)
site_lock.assert_awaited_once_with(self.db, 9, TestBatchScope.formal(), for_update=True)
access.assert_awaited_once_with(self.db, self.user, 9, for_update=True)
inventory_lock.assert_not_awaited()
add_usage.assert_not_awaited()
@@ -1367,10 +1413,15 @@ class TestUsageIdempotency(unittest.IsolatedAsyncioTestCase):
patch.object(MasterDao, 'get_site', new=AsyncMock(return_value=make_site())),
patch.object(AccessService, 'assert_site_access', new=AsyncMock()),
):
result = await UsageService.record_usage_services(self.db, self.page, user)
result = await UsageService.record_usage_services(self.db, self.page, user, TestBatchScope.formal())
line_read.assert_awaited_once_with(self.db, 4)
get_key.assert_awaited_once_with(self.db, 'usage-key', site_ids=[9])
line_read.assert_awaited_once_with(self.db, 4, TestBatchScope.formal())
get_key.assert_awaited_once_with(
self.db,
'usage-key',
TestBatchScope.formal(),
site_ids=[9],
)
self.assertEqual(61, result.result.usage_id)
if user.user and user.user.admin:
scope_read.assert_not_awaited()
@@ -1384,7 +1435,7 @@ class TestUsageIdempotency(unittest.IsolatedAsyncioTestCase):
patch.object(InventoryDao, 'get_inventory_for_update', new=AsyncMock()) as inventory_lock,
self.assertRaises(ServiceException) as raised,
):
await UsageService.record_usage_services(self.db, self.page, self.user)
await UsageService.record_usage_services(self.db, self.page, self.user, TestBatchScope.formal())
self.assertIn('幂等键', raised.exception.message)
inventory_lock.assert_not_awaited()
@@ -1401,7 +1452,7 @@ class TestUsageIdempotency(unittest.IsolatedAsyncioTestCase):
patch.object(AccessService, 'assert_site_access', new=access),
self.assertRaises(PermissionException),
):
await UsageService.record_usage_services(self.db, self.page, self.user)
await UsageService.record_usage_services(self.db, self.page, self.user, TestBatchScope.formal())
access.assert_awaited_once_with(self.db, self.user, 9, for_update=True)
self.db.commit.assert_not_awaited()
@@ -1460,6 +1511,7 @@ class TestUsageIdempotency(unittest.IsolatedAsyncioTestCase):
self.db,
self.page,
self.user,
TestBatchScope.formal(),
)
except ServiceException as exc:
self.fail(f'精确并发重试被旧库存状态提前拒绝:{exc.message}')
@@ -1495,7 +1547,12 @@ class TestUsageIdempotency(unittest.IsolatedAsyncioTestCase):
mocks['filling_lock'].assert_awaited_once()
else:
mocks['filling_lock'].assert_not_awaited()
mocks['site_lock'].assert_awaited_once_with(self.db, 9, for_update=True)
mocks['site_lock'].assert_awaited_once_with(
self.db,
9,
TestBatchScope.formal(),
for_update=True,
)
mocks['line_lock'].assert_not_awaited()
mocks['add_usage'].assert_not_awaited()
mocks['add_event'].assert_not_awaited()
@@ -1541,7 +1598,9 @@ class TestUsageIdempotency(unittest.IsolatedAsyncioTestCase):
)
with stack:
try:
result = await UsageService.record_usage_services(self.db, self.page, self.user)
result = await UsageService.record_usage_services(
self.db, self.page, self.user, TestBatchScope.formal()
)
except ServiceException as exc:
self.fail(f'锁等待期间新增授权后未使用 fresh scope:{exc.message}')
@@ -1590,7 +1649,7 @@ class TestUsageIdempotency(unittest.IsolatedAsyncioTestCase):
)
with stack:
try:
await UsageService.record_usage_services(self.db, self.page, self.user)
await UsageService.record_usage_services(self.db, self.page, self.user, TestBatchScope.formal())
except PermissionException as exc:
self.assertEqual('无权访问该托盘', exc.message)
else:
@@ -1653,13 +1712,13 @@ class TestUsageIdempotency(unittest.IsolatedAsyncioTestCase):
self.db.rollback.side_effect = rollback
with stack, self.assertRaises(ServiceException) as raised:
await UsageService.record_usage_services(self.db, self.page, self.user)
await UsageService.record_usage_services(self.db, self.page, self.user, TestBatchScope.formal())
self.assertEqual('托盘二维码与库存不一致', raised.exception.message)
self.assertTrue(scanned.expired)
self.assertEqual(1, scanned.pallet_id_reads)
mocks['inventory_lock'].assert_awaited_once_with(self.db, 2)
mocks['pallet_lock'].assert_awaited_once_with(self.db, [2])
mocks['inventory_lock'].assert_awaited_once_with(self.db, 2, TestBatchScope.formal())
mocks['pallet_lock'].assert_awaited_once_with(self.db, [2], TestBatchScope.formal())
self.assertEqual(2, scope.await_count)
self.assertEqual(
[{'site_ids': [9]}, {'site_ids': [9]}],
@@ -1688,7 +1747,7 @@ class TestUsageIdempotency(unittest.IsolatedAsyncioTestCase):
access = mocks['access']
with stack:
try:
await UsageService.record_usage_services(self.db, self.page, self.user)
await UsageService.record_usage_services(self.db, self.page, self.user, TestBatchScope.formal())
except PermissionException as exc:
self.assertEqual('无权访问该使用记录', exc.message)
except ServiceException as exc:
@@ -1701,7 +1760,12 @@ class TestUsageIdempotency(unittest.IsolatedAsyncioTestCase):
[call.kwargs for call in key_read.await_args_list],
)
self.assertEqual(2, mocks['scope_read'].await_count)
mocks['site_lock'].assert_awaited_once_with(self.db, 9, for_update=True)
mocks['site_lock'].assert_awaited_once_with(
self.db,
9,
TestBatchScope.formal(),
for_update=True,
)
self.assertEqual([False, True], [call.kwargs.get('for_update', False) for call in access.await_args_list])
mocks['line_lock'].assert_not_awaited()
mocks['add_usage'].assert_not_awaited()
@@ -1734,7 +1798,7 @@ class TestUsageIdempotency(unittest.IsolatedAsyncioTestCase):
key_read = mocks['key_read']
with stack:
try:
await UsageService.record_usage_services(self.db, self.page, self.user)
await UsageService.record_usage_services(self.db, self.page, self.user, TestBatchScope.formal())
except ServiceException as exc:
self.assertEqual(
'使用失败,幂等键已被其他请求使用',
@@ -1768,7 +1832,7 @@ class TestUsageIdempotency(unittest.IsolatedAsyncioTestCase):
add_usage=add_usage,
)
with stack:
result = await UsageService.record_usage_services(self.db, self.page, self.user)
result = await UsageService.record_usage_services(self.db, self.page, self.user, TestBatchScope.formal())
self.assertIsInstance(result.result, UsageSuccessResponseModel)
self.assertEqual(
@@ -1800,7 +1864,7 @@ class TestUsageIdempotency(unittest.IsolatedAsyncioTestCase):
add_usage=AsyncMock(side_effect=integrity_error()),
)
with stack, self.assertRaises(ServiceException) as raised:
await UsageService.record_usage_services(self.db, self.page, self.user)
await UsageService.record_usage_services(self.db, self.page, self.user, TestBatchScope.formal())
self.assertTrue('幂等' in raised.exception.message or '冲突' in raised.exception.message)
self.assertEqual(
[{'site_ids': [9]}, {'site_ids': [9]}, {'site_ids': [9]}],
@@ -1818,7 +1882,7 @@ class TestUsageIdempotency(unittest.IsolatedAsyncioTestCase):
add_usage=AsyncMock(side_effect=integrity_error()),
)
with stack, self.assertRaises(PermissionException):
await UsageService.record_usage_services(self.db, self.page, self.user)
await UsageService.record_usage_services(self.db, self.page, self.user, TestBatchScope.formal())
self.assertEqual(3, scope.await_count)
self.assertEqual(2, key_read.await_count)
@@ -1835,7 +1899,7 @@ class TestUsageIdempotency(unittest.IsolatedAsyncioTestCase):
add_event=AsyncMock(side_effect=RuntimeError('event failed')),
)
with stack, self.assertRaises(RuntimeError):
await UsageService.record_usage_services(self.db, self.page, self.user)
await UsageService.record_usage_services(self.db, self.page, self.user, TestBatchScope.formal())
self.assertEqual(2, self.db.rollback.await_count)
self.db.commit.assert_not_awaited()
@@ -1845,7 +1909,7 @@ class TestUsageIdempotency(unittest.IsolatedAsyncioTestCase):
patch.object(UsageService, '_build_request_hash', side_effect=RuntimeError('hash failed')),
self.assertRaises(RuntimeError),
):
await UsageService.record_usage_services(self.db, self.page, self.user)
await UsageService.record_usage_services(self.db, self.page, self.user, TestBatchScope.formal())
self.db.rollback.assert_awaited_once()
self.db.commit.assert_not_awaited()