import json from datetime import datetime import pytest from app.main import run_auto_import_for_upload, ORDER_INDEX class DummyImportLog: # Minimal stand-in to satisfy attribute assignments; not used by SQLAlchemy def __init__(self, **kwargs): self.import_type = kwargs.get("import_type") self.file_name = kwargs.get("file_name") self.file_path = kwargs.get("file_path") self.status = kwargs.get("status", "pending") self.total_rows = 0 self.success_count = 0 self.error_count = 0 self.error_details = "[]" self.completed_at = None class DummyDB: """Very small in-memory stub for the DB session interactions used by helper.""" def __init__(self, import_results_by_type): self.import_results_by_type = import_results_by_type self.logs = [] # SQLAlchemy-like API surface used by helper def add(self, obj): # record created logs self.logs.append(obj) def commit(self): # no-op for tests return None # Monkeypatch target lookup inside the helper by patching process function in module namespace @pytest.fixture(autouse=True) def patch_process_csv_import(monkeypatch): from app import main as main_mod def fake_process_csv_import(db, import_type, file_path): # return test-configured results from DummyDB return db.import_results_by_type.get(import_type, {"success": 0, "errors": []}) monkeypatch.setattr(main_mod, "process_csv_import", fake_process_csv_import) # Replace ImportLog class with Dummy for isolation (no DB) monkeypatch.setattr(main_mod, "ImportLog", DummyImportLog) def sorted_by_order(items): return sorted(items, key=lambda x: (ORDER_INDEX.get(x["import_type"], 1_000_000), x.get("filename", ""))) def test_auto_import_sorts_and_runs_in_order(): uploaded = [ {"filename": "B.csv", "stored_filename": "files_b.csv", "file_path": "/tmp/b.csv", "import_type": "files"}, {"filename": "A.csv", "stored_filename": "trnstype_a.csv", "file_path": "/tmp/a.csv", "import_type": "trnstype"}, {"filename": "C.csv", "stored_filename": "payments_c.csv", "file_path": "/tmp/c.csv", "import_type": "payments"}, ] # Make all succeed db = DummyDB({ "trnstype": {"success": 1, "errors": [], "total_rows": 10}, "files": {"success": 1, "errors": [], "total_rows": 20}, "payments": {"success": 1, "errors": [], "total_rows": 5}, }) result = run_auto_import_for_upload(db, uploaded) # Should be ordered by IMPORT_ORDER filenames_in_result = [f["stored_filename"] for f in result["files"]] expected_order = [i["stored_filename"] for i in sorted_by_order(uploaded)] assert filenames_in_result == expected_order assert result["stopped"] is False assert result["stopped_on"] is None assert result["skipped_unknowns"] == [] def test_auto_import_skips_unknown_and_reports(): uploaded = [ {"filename": "Unknown.csv", "stored_filename": "unknown_1.csv", "file_path": "/tmp/u1.csv", "import_type": "unknown"}, {"filename": "Rolodex.csv", "stored_filename": "rolodex_2.csv", "file_path": "/tmp/r2.csv", "import_type": "rolodex"}, ] db = DummyDB({"rolodex": {"success": 1, "errors": [], "total_rows": 1}}) result = run_auto_import_for_upload(db, uploaded) # Only known type processed assert [f["stored_filename"] for f in result["files"]] == ["rolodex_2.csv"] # Unknown skipped and listed assert result["skipped_unknowns"] == [{"filename": "Unknown.csv", "stored_filename": "unknown_1.csv"}] def test_auto_import_stops_on_first_error_and_sets_stopped_on(): uploaded = [ {"filename": "A.csv", "stored_filename": "trnstype_a.csv", "file_path": "/tmp/a.csv", "import_type": "trnstype"}, {"filename": "B.csv", "stored_filename": "files_b.csv", "file_path": "/tmp/b.csv", "import_type": "files"}, {"filename": "C.csv", "stored_filename": "payments_c.csv", "file_path": "/tmp/c.csv", "import_type": "payments"}, ] # First succeeds, second returns errors -> should stop before third db = DummyDB({ "trnstype": {"success": 1, "errors": [], "total_rows": 10}, "files": {"success": 0, "errors": ["bad row"], "total_rows": 2}, "payments": {"success": 1, "errors": [], "total_rows": 5}, }) result = run_auto_import_for_upload(db, uploaded) processed = [f["stored_filename"] for f in result["files"]] # The run order starts with trnstype then files; payments should not run assert processed == ["trnstype_a.csv", "files_b.csv"] assert result["stopped"] is True assert result["stopped_on"] == "files_b.csv"