go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/common/tsmon/monitor/serialize_test.go (about) 1 // Copyright 2016 The LUCI Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package monitor 16 17 import ( 18 "testing" 19 "time" 20 21 "github.com/golang/protobuf/proto" 22 "go.chromium.org/luci/common/tsmon/distribution" 23 "go.chromium.org/luci/common/tsmon/field" 24 "go.chromium.org/luci/common/tsmon/target" 25 "go.chromium.org/luci/common/tsmon/types" 26 "google.golang.org/protobuf/types/known/timestamppb" 27 28 . "github.com/smartystreets/goconvey/convey" 29 . "go.chromium.org/luci/common/testing/assertions" 30 pb "go.chromium.org/luci/common/tsmon/ts_mon_proto" 31 ) 32 33 func TestSerializeDistribution(t *testing.T) { 34 Convey("Fixed width params", t, func() { 35 d := distribution.New(distribution.FixedWidthBucketer(10, 20)) 36 dpb := serializeDistribution(d) 37 38 So(dpb, ShouldResembleProto, &pb.MetricsData_Distribution{ 39 Count: proto.Int64(0), 40 BucketOptions: &pb.MetricsData_Distribution_LinearBuckets{ 41 LinearBuckets: &pb.MetricsData_Distribution_LinearOptions{ 42 NumFiniteBuckets: proto.Int32(20), 43 Width: proto.Float64(10), 44 Offset: proto.Float64(0), 45 }, 46 }, 47 }) 48 }) 49 50 Convey("Exponential buckets", t, func() { 51 d := distribution.New(distribution.GeometricBucketer(2, 20)) 52 d.Add(0) 53 d.Add(4) 54 d.Add(1024) 55 d.Add(1536) 56 d.Add(1048576) 57 58 dpb := serializeDistribution(d) 59 So(dpb, ShouldResembleProto, &pb.MetricsData_Distribution{ 60 Count: proto.Int64(5), 61 Mean: proto.Float64(210228), 62 BucketOptions: &pb.MetricsData_Distribution_ExponentialBuckets{ 63 ExponentialBuckets: &pb.MetricsData_Distribution_ExponentialOptions{ 64 NumFiniteBuckets: proto.Int32(20), 65 GrowthFactor: proto.Float64(2), 66 Scale: proto.Float64(1), 67 }, 68 }, 69 BucketCount: []int64{1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 70 0, 0, 0, 0, 0, 1}, 71 }) 72 }) 73 74 Convey("Linear buckets", t, func() { 75 d := distribution.New(distribution.FixedWidthBucketer(10, 2)) 76 d.Add(0) 77 d.Add(1) 78 d.Add(2) 79 d.Add(20) 80 81 dpb := serializeDistribution(d) 82 So(dpb, ShouldResembleProto, &pb.MetricsData_Distribution{ 83 Count: proto.Int64(4), 84 Mean: proto.Float64(5.75), 85 BucketOptions: &pb.MetricsData_Distribution_LinearBuckets{ 86 LinearBuckets: &pb.MetricsData_Distribution_LinearOptions{ 87 NumFiniteBuckets: proto.Int32(2), 88 Width: proto.Float64(10), 89 Offset: proto.Float64(0), 90 }, 91 }, 92 BucketCount: []int64{0, 3, 0, 1}, 93 }) 94 }) 95 } 96 97 func TestSerializeCell(t *testing.T) { 98 now := time.Date(2001, 1, 2, 3, 4, 5, 6, time.UTC) 99 reset := time.Date(2000, 1, 2, 3, 4, 5, 6, time.UTC) 100 101 nowTS := timestamppb.New(now) 102 resetTS := timestamppb.New(reset) 103 104 emptyTaskRootLabels := []*pb.MetricsCollection_RootLabels{ 105 target.RootLabel("proxy_environment", "pa"), 106 target.RootLabel("acquisition_name", "mon-chrome-infra"), 107 target.RootLabel("proxy_zone", "atl"), 108 target.RootLabel("service_name", ""), 109 target.RootLabel("job_name", ""), 110 target.RootLabel("data_center", ""), 111 target.RootLabel("host_name", ""), 112 target.RootLabel("task_num", int64(0)), 113 target.RootLabel("is_tsmon", true), 114 } 115 116 Convey("Int", t, func() { 117 ret := SerializeCells([]types.Cell{{ 118 types.MetricInfo{ 119 Name: "foo", 120 Description: "bar", 121 Fields: []field.Field{}, 122 ValueType: types.NonCumulativeIntType, 123 }, 124 types.MetricMetadata{Units: types.Seconds}, 125 types.CellData{ 126 FieldVals: []any{}, 127 Target: &target.Task{}, 128 ResetTime: reset, 129 Value: int64(42), 130 }, 131 }}, now) 132 So(ret, ShouldResemble, []*pb.MetricsCollection{{ 133 RootLabels: emptyTaskRootLabels, 134 MetricsDataSet: []*pb.MetricsDataSet{{ 135 MetricName: proto.String("/chrome/infra/foo"), 136 FieldDescriptor: []*pb.MetricsDataSet_MetricFieldDescriptor{}, 137 StreamKind: pb.StreamKind_GAUGE.Enum(), 138 ValueType: pb.ValueType_INT64.Enum(), 139 Description: proto.String("bar"), 140 Data: []*pb.MetricsData{{ 141 Value: &pb.MetricsData_Int64Value{42}, 142 Field: []*pb.MetricsData_MetricField{}, 143 StartTimestamp: nowTS, 144 EndTimestamp: nowTS, 145 }}, 146 Annotations: &pb.Annotations{ 147 Unit: proto.String(string(types.Seconds)), 148 Timestamp: proto.Bool(true), 149 }, 150 }}, 151 }}) 152 }) 153 154 Convey("Counter", t, func() { 155 ret := SerializeCells([]types.Cell{{ 156 types.MetricInfo{ 157 Name: "foo", 158 Description: "bar", 159 Fields: []field.Field{}, 160 ValueType: types.CumulativeIntType, 161 }, 162 types.MetricMetadata{Units: types.Bytes}, 163 types.CellData{ 164 FieldVals: []any{}, 165 Target: &target.Task{}, 166 ResetTime: reset, 167 Value: int64(42), 168 }, 169 }}, now) 170 So(ret, ShouldResemble, []*pb.MetricsCollection{{ 171 RootLabels: emptyTaskRootLabels, 172 MetricsDataSet: []*pb.MetricsDataSet{{ 173 MetricName: proto.String("/chrome/infra/foo"), 174 FieldDescriptor: []*pb.MetricsDataSet_MetricFieldDescriptor{}, 175 StreamKind: pb.StreamKind_CUMULATIVE.Enum(), 176 ValueType: pb.ValueType_INT64.Enum(), 177 Description: proto.String("bar"), 178 Data: []*pb.MetricsData{{ 179 Value: &pb.MetricsData_Int64Value{42}, 180 Field: []*pb.MetricsData_MetricField{}, 181 StartTimestamp: resetTS, 182 EndTimestamp: nowTS, 183 }}, 184 Annotations: &pb.Annotations{ 185 Unit: proto.String(string(types.Bytes)), 186 Timestamp: proto.Bool(false), 187 }, 188 }}, 189 }}) 190 }) 191 192 Convey("Float", t, func() { 193 ret := SerializeCells([]types.Cell{{ 194 types.MetricInfo{ 195 Name: "foo", 196 Description: "bar", 197 Fields: []field.Field{}, 198 ValueType: types.NonCumulativeFloatType, 199 }, 200 types.MetricMetadata{}, 201 types.CellData{ 202 FieldVals: []any{}, 203 Target: &target.Task{}, 204 ResetTime: reset, 205 Value: float64(42), 206 }, 207 }}, now) 208 So(ret, ShouldResemble, []*pb.MetricsCollection{{ 209 RootLabels: emptyTaskRootLabels, 210 MetricsDataSet: []*pb.MetricsDataSet{{ 211 MetricName: proto.String("/chrome/infra/foo"), 212 FieldDescriptor: []*pb.MetricsDataSet_MetricFieldDescriptor{}, 213 StreamKind: pb.StreamKind_GAUGE.Enum(), 214 ValueType: pb.ValueType_DOUBLE.Enum(), 215 Description: proto.String("bar"), 216 Data: []*pb.MetricsData{{ 217 Value: &pb.MetricsData_DoubleValue{42}, 218 Field: []*pb.MetricsData_MetricField{}, 219 StartTimestamp: nowTS, 220 EndTimestamp: nowTS, 221 }}, 222 }}, 223 }}) 224 }) 225 226 Convey("FloatCounter", t, func() { 227 ret := SerializeCells([]types.Cell{{ 228 types.MetricInfo{ 229 Name: "foo", 230 Description: "bar", 231 Fields: []field.Field{}, 232 ValueType: types.CumulativeFloatType, 233 }, 234 types.MetricMetadata{}, 235 types.CellData{ 236 FieldVals: []any{}, 237 Target: &target.Task{}, 238 ResetTime: reset, 239 Value: float64(42), 240 }, 241 }}, now) 242 So(ret, ShouldResemble, []*pb.MetricsCollection{{ 243 RootLabels: emptyTaskRootLabels, 244 MetricsDataSet: []*pb.MetricsDataSet{{ 245 MetricName: proto.String("/chrome/infra/foo"), 246 FieldDescriptor: []*pb.MetricsDataSet_MetricFieldDescriptor{}, 247 StreamKind: pb.StreamKind_CUMULATIVE.Enum(), 248 ValueType: pb.ValueType_DOUBLE.Enum(), 249 Description: proto.String("bar"), 250 Data: []*pb.MetricsData{{ 251 Value: &pb.MetricsData_DoubleValue{42}, 252 Field: []*pb.MetricsData_MetricField{}, 253 StartTimestamp: resetTS, 254 EndTimestamp: nowTS, 255 }}, 256 }}, 257 }}) 258 }) 259 260 Convey("String", t, func() { 261 ret := SerializeCells([]types.Cell{{ 262 types.MetricInfo{ 263 Name: "foo", 264 Description: "bar", 265 Fields: []field.Field{}, 266 ValueType: types.StringType, 267 }, 268 types.MetricMetadata{}, 269 types.CellData{ 270 FieldVals: []any{}, 271 Target: &target.Task{}, 272 ResetTime: reset, 273 Value: "hello", 274 }, 275 }}, now) 276 So(ret, ShouldResemble, []*pb.MetricsCollection{{ 277 RootLabels: emptyTaskRootLabels, 278 MetricsDataSet: []*pb.MetricsDataSet{{ 279 MetricName: proto.String("/chrome/infra/foo"), 280 FieldDescriptor: []*pb.MetricsDataSet_MetricFieldDescriptor{}, 281 StreamKind: pb.StreamKind_GAUGE.Enum(), 282 ValueType: pb.ValueType_STRING.Enum(), 283 Description: proto.String("bar"), 284 Data: []*pb.MetricsData{{ 285 Value: &pb.MetricsData_StringValue{"hello"}, 286 Field: []*pb.MetricsData_MetricField{}, 287 StartTimestamp: nowTS, 288 EndTimestamp: nowTS, 289 }}, 290 }}, 291 }}) 292 }) 293 294 Convey("Boolean", t, func() { 295 ret := SerializeCells([]types.Cell{{ 296 types.MetricInfo{ 297 Name: "foo", 298 Description: "bar", 299 Fields: []field.Field{}, 300 ValueType: types.BoolType, 301 }, 302 types.MetricMetadata{}, 303 types.CellData{ 304 FieldVals: []any{}, 305 Target: &target.Task{}, 306 ResetTime: reset, 307 Value: true, 308 }, 309 }}, now) 310 So(ret, ShouldResemble, []*pb.MetricsCollection{{ 311 RootLabels: emptyTaskRootLabels, 312 MetricsDataSet: []*pb.MetricsDataSet{{ 313 MetricName: proto.String("/chrome/infra/foo"), 314 FieldDescriptor: []*pb.MetricsDataSet_MetricFieldDescriptor{}, 315 StreamKind: pb.StreamKind_GAUGE.Enum(), 316 ValueType: pb.ValueType_BOOL.Enum(), 317 Description: proto.String("bar"), 318 Data: []*pb.MetricsData{{ 319 Value: &pb.MetricsData_BoolValue{true}, 320 Field: []*pb.MetricsData_MetricField{}, 321 StartTimestamp: nowTS, 322 EndTimestamp: nowTS, 323 }}, 324 }}, 325 }}) 326 }) 327 328 Convey("NonDefaultTarget", t, func() { 329 taskTarget := target.Task{ 330 ServiceName: "hello", 331 JobName: "world", 332 } 333 334 ret := SerializeCells([]types.Cell{{ 335 types.MetricInfo{ 336 Name: "foo", 337 Description: "bar", 338 Fields: []field.Field{}, 339 ValueType: types.NonCumulativeIntType, 340 }, 341 types.MetricMetadata{}, 342 types.CellData{ 343 FieldVals: []any{}, 344 Target: &taskTarget, 345 ResetTime: reset, 346 Value: int64(42), 347 }, 348 }}, now) 349 So(ret, ShouldResemble, []*pb.MetricsCollection{{ 350 RootLabels: []*pb.MetricsCollection_RootLabels{ 351 target.RootLabel("proxy_environment", "pa"), 352 target.RootLabel("acquisition_name", "mon-chrome-infra"), 353 target.RootLabel("proxy_zone", "atl"), 354 target.RootLabel("service_name", "hello"), 355 target.RootLabel("job_name", "world"), 356 target.RootLabel("data_center", ""), 357 target.RootLabel("host_name", ""), 358 target.RootLabel("task_num", int64(0)), 359 target.RootLabel("is_tsmon", true), 360 }, 361 MetricsDataSet: []*pb.MetricsDataSet{{ 362 MetricName: proto.String("/chrome/infra/foo"), 363 FieldDescriptor: []*pb.MetricsDataSet_MetricFieldDescriptor{}, 364 StreamKind: pb.StreamKind_GAUGE.Enum(), 365 ValueType: pb.ValueType_INT64.Enum(), 366 Description: proto.String("bar"), 367 Data: []*pb.MetricsData{{ 368 Value: &pb.MetricsData_Int64Value{42}, 369 Field: []*pb.MetricsData_MetricField{}, 370 StartTimestamp: nowTS, 371 EndTimestamp: nowTS, 372 }}, 373 }}, 374 }}) 375 }) 376 377 Convey("CumulativeDistribution", t, func() { 378 d := distribution.New(distribution.FixedWidthBucketer(10, 20)) 379 d.Add(1024) 380 ret := SerializeCells([]types.Cell{{ 381 MetricInfo: types.MetricInfo{ 382 Name: "foo", 383 Description: "bar", 384 Fields: []field.Field{}, 385 ValueType: types.CumulativeDistributionType, 386 }, 387 MetricMetadata: types.MetricMetadata{ 388 Units: types.Seconds, 389 }, 390 CellData: types.CellData{ 391 FieldVals: []any{}, 392 Target: &target.Task{}, 393 ResetTime: reset, 394 Value: d, 395 }, 396 }}, now) 397 So(ret, ShouldResemble, []*pb.MetricsCollection{{ 398 RootLabels: emptyTaskRootLabels, 399 MetricsDataSet: []*pb.MetricsDataSet{{ 400 MetricName: proto.String("/chrome/infra/foo"), 401 FieldDescriptor: []*pb.MetricsDataSet_MetricFieldDescriptor{}, 402 StreamKind: pb.StreamKind_CUMULATIVE.Enum(), 403 ValueType: pb.ValueType_DISTRIBUTION.Enum(), 404 Description: proto.String("bar"), 405 Annotations: &pb.Annotations{ 406 Unit: proto.String(string(types.Seconds)), 407 // serializeCells() should have set timestamp with true, 408 // although it is types.Seconds. 409 Timestamp: proto.Bool(false), 410 }, 411 Data: []*pb.MetricsData{{ 412 Value: &pb.MetricsData_DistributionValue{ 413 DistributionValue: &pb.MetricsData_Distribution{ 414 Count: proto.Int64(1), 415 Mean: proto.Float64(1024), 416 BucketOptions: &pb.MetricsData_Distribution_LinearBuckets{ 417 LinearBuckets: &pb.MetricsData_Distribution_LinearOptions{ 418 NumFiniteBuckets: proto.Int32(20), 419 Width: proto.Float64(10), 420 Offset: proto.Float64(0), 421 }, 422 }, 423 BucketCount: []int64{ 424 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 425 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 426 0, 1, 427 }, 428 }, 429 }, 430 Field: []*pb.MetricsData_MetricField{}, 431 StartTimestamp: resetTS, 432 EndTimestamp: nowTS, 433 }}, 434 }}, 435 }}) 436 }) 437 438 Convey("NonCumulativeDistribution", t, func() { 439 d := distribution.New(distribution.FixedWidthBucketer(10, 20)) 440 d.Add(1024) 441 ret := SerializeCells([]types.Cell{{ 442 MetricInfo: types.MetricInfo{ 443 Name: "foo", 444 Description: "bar", 445 Fields: []field.Field{}, 446 ValueType: types.NonCumulativeDistributionType, 447 }, 448 MetricMetadata: types.MetricMetadata{ 449 Units: types.Seconds, 450 }, 451 CellData: types.CellData{ 452 FieldVals: []any{}, 453 Target: &target.Task{}, 454 ResetTime: reset, 455 Value: d, 456 }, 457 }}, now) 458 So(ret, ShouldResemble, []*pb.MetricsCollection{{ 459 RootLabels: emptyTaskRootLabels, 460 MetricsDataSet: []*pb.MetricsDataSet{{ 461 MetricName: proto.String("/chrome/infra/foo"), 462 FieldDescriptor: []*pb.MetricsDataSet_MetricFieldDescriptor{}, 463 StreamKind: pb.StreamKind_GAUGE.Enum(), 464 ValueType: pb.ValueType_DISTRIBUTION.Enum(), 465 Description: proto.String("bar"), 466 Annotations: &pb.Annotations{ 467 Unit: proto.String(string(types.Seconds)), 468 // serializeCells() should have set timestamp with true, 469 // although it is types.Seconds. 470 Timestamp: proto.Bool(false), 471 }, 472 Data: []*pb.MetricsData{{ 473 Value: &pb.MetricsData_DistributionValue{ 474 DistributionValue: &pb.MetricsData_Distribution{ 475 Count: proto.Int64(1), 476 Mean: proto.Float64(1024), 477 BucketOptions: &pb.MetricsData_Distribution_LinearBuckets{ 478 LinearBuckets: &pb.MetricsData_Distribution_LinearOptions{ 479 NumFiniteBuckets: proto.Int32(20), 480 Width: proto.Float64(10), 481 Offset: proto.Float64(0), 482 }, 483 }, 484 BucketCount: []int64{ 485 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 486 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 487 0, 1, 488 }, 489 }, 490 }, 491 Field: []*pb.MetricsData_MetricField{}, 492 StartTimestamp: nowTS, 493 EndTimestamp: nowTS, 494 }}, 495 }}, 496 }}) 497 }) 498 }