@@ -206,6 +206,61 @@ def test_prepare_file_data_file_error(self, mock_file_open, mock_logger):
206206 mock_file_open .assert_called_once ()
207207
208208
209+ class TestGenerateInsertQuery :
210+ def test_generate_model_insert_query_success (self ):
211+ """Test _generate_model_insert_query."""
212+ from kernelCI_app .management .commands .helpers .kcidbng_ingester import (
213+ _generate_model_insert_query ,
214+ )
215+
216+ mock_model = MagicMock ()
217+
218+ mock_field_timestamp = MagicMock ()
219+ mock_field_timestamp .name = "field_timestamp"
220+ mock_field_timestamp .db_column = "_timestamp"
221+ mock_field_timestamp .generated = False
222+ mock_field_timestamp .get_internal_type .return_value = "DateTimeField"
223+
224+ mock_field_comment = MagicMock ()
225+ mock_field_comment .name = "comment"
226+ mock_field_comment .db_column = None
227+ mock_field_comment .generated = False
228+ mock_field_comment .get_internal_type .return_value = "CharField"
229+
230+ mock_field3 = MagicMock ()
231+ mock_field3 .name = "checkout"
232+ mock_field3 .db_column = None
233+ mock_field3 .generated = False
234+ mock_field3 .get_internal_type .return_value = "ForeignKey"
235+
236+ mock_field4 = MagicMock ()
237+ mock_field4 .name = "series"
238+ mock_field4 .generated = True
239+
240+ mock_model ._meta .fields = [
241+ mock_field_timestamp ,
242+ mock_field_comment ,
243+ mock_field3 ,
244+ mock_field4 ,
245+ ]
246+
247+ with patch (
248+ "kernelCI_app.management.commands.helpers.kcidbng_ingester.MODEL_MAP" ,
249+ {"issues" : mock_model },
250+ ):
251+ updateable_fields , query = _generate_model_insert_query (
252+ "issues" , mock_model
253+ )
254+
255+ assert updateable_fields == ["field_timestamp" , "comment" , "checkout_id" ]
256+ assert "INSERT INTO issues" in query
257+ assert "_timestamp, comment, checkout_id" in query
258+ assert "GREATEST(issues._timestamp, EXCLUDED._timestamp)" in query
259+ assert "COALESCE(issues.comment, EXCLUDED.comment)" in query
260+ assert "COALESCE(issues.checkout_id, EXCLUDED.checkout_id)" in query
261+ assert "series" not in query
262+
263+
209264class TestConsumeBuffer :
210265 """Test cases for consume_buffer function."""
211266
@@ -218,24 +273,45 @@ class TestConsumeBuffer:
218273 INGEST_BATCH_SIZE_MOCK ,
219274 )
220275 @patch ("kernelCI_app.management.commands.helpers.kcidbng_ingester.out" )
276+ @patch (
277+ "kernelCI_app.management.commands.helpers.kcidbng_ingester._generate_model_insert_query"
278+ )
279+ @patch ("kernelCI_app.management.commands.helpers.kcidbng_ingester.connections" )
221280 @patch ("time.time" , side_effect = TIME_MOCK )
222- def test_consume_buffer_with_items (self , mock_time , mock_out ):
281+ def test_consume_buffer_with_items (
282+ self , mock_time , mock_connections , mock_generate_query , mock_out
283+ ):
223284 """Test consume_buffer with items in buffer."""
285+ table_name = "issues"
224286 mock_model = MagicMock ()
225287 mock_buffer = [MagicMock (), MagicMock ()]
288+ mock_generate_query .return_value = (
289+ ["_timestamp" , "other_field" ],
290+ """
291+ INSERT INTO issues (
292+ _timestamp, other_field
293+ )
294+ VALUES (
295+ %s, %s
296+ )
297+ ON CONFLICT (id)
298+ DO UPDATE SET
299+ GREATEST(issues._timestamp, EXCLUDED._timestamp),
300+ COALESCE(issues.other_field, EXCLUDED.other_field);""" ,
301+ )
302+ mock_cursor = MagicMock ()
303+ mock_connections ["default" ].cursor .return_value .__enter__ .return_value = (
304+ mock_cursor
305+ )
226306
227307 with patch (
228308 "kernelCI_app.management.commands.helpers.kcidbng_ingester.MODEL_MAP" ,
229309 {"issues" : mock_model },
230310 ):
231- consume_buffer (mock_buffer , "issues" )
311+ consume_buffer (mock_buffer , table_name )
232312
233313 assert mock_time .call_count == 2
234- mock_model .objects .bulk_create .assert_called_once_with (
235- mock_buffer ,
236- batch_size = INGEST_BATCH_SIZE_MOCK ,
237- ignore_conflicts = True ,
238- )
314+ mock_cursor .executemany .assert_called_once ()
239315 mock_out .assert_called_once ()
240316
241317 @patch ("kernelCI_app.management.commands.helpers.kcidbng_ingester.out" )
@@ -254,6 +330,12 @@ def test_consume_buffer_empty_buffer(self, mock_time, mock_out):
254330 mock_time .assert_not_called ()
255331 mock_out .assert_not_called ()
256332
333+ def test_consume_buffer_wrong_table (self ):
334+ """Test consume_buffer with invalid table name raises KeyError."""
335+ with pytest .raises (KeyError ):
336+ mock_model = MagicMock ()
337+ consume_buffer ([mock_model ], "another" )
338+
257339
258340class TestFlushBuffers :
259341 """Test cases for flush_buffers function."""
0 commit comments