@@ -17,17 +17,30 @@ def setUp(self):
1717 self .mock_logger_exception = self .logger_exception_patcher .start ()
1818 self .logger_error_patcher = patch ("common.log_decorator.logger.error" )
1919 self .mock_logger_error = self .logger_error_patcher .start ()
20+ self .firehose_client_patcher = patch ("common.log_decorator.firehose_client" )
21+ self .mock_firehose_client = self .firehose_client_patcher .start ()
22+ # patch common.log_decorator.time
23+ self .mock_generate_send = patch ("common.log_decorator.generate_and_send_logs" ).start ()
2024
2125 def tearDown (self ):
2226 patch .stopall ()
2327
24- @patch ("common.log_decorator.firehose_client" )
2528 def test_send_log_to_firehose_success (self , mock_firehose_client ):
2629 """Test send_log_to_firehose with successful firehose response"""
2730 # Arrange
2831 test_log_data = {"function_name" : "test_func" , "result" : "success" }
2932 mock_response = {"ResponseMetadata" : {"HTTPStatusCode" : 200 }}
30- mock_firehose_client .put_record .return_value = mock_response
33+ self .mock_firehose_client .put_record .return_value = mock_response
34+
35+ # Act
36+ send_log_to_firehose (self .test_stream , test_log_data )
37+
38+ # Assert
39+ expected_record = {"Data" : json .dumps ({"event" : test_log_data }).encode ("utf-8" )}
40+ self .mock_firehose_client .put_record .assert_called_once_with (
41+ DeliveryStreamName = self .test_stream ,
42+ Record = expected_record
43+ )
3144
3245 # Act
3346 send_log_to_firehose (self .test_stream , test_log_data )
@@ -39,26 +52,24 @@ def test_send_log_to_firehose_success(self, mock_firehose_client):
3952 Record = expected_record
4053 )
4154
42- @patch ("common.log_decorator.firehose_client" )
43- def test_send_log_to_firehose_exception (self , mock_firehose_client ):
55+ def test_send_log_to_firehose_exception (self ):
4456 """Test send_log_to_firehose with firehose exception"""
4557 # Arrange
4658 test_log_data = {"function_name" : "test_func" , "result" : "error" }
47- mock_firehose_client .put_record .side_effect = Exception ("Firehose error" )
59+ self . mock_firehose_client .put_record .side_effect = Exception ("Firehose error" )
4860
4961 # Act
5062 send_log_to_firehose (self .test_stream , test_log_data )
5163
5264 # Assert
53- mock_firehose_client .put_record .assert_called_once ()
65+ self . mock_firehose_client .put_record .assert_called_once ()
5466 self .mock_logger_exception .assert_called_once_with (
5567 "Error sending log to Firehose: %s" ,
56- mock_firehose_client .put_record .side_effect
68+ self . mock_firehose_client .put_record .side_effect
5769 )
5870
59- @patch ("common.log_decorator.send_log_to_firehose" )
6071 @patch ("time.time" )
61- def test_generate_and_send_logs_success (self , mock_time , mock_send_log ):
72+ def test_generate_and_send_logs_success (self , mock_time ):
6273 """Test generate_and_send_logs with successful log generation"""
6374 # Arrange
6475 mock_time .return_value = 1000.5
@@ -78,11 +89,10 @@ def test_generate_and_send_logs_success(self, mock_time, mock_send_log):
7889 "result" : "success"
7990 }
8091 self .mock_logger_error .assert_not_called ()
81- mock_send_log .assert_called_once_with (self .test_stream , expected_log_data )
92+ self . mock_send_log .assert_called_once_with (self .test_stream , expected_log_data )
8293
83- @patch ("common.log_decorator.send_log_to_firehose" )
8494 @patch ("time.time" )
85- def test_generate_and_send_logs_error (self , mock_time , mock_send_log ):
95+ def test_generate_and_send_logs_error (self , mock_time ):
8696 """Test generate_and_send_logs with error log generation"""
8797 # Arrange
8898 mock_time .return_value = 1000.75
@@ -102,17 +112,16 @@ def test_generate_and_send_logs_error(self, mock_time, mock_send_log):
102112 "error" : "Test error"
103113 }
104114 self .mock_logger_error .assert_called_once_with (json .dumps (expected_log_data ))
105- mock_send_log .assert_called_once_with (self .test_stream , expected_log_data )
115+ self . mock_send_log .assert_called_once_with (self .test_stream , expected_log_data )
106116
107- @patch ("common.log_decorator.generate_and_send_logs" )
108117 @patch ("common.log_decorator.time" )
109118 @patch ("common.log_decorator.datetime" )
110- def test_logging_decorator_success (self , mock_datetime , mock_time , mock_generate_send ):
119+ def test_logging_decorator_success (self , mock_datetime , mock_time ):
111120 """Test logging_decorator with successful function execution"""
112121 # Arrange
113122 mock_datetime .now .return_value = datetime (2023 , 1 , 1 , 12 , 0 , 0 )
114123 mock_time .time .return_value = 1000.0
115- mock_generate_send .return_value = None
124+ self . mock_generate_send .return_value = None
116125
117126 @logging_decorator (self .test_prefix , self .test_stream )
118127 def test_function (x , y ):
@@ -125,24 +134,23 @@ def test_function(x, y):
125134 self .assertEqual (result , {"statusCode" : 200 , "result" : 5 })
126135
127136 # Verify generate_and_send_logs was called with correct parameters
128- mock_generate_send .assert_called_once ()
129- call_args = mock_generate_send .call_args [0 ]
130- call_kwargs = mock_generate_send .call_args [1 ]
137+ self . mock_generate_send .assert_called_once ()
138+ call_args = self . mock_generate_send .call_args [0 ]
139+ call_kwargs = self . mock_generate_send .call_args [1 ]
131140 self .assertEqual (call_args [0 ], self .test_stream ) # stream_name
132141 self .assertEqual (call_args [1 ], 1000.0 ) # start_time
133142 self .assertEqual (call_args [2 ]["function_name" ], f"{ self .test_prefix } _test_function" ) # base_log_data
134143 self .assertEqual (call_kwargs ['additional_log_data' ], {"statusCode" : 200 , "result" : 5 }) # additional_log_data
135144 self .assertNotIn ("is_error_log" , call_kwargs ) # Should not be error log
136145
137- @patch ("common.log_decorator.generate_and_send_logs" )
138146 @patch ("common.log_decorator.time" )
139147 @patch ("common.log_decorator.datetime" )
140- def test_logging_decorator_exception (self , mock_datetime , mock_time , mock_generate_send ):
148+ def test_logging_decorator_exception (self , mock_datetime , mock_time ):
141149 """Test logging_decorator with function raising exception"""
142150 # Arrange
143151 mock_datetime .now .return_value = datetime (2023 , 1 , 1 , 12 , 0 , 0 )
144152 mock_time .time .return_value = 1000.0
145- mock_generate_send .return_value = None
153+ self . mock_generate_send .return_value = None
146154
147155 @logging_decorator (self .test_prefix , self .test_stream )
148156 def test_function_with_error ():
@@ -153,21 +161,20 @@ def test_function_with_error():
153161 test_function_with_error ()
154162
155163 # Verify generate_and_send_logs was called with error parameters
156- mock_generate_send .assert_called_once ()
157- call_args = mock_generate_send .call_args [0 ]
158- call_kwargs = mock_generate_send .call_args [1 ]
164+ self . mock_generate_send .assert_called_once ()
165+ call_args = self . mock_generate_send .call_args [0 ]
166+ call_kwargs = self . mock_generate_send .call_args [1 ]
159167
160168 self .assertEqual (call_args [0 ], self .test_stream ) # stream_name
161169 self .assertEqual (call_args [1 ], 1000.0 ) # start_time
162170 self .assertEqual (call_args [2 ]["function_name" ], f"{ self .test_prefix } _test_function_with_error" ) # base_log_data
163171 self .assertEqual (call_args [3 ], {"statusCode" : 500 , "error" : "Test error" }) # additional_log_data
164172 self .assertTrue (call_kwargs .get ("is_error_log" , False )) # Should be error log
165173
166- @patch ("common.log_decorator.generate_and_send_logs" )
167- def test_logging_decorator_preserves_function_metadata (self , mock_generate_send ):
174+ def test_logging_decorator_preserves_function_metadata (self ):
168175 """Test that the decorator preserves the original function's metadata"""
169176 # Arrange
170- mock_generate_send .return_value = None
177+ self . mock_generate_send .return_value = None
171178
172179 @logging_decorator (self .test_prefix , self .test_stream )
173180 def documented_function ():
@@ -177,3 +184,28 @@ def documented_function():
177184 # Act & Assert
178185 self .assertEqual (documented_function .__name__ , "documented_function" )
179186 self .assertEqual (documented_function .__doc__ , "This is a test function with documentation" )
187+
188+ def test_send_log_to_firehose_exception_logging (self ):
189+ """Test that logger.exception is called when firehose_client.put_record throws an error"""
190+ # Arrange
191+ test_log_data = {"function_name" : "test_func" , "result" : "error" }
192+ test_error = Exception ("Firehose connection failed" )
193+ self .mock_firehose_client .put_record .side_effect = test_error
194+
195+ # Act
196+ send_log_to_firehose (self .test_stream , test_log_data )
197+
198+ # Assert
199+ # Verify firehose_client.put_record was called
200+ expected_record = {"Data" : json .dumps ({"event" : test_log_data }).encode ("utf-8" )}
201+ self .mock_firehose_client .put_record .assert_called_once_with (
202+ DeliveryStreamName = self .test_stream ,
203+ Record = expected_record
204+ )
205+
206+ # Verify logger.exception was called with the correct message and error
207+ self .mock_logger_exception .assert_called_once_with (
208+ "Error sending log to Firehose: %s" ,
209+ test_error
210+ )
211+
0 commit comments