@@ -955,3 +955,176 @@ def test_run_parser_validation_non_string_log(chronicle_client):
955955 )
956956 assert "All logs must be strings" in str (exc_info .value )
957957 assert "index 1" in str (exc_info .value )
958+
959+
960+ def test_run_parser_with_statedump_parsing (chronicle_client , mock_response ):
961+ """Test run_parser with parse_statedump=True."""
962+ log_type = "WINEVTLOG"
963+ parser_code = "filter {}"
964+ logs = ["test log" ]
965+
966+ statedump_string = '\n \n Internal State (label=):\n {\n "key": "value"\n }'
967+
968+ expected_result = {
969+ "runParserResults" : [
970+ {
971+ "parsedEvents" : {"events" : []},
972+ "statedumpResults" : [{"statedumpResult" : statedump_string }],
973+ }
974+ ]
975+ }
976+ mock_response .json .return_value = expected_result
977+
978+ with patch .object (
979+ chronicle_client .session , "post" , return_value = mock_response
980+ ) as mock_post :
981+ result = run_parser (
982+ chronicle_client ,
983+ log_type = log_type ,
984+ parser_code = parser_code ,
985+ parser_extension_code = "" ,
986+ logs = logs ,
987+ statedump_allowed = True ,
988+ parse_statedump = True ,
989+ )
990+
991+ called_args = mock_post .call_args
992+ request_body = called_args [1 ]["json" ]
993+ assert request_body ["statedump_allowed" ] is True
994+
995+ assert "runParserResults" in result
996+ assert len (result ["runParserResults" ]) == 1
997+ statedump_results = result ["runParserResults" ][0 ]["statedumpResults" ]
998+ assert len (statedump_results ) == 1
999+ parsed_statedump = statedump_results [0 ]["statedumpResult" ]
1000+ assert isinstance (parsed_statedump , dict )
1001+ assert "info" in parsed_statedump
1002+ assert "state" in parsed_statedump
1003+ assert parsed_statedump ["info" ] == "Internal State (label=):"
1004+ assert parsed_statedump ["state" ]["key" ] == "value"
1005+
1006+
1007+ def test_run_parser_without_statedump_parsing (chronicle_client , mock_response ):
1008+ """Test run_parser with parse_statedump=False (default)."""
1009+ log_type = "WINEVTLOG"
1010+ parser_code = "filter {}"
1011+ logs = ["test log" ]
1012+
1013+ statedump_string = '\n \n Internal State (label=):\n {\n "key": "value"\n }'
1014+
1015+ expected_result = {
1016+ "runParserResults" : [
1017+ {
1018+ "parsedEvents" : {"events" : []},
1019+ "statedumpResults" : [{"statedumpResult" : statedump_string }],
1020+ }
1021+ ]
1022+ }
1023+ mock_response .json .return_value = expected_result
1024+
1025+ with patch .object (
1026+ chronicle_client .session , "post" , return_value = mock_response
1027+ ):
1028+ result = run_parser (
1029+ chronicle_client ,
1030+ log_type = log_type ,
1031+ parser_code = parser_code ,
1032+ parser_extension_code = "" ,
1033+ logs = logs ,
1034+ statedump_allowed = True ,
1035+ parse_statedump = False ,
1036+ )
1037+
1038+ assert "runParserResults" in result
1039+ statedump_results = result ["runParserResults" ][0 ]["statedumpResults" ]
1040+ original_statedump = statedump_results [0 ]["statedumpResult" ]
1041+ assert original_statedump == statedump_string
1042+
1043+
1044+ def test_run_parser_statedump_parsing_with_invalid_json (
1045+ chronicle_client , mock_response , capsys
1046+ ):
1047+ """Test statedump parsing handles invalid JSON gracefully."""
1048+ log_type = "WINEVTLOG"
1049+ parser_code = "filter {}"
1050+ logs = ["test log" ]
1051+
1052+ expected_result = {
1053+ "runParserResults" : [
1054+ {
1055+ "parsedEvents" : {"events" : []},
1056+ "statedumpResults" : [
1057+ {"statedumpResult" : "Internal State:\n {invalid json}" }
1058+ ],
1059+ }
1060+ ]
1061+ }
1062+ mock_response .json .return_value = expected_result
1063+
1064+ with patch .object (
1065+ chronicle_client .session , "post" , return_value = mock_response
1066+ ):
1067+ result = run_parser (
1068+ chronicle_client ,
1069+ log_type = log_type ,
1070+ parser_code = parser_code ,
1071+ parser_extension_code = "" ,
1072+ logs = logs ,
1073+ statedump_allowed = True ,
1074+ parse_statedump = True ,
1075+ )
1076+
1077+ captured = capsys .readouterr ()
1078+ assert "Warning: Failed to parse statedump" in captured .out
1079+
1080+ assert "runParserResults" in result
1081+ statedump_results = result ["runParserResults" ][0 ]["statedumpResults" ]
1082+ assert (
1083+ statedump_results [0 ]["statedumpResult" ]
1084+ == "Internal State:\n {invalid json}"
1085+ )
1086+
1087+
1088+ def test_run_parser_statedump_parsing_multiple_results (
1089+ chronicle_client , mock_response
1090+ ):
1091+ """Test statedump parsing with multiple statedump results."""
1092+ log_type = "WINEVTLOG"
1093+ parser_code = "filter {}"
1094+ logs = ["test log 1" , "test log 2" ]
1095+
1096+ statedump1 = '\n \n Internal State (label=):\n {\n "log": "1"\n }'
1097+ statedump2 = '\n \n Internal State (label=):\n {\n "log": "2"\n }'
1098+
1099+ expected_result = {
1100+ "runParserResults" : [
1101+ {
1102+ "parsedEvents" : {"events" : []},
1103+ "statedumpResults" : [
1104+ {"statedumpResult" : statedump1 },
1105+ {"statedumpResult" : statedump2 },
1106+ ],
1107+ }
1108+ ]
1109+ }
1110+ mock_response .json .return_value = expected_result
1111+
1112+ with patch .object (
1113+ chronicle_client .session , "post" , return_value = mock_response
1114+ ):
1115+ result = run_parser (
1116+ chronicle_client ,
1117+ log_type = log_type ,
1118+ parser_code = parser_code ,
1119+ parser_extension_code = "" ,
1120+ logs = logs ,
1121+ statedump_allowed = True ,
1122+ parse_statedump = True ,
1123+ )
1124+
1125+ statedump_results = result ["runParserResults" ][0 ]["statedumpResults" ]
1126+ assert len (statedump_results ) == 2
1127+ assert isinstance (statedump_results [0 ]["statedumpResult" ], dict )
1128+ assert statedump_results [0 ]["statedumpResult" ]["state" ]["log" ] == "1"
1129+ assert isinstance (statedump_results [1 ]["statedumpResult" ], dict )
1130+ assert statedump_results [1 ]["statedumpResult" ]["state" ]["log" ] == "2"
0 commit comments