Files
ShiErFeng/shierfeng-fastapi-backend/tests/module_business/test_tunnel_flow_contract.py
T

122 lines
4.7 KiB
Python

import unittest
import hashlib
import json
from pydantic import ValidationError
from module_business.domain.enums import PalletEventType
from module_business.entity.do.master_do import BizTunnel
from module_business.entity.do.operation_do import BizPalletEvent, BizPalletInventory, BizReturnItem, BizUsageRecord
from module_business.entity.vo.master_vo import PalletCreateModel, TunnelModel, TunnelPageQueryModel
from module_business.entity.vo.operation_vo import FillingCreateModel, TunnelEntryCreateModel, UsageCreateModel
from module_business.service.usage_service import UsageService
class TestTunnelFlowContract(unittest.TestCase):
def test_tunnel_master_data_belongs_to_site_and_has_scoped_code(self) -> None:
self.assertEqual(BizTunnel.__tablename__, 'biz_tunnel')
self.assertIn('site_id', BizTunnel.__table__.c)
self.assertIn('tunnel_code', BizTunnel.__table__.c)
self.assertIn('current_trace_no', BizTunnel.__table__.c)
self.assertEqual(
{constraint.name for constraint in BizTunnel.__table__.constraints if constraint.name},
{
'uq_biz_tunnel_site_code',
'ck_biz_tunnel_status',
},
)
def test_tunnel_master_vo_supports_list_and_write_contract(self) -> None:
tunnel = TunnelModel(
siteId=9,
tunnelCode='T-01',
tunnelName='一号隧道',
)
self.assertEqual(tunnel.model_dump(by_alias=True)['tunnelCode'], 'T-01')
query = TunnelPageQueryModel(siteId=9, tunnelCode='T-01')
self.assertEqual(query.site_id, 9)
def test_usage_requires_tunnel_but_keeps_line_optional(self) -> None:
usage = UsageCreateModel(
qrToken='qr-1',
tunnelId=9,
usedPackages=20,
idempotencyKey='usage-key',
)
self.assertIsNone(usage.line_id)
with self.assertRaises(ValidationError):
UsageCreateModel(
qrToken='qr-1',
usedPackages=20,
idempotencyKey='usage-key',
)
def test_tunnel_entry_is_idempotent_command(self) -> None:
command = TunnelEntryCreateModel(
qrToken='qr-1',
tunnelId=9,
idempotencyKey='entry-key',
)
self.assertEqual(command.tunnel_id, 9)
def test_flow_records_keep_tunnel_and_trace_snapshots(self) -> None:
self.assertIn('tunnel_id', BizPalletInventory.__table__.c)
self.assertIn('trace_no', BizPalletInventory.__table__.c)
self.assertIn('tunnel_id', BizUsageRecord.__table__.c)
self.assertIn('trace_no', BizUsageRecord.__table__.c)
self.assertIn('batch_no_snapshot', BizUsageRecord.__table__.c)
self.assertIn('tunnel_id_snapshot', BizReturnItem.__table__.c)
self.assertIn('trace_no_snapshot', BizReturnItem.__table__.c)
self.assertIn('before_tunnel_id', BizPalletEvent.__table__.c)
self.assertIn('after_tunnel_id', BizPalletEvent.__table__.c)
self.assertIn('trace_no', BizPalletEvent.__table__.c)
self.assertEqual(PalletEventType.TUNNEL_ENTERED.value, 'TUNNEL_ENTERED')
def test_new_pallet_and_filling_are_fixed_to_one_hundred_packages(self) -> None:
PalletCreateModel(palletCode='P-001', capacityPackages=100)
FillingCreateModel(
qrToken='qr-1',
warehouseId=1,
strainId=1,
batchNo='B-1',
productionDate='2026-10-01',
expiryDate='2027-04-01',
packageSpec='标准包',
initialPackages=100,
idempotencyKey='fill-key',
)
with self.assertRaises(ValidationError):
PalletCreateModel(palletCode='P-002', capacityPackages=20)
with self.assertRaises(ValidationError):
FillingCreateModel(
qrToken='qr-1',
warehouseId=1,
strainId=1,
batchNo='B-1',
packageSpec='标准包',
initialPackages=20,
idempotencyKey='fill-key',
)
def test_usage_idempotency_hash_includes_tunnel(self) -> None:
command = UsageCreateModel(
qrToken=' qr-1 ',
tunnelId=9,
lineId=None,
usedPackages=20,
idempotencyKey='usage-key',
)
expected = hashlib.sha256(
json.dumps(
{
'qr_token': 'qr-1',
'tunnel_id': 9,
'line_id': None,
'used_packages': 20,
},
sort_keys=True,
separators=(',', ':'),
).encode()
).hexdigest()
self.assertEqual(expected, UsageService._build_request_hash(command))