|
1 | | -"""Test the high-level import orchestrator.""" |
| 1 | +"""Test the high-level import orchestrator, including pre-flight checks.""" |
2 | 2 |
|
3 | 3 | from pathlib import Path |
4 | 4 | from unittest.mock import MagicMock, patch |
@@ -140,3 +140,123 @@ def test_run_import_for_migration(mock_import_data: MagicMock) -> None: |
140 | 140 | assert call_kwargs["max_connection"] == 2 |
141 | 141 | assert call_kwargs["batch_size"] == 50 |
142 | 142 | assert "tracking_disable" in call_kwargs["context"] |
| 143 | + |
| 144 | + |
| 145 | +@patch("odoo_data_flow.importer.import_threaded.import_data") |
| 146 | +@patch("odoo_data_flow.importer._verify_import_fields") |
| 147 | +def test_run_import_skips_verification_by_default( |
| 148 | + mock_verify_fields: MagicMock, mock_import_data: MagicMock, tmp_path: Path |
| 149 | +) -> None: |
| 150 | + """Tests that the field verification step is NOT run if the flag is omitted.""" |
| 151 | + source_file = tmp_path / "data.csv" |
| 152 | + source_file.write_text("id,name\n1,test") |
| 153 | + |
| 154 | + run_import( |
| 155 | + config="dummy.conf", |
| 156 | + filename=str(source_file), |
| 157 | + model="res.partner", |
| 158 | + verify_fields=False, # Explicitly False |
| 159 | + ) |
| 160 | + |
| 161 | + mock_verify_fields.assert_not_called() |
| 162 | + mock_import_data.assert_called_once() |
| 163 | + |
| 164 | + |
| 165 | +@patch("odoo_data_flow.importer.import_threaded.import_data") |
| 166 | +@patch("odoo_data_flow.importer.conf_lib.get_connection_from_config") |
| 167 | +def test_verify_fields_success( |
| 168 | + mock_get_connection: MagicMock, mock_import_data: MagicMock, tmp_path: Path |
| 169 | +) -> None: |
| 170 | + """Tests the success path where all CSV columns exist on the Odoo model.""" |
| 171 | + # 1. Setup |
| 172 | + source_file = tmp_path / "data.csv" |
| 173 | + source_file.write_text("id,name,email") # Header for the file to be read |
| 174 | + |
| 175 | + # Mock the Odoo model object and its return value |
| 176 | + mock_model_fields_obj = MagicMock() |
| 177 | + # Simulate Odoo returning a list of valid fields |
| 178 | + mock_model_fields_obj.search_read.return_value = [ |
| 179 | + {"name": "id"}, |
| 180 | + {"name": "name"}, |
| 181 | + {"name": "email"}, |
| 182 | + ] |
| 183 | + mock_connection = MagicMock() |
| 184 | + mock_connection.get_model.return_value = mock_model_fields_obj |
| 185 | + mock_get_connection.return_value = mock_connection |
| 186 | + |
| 187 | + # 2. Action |
| 188 | + run_import( |
| 189 | + config="dummy.conf", |
| 190 | + filename=str(source_file), |
| 191 | + model="res.partner", |
| 192 | + verify_fields=True, |
| 193 | + separator=",", # Use the correct separator for the test file |
| 194 | + ) |
| 195 | + |
| 196 | + # 3. Assertions |
| 197 | + # The verification should pass, and the main import function should be called |
| 198 | + mock_import_data.assert_called_once() |
| 199 | + |
| 200 | + |
| 201 | +@patch("odoo_data_flow.importer.import_threaded.import_data") |
| 202 | +@patch("odoo_data_flow.importer.log.error") |
| 203 | +@patch("odoo_data_flow.importer.conf_lib.get_connection_from_config") |
| 204 | +def test_verify_fields_failure_missing_field( |
| 205 | + mock_get_connection: MagicMock, |
| 206 | + mock_log_error: MagicMock, |
| 207 | + mock_import_data: MagicMock, |
| 208 | + tmp_path: Path, |
| 209 | +) -> None: |
| 210 | + """Tests the failure path where a CSV column does not exist on the Odoo model.""" |
| 211 | + # 1. Setup |
| 212 | + source_file = tmp_path / "data.csv" |
| 213 | + # This file contains a column that is not on the mocked model below |
| 214 | + source_file.write_text("id,name,x_studio_legacy_field") |
| 215 | + |
| 216 | + mock_model_fields_obj = MagicMock() |
| 217 | + # Simulate Odoo returning only two valid fields |
| 218 | + mock_model_fields_obj.search_read.return_value = [ |
| 219 | + {"name": "id"}, |
| 220 | + {"name": "name"}, |
| 221 | + ] |
| 222 | + mock_connection = MagicMock() |
| 223 | + mock_connection.get_model.return_value = mock_model_fields_obj |
| 224 | + mock_get_connection.return_value = mock_connection |
| 225 | + |
| 226 | + # 2. Action |
| 227 | + run_import( |
| 228 | + config="dummy.conf", |
| 229 | + filename=str(source_file), |
| 230 | + model="res.partner", |
| 231 | + verify_fields=True, |
| 232 | + separator=",", |
| 233 | + ) |
| 234 | + |
| 235 | + # 3. Assertions |
| 236 | + # An error should be logged, and the main import should NOT be called |
| 237 | + assert mock_log_error.call_count > 0 |
| 238 | + # Check that the specific error message was one of the logs |
| 239 | + assert any( |
| 240 | + "is not a valid field" in call[0][0] for call in mock_log_error.call_args_list |
| 241 | + ) |
| 242 | + mock_import_data.assert_not_called() |
| 243 | + |
| 244 | + |
| 245 | +@patch("odoo_data_flow.importer.import_threaded.import_data") |
| 246 | +@patch("odoo_data_flow.importer.log.error") |
| 247 | +def test_verify_fields_failure_file_not_found( |
| 248 | + mock_log_error: MagicMock, mock_import_data: MagicMock |
| 249 | +) -> None: |
| 250 | + """Tests that verification fails gracefully if the source file is not found.""" |
| 251 | + run_import( |
| 252 | + config="dummy.conf", |
| 253 | + filename="non_existent_file.csv", |
| 254 | + model="res.partner", |
| 255 | + verify_fields=True, |
| 256 | + ) |
| 257 | + |
| 258 | + # Assert that the specific error message was logged |
| 259 | + assert any( |
| 260 | + "Input file not found" in call[0][0] for call in mock_log_error.call_args_list |
| 261 | + ) |
| 262 | + mock_import_data.assert_not_called() |
0 commit comments