| 
									
										
										
										
											2024-12-13 20:38:00 -06:00
										 |  |  | # -*- coding: utf-8; -*- | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-14 19:39:02 -06:00
										 |  |  | import os | 
					
						
							|  |  |  | from unittest.mock import patch | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-13 20:38:00 -06:00
										 |  |  | from wuttjamaican import batch as mod | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | try: | 
					
						
							|  |  |  |     import sqlalchemy as sa | 
					
						
							|  |  |  |     from wuttjamaican.db import model | 
					
						
							|  |  |  |     from wuttjamaican.testing import DataTestCase | 
					
						
							|  |  |  | except ImportError: | 
					
						
							|  |  |  |     pass | 
					
						
							|  |  |  | else: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     class MockBatch(model.BatchMixin, model.Base): | 
					
						
							| 
									
										
										
										
											2025-08-30 21:25:44 -05:00
										 |  |  |         __tablename__ = "testing_batch_mock" | 
					
						
							| 
									
										
										
										
											2024-12-13 20:38:00 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |     class MockBatchRow(model.BatchRowMixin, model.Base): | 
					
						
							| 
									
										
										
										
											2025-08-30 21:25:44 -05:00
										 |  |  |         __tablename__ = "testing_batch_mock_row" | 
					
						
							| 
									
										
										
										
											2024-12-13 20:38:00 -06:00
										 |  |  |         __batch_class__ = MockBatch | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     class MockBatchHandler(mod.BatchHandler): | 
					
						
							|  |  |  |         model_class = MockBatch | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     class TestBatchHandler(DataTestCase): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def make_handler(self, **kwargs): | 
					
						
							|  |  |  |             return MockBatchHandler(self.config, **kwargs) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def test_model_class(self): | 
					
						
							|  |  |  |             handler = mod.BatchHandler(self.config) | 
					
						
							| 
									
										
										
										
											2025-08-30 21:25:44 -05:00
										 |  |  |             self.assertRaises(NotImplementedError, getattr, handler, "model_class") | 
					
						
							| 
									
										
										
										
											2024-12-13 20:38:00 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-14 19:39:02 -06:00
										 |  |  |         def test_batch_type(self): | 
					
						
							| 
									
										
										
										
											2025-08-30 21:25:44 -05:00
										 |  |  |             with patch.object(mod.BatchHandler, "model_class", new=MockBatch): | 
					
						
							| 
									
										
										
										
											2024-12-14 19:39:02 -06:00
										 |  |  |                 handler = mod.BatchHandler(self.config) | 
					
						
							| 
									
										
										
										
											2025-08-30 21:25:44 -05:00
										 |  |  |                 self.assertEqual(handler.batch_type, "testing_batch_mock") | 
					
						
							| 
									
										
										
										
											2024-12-14 19:39:02 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-13 20:38:00 -06:00
										 |  |  |         def test_make_batch(self): | 
					
						
							|  |  |  |             handler = self.make_handler() | 
					
						
							|  |  |  |             batch = handler.make_batch(self.session) | 
					
						
							|  |  |  |             self.assertIsInstance(batch, MockBatch) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def test_consume_batch_id(self): | 
					
						
							|  |  |  |             handler = self.make_handler() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             first = handler.consume_batch_id(self.session) | 
					
						
							|  |  |  |             second = handler.consume_batch_id(self.session) | 
					
						
							|  |  |  |             self.assertEqual(second, first + 1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             third = handler.consume_batch_id(self.session, as_str=True) | 
					
						
							| 
									
										
										
										
											2025-08-30 21:25:44 -05:00
										 |  |  |             self.assertEqual(third, f"{first + 2:08d}") | 
					
						
							| 
									
										
										
										
											2024-12-13 20:38:00 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-14 19:39:02 -06:00
										 |  |  |         def test_get_data_path(self): | 
					
						
							|  |  |  |             model = self.app.model | 
					
						
							| 
									
										
										
										
											2025-08-30 21:25:44 -05:00
										 |  |  |             user = model.User(username="barney") | 
					
						
							| 
									
										
										
										
											2024-12-14 19:39:02 -06:00
										 |  |  |             self.session.add(user) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-30 21:25:44 -05:00
										 |  |  |             with patch.object(mod.BatchHandler, "model_class", new=MockBatch): | 
					
						
							| 
									
										
										
										
											2024-12-14 19:39:02 -06:00
										 |  |  |                 handler = self.make_handler() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 # root storage (default) | 
					
						
							| 
									
										
										
										
											2025-08-30 21:25:44 -05:00
										 |  |  |                 with patch.object(self.app, "get_appdir", return_value=self.tempdir): | 
					
						
							| 
									
										
										
										
											2024-12-14 19:39:02 -06:00
										 |  |  |                     path = handler.get_data_path() | 
					
						
							| 
									
										
										
										
											2025-08-30 21:25:44 -05:00
										 |  |  |                     self.assertEqual( | 
					
						
							|  |  |  |                         path, | 
					
						
							|  |  |  |                         os.path.join( | 
					
						
							|  |  |  |                             self.tempdir, "data", "batch", "testing_batch_mock" | 
					
						
							|  |  |  |                         ), | 
					
						
							|  |  |  |                     ) | 
					
						
							| 
									
										
										
										
											2024-12-14 19:39:02 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |                 # root storage (configured) | 
					
						
							| 
									
										
										
										
											2025-08-30 21:25:44 -05:00
										 |  |  |                 self.config.setdefault("wutta.batch.storage_path", self.tempdir) | 
					
						
							| 
									
										
										
										
											2024-12-14 19:39:02 -06:00
										 |  |  |                 path = handler.get_data_path() | 
					
						
							| 
									
										
										
										
											2025-08-30 21:25:44 -05:00
										 |  |  |                 self.assertEqual(path, os.path.join(self.tempdir, "testing_batch_mock")) | 
					
						
							| 
									
										
										
										
											2024-12-14 19:39:02 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |                 batch = handler.make_batch(self.session, created_by=user) | 
					
						
							|  |  |  |                 self.session.add(batch) | 
					
						
							|  |  |  |                 self.session.flush() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 # batch-specific | 
					
						
							|  |  |  |                 path = handler.get_data_path(batch) | 
					
						
							|  |  |  |                 uuid = batch.uuid.hex | 
					
						
							|  |  |  |                 final = os.path.join(uuid[-2:], uuid[:-2]) | 
					
						
							| 
									
										
										
										
											2025-08-30 21:25:44 -05:00
										 |  |  |                 self.assertEqual( | 
					
						
							|  |  |  |                     path, os.path.join(self.tempdir, "testing_batch_mock", final) | 
					
						
							|  |  |  |                 ) | 
					
						
							| 
									
										
										
										
											2024-12-14 19:39:02 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |                 # with filename | 
					
						
							| 
									
										
										
										
											2025-08-30 21:25:44 -05:00
										 |  |  |                 path = handler.get_data_path(batch, "input.csv") | 
					
						
							|  |  |  |                 self.assertEqual( | 
					
						
							|  |  |  |                     path, | 
					
						
							|  |  |  |                     os.path.join( | 
					
						
							|  |  |  |                         self.tempdir, "testing_batch_mock", final, "input.csv" | 
					
						
							|  |  |  |                     ), | 
					
						
							|  |  |  |                 ) | 
					
						
							| 
									
										
										
										
											2024-12-14 19:39:02 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |                 # makedirs | 
					
						
							|  |  |  |                 path = handler.get_data_path(batch) | 
					
						
							|  |  |  |                 self.assertFalse(os.path.exists(path)) | 
					
						
							|  |  |  |                 path = handler.get_data_path(batch, makedirs=True) | 
					
						
							|  |  |  |                 self.assertTrue(os.path.exists(path)) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-13 20:38:00 -06:00
										 |  |  |         def test_should_populate(self): | 
					
						
							|  |  |  |             handler = self.make_handler() | 
					
						
							|  |  |  |             batch = handler.make_batch(self.session) | 
					
						
							|  |  |  |             self.assertFalse(handler.should_populate(batch)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def test_do_populate(self): | 
					
						
							|  |  |  |             handler = self.make_handler() | 
					
						
							|  |  |  |             batch = handler.make_batch(self.session) | 
					
						
							|  |  |  |             # nb. coverage only; tests nothing | 
					
						
							|  |  |  |             handler.do_populate(batch) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def test_make_row(self): | 
					
						
							|  |  |  |             handler = self.make_handler() | 
					
						
							|  |  |  |             row = handler.make_row() | 
					
						
							|  |  |  |             self.assertIsInstance(row, MockBatchRow) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def test_add_row(self): | 
					
						
							|  |  |  |             handler = self.make_handler() | 
					
						
							|  |  |  |             batch = handler.make_batch(self.session) | 
					
						
							|  |  |  |             self.session.add(batch) | 
					
						
							|  |  |  |             row = handler.make_row() | 
					
						
							|  |  |  |             self.assertIsNone(batch.row_count) | 
					
						
							|  |  |  |             handler.add_row(batch, row) | 
					
						
							|  |  |  |             self.assertEqual(batch.row_count, 1) | 
					
						
							| 
									
										
										
										
											2024-12-14 19:39:02 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-02 19:48:26 -06:00
										 |  |  |         def test_remove_row(self): | 
					
						
							|  |  |  |             model = self.app.model | 
					
						
							|  |  |  |             handler = self.make_handler() | 
					
						
							| 
									
										
										
										
											2025-08-30 21:25:44 -05:00
										 |  |  |             user = model.User(username="barney") | 
					
						
							| 
									
										
										
										
											2025-01-02 19:48:26 -06:00
										 |  |  |             self.session.add(user) | 
					
						
							|  |  |  |             batch = handler.make_batch(self.session, created_by=user) | 
					
						
							|  |  |  |             self.session.add(batch) | 
					
						
							|  |  |  |             row = handler.make_row() | 
					
						
							|  |  |  |             handler.add_row(batch, row) | 
					
						
							|  |  |  |             self.session.flush() | 
					
						
							|  |  |  |             self.assertEqual(batch.row_count, 1) | 
					
						
							|  |  |  |             handler.do_remove_row(row) | 
					
						
							|  |  |  |             self.session.flush() | 
					
						
							|  |  |  |             self.assertEqual(batch.row_count, 0) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-06 16:36:47 -06:00
										 |  |  |         def test_get_effective_rows(self): | 
					
						
							|  |  |  |             model = self.app.model | 
					
						
							|  |  |  |             handler = self.make_handler() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-30 21:25:44 -05:00
										 |  |  |             user = model.User(username="barney") | 
					
						
							| 
									
										
										
										
											2025-01-06 16:36:47 -06:00
										 |  |  |             self.session.add(user) | 
					
						
							|  |  |  |             batch = handler.make_batch(self.session, created_by=user) | 
					
						
							|  |  |  |             self.session.add(batch) | 
					
						
							|  |  |  |             self.session.flush() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             self.assertEqual(handler.get_effective_rows(batch), []) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             row = handler.make_row() | 
					
						
							|  |  |  |             handler.add_row(batch, row) | 
					
						
							|  |  |  |             self.session.flush() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             rows = handler.get_effective_rows(batch) | 
					
						
							|  |  |  |             self.assertEqual(len(rows), 1) | 
					
						
							|  |  |  |             self.assertIs(rows[0], row) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-14 19:39:02 -06:00
										 |  |  |         def test_do_execute(self): | 
					
						
							|  |  |  |             model = self.app.model | 
					
						
							| 
									
										
										
										
											2025-08-30 21:25:44 -05:00
										 |  |  |             user = model.User(username="barney") | 
					
						
							| 
									
										
										
										
											2024-12-14 19:39:02 -06:00
										 |  |  |             self.session.add(user) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             handler = self.make_handler() | 
					
						
							|  |  |  |             batch = handler.make_batch(self.session, created_by=user) | 
					
						
							|  |  |  |             self.session.add(batch) | 
					
						
							|  |  |  |             self.session.flush() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # error if execution not allowed | 
					
						
							| 
									
										
										
										
											2025-08-30 21:25:44 -05:00
										 |  |  |             with patch.object(handler, "why_not_execute", return_value="bad batch"): | 
					
						
							| 
									
										
										
										
											2024-12-14 19:39:02 -06:00
										 |  |  |                 self.assertRaises(RuntimeError, handler.do_execute, batch, user) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # nb. coverage only; tests nothing | 
					
						
							|  |  |  |             self.assertIsNone(batch.executed) | 
					
						
							|  |  |  |             self.assertIsNone(batch.executed_by) | 
					
						
							|  |  |  |             handler.do_execute(batch, user) | 
					
						
							|  |  |  |             self.assertIsNotNone(batch.executed) | 
					
						
							|  |  |  |             self.assertIs(batch.executed_by, user) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # error if execution already happened | 
					
						
							|  |  |  |             self.assertRaises(ValueError, handler.do_execute, batch, user) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def test_do_delete(self): | 
					
						
							|  |  |  |             model = self.app.model | 
					
						
							|  |  |  |             handler = self.make_handler() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-30 21:25:44 -05:00
										 |  |  |             user = model.User(username="barney") | 
					
						
							| 
									
										
										
										
											2024-12-14 19:39:02 -06:00
										 |  |  |             self.session.add(user) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # simple delete | 
					
						
							|  |  |  |             batch = handler.make_batch(self.session, created_by=user) | 
					
						
							|  |  |  |             self.session.add(batch) | 
					
						
							|  |  |  |             self.session.flush() | 
					
						
							|  |  |  |             self.assertEqual(self.session.query(MockBatch).count(), 1) | 
					
						
							|  |  |  |             handler.do_delete(batch, user) | 
					
						
							|  |  |  |             self.assertEqual(self.session.query(MockBatch).count(), 0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # delete w/ rows | 
					
						
							|  |  |  |             batch = handler.make_batch(self.session, created_by=user) | 
					
						
							|  |  |  |             self.session.add(batch) | 
					
						
							|  |  |  |             for i in range(5): | 
					
						
							|  |  |  |                 row = handler.make_row() | 
					
						
							|  |  |  |                 handler.add_row(batch, row) | 
					
						
							|  |  |  |             self.session.flush() | 
					
						
							|  |  |  |             self.assertEqual(self.session.query(MockBatch).count(), 1) | 
					
						
							|  |  |  |             handler.do_delete(batch, user) | 
					
						
							|  |  |  |             self.assertEqual(self.session.query(MockBatch).count(), 0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # delete w/ files | 
					
						
							| 
									
										
										
										
											2025-08-30 21:25:44 -05:00
										 |  |  |             self.config.setdefault("wutta.batch.storage_path", self.tempdir) | 
					
						
							| 
									
										
										
										
											2024-12-14 19:39:02 -06:00
										 |  |  |             batch = handler.make_batch(self.session, created_by=user) | 
					
						
							|  |  |  |             self.session.add(batch) | 
					
						
							|  |  |  |             self.session.flush() | 
					
						
							| 
									
										
										
										
											2025-08-30 21:25:44 -05:00
										 |  |  |             path = handler.get_data_path(batch, "data.txt", makedirs=True) | 
					
						
							|  |  |  |             with open(path, "wt") as f: | 
					
						
							|  |  |  |                 f.write("foo=bar") | 
					
						
							| 
									
										
										
										
											2024-12-14 19:39:02 -06:00
										 |  |  |             self.assertEqual(self.session.query(MockBatch).count(), 1) | 
					
						
							|  |  |  |             path = handler.get_data_path(batch) | 
					
						
							|  |  |  |             self.assertTrue(os.path.exists(path)) | 
					
						
							|  |  |  |             handler.do_delete(batch, user) | 
					
						
							|  |  |  |             self.assertEqual(self.session.query(MockBatch).count(), 0) | 
					
						
							|  |  |  |             self.assertFalse(os.path.exists(path)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # delete w/ files (dry-run) | 
					
						
							| 
									
										
										
										
											2025-08-30 21:25:44 -05:00
										 |  |  |             self.config.setdefault("wutta.batch.storage_path", self.tempdir) | 
					
						
							| 
									
										
										
										
											2024-12-14 19:39:02 -06:00
										 |  |  |             batch = handler.make_batch(self.session, created_by=user) | 
					
						
							|  |  |  |             self.session.add(batch) | 
					
						
							|  |  |  |             self.session.flush() | 
					
						
							| 
									
										
										
										
											2025-08-30 21:25:44 -05:00
										 |  |  |             path = handler.get_data_path(batch, "data.txt", makedirs=True) | 
					
						
							|  |  |  |             with open(path, "wt") as f: | 
					
						
							|  |  |  |                 f.write("foo=bar") | 
					
						
							| 
									
										
										
										
											2024-12-14 19:39:02 -06:00
										 |  |  |             self.assertEqual(self.session.query(MockBatch).count(), 1) | 
					
						
							|  |  |  |             path = handler.get_data_path(batch) | 
					
						
							|  |  |  |             self.assertTrue(os.path.exists(path)) | 
					
						
							|  |  |  |             handler.do_delete(batch, user, dry_run=True) | 
					
						
							|  |  |  |             # nb. batch appears missing from session even in dry-run | 
					
						
							|  |  |  |             self.assertEqual(self.session.query(MockBatch).count(), 0) | 
					
						
							|  |  |  |             # nb. but its files remain intact | 
					
						
							|  |  |  |             self.assertTrue(os.path.exists(path)) |