数据:增加测试批次模型与迁移契约
This commit is contained in:
@@ -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')"},
|
||||
|
||||
Reference in New Issue
Block a user