diff --git a/app/db/mock_seed.py b/app/db/mock_seed.py index e3f04c1..833c8c0 100644 --- a/app/db/mock_seed.py +++ b/app/db/mock_seed.py @@ -33,12 +33,91 @@ NAMES = [ "Joao Ribeiro", ] +TARGET_VEHICLE_COUNT = 180 +TARGET_CUSTOMER_COUNT = 320 +TARGET_ORDER_COUNT = 80 +VEHICLE_PRICE_BANDS = ( + 38990, + 42990, + 46990, + 50990, + 54990, + 58990, + 62990, + 66990, + 69990, + 73990, + 77990, + 82990, + 87990, + 93990, + 99990, + 106990, + 114990, + 123990, + 132990, + 141990, +) + def _cpf_from_index(index: int) -> str: """Gera um CPF numerico deterministico de 11 digitos a partir do indice.""" return str(10_000_000_000 + index).zfill(11) +def _vehicle_price_from_index(index: int, rng: random.Random) -> float: + band_price = VEHICLE_PRICE_BANDS[index % len(VEHICLE_PRICE_BANDS)] + cycle_increment = (index // len(VEHICLE_PRICE_BANDS)) * 750 + noise = rng.randint(-1800, 2200) + return float(max(35000, band_price + cycle_increment + noise)) + + +def _seed_vehicle_records(existing_count: int, target_count: int, rng: random.Random) -> list[Vehicle]: + vehicles = [] + for idx in range(existing_count, target_count): + model = VEHICLE_MODELS[idx % len(VEHICLE_MODELS)] + category = CATEGORIES[idx % len(CATEGORIES)] + vehicles.append( + Vehicle( + modelo=f"{model} {2020 + (idx % 6)}", + categoria=category, + preco=_vehicle_price_from_index(idx, rng), + ) + ) + return vehicles + + +def _seed_customer_records(existing_count: int, target_count: int) -> list[Customer]: + customers = [] + for idx in range(existing_count, target_count): + entropy = (idx * 9973) % 10_000 + customers.append( + Customer( + cpf=_cpf_from_index(idx), + nome=f"{NAMES[idx % len(NAMES)]} {idx + 1}", + score=300 + (entropy % 550), + limite_credito=float(30_000 + (entropy * 12)), + possui_restricao=(idx % 11 == 0), + ) + ) + return customers + + +def _seed_order_records(existing_count: int, target_count: int) -> list[Order]: + orders = [] + created = datetime(2026, 1, 1, 8, 0, 0) + for idx in range(existing_count, target_count): + orders.append( + Order( + numero_pedido=f"PED-MOCK-2026-{idx + 1:05d}", + cpf=_cpf_from_index(idx), + status="Ativo", + created_at=created, + ) + ) + return orders + + def seed_mock_data() -> None: """Popula dados mock iniciais de veiculos, clientes e pedidos quando habilitado.""" if not settings.mock_seed_enabled: @@ -47,51 +126,31 @@ def seed_mock_data() -> None: rng = random.Random(42) db = SessionMockLocal() try: - if db.query(Vehicle).count() == 0: - vehicles = [] - for idx in range(60): - model = VEHICLE_MODELS[idx % len(VEHICLE_MODELS)] - category = CATEGORIES[idx % len(CATEGORIES)] - base_price = 55_000 + (idx * 1_700) - noise = rng.randint(-7_000, 9_000) - vehicles.append( - Vehicle( - modelo=f"{model} {2020 + (idx % 6)}", - categoria=category, - preco=float(max(35_000, base_price + noise)), - ) - ) + vehicle_count = db.query(Vehicle).count() + if vehicle_count < TARGET_VEHICLE_COUNT: + vehicles = _seed_vehicle_records( + existing_count=vehicle_count, + target_count=TARGET_VEHICLE_COUNT, + rng=rng, + ) db.add_all(vehicles) db.commit() - if db.query(Customer).count() == 0: - customers = [] - for idx in range(120): - entropy = (idx * 9973) % 10_000 - customers.append( - Customer( - cpf=_cpf_from_index(idx), - nome=f"{NAMES[idx % len(NAMES)]} {idx + 1}", - score=300 + (entropy % 550), - limite_credito=float(30_000 + (entropy * 12)), - possui_restricao=(idx % 11 == 0), - ) - ) + customer_count = db.query(Customer).count() + if customer_count < TARGET_CUSTOMER_COUNT: + customers = _seed_customer_records( + existing_count=customer_count, + target_count=TARGET_CUSTOMER_COUNT, + ) db.add_all(customers) db.commit() - if db.query(Order).count() == 0: - orders = [] - for idx in range(40): - created = datetime(2026, 1, 1, 8, 0, 0) - orders.append( - Order( - numero_pedido=f"PED-{2026}{idx + 1:05d}", - cpf=_cpf_from_index(idx), - status="Ativo", - created_at=created, - ) - ) + order_count = db.query(Order).count() + if order_count < TARGET_ORDER_COUNT: + orders = _seed_order_records( + existing_count=order_count, + target_count=TARGET_ORDER_COUNT, + ) db.add_all(orders) db.commit() finally: diff --git a/tests/test_mock_seed.py b/tests/test_mock_seed.py new file mode 100644 index 0000000..c7186eb --- /dev/null +++ b/tests/test_mock_seed.py @@ -0,0 +1,88 @@ +import unittest +from unittest.mock import patch + +from sqlalchemy import create_engine +from sqlalchemy.orm import sessionmaker + +from app.db import mock_seed as mock_seed_module +from app.db.mock_database import MockBase +from app.db.mock_models import Customer, Order, Vehicle + + +class MockSeedDataTests(unittest.TestCase): + def _build_session_local(self): + engine = create_engine("sqlite:///:memory:") + SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) + MockBase.metadata.create_all(bind=engine) + self.addCleanup(engine.dispose) + return SessionLocal + + def test_seed_mock_data_populates_target_volume_with_affordable_inventory(self): + SessionLocal = self._build_session_local() + + with patch.object(mock_seed_module, "SessionMockLocal", SessionLocal), patch.object( + mock_seed_module.settings, + "mock_seed_enabled", + True, + ): + mock_seed_module.seed_mock_data() + + db = SessionLocal() + try: + self.assertEqual(db.query(Vehicle).count(), mock_seed_module.TARGET_VEHICLE_COUNT) + self.assertEqual(db.query(Customer).count(), mock_seed_module.TARGET_CUSTOMER_COUNT) + self.assertEqual(db.query(Order).count(), mock_seed_module.TARGET_ORDER_COUNT) + self.assertGreaterEqual( + db.query(Vehicle).filter(Vehicle.preco <= 70000).count(), + 50, + ) + finally: + db.close() + + def test_seed_mock_data_tops_up_existing_partial_database(self): + SessionLocal = self._build_session_local() + db = SessionLocal() + try: + db.add_all( + [ + Vehicle(modelo="Base Hatch 2020", categoria="hatch", preco=45990.0), + Vehicle(modelo="Base Sedan 2021", categoria="sedan", preco=58990.0), + Customer( + cpf=mock_seed_module._cpf_from_index(0), + nome="Cliente Base 1", + score=650, + limite_credito=75000.0, + possui_restricao=False, + ), + Order( + numero_pedido="PED-LEGADO-00001", + cpf=mock_seed_module._cpf_from_index(0), + status="Ativo", + ), + ] + ) + db.commit() + finally: + db.close() + + with patch.object(mock_seed_module, "SessionMockLocal", SessionLocal), patch.object( + mock_seed_module.settings, + "mock_seed_enabled", + True, + ): + mock_seed_module.seed_mock_data() + mock_seed_module.seed_mock_data() + + db = SessionLocal() + try: + self.assertEqual(db.query(Vehicle).count(), mock_seed_module.TARGET_VEHICLE_COUNT) + self.assertEqual(db.query(Customer).count(), mock_seed_module.TARGET_CUSTOMER_COUNT) + self.assertEqual(db.query(Order).count(), mock_seed_module.TARGET_ORDER_COUNT) + self.assertEqual(db.query(Order).filter(Order.numero_pedido == "PED-LEGADO-00001").count(), 1) + self.assertEqual(db.query(Vehicle).filter(Vehicle.modelo == "Base Hatch 2020").count(), 1) + finally: + db.close() + + +if __name__ == "__main__": + unittest.main()