13
13
# limitations under the License.
14
14
import pytest
15
15
16
+ from prometheus_client .core import CounterMetricFamily
17
+ from unittest .mock import MagicMock , patch
18
+
16
19
from aibrix .metrics .engine_rules import get_metric_standard_rules
20
+ from aibrix .metrics .http_collector import HTTPCollector
21
+ from aibrix .metrics .standard_rules import RenameStandardRule
17
22
18
23
19
24
def test_get_metric_standard_rules_ignore_case ():
@@ -33,3 +38,189 @@ def test_get_metric_standard_rules_not_support():
33
38
34
39
with pytest .raises (ValueError ):
35
40
get_metric_standard_rules ("TensorRT-LLM" )
41
+
42
+
43
+ class TestRenameStandardRule :
44
+ @staticmethod
45
+ def create_sample_metric (
46
+ name : str , value : float = 1.0 , metric_type : str = "counter"
47
+ ):
48
+ if metric_type == "counter" :
49
+ metric = CounterMetricFamily (name , f"Test { metric_type } metric for { name } " )
50
+ else :
51
+ raise ValueError (f"Unsupported metric type: { metric_type } " )
52
+ metric .add_metric (labels = [], value = value )
53
+ return metric
54
+
55
+ def test_rename (self ):
56
+ metric = self .create_sample_metric ("old_metric_name" )
57
+ rule = RenameStandardRule (
58
+ original_name = "old_metric_name" , new_name = "new_metric_name"
59
+ )
60
+
61
+ result = list (rule (metric ))
62
+
63
+ assert len (result ) == 1
64
+ assert len (result [0 ].samples ) == 1
65
+ renamed_metric = result [0 ]
66
+ assert renamed_metric .name == "new_metric_name"
67
+ assert renamed_metric .samples [0 ].name == "new_metric_name_total"
68
+
69
+ def test_rename_with_prefix_suffix (self ):
70
+ metric = self .create_sample_metric ("http_requests" )
71
+ rule = RenameStandardRule (
72
+ original_name = "http_requests" , new_name = "http_requests_renamed"
73
+ )
74
+
75
+ result = list (rule (metric ))
76
+
77
+ assert len (result ) == 1
78
+ assert len (result [0 ].samples ) == 1
79
+ renamed_metric = result [0 ]
80
+ assert renamed_metric .name == "http_requests_renamed"
81
+ assert renamed_metric .samples [0 ].name == "http_requests_renamed_total"
82
+
83
+ def test_assertion_on_name_mismatch (self ):
84
+ metric = self .create_sample_metric ("wrong_metric_name" )
85
+ rule = RenameStandardRule (original_name = "expected_name" , new_name = "new_name" )
86
+
87
+ with pytest .raises (AssertionError ) as exc_info :
88
+ list (rule (metric ))
89
+
90
+ assert "does not match Rule original name" in str (exc_info .value )
91
+
92
+ def test_multiple_samples (self ):
93
+ metric = CounterMetricFamily ("old_metric" , "Test multiple samples" )
94
+ metric .add_metric ([], 1.0 )
95
+ metric .add_metric ([], 2.0 )
96
+
97
+ rule = RenameStandardRule (original_name = "old_metric" , new_name = "new_metric" )
98
+
99
+ result = list (rule (metric ))
100
+
101
+ assert len (result ) == 1
102
+ assert len (result [0 ].samples ) == 2
103
+ renamed_metric = result [0 ]
104
+ assert renamed_metric .name == "new_metric"
105
+ assert renamed_metric .samples [0 ].name == "new_metric_total"
106
+ assert renamed_metric .samples [1 ].name == "new_metric_total"
107
+
108
+
109
+ class TestHTTPCollector :
110
+ SAMPLE_METRICS_TEXT = """
111
+ # HELP http_requests The total number of HTTP requests.
112
+ # TYPE http_requests counter
113
+ http_requests{job="api-server",instance="localhost:9090"} 100
114
+ # HELP temperature_degrees Current temperature in degrees.
115
+ # TYPE temperature_degrees gauge
116
+ temperature_degrees{} 25.5
117
+ """
118
+
119
+ @patch ("aibrix.metrics.http_collector.requests.Session" )
120
+ def test_collect_success (self , mock_session ):
121
+ # Arrange
122
+ mock_response = MagicMock ()
123
+ mock_response .status_code = 200
124
+ mock_response .text = self .SAMPLE_METRICS_TEXT
125
+ mock_session .return_value .get .return_value = mock_response
126
+
127
+ metrics_rules = {
128
+ "http_requests" : RenameStandardRule (
129
+ original_name = "http_requests" , new_name = "http_requests_renamed"
130
+ )
131
+ }
132
+
133
+ collector = HTTPCollector (
134
+ endpoint = "http://fake.metrics.url" ,
135
+ metrics_rules = metrics_rules ,
136
+ keep_original_metric = False ,
137
+ timeout = 5 ,
138
+ )
139
+
140
+ results = list (collector .collect ())
141
+ # Assert
142
+ assert len (collector .metrics_rules ) == 1
143
+
144
+ original_metric = next ((m for m in results if m .name == "http_requests" ), None )
145
+ assert original_metric is None
146
+
147
+ renamed_metric = next (
148
+ (m for m in results if m .name == "http_requests_renamed" ), None
149
+ )
150
+ assert renamed_metric is not None
151
+ assert renamed_metric .samples [0 ].name == "http_requests_renamed_total"
152
+
153
+ @patch ("aibrix.metrics.http_collector.requests.Session" )
154
+ def test_collect_keep_original_metric (self , mock_session ):
155
+ # Arrange
156
+ mock_response = MagicMock ()
157
+ mock_response .status_code = 200
158
+ mock_response .text = self .SAMPLE_METRICS_TEXT
159
+ mock_session .return_value .get .return_value = mock_response
160
+
161
+ metrics_rules = {
162
+ "http_requests" : RenameStandardRule (
163
+ original_name = "http_requests" , new_name = "http_requests_renamed"
164
+ )
165
+ }
166
+
167
+ collector = HTTPCollector (
168
+ endpoint = "http://fake.metrics.url" ,
169
+ metrics_rules = metrics_rules ,
170
+ keep_original_metric = True ,
171
+ timeout = 5 ,
172
+ )
173
+
174
+ results = list (collector .collect ())
175
+ # Assert
176
+ assert len (collector .metrics_rules ) == 1
177
+
178
+ original_metric = next ((m for m in results if m .name == "http_requests" ), None )
179
+ assert original_metric is None
180
+
181
+ renamed_metric = next (
182
+ (m for m in results if m .name == "http_requests_renamed" ), None
183
+ )
184
+ assert renamed_metric is not None
185
+
186
+ @patch ("aibrix.metrics.http_collector.requests.Session" )
187
+ def test_collect_request_failure (self , mock_session ):
188
+ # Arrange
189
+ mock_session .return_value .get .side_effect = Exception ("Connection refused" )
190
+
191
+ collector = HTTPCollector (
192
+ endpoint = "http://fake.metrics.url" , metrics_rules = {}, timeout = 1
193
+ )
194
+
195
+ results = list (collector .collect ())
196
+ # Assert
197
+ assert len (results ) == 0
198
+
199
+ @patch ("aibrix.metrics.http_collector.requests.Session" )
200
+ def test_collect_non_200_response (self , mock_session ):
201
+ # Arrange
202
+ mock_response = MagicMock ()
203
+ mock_response .status_code = 500
204
+ mock_response .text = "Internal Server Error"
205
+ mock_session .return_value .get .return_value = mock_response
206
+
207
+ collector = HTTPCollector (
208
+ endpoint = "http://fake.metrics.url" , metrics_rules = {}, timeout = 5
209
+ )
210
+
211
+ results = list (collector .collect ())
212
+ # Assert
213
+ assert len (results ) == 0
214
+
215
+ def test_empty_metrics_text (self ):
216
+ class FakeHTTPCollector (HTTPCollector ):
217
+ def _collect (self ):
218
+ return ""
219
+
220
+ collector = FakeHTTPCollector (
221
+ endpoint = "http://fake.metrics.url" , metrics_rules = {}
222
+ )
223
+
224
+ results = list (collector .collect ())
225
+ # Assert
226
+ assert len (results ) == 0
0 commit comments