数据:增加测试批次模型与迁移契约

This commit is contained in:
焦龙言
2026-09-22 14:37:31 +08:00
parent 40c56c6b33
commit 17bfa2c5fe
12 changed files with 1278 additions and 32 deletions
@@ -1,11 +1,32 @@
import unittest
from sqlalchemy import CHAR, BigInteger, CheckConstraint, DateTime, Integer, String, Table, UniqueConstraint
from sqlalchemy import CHAR, BigInteger, CheckConstraint, DateTime, Integer, String, Table, Text, UniqueConstraint
from sqlalchemy.dialects import mysql, postgresql
from sqlalchemy.schema import CreateColumn
from sqlalchemy.schema import CreateColumn, CreateTable
from config.database import Base
from module_business.entity.do import master_do, operation_do
from module_admin.entity.do import user_do
from module_business.entity.do import master_do, operation_do, test_batch_do
EXPECTED_TEST_BATCH_TABLES = {'biz_test_batch', 'biz_test_batch_user'}
TEST_BATCH_OWNED_TABLES = {
'biz_strain',
'biz_customer',
'biz_customer_site',
'biz_production_line',
'biz_warehouse',
'biz_pallet',
'biz_inbound_order',
'biz_inbound_item',
'biz_filling_record',
'biz_shipment_order',
'biz_shipment_item',
'biz_usage_record',
'biz_return_order',
'biz_return_item',
'biz_pallet_inventory',
'biz_pallet_event',
}
EXPECTED_COLUMNS = {
'biz_strain': {
@@ -892,6 +913,136 @@ EXPECTED_UNIQUE_SETS = {
},
}
for table_name in TEST_BATCH_OWNED_TABLES:
EXPECTED_COLUMNS[table_name].add('test_batch_id')
EXPECTED_COLUMN_TYPES[table_name]['test_batch_id'] = (BigInteger, None)
EXPECTED_NULLABILITY[table_name]['test_batch_id'] = True
EXPECTED_FOREIGN_KEYS[table_name].add(('test_batch_id', 'biz_test_batch.batch_id'))
EXPECTED_COLUMNS.update(
{
'biz_test_batch': {
'batch_id',
'batch_code',
'batch_name',
'status',
'create_by',
'create_time',
'update_by',
'update_time',
'closed_by',
'closed_at',
'purged_by',
'purged_at',
'purge_summary',
'preview_action',
'preview_token_hash',
'preview_scope_hash',
'preview_expires_at',
'remark',
},
'biz_test_batch_user': {'batch_id', 'user_id', 'create_by', 'create_time'},
}
)
EXPECTED_COLUMN_TYPES.update(
{
'biz_test_batch': {
'batch_id': (BigInteger, None),
'batch_code': (String, 64),
'batch_name': (String, 100),
'status': (String, 16),
'create_by': (String, 64),
'create_time': (DateTime, None),
'update_by': (String, 64),
'update_time': (DateTime, None),
'closed_by': (BigInteger, None),
'closed_at': (DateTime, None),
'purged_by': (BigInteger, None),
'purged_at': (DateTime, None),
'purge_summary': (Text, None),
'preview_action': (String, 16),
'preview_token_hash': (CHAR, 64),
'preview_scope_hash': (CHAR, 64),
'preview_expires_at': (DateTime, None),
'remark': (String, 500),
},
'biz_test_batch_user': {
'batch_id': (BigInteger, None),
'user_id': (BigInteger, None),
'create_by': (String, 64),
'create_time': (DateTime, None),
},
}
)
EXPECTED_NULLABILITY.update(
{
'biz_test_batch': {
'batch_id': False,
'batch_code': False,
'batch_name': False,
'status': False,
'create_by': False,
'create_time': False,
'update_by': False,
'update_time': False,
'closed_by': True,
'closed_at': True,
'purged_by': True,
'purged_at': True,
'purge_summary': True,
'preview_action': True,
'preview_token_hash': True,
'preview_scope_hash': True,
'preview_expires_at': True,
'remark': True,
},
'biz_test_batch_user': {
'batch_id': False,
'user_id': False,
'create_by': False,
'create_time': False,
},
}
)
EXPECTED_CALLABLE_DATETIME_DEFAULTS.update(
{
('biz_test_batch', 'create_time'),
('biz_test_batch', 'update_time'),
('biz_test_batch_user', 'create_time'),
}
)
EXPECTED_EMPTY_AUDIT_SERVER_DEFAULTS.update(
{
('biz_test_batch', 'create_by'),
('biz_test_batch', 'update_by'),
('biz_test_batch_user', 'create_by'),
}
)
EXPECTED_PRIMARY_KEYS.update(
{
'biz_test_batch': ('batch_id',),
'biz_test_batch_user': ('batch_id', 'user_id'),
}
)
EXPECTED_FOREIGN_KEYS.update(
{
'biz_test_batch': {
('closed_by', 'sys_user.user_id'),
('purged_by', 'sys_user.user_id'),
},
'biz_test_batch_user': {
('batch_id', 'biz_test_batch.batch_id'),
('user_id', 'sys_user.user_id'),
},
}
)
EXPECTED_UNIQUE_SETS.update(
{
'biz_test_batch': {frozenset({'batch_code'})},
'biz_test_batch_user': set(),
}
)
def _unique_column_sets(table: Table) -> set[frozenset[str]]:
return {
@@ -910,6 +1061,16 @@ def _normalized_check_sql(table: Table) -> dict[str, str]:
class BusinessModelContractTest(unittest.TestCase):
def test_batch_related_tables_compile_for_mysql_and_postgresql(self) -> None:
self.assertIs(Base.metadata.tables['sys_user'], user_do.SysUser.__table__)
batch_tables = EXPECTED_TEST_BATCH_TABLES | TEST_BATCH_OWNED_TABLES
self.assertEqual(18, len(batch_tables))
for table_name in batch_tables:
for dialect_name, dialect in (('mysql', mysql.dialect()), ('postgresql', postgresql.dialect())):
with self.subTest(table_name=table_name, dialect=dialect_name):
compiled = str(CreateTable(Base.metadata.tables[table_name]).compile(dialect=dialect))
self.assertIn(table_name, compiled)
def test_exact_business_tables_are_registered(self) -> None:
expected = {
'biz_strain',
@@ -930,7 +1091,7 @@ class BusinessModelContractTest(unittest.TestCase):
'biz_return_item',
'biz_pallet_inventory',
'biz_pallet_event',
}
} | EXPECTED_TEST_BATCH_TABLES
actual = {name for name in Base.metadata.tables if name.startswith('biz_')}
self.assertEqual(expected, actual)
@@ -954,6 +1115,8 @@ class BusinessModelContractTest(unittest.TestCase):
operation_do.BizReturnItem: 'biz_return_item',
operation_do.BizPalletInventory: 'biz_pallet_inventory',
operation_do.BizPalletEvent: 'biz_pallet_event',
test_batch_do.BizTestBatch: 'biz_test_batch',
test_batch_do.BizTestBatchUser: 'biz_test_batch_user',
}
self.assertEqual(set(EXPECTED_COLUMNS), set(models.values()))
for model, table_name in models.items():
@@ -1032,6 +1195,7 @@ class BusinessModelContractTest(unittest.TestCase):
_, separator, compiled_default = compiled_column.partition(' DEFAULT ')
if separator:
compiled_default = compiled_default.split(' COMMENT ', maxsplit=1)[0].strip()
compiled_default = compiled_default.removesuffix(' NOT NULL')
if compiled_default != "''":
violations.append((dialect_name, table_name, column_name, compiled_default))
self.assertEqual([], violations)
@@ -1058,6 +1222,26 @@ class BusinessModelContractTest(unittest.TestCase):
with self.subTest(table_name=table_name):
self.assertEqual(expected_unique_sets, _unique_column_sets(Base.metadata.tables[table_name]))
def test_all_owned_models_have_nullable_indexed_batch_fk(self) -> None:
for table_name in TEST_BATCH_OWNED_TABLES:
table = Base.metadata.tables[table_name]
column = table.c.test_batch_id
self.assertTrue(column.nullable, table_name)
self.assertTrue(column.index, table_name)
fk = next(iter(column.foreign_keys))
self.assertEqual('biz_test_batch.batch_id', fk.target_fullname)
self.assertIsNone(fk.ondelete)
def test_test_batch_model_defaults_and_comments_match_contract(self) -> None:
table = Base.metadata.tables['biz_test_batch']
self.assertEqual('测试数据批次', table.comment)
self.assertEqual('ACTIVE', str(table.c.status.server_default.arg))
for table_name in TEST_BATCH_OWNED_TABLES:
self.assertEqual(
'测试数据批次ID;NULL表示正式数据',
Base.metadata.tables[table_name].c.test_batch_id.comment,
)
def test_pallet_identifiers_are_unique(self) -> None:
table = Base.metadata.tables['biz_pallet']
unique_columns = {column.name for column in table.columns if column.unique}
@@ -1065,6 +1249,10 @@ class BusinessModelContractTest(unittest.TestCase):
def test_checks_lock_quantities_states_active_slot_and_location(self) -> None:
expected_checks = {
'biz_test_batch': {
'ck_biz_test_batch_status': "statusIN('ACTIVE','CLOSED','PURGED')",
'ck_biz_test_batch_preview_action': "preview_actionISNULLORpreview_actionIN('ADOPT','PURGE')",
},
'biz_strain': {'ck_biz_strain_status': "statusIN('0','1')"},
'biz_warehouse': {'ck_biz_warehouse_status': "statusIN('0','1')"},
'biz_customer': {'ck_biz_customer_status': "statusIN('0','1')"},