13
13
# limitations under the License.
14
14
15
15
import unittest
16
+ from unittest import mock
16
17
17
18
from opentelemetry .exporter .prometheus_remote_write import (
18
19
PrometheusRemoteWriteMetricsExporter ,
19
20
)
21
+ from opentelemetry .exporter .prometheus_remote_write .gen .types_pb2 import (
22
+ TimeSeries ,
23
+ )
24
+ from opentelemetry .sdk .metrics import Counter
25
+ from opentelemetry .sdk .metrics .export import ExportRecord , MetricsExportResult
26
+ from opentelemetry .sdk .metrics .export .aggregate import (
27
+ HistogramAggregator ,
28
+ LastValueAggregator ,
29
+ MinMaxSumCountAggregator ,
30
+ SumAggregator ,
31
+ ValueObserverAggregator ,
32
+ )
33
+ from opentelemetry .sdk .resources import Resource
34
+ from opentelemetry .sdk .util import get_dict_as_key
20
35
21
36
22
37
class TestValidation (unittest .TestCase ):
@@ -102,35 +117,154 @@ def test_invalid_conflicting_auth_param(self):
102
117
class TestConversion (unittest .TestCase ):
103
118
# Initializes test data that is reused across tests
104
119
def setUp (self ):
105
- pass
120
+ self ._test_metric = Counter (
121
+ "testname" , "testdesc" , "testunit" , int , None
122
+ )
123
+ self ._exporter = PrometheusRemoteWriteMetricsExporter (
124
+ endpoint = "/prom/test_endpoint"
125
+ )
126
+
127
+ def generate_record (aggregator_type ):
128
+ return ExportRecord (
129
+ self ._test_metric ,
130
+ None ,
131
+ aggregator_type (),
132
+ Resource ({}),
133
+ )
134
+
135
+ self ._generate_record = generate_record
136
+
137
+ def converter_method (record , name , value ):
138
+ return (type (record .aggregator ), name , value )
139
+
140
+ self ._converter_mock = mock .MagicMock (return_value = converter_method )
106
141
107
142
# Ensures conversion to timeseries function works with valid aggregation types
108
143
def test_valid_convert_to_timeseries (self ):
109
- pass
144
+ timeseries_mock_method = mock .Mock (return_value = ["test_value" ])
145
+ self ._exporter .convert_from_sum = timeseries_mock_method
146
+ self ._exporter .convert_from_min_max_sum_count = timeseries_mock_method
147
+ self ._exporter .convert_from_histogram = timeseries_mock_method
148
+ self ._exporter .convert_from_last_value = timeseries_mock_method
149
+ self ._exporter .convert_from_value_observer = timeseries_mock_method
150
+ test_records = [
151
+ self ._generate_record (SumAggregator ),
152
+ self ._generate_record (MinMaxSumCountAggregator ),
153
+ self ._generate_record (HistogramAggregator ),
154
+ self ._generate_record (LastValueAggregator ),
155
+ self ._generate_record (ValueObserverAggregator ),
156
+ ]
157
+ data = self ._exporter .convert_to_timeseries (test_records )
158
+ self .assertEqual (len (data ), 5 )
159
+ for timeseries in data :
160
+ self .assertEqual (timeseries , "test_value" )
161
+
162
+ no_type_records = [self ._generate_record (lambda : None )]
163
+ with self .assertRaises (ValueError ):
164
+ self ._exporter .convert_to_timeseries (no_type_records )
110
165
111
166
# Ensures conversion to timeseries fails for unsupported aggregation types
112
167
def test_invalid_convert_to_timeseries (self ):
113
- pass
168
+ no_type_records = [self ._generate_record (lambda : None )]
169
+ with self .assertRaises (ValueError ):
170
+ self ._exporter .convert_to_timeseries (no_type_records )
114
171
115
172
# Ensures sum aggregator is correctly converted to timeseries
116
173
def test_convert_from_sum (self ):
117
- pass
174
+ sum_record = self ._generate_record (SumAggregator )
175
+ sum_record .aggregator .update (3 )
176
+ sum_record .aggregator .update (2 )
177
+ sum_record .aggregator .take_checkpoint ()
178
+
179
+ self ._exporter .create_timeseries = self ._converter_mock ()
180
+ timeseries = self ._exporter .convert_from_sum (sum_record )
181
+ self .assertEqual (timeseries [0 ], (SumAggregator , "testname" , 5 ))
118
182
119
183
# Ensures sum min_max_count aggregator is correctly converted to timeseries
120
184
def test_convert_from_min_max_sum_count (self ):
121
- pass
185
+ min_max_sum_count_record = self ._generate_record (
186
+ MinMaxSumCountAggregator
187
+ )
188
+ min_max_sum_count_record .aggregator .update (5 )
189
+ min_max_sum_count_record .aggregator .update (1 )
190
+ min_max_sum_count_record .aggregator .take_checkpoint ()
191
+
192
+ self ._exporter .create_timeseries = self ._converter_mock ()
193
+ timeseries = self ._exporter .convert_from_min_max_sum_count (
194
+ min_max_sum_count_record
195
+ )
196
+ self .assertEqual (
197
+ timeseries [0 ], (MinMaxSumCountAggregator , "testname_min" , 1 )
198
+ )
199
+ self .assertEqual (
200
+ timeseries [1 ], (MinMaxSumCountAggregator , "testname_max" , 5 )
201
+ )
202
+ self .assertEqual (
203
+ timeseries [2 ], (MinMaxSumCountAggregator , "testname_sum" , 6 )
204
+ )
205
+ self .assertEqual (
206
+ timeseries [3 ], (MinMaxSumCountAggregator , "testname_count" , 2 )
207
+ )
122
208
123
209
# Ensures histogram aggregator is correctly converted to timeseries
124
210
def test_convert_from_histogram (self ):
125
- pass
211
+ histogram_record = self ._generate_record (HistogramAggregator )
212
+ histogram_record .aggregator .update (5 )
213
+ histogram_record .aggregator .update (2 )
214
+ histogram_record .aggregator .update (- 1 )
215
+ histogram_record .aggregator .take_checkpoint ()
216
+
217
+ self ._exporter .create_timeseries = self ._converter_mock ()
218
+ timeseries = self ._exporter .convert_from_histogram (histogram_record )
219
+ self .assertEqual (
220
+ timeseries [0 ], (HistogramAggregator , 'testname_bucket{le="0"}' , 1 )
221
+ )
222
+ self .assertEqual (
223
+ timeseries [1 ],
224
+ (HistogramAggregator , 'testname_bucket{le="+Inf"}' , 2 ),
225
+ )
226
+ self .assertEqual (
227
+ timeseries [2 ], (HistogramAggregator , "testname_count" , 3 )
228
+ )
126
229
127
230
# Ensures last value aggregator is correctly converted to timeseries
128
231
def test_convert_from_last_value (self ):
129
- pass
232
+ last_value_record = self ._generate_record (LastValueAggregator )
233
+ last_value_record .aggregator .update (1 )
234
+ last_value_record .aggregator .update (5 )
235
+ last_value_record .aggregator .take_checkpoint ()
236
+
237
+ self ._exporter .create_timeseries = self ._converter_mock ()
238
+ timeseries = self ._exporter .convert_from_last_value (last_value_record )
239
+ self .assertEqual (timeseries [0 ], (LastValueAggregator , "testname" , 5 ))
130
240
131
241
# Ensures value observer aggregator is correctly converted to timeseries
132
242
def test_convert_from_value_observer (self ):
133
- pass
243
+ value_observer_record = self ._generate_record (ValueObserverAggregator )
244
+ value_observer_record .aggregator .update (5 )
245
+ value_observer_record .aggregator .update (1 )
246
+ value_observer_record .aggregator .update (2 )
247
+ value_observer_record .aggregator .take_checkpoint ()
248
+
249
+ self ._exporter .create_timeseries = self ._converter_mock ()
250
+ timeseries = self ._exporter .convert_from_value_observer (
251
+ value_observer_record
252
+ )
253
+ self .assertEqual (
254
+ timeseries [0 ], (ValueObserverAggregator , "testname_min" , 1 )
255
+ )
256
+ self .assertEqual (
257
+ timeseries [1 ], (ValueObserverAggregator , "testname_max" , 5 )
258
+ )
259
+ self .assertEqual (
260
+ timeseries [2 ], (ValueObserverAggregator , "testname_sum" , 8 )
261
+ )
262
+ self .assertEqual (
263
+ timeseries [3 ], (ValueObserverAggregator , "testname_count" , 3 )
264
+ )
265
+ self .assertEqual (
266
+ timeseries [4 ], (ValueObserverAggregator , "testname_last" , 2 )
267
+ )
134
268
135
269
# Ensures quantile aggregator is correctly converted to timeseries
136
270
# TODO: Add test once method is implemented
@@ -139,11 +273,36 @@ def test_convert_from_quantile(self):
139
273
140
274
# Ensures timeseries produced contains appropriate sample and labels
141
275
def test_create_timeseries (self ):
142
- pass
276
+ sum_aggregator = SumAggregator ()
277
+ sum_aggregator .update (5 )
278
+ sum_aggregator .take_checkpoint ()
279
+ sum_aggregator .last_update_timestamp = 10
280
+ export_record = ExportRecord (
281
+ self ._test_metric ,
282
+ get_dict_as_key ({"record_name" : "record_value" }),
283
+ sum_aggregator ,
284
+ Resource ({"resource_name" : "resource_value" }),
285
+ )
143
286
144
- # Ensure correct headers are added when valid config is provided
145
- def test_get_headers (self ):
146
- pass
287
+ expected_timeseries = TimeSeries ()
288
+ expected_timeseries .labels .append (
289
+ self ._exporter .create_label ("__name__" , "testname" )
290
+ )
291
+ expected_timeseries .labels .append (
292
+ self ._exporter .create_label ("resource_name" , "resource_value" )
293
+ )
294
+ expected_timeseries .labels .append (
295
+ self ._exporter .create_label ("record_name" , "record_value" )
296
+ )
297
+ expected_timeseries .samples .append (
298
+ self ._exporter .create_sample (10 , 5.0 ),
299
+ )
300
+ timeseries = self ._exporter .create_timeseries (
301
+ export_record ,
302
+ "testname" ,
303
+ 5.0 ,
304
+ )
305
+ self .assertEqual (timeseries , expected_timeseries )
147
306
148
307
149
308
class TestExport (unittest .TestCase ):
0 commit comments