@@ -85,7 +85,7 @@ class DetectionTestingInfrastructure(BaseModel, abc.ABC):
85
85
hec_channel : str = ""
86
86
_conn : client .Service = PrivateAttr ()
87
87
pbar : tqdm .tqdm = None
88
- start_time : float = None
88
+ start_time : Optional [ float ] = None
89
89
90
90
class Config :
91
91
arbitrary_types_allowed = True
@@ -136,7 +136,6 @@ def setup(self):
136
136
TestReportingType .SETUP ,
137
137
self .get_name (),
138
138
msg ,
139
- self .start_time ,
140
139
update_sync_status = True ,
141
140
)
142
141
func ()
@@ -147,7 +146,7 @@ def setup(self):
147
146
self .finish ()
148
147
return
149
148
150
- self .format_pbar_string (TestReportingType .SETUP , self .get_name (), "Finished Setup!" , self . start_time )
149
+ self .format_pbar_string (TestReportingType .SETUP , self .get_name (), "Finished Setup!" )
151
150
152
151
def wait_for_ui_ready (self ):
153
152
self .get_conn ()
@@ -216,7 +215,6 @@ def connect_to_api(self, sleep_seconds: int = 5):
216
215
TestReportingType .SETUP ,
217
216
self .get_name (),
218
217
"Waiting for reboot" ,
219
- self .start_time ,
220
218
update_sync_status = True ,
221
219
)
222
220
else :
@@ -236,18 +234,12 @@ def connect_to_api(self, sleep_seconds: int = 5):
236
234
self .pbar .write (
237
235
f"Error getting API connection (not quitting) '{ type (e ).__name__ } ': { str (e )} "
238
236
)
239
- print ("wow" )
240
- # self.pbar.write(
241
- # f"Unhandled exception getting connection to splunk server: {str(e)}"
242
- # )
243
- # self.sync_obj.terminate = True
244
237
245
238
for _ in range (sleep_seconds ):
246
239
self .format_pbar_string (
247
240
TestReportingType .SETUP ,
248
241
self .get_name (),
249
242
"Getting API Connection" ,
250
- self .start_time ,
251
243
update_sync_status = True ,
252
244
)
253
245
time .sleep (1 )
@@ -318,7 +310,6 @@ def wait_for_conf_file(self, app_name: str, conf_file_name: str):
318
310
TestReportingType .SETUP ,
319
311
self .get_name (),
320
312
"Configuring Datamodels" ,
321
- self .start_time ,
322
313
)
323
314
324
315
def configure_conf_file_datamodels (self , APP_NAME : str = "Splunk_SA_CIM" ):
@@ -424,7 +415,7 @@ def test_detection(self, detection: Detection) -> None:
424
415
TestReportingType .GROUP ,
425
416
test_group .name ,
426
417
FinalTestingStates .SKIP .value ,
427
- time .time (),
418
+ start_time = time .time (),
428
419
set_pbar = False ,
429
420
)
430
421
)
@@ -465,7 +456,7 @@ def test_detection(self, detection: Detection) -> None:
465
456
TestReportingType .GROUP ,
466
457
test_group .name ,
467
458
TestingStates .DONE_GROUP .value ,
468
- setup_results .start_time ,
459
+ start_time = setup_results .start_time ,
469
460
set_pbar = False ,
470
461
)
471
462
)
@@ -486,7 +477,7 @@ def setup_test_group(self, test_group: TestGroup) -> SetupTestGroupResults:
486
477
TestReportingType .GROUP ,
487
478
test_group .name ,
488
479
TestingStates .BEGINNING_GROUP .value ,
489
- setup_start_time
480
+ start_time = setup_start_time
490
481
)
491
482
# https://github.com/WoLpH/python-progressbar/issues/164
492
483
# Use NullBar if there is more than 1 container or we are running
@@ -526,7 +517,7 @@ def cleanup_test_group(
526
517
TestReportingType .GROUP ,
527
518
test_group .name ,
528
519
TestingStates .DELETING .value ,
529
- test_group_start_time ,
520
+ start_time = test_group_start_time ,
530
521
)
531
522
532
523
# TODO: do we want to clean up even if replay failed? Could have been partial failure?
@@ -544,7 +535,7 @@ def format_pbar_string(
544
535
test_reporting_type : TestReportingType ,
545
536
test_name : str ,
546
537
state : str ,
547
- start_time : Union [float , None ] ,
538
+ start_time : Optional [float ] = None ,
548
539
set_pbar : bool = True ,
549
540
update_sync_status : bool = False ,
550
541
) -> str :
@@ -559,8 +550,13 @@ def format_pbar_string(
559
550
:param update_sync_status: bool indicating whether a sync status update should be queued
560
551
:returns: a formatted string for use w/ pbar
561
552
"""
562
- # set start time id not provided
553
+ # set start time if not provided
563
554
if start_time is None :
555
+ # if self.start_time is still None, something went wrong
556
+ if self .start_time is None :
557
+ raise ValueError (
558
+ "self.start_time is still None; a function may have been called before self.setup()"
559
+ )
564
560
start_time = self .start_time
565
561
566
562
# invoke the helper method
@@ -575,7 +571,7 @@ def format_pbar_string(
575
571
576
572
# update sync status if needed
577
573
if update_sync_status :
578
- self .sync_obj .currentTestingQueue [self .get_name ()] = {
574
+ self .sync_obj .currentTestingQueue [self .get_name ()] = { # type: ignore
579
575
"name" : state ,
580
576
"search" : "N/A" ,
581
577
}
@@ -621,7 +617,7 @@ def execute_unit_test(
621
617
TestReportingType .UNIT ,
622
618
f"{ detection .name } :{ test .name } " ,
623
619
TestingStates .BEGINNING_TEST ,
624
- test_start_time ,
620
+ start_time = test_start_time ,
625
621
)
626
622
627
623
# if the replay failed, record the test failure and return
@@ -690,14 +686,14 @@ def execute_unit_test(
690
686
res = "ERROR"
691
687
link = detection .search
692
688
else :
693
- res = test .result .status .value .upper ()
689
+ res = test .result .status .value .upper () # type: ignore
694
690
link = test .result .get_summary_dict ()["sid_link" ]
695
691
696
692
self .format_pbar_string (
697
693
TestReportingType .UNIT ,
698
694
f"{ detection .name } :{ test .name } " ,
699
695
f"{ res } - { link } (CTRL+D to continue)" ,
700
- test_start_time ,
696
+ start_time = test_start_time ,
701
697
)
702
698
703
699
# Wait for user input
@@ -722,7 +718,7 @@ def execute_unit_test(
722
718
TestReportingType .UNIT ,
723
719
f"{ detection .name } :{ test .name } " ,
724
720
FinalTestingStates .PASS .value ,
725
- test_start_time ,
721
+ start_time = test_start_time ,
726
722
set_pbar = False ,
727
723
)
728
724
)
@@ -744,7 +740,7 @@ def execute_unit_test(
744
740
TestReportingType .UNIT ,
745
741
f"{ detection .name } :{ test .name } " ,
746
742
FinalTestingStates .FAIL .value ,
747
- test_start_time ,
743
+ start_time = test_start_time ,
748
744
set_pbar = False ,
749
745
)
750
746
)
@@ -755,7 +751,7 @@ def execute_unit_test(
755
751
TestReportingType .UNIT ,
756
752
f"{ detection .name } :{ test .name } " ,
757
753
FinalTestingStates .ERROR .value ,
758
- test_start_time ,
754
+ start_time = test_start_time ,
759
755
set_pbar = False ,
760
756
)
761
757
)
@@ -770,7 +766,7 @@ def execute_unit_test(
770
766
stdout .flush ()
771
767
test .result .duration = round (time .time () - test_start_time , 2 )
772
768
773
- # TODO (cmcginley ): break up the execute routines for integration/unit tests some more to remove
769
+ # TODO (#227 ): break up the execute routines for integration/unit tests some more to remove
774
770
# code w/ similar structure
775
771
def execute_integration_test (
776
772
self ,
@@ -837,7 +833,7 @@ def execute_integration_test(
837
833
TestReportingType .INTEGRATION ,
838
834
f"{ detection .name } :{ test .name } " ,
839
835
TestingStates .BEGINNING_TEST ,
840
- test_start_time ,
836
+ start_time = test_start_time ,
841
837
)
842
838
843
839
# if the replay failed, record the test failure and return
@@ -874,15 +870,10 @@ def execute_integration_test(
874
870
start_time = test_start_time
875
871
)
876
872
877
- # TODO (cmcginley): right now, we are creating one CorrelationSearch instance for each
878
- # test case; typically, there is only one unit test, and thus one integration test,
879
- # per detection, so this is not an issue. However, if we start having many test cases
880
- # per detection, we will be duplicating some effort & network calls that we don't need
881
- # to. Consider refactoring in order to re-use CorrelationSearch objects across tests
882
- # in such a case
873
+ # TODO (#228): consider reusing CorrelationSearch instances across test cases
883
874
# Instantiate the CorrelationSearch
884
875
correlation_search = CorrelationSearch (
885
- detection_name = detection . name ,
876
+ detection = detection ,
886
877
service = self .get_conn (),
887
878
pbar_data = pbar_data ,
888
879
)
@@ -892,14 +883,12 @@ def execute_integration_test(
892
883
except Exception as e :
893
884
# Catch and report and unhandled exceptions in integration testing
894
885
test .result = IntegrationTestResult (
895
- message = "TEST FAILED : unhandled exception in CorrelationSearch" ,
886
+ message = "TEST ERROR : unhandled exception in CorrelationSearch" ,
896
887
exception = e ,
897
888
status = TestResultStatus .ERROR
898
889
)
899
890
900
- # TODO (cmcginley): when in interactive mode, consider maybe making the cleanup routine in
901
- # correlation_search happen after the user breaks the interactivity; currently
902
- # risk/notable indexes are dumped before the user can inspect
891
+ # TODO (#229): when in interactive mode, cleanup should happen after user interaction
903
892
# Pause here if the terminate flag has NOT been set AND either of the below are true:
904
893
# 1. the behavior is always_pause
905
894
# 2. the behavior is pause_on_failure and the test failed
@@ -908,7 +897,7 @@ def execute_integration_test(
908
897
if test .result is None :
909
898
res = "ERROR"
910
899
else :
911
- res = test .result .status .value .upper ()
900
+ res = test .result .status .value .upper () # type: ignore
912
901
913
902
# Get the link to the saved search in this specific instance
914
903
link = f"https://{ self .infrastructure .instance_address } :{ self .infrastructure .web_ui_port } "
@@ -917,7 +906,7 @@ def execute_integration_test(
917
906
TestReportingType .INTEGRATION ,
918
907
f"{ detection .name } :{ test .name } " ,
919
908
f"{ res } - { link } (CTRL+D to continue)" ,
920
- test_start_time ,
909
+ start_time = test_start_time ,
921
910
)
922
911
923
912
# Wait for user input
@@ -1036,8 +1025,8 @@ def retry_search_until_timeout(
1036
1025
search = f"{ detection .search } { test .pass_condition } "
1037
1026
1038
1027
# Ensure searches that do not begin with '|' must begin with 'search '
1039
- if not search .strip ().startswith ("|" ):
1040
- if not search .strip ().startswith ("search " ):
1028
+ if not search .strip ().startswith ("|" ): # type: ignore
1029
+ if not search .strip ().startswith ("search " ): # type: ignore
1041
1030
search = f"search { search } "
1042
1031
1043
1032
# exponential backoff for wait time
@@ -1054,7 +1043,7 @@ def retry_search_until_timeout(
1054
1043
TestReportingType .UNIT ,
1055
1044
f"{ detection .name } :{ test .name } " ,
1056
1045
TestingStates .PROCESSING .value ,
1057
- start_time
1046
+ start_time = start_time
1058
1047
)
1059
1048
1060
1049
time .sleep (1 )
@@ -1063,7 +1052,7 @@ def retry_search_until_timeout(
1063
1052
TestReportingType .UNIT ,
1064
1053
f"{ detection .name } :{ test .name } " ,
1065
1054
TestingStates .SEARCHING .value ,
1066
- start_time ,
1055
+ start_time = start_time ,
1067
1056
)
1068
1057
1069
1058
# Execute the search and read the results
@@ -1079,7 +1068,7 @@ def retry_search_until_timeout(
1079
1068
test .result = UnitTestResult ()
1080
1069
1081
1070
# Initialize the collection of fields that are empty that shouldn't be
1082
- empty_fields = set ()
1071
+ empty_fields : set [ str ] = set ()
1083
1072
1084
1073
# Filter out any messages in the results
1085
1074
for result in results :
@@ -1194,10 +1183,15 @@ def replay_attack_data_file(
1194
1183
):
1195
1184
tempfile = mktemp (dir = tmp_dir )
1196
1185
1186
+
1197
1187
if not (str (attack_data_file .data ).startswith ("http://" ) or
1198
1188
str (attack_data_file .data ).startswith ("https://" )) :
1199
1189
if pathlib .Path (str (attack_data_file .data )).is_file ():
1200
- self .format_pbar_string (TestReportingType .GROUP , test_group .name , "Copying Data" , test_group_start_time )
1190
+ self .format_pbar_string (TestReportingType .GROUP ,
1191
+ test_group .name ,
1192
+ "Copying Data" ,
1193
+ test_group_start_time )
1194
+
1201
1195
try :
1202
1196
copyfile (str (attack_data_file .data ), tempfile )
1203
1197
except Exception as e :
@@ -1221,7 +1215,7 @@ def replay_attack_data_file(
1221
1215
TestReportingType .GROUP ,
1222
1216
test_group .name ,
1223
1217
TestingStates .DOWNLOADING .value ,
1224
- test_group_start_time
1218
+ start_time = test_group_start_time
1225
1219
)
1226
1220
1227
1221
Utils .download_file_from_http (
@@ -1240,7 +1234,7 @@ def replay_attack_data_file(
1240
1234
TestReportingType .GROUP ,
1241
1235
test_group .name ,
1242
1236
TestingStates .REPLAYING .value ,
1243
- test_group_start_time
1237
+ start_time = test_group_start_time
1244
1238
)
1245
1239
1246
1240
self .hec_raw_replay (tempfile , attack_data_file )
0 commit comments