5151
5252STACK_HAWK_FILENAME = get_unit_tests_scans_path ("stackhawk" ) / "stackhawk_many_vul_without_duplicated_findings.json"
5353STACK_HAWK_SUBSET_FILENAME = get_unit_tests_scans_path ("stackhawk" ) / "stackhawk_many_vul_without_duplicated_findings_subset.json"
54+ STACK_HAWK_EMPTY = get_unit_tests_scans_path ("stackhawk" ) / "stackhawk_empty.json"
5455STACK_HAWK_SCAN_TYPE = "StackHawk HawkScan"
5556
5657
@@ -126,12 +127,17 @@ def _import_reimport_performance(
126127 expected_num_async_tasks2 ,
127128 expected_num_queries3 ,
128129 expected_num_async_tasks3 ,
130+ expected_num_queries4 ,
131+ expected_num_async_tasks4 ,
129132 scan_file1 ,
130133 scan_file2 ,
131134 scan_file3 ,
135+ scan_file4 ,
132136 scan_type ,
133137 product_name ,
134138 engagement_name ,
139+ * ,
140+ close_old_findings4 = False ,
135141 ):
136142 """
137143 Test import/reimport/reimport performance with specified scan files and scan type.
@@ -195,6 +201,7 @@ def _import_reimport_performance(
195201 "verified" : True ,
196202 "sync" : True ,
197203 "scan_type" : scan_type ,
204+ "service" : "Secured Application" ,
198205 "tags" : ["performance-test-reimport" , "reimport-tag-in-param" , "reimport-go-faster" ],
199206 "apply_tags_to_findings" : True ,
200207 }
@@ -224,18 +231,52 @@ def _import_reimport_performance(
224231 "verified" : True ,
225232 "sync" : True ,
226233 "scan_type" : scan_type ,
234+ "service" : "Secured Application" ,
227235 }
228236 reimporter = DefaultReImporter (** reimport_options )
229237 test , _ , _len_new_findings , _len_closed_findings , _ , _ , _ = reimporter .process_scan (scan )
230238
239+ # Fourth import (reimport again, empty report)
240+ # Each assertion context manager is wrapped in its own subTest so that if one fails, the others still run.
241+ # This allows us to see all count mismatches in a single test run, making it easier to fix
242+ # all incorrect expected values at once rather than fixing them one at a time.
243+ # Nested with statements are intentional - each assertion needs its own subTest wrapper.
244+ with ( # noqa: SIM117
245+ self .subTest ("reimport3" ), impersonate (Dojo_User .objects .get (username = "admin" )),
246+ scan_file4 .open (encoding = "utf-8" ) as scan ,
247+ ):
248+ with self .subTest (step = "reimport3" , metric = "queries" ):
249+ with self .assertNumQueries (expected_num_queries4 ):
250+ with self .subTest (step = "reimport3" , metric = "async_tasks" ):
251+ with self ._assertNumAsyncTask (expected_num_async_tasks4 ):
252+ reimport_options = {
253+ "test" : test ,
254+ "user" : lead ,
255+ "lead" : lead ,
256+ "scan_date" : None ,
257+ "minimum_severity" : "Info" ,
258+ "active" : True ,
259+ "verified" : True ,
260+ "sync" : True ,
261+ "scan_type" : scan_type ,
262+ # StackHawk parser sets the service field causing close old findings to fail if we do not specify the service field
263+ # This is a big problem that needs fixing. Parsers should not set the service field.
264+ "service" : "Secured Application" ,
265+ "close_old_findings" : close_old_findings4 ,
266+ }
267+ reimporter = DefaultReImporter (** reimport_options )
268+ test , _ , len_new_findings4 , len_closed_findings4 , _ , _ , _ = reimporter .process_scan (scan )
269+ logger .info ("Step 4: new=%s closed=%s" , len_new_findings4 , len_closed_findings4 )
270+ self .assertGreater (len_closed_findings4 , 0 , "Step 4 (empty reimport with close_old_findings=True) should close findings" )
271+
231272
232273@tag ("performance" )
233274@skip_unless_v2
234275class TestDojoImporterPerformanceSmall (TestDojoImporterPerformanceBase ):
235276
236277 """Performance tests using small sample files (StackHawk, ~6 findings)."""
237278
238- def _import_reimport_performance (self , expected_num_queries1 , expected_num_async_tasks1 , expected_num_queries2 , expected_num_async_tasks2 , expected_num_queries3 , expected_num_async_tasks3 ):
279+ def _import_reimport_performance (self , expected_num_queries1 , expected_num_async_tasks1 , expected_num_queries2 , expected_num_async_tasks2 , expected_num_queries3 , expected_num_async_tasks3 , expected_num_queries4 , expected_num_async_tasks4 ):
239280 """
240281 Log output can be quite large as when the assertNumQueries fails, all queries are printed.
241282 It could be usefule to capture the output in `less`:
@@ -251,12 +292,16 @@ def _import_reimport_performance(self, expected_num_queries1, expected_num_async
251292 expected_num_async_tasks2 ,
252293 expected_num_queries3 ,
253294 expected_num_async_tasks3 ,
295+ expected_num_queries4 ,
296+ expected_num_async_tasks4 ,
254297 scan_file1 = STACK_HAWK_SUBSET_FILENAME ,
255298 scan_file2 = STACK_HAWK_FILENAME ,
256299 scan_file3 = STACK_HAWK_SUBSET_FILENAME ,
300+ scan_file4 = STACK_HAWK_EMPTY ,
257301 scan_type = STACK_HAWK_SCAN_TYPE ,
258302 product_name = "TestDojoDefaultImporter" ,
259303 engagement_name = "Test Create Engagement" ,
304+ close_old_findings4 = True ,
260305 )
261306
262307 @override_settings (ENABLE_AUDITLOG = True )
@@ -275,6 +320,8 @@ def test_import_reimport_reimport_performance_pghistory_async(self):
275320 expected_num_async_tasks2 = 17 ,
276321 expected_num_queries3 = 108 ,
277322 expected_num_async_tasks3 = 16 ,
323+ expected_num_queries4 = 155 ,
324+ expected_num_async_tasks4 = 6 ,
278325 )
279326
280327 @override_settings (ENABLE_AUDITLOG = True )
@@ -297,6 +344,8 @@ def test_import_reimport_reimport_performance_pghistory_no_async(self):
297344 expected_num_async_tasks2 = 17 ,
298345 expected_num_queries3 = 115 ,
299346 expected_num_async_tasks3 = 16 ,
347+ expected_num_queries4 = 155 ,
348+ expected_num_async_tasks4 = 6 ,
300349 )
301350
302351 @override_settings (ENABLE_AUDITLOG = True )
@@ -320,6 +369,8 @@ def test_import_reimport_reimport_performance_pghistory_no_async_with_product_gr
320369 expected_num_async_tasks2 = 19 ,
321370 expected_num_queries3 = 119 ,
322371 expected_num_async_tasks3 = 18 ,
372+ expected_num_queries4 = 162 ,
373+ expected_num_async_tasks4 = 8 ,
323374 )
324375
325376 # Deduplication is enabled in the tests above, but to properly test it we must run the same import twice and capture the results.
@@ -486,7 +537,7 @@ def setUp(self):
486537 for model in [Location , LocationFindingReference ]:
487538 ContentType .objects .get_for_model (model )
488539
489- def _import_reimport_performance (self , expected_num_queries1 , expected_num_async_tasks1 , expected_num_queries2 , expected_num_async_tasks2 , expected_num_queries3 , expected_num_async_tasks3 ):
540+ def _import_reimport_performance (self , expected_num_queries1 , expected_num_async_tasks1 , expected_num_queries2 , expected_num_async_tasks2 , expected_num_queries3 , expected_num_async_tasks3 , expected_num_queries4 , expected_num_async_tasks4 ):
490541 r"""
491542 Log output can be quite large as when the assertNumQueries fails, all queries are printed.
492543 It could be useful to capture the output in `less`:
@@ -502,12 +553,16 @@ def _import_reimport_performance(self, expected_num_queries1, expected_num_async
502553 expected_num_async_tasks2 ,
503554 expected_num_queries3 ,
504555 expected_num_async_tasks3 ,
556+ expected_num_queries4 ,
557+ expected_num_async_tasks4 ,
505558 scan_file1 = STACK_HAWK_SUBSET_FILENAME ,
506559 scan_file2 = STACK_HAWK_FILENAME ,
507560 scan_file3 = STACK_HAWK_SUBSET_FILENAME ,
561+ scan_file4 = STACK_HAWK_EMPTY ,
508562 scan_type = STACK_HAWK_SCAN_TYPE ,
509563 product_name = "TestDojoDefaultImporterLocations" ,
510564 engagement_name = "Test Create Engagement Locations" ,
565+ close_old_findings4 = True ,
511566 )
512567
513568 @override_settings (ENABLE_AUDITLOG = True )
@@ -526,6 +581,8 @@ def test_import_reimport_reimport_performance_pghistory_async(self):
526581 expected_num_async_tasks2 = 17 ,
527582 expected_num_queries3 = 346 ,
528583 expected_num_async_tasks3 = 16 ,
584+ expected_num_queries4 = 212 ,
585+ expected_num_async_tasks4 = 6 ,
529586 )
530587
531588 @override_settings (ENABLE_AUDITLOG = True )
@@ -548,6 +605,8 @@ def test_import_reimport_reimport_performance_pghistory_no_async(self):
548605 expected_num_async_tasks2 = 17 ,
549606 expected_num_queries3 = 355 ,
550607 expected_num_async_tasks3 = 16 ,
608+ expected_num_queries4 = 212 ,
609+ expected_num_async_tasks4 = 6 ,
551610 )
552611
553612 @override_settings (ENABLE_AUDITLOG = True )
@@ -571,6 +630,8 @@ def test_import_reimport_reimport_performance_pghistory_no_async_with_product_gr
571630 expected_num_async_tasks2 = 19 ,
572631 expected_num_queries3 = 359 ,
573632 expected_num_async_tasks3 = 18 ,
633+ expected_num_queries4 = 222 ,
634+ expected_num_async_tasks4 = 8 ,
574635 )
575636
576637 def _deduplication_performance (self , expected_num_queries1 , expected_num_async_tasks1 , expected_num_queries2 , expected_num_async_tasks2 , * , check_duplicates = True ):
0 commit comments