""" Test cases for o11ydiagnosis/subtasks/logreporter/feishu.py """ import os import sys import unittest from unittest.mock import patch, MagicMock, Mock # Add project root to path sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../../../../'))) from o11ydiagnosis.subtasks.logreporter.feishu import ( send_feishu_message, send_feishu_file, generate_daily_statistic ) class TestSendFeishuMessage(unittest.TestCase): """Test send_feishu_message function""" @patch('o11ydiagnosis.subtasks.logreporter.feishu.requests.post') def test_send_feishu_message_success(self, mock_post): """Test successful message sending""" mock_response = MagicMock() mock_response.status_code = 200 mock_response.json.return_value = {"code": 0, "msg": "success"} mock_post.return_value = mock_response cluster_id = "test-cluster" utc_day = "20240101" json_data = {"error_count": 10, "warn_count": 5} bucket = "test-bucket" file = "test-file.json" webhook_url = "https://test-webhook.com" result = send_feishu_message(cluster_id, utc_day, json_data, bucket, file, webhook_url) self.assertTrue(result) mock_post.assert_called_once() # Verify the call arguments call_args = mock_post.call_args self.assertEqual(call_args[0][0], webhook_url) self.assertEqual(call_args[1]['headers']['Content-Type'], 'application/json') @patch('o11ydiagnosis.subtasks.logreporter.feishu.requests.post') def test_send_feishu_message_failure_code(self, mock_post): """Test message sending with non-zero code""" mock_response = MagicMock() mock_response.status_code = 200 mock_response.json.return_value = {"code": 1, "msg": "error message"} mock_post.return_value = mock_response result = send_feishu_message("cluster", "20240101", {}, "bucket", "file", "url") self.assertFalse(result) @patch('o11ydiagnosis.subtasks.logreporter.feishu.requests.post') def test_send_feishu_message_failure_status(self, mock_post): """Test message sending with non-200 status code""" mock_response = MagicMock() mock_response.status_code = 500 mock_response.json.return_value = {"code": 0, "msg": "success"} mock_post.return_value = mock_response result = send_feishu_message("cluster", "20240101", {}, "bucket", "file", "url") self.assertFalse(result) @patch('o11ydiagnosis.subtasks.logreporter.feishu.requests.post') def test_send_feishu_message_exception(self, mock_post): """Test message sending with exception""" mock_post.side_effect = Exception("Network error") result = send_feishu_message("cluster", "20240101", {}, "bucket", "file", "url") self.assertFalse(result) @patch('o11ydiagnosis.subtasks.logreporter.feishu.requests.post') def test_send_feishu_message_content(self, mock_post): """Test message content structure""" mock_response = MagicMock() mock_response.status_code = 200 mock_response.json.return_value = {"code": 0} mock_post.return_value = mock_response cluster_id = "my-cluster" utc_day = "20240115" json_data = {"test": "data"} bucket = "my-bucket" file = "path/to/file.json" webhook_url = "https://webhook.com" send_feishu_message(cluster_id, utc_day, json_data, bucket, file, webhook_url) # Verify message structure call_args = mock_post.call_args data = call_args[1]['data'] # Check that data contains expected fields self.assertIn(b'msg_type', data) self.assertIn(b'interactive', data) self.assertIn(b'card', data) self.assertIn(cluster_id.encode(), data) self.assertIn(utc_day.encode(), data) self.assertIn(bucket.encode(), data) self.assertIn(file.encode(), data) class TestSendFeishuFile(unittest.TestCase): """Test send_feishu_file function""" def test_send_feishu_file(self): """Test send_feishu_file function (currently just returns)""" result = send_feishu_file("cluster", "local_file") self.assertIsNone(result) class TestGenerateDailyStatistic(unittest.TestCase): """Test generate_daily_statistic function""" def test_generate_daily_statistic_basic(self): """Test basic daily statistic generation""" data = [ { "level": "ERROR", "component": "component1", "position": "pos1", "total": 100, "tags": ["new"] }, { "level": "WARN", "component": "component2", "position": "pos2", "total": 50, "tags": ["new"] }, { "level": "ERROR", "component": "component1", "position": "pos3", "total": 200, "tags": [] }, { "level": "INFO", "component": "component3", "position": "pos4", "total": 300, "tags": [] } ] result = generate_daily_statistic(data) # Check structure self.assertIn("all_logs_statistics", result) self.assertIn("new_logs_statistics", result) # Check all_logs_statistics all_stats = result["all_logs_statistics"] self.assertIn("ERROR", all_stats) self.assertIn("WARN", all_stats) self.assertIn("INFO", all_stats) self.assertEqual(all_stats["ERROR"]["component1"], 300) # 100 + 200 self.assertEqual(all_stats["WARN"]["component2"], 50) self.assertEqual(all_stats["INFO"]["component3"], 300) # Check new_logs_statistics new_stats = result["new_logs_statistics"] self.assertIn("new_error", new_stats) self.assertIn("new_warn", new_stats) # new_error should be sum of ERROR items with "new" tag self.assertEqual(new_stats["new_error"], 100) self.assertEqual(new_stats["new_warn"], 50) def test_generate_daily_statistic_no_new_tags(self): """Test with no new tags""" data = [ { "level": "ERROR", "component": "component1", "position": "pos1", "total": 100, "tags": [] }, { "level": "WARN", "component": "component2", "position": "pos2", "total": 50, "tags": ["surge"] } ] result = generate_daily_statistic(data) new_stats = result["new_logs_statistics"] self.assertEqual(new_stats["new_error"], 0) self.assertEqual(new_stats["new_warn"], 0) def test_generate_daily_statistic_no_tags_field(self): """Test with items that don't have tags field""" data = [ { "level": "ERROR", "component": "component1", "position": "pos1", "total": 100 }, { "level": "WARN", "component": "component2", "position": "pos2", "total": 50, "tags": ["new"] } ] result = generate_daily_statistic(data) new_stats = result["new_logs_statistics"] self.assertEqual(new_stats["new_error"], 0) # No tags field, so not counted as new self.assertEqual(new_stats["new_warn"], 50) def test_generate_daily_statistic_case_insensitive_new_tag(self): """Test that new tag matching is case insensitive""" data = [ { "level": "ERROR", "component": "component1", "position": "pos1", "total": 100, "tags": ["NEW"] }, { "level": "WARN", "component": "component2", "position": "pos2", "total": 50, "tags": ["New"] }, { "level": "ERROR", "component": "component3", "position": "pos3", "total": 75, "tags": ["new", "surge"] } ] result = generate_daily_statistic(data) new_stats = result["new_logs_statistics"] # accumulate([100, 75], initial=0) = [0, 100, 175], sum = 275 self.assertEqual(new_stats["new_error"], 275) # sum(accumulate([100, 75], initial=0)) self.assertEqual(new_stats["new_warn"], 50) def test_generate_daily_statistic_multiple_components_same_level(self): """Test with multiple components at same level""" data = [ { "level": "ERROR", "component": "component1", "position": "pos1", "total": 100, "tags": [] }, { "level": "ERROR", "component": "component1", "position": "pos2", "total": 50, "tags": [] }, { "level": "ERROR", "component": "component2", "position": "pos3", "total": 200, "tags": [] } ] result = generate_daily_statistic(data) all_stats = result["all_logs_statistics"] self.assertEqual(all_stats["ERROR"]["component1"], 150) # 100 + 50 self.assertEqual(all_stats["ERROR"]["component2"], 200) def test_generate_daily_statistic_empty_data(self): """Test with empty data""" data = [] result = generate_daily_statistic(data) self.assertIn("all_logs_statistics", result) self.assertIn("new_logs_statistics", result) self.assertEqual(result["all_logs_statistics"], {}) self.assertEqual(result["new_logs_statistics"]["new_error"], 0) self.assertEqual(result["new_logs_statistics"]["new_warn"], 0) def test_generate_daily_statistic_complex_tags(self): """Test with complex tag scenarios""" data = [ { "level": "ERROR", "component": "component1", "position": "pos1", "total": 100, "tags": ["new", "surge", "other"] }, { "level": "WARN", "component": "component2", "position": "pos2", "total": 50, "tags": ["surge"] # No "new" tag } ] result = generate_daily_statistic(data) new_stats = result["new_logs_statistics"] self.assertEqual(new_stats["new_error"], 100) # Has "new" in tags self.assertEqual(new_stats["new_warn"], 0) # No "new" in tags if __name__ == '__main__': unittest.main()