@@ -139,14 +139,15 @@ impl Hash for AttributeSet {
139
139
140
140
#[ cfg( all( test, feature = "testing" ) ) ]
141
141
mod tests {
142
- use self :: data:: { DataPoint , ScopeMetrics } ;
142
+ use self :: data:: { DataPoint , HistogramDataPoint , ScopeMetrics } ;
143
143
use super :: * ;
144
144
use crate :: metrics:: data:: { ResourceMetrics , Temporality } ;
145
145
use crate :: metrics:: reader:: TemporalitySelector ;
146
146
use crate :: testing:: metrics:: InMemoryMetricsExporterBuilder ;
147
147
use crate :: { runtime, testing:: metrics:: InMemoryMetricsExporter } ;
148
148
use opentelemetry:: metrics:: { Counter , Meter , UpDownCounter } ;
149
149
use opentelemetry:: { metrics:: MeterProvider as _, KeyValue } ;
150
+ use rand:: { rngs, Rng , SeedableRng } ;
150
151
use std:: borrow:: Cow ;
151
152
use std:: sync:: { Arc , Mutex } ;
152
153
@@ -199,6 +200,20 @@ mod tests {
199
200
counter_aggregation_helper ( Temporality :: Delta ) ;
200
201
}
201
202
203
+ #[ tokio:: test( flavor = "multi_thread" , worker_threads = 1 ) ]
204
+ async fn histogram_aggregation_cumulative ( ) {
205
+ // Run this test with stdout enabled to see output.
206
+ // cargo test histogram_aggregation_cumulative --features=metrics,testing -- --nocapture
207
+ histogram_aggregation_helper ( Temporality :: Cumulative ) ;
208
+ }
209
+
210
+ #[ tokio:: test( flavor = "multi_thread" , worker_threads = 1 ) ]
211
+ async fn histogram_aggregation_delta ( ) {
212
+ // Run this test with stdout enabled to see output.
213
+ // cargo test histogram_aggregation_delta --features=metrics,testing -- --nocapture
214
+ histogram_aggregation_helper ( Temporality :: Delta ) ;
215
+ }
216
+
202
217
#[ tokio:: test( flavor = "multi_thread" , worker_threads = 1 ) ]
203
218
async fn updown_counter_aggregation_cumulative ( ) {
204
219
// Run this test with stdout enabled to see output.
@@ -1007,6 +1022,65 @@ mod tests {
1007
1022
assert ! ( resource_metrics. is_empty( ) , "No metrics should be exported as no new measurements were recorded since last collect." ) ;
1008
1023
}
1009
1024
1025
+ fn histogram_aggregation_helper ( temporality : Temporality ) {
1026
+ // Arrange
1027
+ let mut test_context = TestContext :: new ( temporality) ;
1028
+ let histogram = test_context. meter ( ) . u64_histogram ( "my_histogram" ) . init ( ) ;
1029
+
1030
+ // Act
1031
+ let mut rand = rngs:: SmallRng :: from_entropy ( ) ;
1032
+ let values_kv1 = ( 0 ..50 )
1033
+ . map ( |_| rand. gen_range ( 0 ..100 ) )
1034
+ . collect :: < Vec < u64 > > ( ) ;
1035
+ for value in values_kv1. iter ( ) {
1036
+ histogram. record ( * value, & [ KeyValue :: new ( "key1" , "value1" ) ] ) ;
1037
+ }
1038
+
1039
+ let values_kv2 = ( 0 ..30 )
1040
+ . map ( |_| rand. gen_range ( 0 ..100 ) )
1041
+ . collect :: < Vec < u64 > > ( ) ;
1042
+ for value in values_kv2. iter ( ) {
1043
+ histogram. record ( * value, & [ KeyValue :: new ( "key1" , "value2" ) ] ) ;
1044
+ }
1045
+
1046
+ test_context. flush_metrics ( ) ;
1047
+
1048
+ // Assert
1049
+ let histogram = test_context. get_aggregation :: < data:: Histogram < u64 > > ( "my_histogram" , None ) ;
1050
+ // Expecting 2 time-series.
1051
+ assert_eq ! ( histogram. data_points. len( ) , 2 ) ;
1052
+ if let Temporality :: Cumulative = temporality {
1053
+ assert_eq ! (
1054
+ histogram. temporality,
1055
+ Temporality :: Cumulative ,
1056
+ "Should produce cumulative"
1057
+ ) ;
1058
+ } else {
1059
+ assert_eq ! (
1060
+ histogram. temporality,
1061
+ Temporality :: Delta ,
1062
+ "Should produce delta"
1063
+ ) ;
1064
+ }
1065
+
1066
+ // find and validate key1=value2 datapoint
1067
+ let data_point1 =
1068
+ find_histogram_datapoint_with_key_value ( & histogram. data_points , "key1" , "value1" )
1069
+ . expect ( "datapoint with key1=value1 expected" ) ;
1070
+ assert_eq ! ( data_point1. count, values_kv1. len( ) as u64 ) ;
1071
+ assert_eq ! ( data_point1. sum, values_kv1. iter( ) . sum:: <u64 >( ) ) ;
1072
+ assert_eq ! ( data_point1. min. unwrap( ) , * values_kv1. iter( ) . min( ) . unwrap( ) ) ;
1073
+ assert_eq ! ( data_point1. max. unwrap( ) , * values_kv1. iter( ) . max( ) . unwrap( ) ) ;
1074
+
1075
+ let data_point2 =
1076
+ find_histogram_datapoint_with_key_value ( & histogram. data_points , "key1" , "value2" )
1077
+ . expect ( "datapoint with key1=value2 expected" ) ;
1078
+ assert_eq ! ( data_point2. count, values_kv2. len( ) as u64 ) ;
1079
+ assert_eq ! ( data_point2. sum, values_kv2. iter( ) . sum:: <u64 >( ) ) ;
1080
+ assert_eq ! ( data_point2. min. unwrap( ) , * values_kv2. iter( ) . min( ) . unwrap( ) ) ;
1081
+ assert_eq ! ( data_point2. max. unwrap( ) , * values_kv2. iter( ) . max( ) . unwrap( ) ) ;
1082
+ }
1083
+
1010
1084
fn counter_aggregation_helper ( temporality : Temporality ) {
1011
1085
// Arrange
1012
1086
let mut test_context = TestContext :: new ( temporality) ;
@@ -1109,6 +1183,19 @@ mod tests {
1109
1183
} )
1110
1184
}
1111
1185
1186
+ fn find_histogram_datapoint_with_key_value < ' a , T > (
1187
+ data_points : & ' a [ HistogramDataPoint < T > ] ,
1188
+ key : & str ,
1189
+ value : & str ,
1190
+ ) -> Option < & ' a HistogramDataPoint < T > > {
1191
+ data_points. iter ( ) . find ( |& datapoint| {
1192
+ datapoint
1193
+ . attributes
1194
+ . iter ( )
1195
+ . any ( |kv| kv. key . as_str ( ) == key && kv. value . as_str ( ) == value)
1196
+ } )
1197
+ }
1198
+
1112
1199
fn find_scope_metric < ' a > (
1113
1200
metrics : & ' a [ ScopeMetrics ] ,
1114
1201
name : & ' a str ,
0 commit comments