github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/metrics/aggregation/type_test.go (about) 1 // Copyright (c) 2017 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 package aggregation 22 23 import ( 24 "encoding/json" 25 "fmt" 26 "testing" 27 28 "github.com/m3db/m3/src/x/pool" 29 "github.com/m3db/m3/src/x/test/testmarshal" 30 31 "github.com/stretchr/testify/require" 32 yaml "gopkg.in/yaml.v2" 33 ) 34 35 func TestTypeIsValid(t *testing.T) { 36 require.True(t, P75.IsValid()) 37 require.False(t, Type(int(P75)+1).IsValid()) 38 } 39 40 func TestTypeMaxID(t *testing.T) { 41 require.Equal(t, maxTypeID, P75.ID()) 42 require.Equal(t, P75, Type(maxTypeID)) 43 require.Equal(t, maxTypeID, len(ValidTypes)) 44 } 45 46 func TestTypeUnmarshalYAML(t *testing.T) { 47 inputs := []struct { 48 str string 49 expected Type 50 expectedErr bool 51 }{ 52 { 53 str: "Min", 54 expected: Min, 55 }, 56 { 57 str: "Mean,", 58 expectedErr: true, 59 }, 60 { 61 str: "asd", 62 expectedErr: true, 63 }, 64 } 65 for _, input := range inputs { 66 var aggtype Type 67 err := yaml.Unmarshal([]byte(input.str), &aggtype) 68 69 if input.expectedErr { 70 require.Error(t, err) 71 continue 72 } 73 74 require.NoError(t, err) 75 require.Equal(t, input.expected, aggtype) 76 } 77 } 78 79 func TestTypesIsDefault(t *testing.T) { 80 require.True(t, DefaultTypes.IsDefault()) 81 82 require.False(t, Types{Max}.IsDefault()) 83 } 84 85 func TestTypesMarshalJSON(t *testing.T) { 86 inputs := []struct { 87 types Types 88 expected string 89 expectedErr bool 90 }{ 91 { 92 types: Types{}, 93 expected: `[]`, 94 }, 95 { 96 types: Types{Min}, 97 expected: `["Min"]`, 98 }, 99 { 100 types: Types{Mean, Max, P99, P9999}, 101 expected: `["Mean","Max","P99","P9999"]`, 102 }, 103 { 104 types: Types{Type(1000)}, 105 expectedErr: true, 106 }, 107 } 108 for _, input := range inputs { 109 b, err := json.Marshal(input.types) 110 if input.expectedErr { 111 require.Error(t, err) 112 continue 113 } 114 require.NoError(t, err) 115 require.Equal(t, input.expected, string(b)) 116 } 117 } 118 119 func TestTypesUnMarshalJSON(t *testing.T) { 120 inputs := []struct { 121 str string 122 expected Types 123 expectedErr bool 124 }{ 125 { 126 str: `[]`, 127 expected: Types{}, 128 }, 129 { 130 str: `["Min"]`, 131 expected: Types{Min}, 132 }, 133 { 134 str: `["Mean","Max","P99","P9999"]`, 135 expected: Types{Mean, Max, P99, P9999}, 136 }, 137 { 138 str: `[P100]`, 139 expectedErr: true, 140 }, 141 } 142 for _, input := range inputs { 143 var aggTypes Types 144 err := json.Unmarshal([]byte(input.str), &aggTypes) 145 if input.expectedErr { 146 require.Error(t, err) 147 continue 148 } 149 require.NoError(t, err) 150 require.Equal(t, input.expected, aggTypes) 151 } 152 } 153 154 func TestTypesMarshalRoundTrip(t *testing.T) { 155 inputs := []Types{ 156 {}, 157 {Min}, 158 {Mean, Max, P99, P9999}, 159 } 160 161 testmarshal.TestMarshalersRoundtrip(t, inputs, []testmarshal.Marshaler{ 162 testmarshal.JSONMarshaler, 163 testmarshal.YAMLMarshaler, 164 }) 165 } 166 167 func TestTypesMarshalText(t *testing.T) { 168 cases := []struct { 169 In Type 170 Expected string 171 }{{ 172 In: Mean, 173 Expected: "Mean", 174 }, { 175 In: Last, 176 Expected: "Last", 177 }} 178 179 for _, tc := range cases { 180 t.Run(tc.Expected, func(t *testing.T) { 181 testmarshal.AssertMarshals(t, testmarshal.TextMarshaler, tc.In, []byte(tc.Expected)) 182 }) 183 } 184 } 185 186 func TestTypesUnmarshalTextError(t *testing.T) { 187 cases := []string{ 188 "unknown_at", 189 `"Mean"`, // double JSON encoded 190 } 191 192 for _, tc := range cases { 193 t.Run(tc, func(t *testing.T) { 194 var target Type 195 require.EqualError(t, target.UnmarshalText([]byte(tc)), fmt.Sprintf("invalid aggregation type: %s", tc)) 196 }) 197 } 198 } 199 200 func TestTypesUnmarshalYAML(t *testing.T) { 201 inputs := []struct { 202 str string 203 expected Types 204 expectedErr bool 205 }{ 206 { 207 str: "", 208 expected: Types(nil), 209 }, 210 { 211 str: "[Min]", 212 expected: Types{Min}, 213 }, 214 { 215 str: "[Mean,Max,P99,P9999]", 216 expected: Types{Mean, Max, P99, P9999}, 217 }, 218 { 219 str: "[Min,Max,P99,P9999,P100]", 220 expectedErr: true, 221 }, 222 { 223 str: "[Min,Max,P99,P9999,P100]", 224 expectedErr: true, 225 }, 226 { 227 str: ",Mean", 228 expectedErr: true, 229 }, 230 { 231 str: "Mean,", 232 expectedErr: true, 233 }, 234 { 235 str: ",Mean,", 236 expectedErr: true, 237 }, 238 } 239 for _, input := range inputs { 240 var aggtypes Types 241 err := yaml.Unmarshal([]byte(input.str), &aggtypes) 242 243 if input.expectedErr { 244 require.Error(t, err) 245 continue 246 } 247 248 require.NoError(t, err) 249 require.Equal(t, input.expected, aggtypes) 250 } 251 } 252 253 func TestParseTypes(t *testing.T) { 254 inputs := []struct { 255 str string 256 expected Types 257 }{ 258 { 259 str: "Min", 260 expected: Types{Min}, 261 }, 262 { 263 str: "Min,Max", 264 expected: Types{Min, Max}, 265 }, 266 { 267 str: "min,max", 268 expected: Types{Min, Max}, 269 }, 270 } 271 for _, input := range inputs { 272 res, err := ParseTypes(input.str) 273 require.NoError(t, err) 274 require.Equal(t, input.expected, res) 275 } 276 } 277 278 func TestQuantiles(t *testing.T) { 279 res, ok := Types{Median, P95, P99}.PooledQuantiles(nil) 280 require.Equal(t, []float64{0.5, 0.95, 0.99}, res) 281 require.False(t, ok) 282 283 p := pool.NewFloatsPool( 284 []pool.Bucket{ 285 pool.Bucket{Capacity: 10, Count: 1}, 286 }, 287 nil, 288 ) 289 p.Init() 290 res, ok = Types{Median, P95, P99}.PooledQuantiles(p) 291 require.Equal(t, []float64{0.5, 0.95, 0.99}, res) 292 require.True(t, ok) 293 294 p.Put(res) 295 296 res2, ok := Types{P90, P95, P99}.PooledQuantiles(p) 297 require.Equal(t, []float64{0.9, 0.95, 0.99}, res2) 298 require.Equal(t, res, res2) 299 require.True(t, ok) 300 p.Put(res2) 301 302 res3, ok := Types{Count}.PooledQuantiles(p) 303 require.Nil(t, res3) 304 require.False(t, ok) 305 306 res4, ok := Types{P10, P20, P25, P30, P40, P50, Median, P60, P70, P75, P80, P90, P95, P99, P999, P9999}. 307 PooledQuantiles(p) 308 require.Equal( 309 t, 310 []float64{0.1, 0.2, 0.25, 0.3, 0.4, 0.5, 0.6, 0.7, 0.75, 0.8, 0.9, 0.95, 0.99, 0.999, 0.9999}, 311 res4) 312 require.True(t, ok) 313 } 314 315 func TestIDContains(t *testing.T) { 316 require.True(t, MustCompressTypes(P99).Contains(P99)) 317 require.True(t, MustCompressTypes(P99, P95).Contains(P99)) 318 require.True(t, MustCompressTypes(P99, P95).Contains(P95)) 319 require.True(t, MustCompressTypes(Sum, Last, P999).Contains(Sum)) 320 require.True(t, MustCompressTypes(Sum, Last, P999).Contains(Last)) 321 require.True(t, MustCompressTypes(Sum, Last, P999).Contains(P999)) 322 require.False(t, MustCompressTypes(Sum, Last, P999).Contains(P9999)) 323 require.False(t, MustCompressTypes().Contains(P99)) 324 require.False(t, MustCompressTypes(P99, P95).Contains(P9999)) 325 } 326 327 func TestCompressedTypesIsDefault(t *testing.T) { 328 var id ID 329 require.True(t, id.IsDefault()) 330 331 id[0] = 8 332 require.False(t, id.IsDefault()) 333 334 id[0] = 0 335 require.True(t, id.IsDefault()) 336 }