github.com/GuanceCloud/cliutils@v1.1.21/point/point_test.go (about) 1 // Unless explicitly stated otherwise all files in this repository are licensed 2 // under the MIT License. 3 // This product includes software developed at Guance Cloud (https://www.guance.com/). 4 // Copyright 2021-present Guance, Inc. 5 6 package point 7 8 import ( 9 "encoding/json" 10 "fmt" 11 "math" 12 "reflect" 13 "sort" 14 "strings" 15 T "testing" 16 "time" 17 18 "github.com/GuanceCloud/cliutils" 19 influxm "github.com/influxdata/influxdb1-client/models" 20 "github.com/stretchr/testify/assert" 21 ) 22 23 func TestInfluxFields(t *T.T) { 24 t.Run("bytes-array", func(t *T.T) { 25 var kvs KVs 26 kvs = kvs.Add("f1", MustNewAnyArray([]byte("hello"), []byte("world")), false, false) 27 pt := NewPointV2("m1", kvs) 28 fields := pt.InfluxFields() 29 t.Logf("fields: %+#v", fields) 30 }) 31 } 32 33 func TestSizeofPoint(t *T.T) { 34 t.Run("small-pt", func(t *T.T) { 35 var kvs KVs 36 kvs = kvs.Add("f1", 123, false, true) 37 kvs = kvs.Add("f2", 3.14, false, true) 38 kvs = kvs.MustAddTag("t1", "v1") 39 kvs = kvs.MustAddTag("t2", "v2") 40 41 pbpt := NewPointV2("some", kvs) 42 t.Logf("type size(pbpt): %d", reflect.TypeOf(*pbpt).Size()) 43 t.Logf("value size(pbpt): %d", pbpt.Size()) 44 }) 45 46 t.Run("rand-large-pt", func(t *T.T) { 47 r := NewRander(WithFixedTags(true), WithRandText(3)) 48 pts := r.Rand(1) 49 t.Logf("type size(pbpt): %d", reflect.TypeOf(*pts[0]).Size()) 50 t.Logf("value size(pbpt): %d", pts[0].Size()) 51 }) 52 } 53 54 func BenchmarkLPPoint(b *T.B) { 55 now := time.Now() 56 b.Run("pt-lppt", func(b *T.B) { 57 fields := map[string]any{ 58 "f1": 123, 59 "f2": 3.14, 60 } 61 tags := influxm.Tags{ 62 influxm.Tag{Key: []byte("t1"), Value: []byte("v1")}, 63 influxm.Tag{Key: []byte("t2"), Value: []byte("v2")}, 64 } 65 66 b.ResetTimer() 67 for i := 0; i < b.N; i++ { 68 influxm.NewPoint("some", tags, fields, now) 69 } 70 }) 71 72 b.Run("pt-pbpt", func(b *T.B) { 73 b.ResetTimer() 74 for i := 0; i < b.N; i++ { 75 var kvs KVs 76 kvs = kvs.Add("f1", 123, false, true) 77 kvs = kvs.Add("f2", 3.14, false, true) 78 kvs = kvs.MustAddTag("t1", "v1") 79 kvs = kvs.MustAddTag("t2", "v2") 80 81 NewPointV2("some", kvs, WithPrecheck(false), WithTime(now)) 82 } 83 }) 84 85 b.Run("pt-pbpt-with-check", func(b *T.B) { 86 b.ResetTimer() 87 for i := 0; i < b.N; i++ { 88 var kvs KVs 89 kvs = kvs.Add("f1", 123, false, true) 90 kvs = kvs.Add("f2", 3.14, false, true) 91 kvs = kvs.MustAddTag("t1", "v1") 92 kvs = kvs.MustAddTag("t2", "v2") 93 94 NewPointV2("some", kvs, WithTime(now)) 95 } 96 }) 97 } 98 99 func BenchmarkFromModelsLP(b *T.B) { 100 r := NewRander(WithFixedTags(true), WithRandText(3)) 101 pts := r.Rand(1) 102 103 enc := GetEncoder() 104 defer PutEncoder(enc) 105 106 data, err := enc.Encode(pts) 107 assert.NoError(b, err) 108 assert.Len(b, data, 1) 109 110 b.Run("basic", func(b *T.B) { 111 lppts, err := influxm.ParsePointsWithPrecision(data[0], time.Now(), "n") 112 assert.NoError(b, err) 113 assert.Len(b, lppts, 1) 114 115 b.ResetTimer() 116 for i := 0; i < b.N; i++ { 117 FromModelsLP(lppts[0]) 118 } 119 }) 120 121 b.Run("with-check", func(b *T.B) { 122 lppts, err := influxm.ParsePointsWithPrecision(data[0], time.Now(), "n") 123 assert.NoError(b, err) 124 assert.Len(b, lppts, 1) 125 126 c := GetCfg() 127 chk := checker{cfg: c} 128 129 b.ResetTimer() 130 for i := 0; i < b.N; i++ { 131 pt := FromModelsLP(lppts[0]) 132 133 pt = chk.check(pt) 134 pt.pt.Warns = chk.warns 135 chk.reset() 136 137 // re-sort again: check may update pt.kvs 138 if c.keySorted { 139 kvs := KVs(pt.pt.Fields) 140 sort.Sort(kvs) 141 pt.pt.Fields = kvs 142 } 143 } 144 }) 145 } 146 147 func TestGet(t *T.T) { 148 t.Run(`get-tag`, func(t *T.T) { 149 pt := NewPointV2(`abc`, NewKVs(nil).MustAddTag(`t1`, `v1`)) 150 151 assert.Equal(t, `v1`, pt.GetTag(`t1`)) 152 assert.Equal(t, "", pt.GetTag(`not-exist`)) 153 154 // get non-tag key 155 pt.pt.Fields = KVs(pt.pt.Fields).MustAddKV(NewKV(`f1`, 1.23, 156 WithKVUnit("bytes"), 157 WithKVTagSet(true), // set failed 158 WithKVType(COUNT))) 159 assert.Equal(t, "", pt.GetTag(`f1`)) 160 161 pt.AddTag(`empty-tag`, ``) 162 assert.Equal(t, ``, pt.GetTag(`empty-tag`)) 163 164 t.Logf("kvs:\n%s", KVs(pt.pt.Fields).Pretty()) 165 }) 166 167 t.Run("get", func(t *T.T) { 168 var kvs KVs 169 170 EnableDictField = true 171 EnableMixedArrayField = true 172 defer func() { 173 EnableDictField = false 174 EnableMixedArrayField = false 175 }() 176 177 kvs = kvs.Add("si1", int8(1), false, true) 178 kvs = kvs.Add("si2", int16(1), false, true) 179 kvs = kvs.Add("si3", int32(1), false, true) 180 kvs = kvs.Add("si4", int(1), false, true) 181 kvs = kvs.Add("si5", int64(1), false, true) 182 183 kvs = kvs.Add("ui1", uint8(1), false, true) 184 kvs = kvs.Add("ui2", uint16(1), false, true) 185 kvs = kvs.Add("ui3", uint32(1), false, true) 186 kvs = kvs.Add("ui4", uint(1), false, true) 187 kvs = kvs.Add("ui5", uint64(1), false, true) 188 189 kvs = kvs.Add("b1", false, false, true) 190 kvs = kvs.Add("b2", true, false, true) 191 192 kvs = kvs.Add("d", []byte(`hello`), false, true) 193 kvs = kvs.Add("s", `hello`, false, true) 194 195 kvs = kvs.Add("arr", MustNewAnyArray(1, 2.0, false), false, true) 196 kvs = kvs.Add("map", MustNewAny(MustNewMap(map[string]any{"i": 1, "f": 3.14, "s": "world"})), false, true) 197 198 pt := NewPointV2("get", kvs) 199 200 t.Logf("pt: %s", pt.Pretty()) 201 202 assert.Equal(t, int64(1), pt.Get("si1")) 203 assert.Equal(t, int64(1), pt.Get("si2")) 204 assert.Equal(t, int64(1), pt.Get("si3")) 205 assert.Equal(t, int64(1), pt.Get("si4")) 206 assert.Equal(t, int64(1), pt.Get("si5")) 207 208 assert.Equal(t, uint64(1), pt.Get("ui1")) 209 assert.Equal(t, uint64(1), pt.Get("ui2")) 210 assert.Equal(t, uint64(1), pt.Get("ui3")) 211 assert.Equal(t, uint64(1), pt.Get("ui4")) 212 assert.Equal(t, uint64(1), pt.Get("ui5")) 213 214 assert.Equal(t, false, pt.Get("b1")) 215 assert.Equal(t, true, pt.Get("b2")) 216 assert.Equal(t, []byte(`hello`), pt.Get("d")) 217 assert.Equal(t, `hello`, pt.Get("s")) 218 219 assert.Equal(t, []any{int64(1), 2.0, false}, pt.Get("arr")) 220 assert.Equal(t, map[string]any{"i": int64(1), "f": 3.14, "s": "world"}, pt.Get("map")) 221 }) 222 223 t.Run("get", func(t *T.T) { 224 var kvs KVs 225 226 EnableDictField = true 227 EnableMixedArrayField = true 228 defer func() { 229 EnableDictField = false 230 EnableMixedArrayField = false 231 }() 232 233 kvs = kvs.Add("si1", int8(1), false, true) 234 kvs = kvs.Add("si2", int16(1), false, true) 235 kvs = kvs.Add("si3", int32(1), false, true) 236 kvs = kvs.Add("si4", int(1), false, true) 237 kvs = kvs.Add("si5", int64(1), false, true) 238 239 kvs = kvs.Add("ui1", uint8(1), false, true) 240 kvs = kvs.Add("ui2", uint16(1), false, true) 241 kvs = kvs.Add("ui3", uint32(1), false, true) 242 kvs = kvs.Add("ui4", uint(1), false, true) 243 kvs = kvs.Add("ui5", uint64(1), false, true) 244 245 kvs = kvs.Add("b1", false, false, true) 246 kvs = kvs.Add("b2", true, false, true) 247 248 kvs = kvs.Add("d", []byte(`hello`), false, true) 249 kvs = kvs.Add("s", `hello`, false, true) 250 251 kvs = kvs.Add("arr", MustNewAnyArray(1, 2.0, false), false, true) 252 kvs = kvs.Add("map", MustNewAny(MustNewMap(map[string]any{"i": 1, "f": 3.14, "s": "world"})), false, true) 253 254 pt := NewPointV2("get", kvs) 255 256 t.Logf("pt: %s", pt.Pretty()) 257 258 assert.Equal(t, int64(1), pt.Get("si1")) 259 assert.Equal(t, int64(1), pt.Get("si2")) 260 assert.Equal(t, int64(1), pt.Get("si3")) 261 assert.Equal(t, int64(1), pt.Get("si4")) 262 assert.Equal(t, int64(1), pt.Get("si5")) 263 264 assert.Equal(t, uint64(1), pt.Get("ui1")) 265 assert.Equal(t, uint64(1), pt.Get("ui2")) 266 assert.Equal(t, uint64(1), pt.Get("ui3")) 267 assert.Equal(t, uint64(1), pt.Get("ui4")) 268 assert.Equal(t, uint64(1), pt.Get("ui5")) 269 270 assert.Equal(t, false, pt.Get("b1")) 271 assert.Equal(t, true, pt.Get("b2")) 272 assert.Equal(t, []byte(`hello`), pt.Get("d")) 273 assert.Equal(t, `hello`, pt.Get("s")) 274 275 assert.Equal(t, []any{int64(1), 2.0, false}, pt.Get("arr")) 276 assert.Equal(t, map[string]any{"i": int64(1), "f": 3.14, "s": "world"}, pt.Get("map")) 277 }) 278 } 279 280 func TestFlags(t *T.T) { 281 t.Run("test-flag-value", func(t *T.T) { 282 t.Logf("Psent: %d", Psent) 283 t.Logf("Ppb: %d", Ppb) 284 }) 285 286 t.Run("test-flag-set-clear", func(t *T.T) { 287 pt := &Point{} 288 pt.SetFlag(Psent) 289 290 assert.True(t, pt.HasFlag(Psent)) 291 292 pt.SetFlag(Ppb) 293 assert.True(t, pt.HasFlag(Ppb)) 294 295 pt.ClearFlag(Ppb) 296 assert.False(t, pt.HasFlag(Ppb)) 297 298 pt.ClearFlag(Psent) 299 assert.False(t, pt.HasFlag(Psent)) 300 301 pt.SetFlag(Ppooled) 302 assert.True(t, pt.HasFlag(Ppooled)) 303 pt.ClearFlag(Ppooled) 304 assert.False(t, pt.HasFlag(Ppooled)) 305 }) 306 } 307 308 func TestPrettyPoint(t *T.T) { 309 t.Run(`basic`, func(t *T.T) { 310 pt := NewPointV2(`abc`, NewKVs(map[string]any{"f1": 123}).AddTag("t1", "v1")) 311 t.Logf("%s", pt.Pretty()) 312 }) 313 314 t.Run(`with-warns`, func(t *T.T) { 315 pt := NewPointV2(`abc`, NewKVs(map[string]any{"f1": 123}). 316 AddTag("t1", "v1"). 317 AddTag("t2", "v1"), 318 WithDisabledKeys(NewTagKey(`t2`, ""))) 319 320 t.Logf("%s", pt.Pretty()) 321 }) 322 323 t.Run(`with-all-types`, func(t *T.T) { 324 pt := NewPointV2(`abc`, NewKVs(map[string]any{ 325 "f1": 123, 326 "f2": uint64(321), 327 "f3": 3.14, 328 "f4": false, 329 "f5": []byte("hello"), 330 }).AddTag("t1", "v1").AddTag("t2", "v1"), WithDisabledKeys(NewTagKey(`t2`, ""))) 331 332 t.Logf("%s", pt.Pretty()) 333 }) 334 } 335 336 func TestPointString(t *T.T) { 337 cases := []struct { 338 name string 339 pt *Point 340 expect string 341 }{ 342 { 343 name: "normal-lppt", 344 pt: func() *Point { 345 pt, err := NewPoint("abc", 346 map[string]string{"tag1": "v1"}, 347 map[string]interface{}{ 348 "f1": 123, "f2": true, 349 }, 350 WithTime(time.Unix(0, 123))) 351 assert.NoError(t, err) 352 return pt 353 }(), 354 expect: `abc,tag1=v1 f1=123i,f2=true 123`, 355 }, 356 357 { 358 name: "normal-pbpt", 359 pt: func() *Point { 360 pt, err := NewPoint("abc", 361 map[string]string{ 362 "tag1": "v1", 363 "tag2": "v2", 364 "xtag": "vx", 365 }, map[string]interface{}{ 366 "f1": 123, 367 "f2": true, 368 "f3": uint64(123), 369 "f4": 123.4, 370 "f5": "foobar", 371 "f6": []byte("hello, 屈原"), 372 "f7": struct{ a int }{a: 123}, 373 }, 374 WithTime(time.Unix(0, 123)), WithEncoding(Protobuf)) 375 assert.NoError(t, err) 376 return pt 377 }(), 378 }, 379 } 380 381 for _, tc := range cases { 382 t.Run(tc.name, func(t *T.T) { 383 if tc.pt.HasFlag(Ppb) { 384 j, err := json.Marshal(tc.pt) // json protobuf point 385 assert.NoError(t, err) 386 387 var marshalPt Point 388 assert.NoError(t, json.Unmarshal(j, &marshalPt)) 389 390 t.Logf("pb.JSON string: %s", j) 391 392 assert.True(t, tc.pt.Equal(&marshalPt)) 393 394 t.Logf("pb.String: %s", marshalPt.Pretty()) 395 } else { 396 assert.Equal(t, tc.expect, tc.pt.LineProto()) 397 } 398 }) 399 } 400 } 401 402 func TestInfluxTags(t *T.T) { 403 t.Run("get-tags", func(t *T.T) { 404 pt := NewPointV2(`abc`, NewKVs(map[string]any{"f1": 123}).AddTag(`t1`, `v1`)) 405 tags := pt.InfluxTags() 406 assert.Equal(t, 407 influxm.Tags{influxm.Tag{Key: []byte("t1"), Value: []byte("v1")}}, 408 tags) 409 410 t.Log(pt.Pretty()) 411 }) 412 413 t.Run("no-tags", func(t *T.T) { 414 pt := NewPointV2(`abc`, 415 NewKVs(map[string]any{"v1": 123}). 416 AddTag(`v1`, `foo`)) // tag key exist, skipped 417 418 tags := pt.InfluxTags() 419 assert.Equal(t, 0, len(tags), "pt: %s", pt.Pretty()) 420 421 t.Log(pt.Pretty()) 422 }) 423 } 424 425 func TestPointLineProtocol(t *T.T) { 426 EnableDictField = true 427 EnableMixedArrayField = true 428 defer func() { 429 EnableDictField = false 430 EnableMixedArrayField = false 431 }() 432 433 cases := []struct { 434 name string 435 pt *Point 436 437 prec Precision 438 expect string 439 }{ 440 { 441 name: "lp-point-ns-prec", 442 prec: PrecNS, 443 pt: func() *Point { 444 pt, err := NewPoint("abc", nil, map[string]interface{}{"f1": 1}, 445 append(DefaultLoggingOptions(), WithTime(time.Unix(0, 123)))...) 446 447 assert.NoError(t, err) 448 449 t.Logf("pt: %s", pt.Pretty()) 450 return pt 451 }(), 452 expect: `abc f1=1i,status="unknown" 123`, 453 }, 454 455 { 456 name: "lp-point-ms-prec", 457 prec: PrecMS, 458 pt: func() *Point { 459 pt, err := NewPoint("abc", nil, map[string]interface{}{"f1": 1}, 460 append(DefaultLoggingOptions(), WithTime(time.Unix(0, 12345678)))...) 461 462 assert.NoError(t, err) 463 return pt 464 }(), 465 expect: `abc f1=1i,status="unknown" 12`, 466 }, 467 468 { 469 name: "lp-point-us-prec", 470 prec: PrecUS, // only accept u 471 pt: func() *Point { 472 pt, err := NewPoint("abc", nil, map[string]interface{}{"f1": 1}, 473 append(DefaultLoggingOptions(), WithTime(time.Unix(0, 12345678)))...) 474 475 assert.NoError(t, err) 476 return pt 477 }(), 478 expect: `abc f1=1i,status="unknown" 12345`, 479 }, 480 481 { 482 name: "lp-point-ns-prec", 483 prec: PrecNS, // only accept u 484 pt: func() *Point { 485 pt, err := NewPoint("abc", nil, map[string]interface{}{"f1": 1}, 486 append(DefaultLoggingOptions(), WithTime(time.Unix(0, 12345678)))...) 487 assert.NoError(t, err) 488 return pt 489 }(), 490 expect: `abc f1=1i,status="unknown" 12345678`, 491 }, 492 493 { 494 name: "lp-point-invalid-prec", 495 prec: -1, 496 pt: func() *Point { 497 pt, err := NewPoint("abc", nil, map[string]interface{}{"f1": 1}, 498 append(DefaultLoggingOptions(), WithTime(time.Unix(0, 12345678)))...) 499 assert.NoError(t, err) 500 return pt 501 }(), 502 expect: `abc f1=1i,status="unknown" 12345678`, 503 }, 504 505 { 506 name: "lp-point-second-prec", 507 prec: PrecS, 508 pt: func() *Point { 509 pt, err := NewPoint("abc", nil, map[string]interface{}{"f1": 1}, 510 append(DefaultLoggingOptions(), WithTime(time.Unix(1, 123456789)))...) 511 assert.NoError(t, err) 512 return pt 513 }(), 514 expect: `abc f1=1i,status="unknown" 1`, 515 }, 516 517 { 518 name: "lp-point-minute-prec", 519 prec: PrecM, 520 pt: func() *Point { 521 pt, err := NewPoint("abc", nil, map[string]interface{}{"f1": 1}, 522 append(DefaultLoggingOptions(), WithTime(time.Unix(120, 123456789)))...) 523 assert.NoError(t, err) 524 return pt 525 }(), 526 expect: `abc f1=1i,status="unknown" 2`, 527 }, 528 529 { 530 name: "lp-point-hour-prec", 531 prec: PrecH, 532 pt: func() *Point { 533 pt, err := NewPoint("abc", nil, map[string]interface{}{"f1": 1}, 534 append(DefaultLoggingOptions(), WithTime(time.Unix(7199, 123456789)))...) 535 assert.NoError(t, err) 536 return pt 537 }(), 538 expect: `abc f1=1i,status="unknown" 1`, // 7199 not reached 2hour 539 }, 540 541 // pb point 542 { 543 name: "pb-point", 544 prec: PrecNS, 545 pt: func() *Point { 546 pt, err := NewPoint("abc", 547 nil, 548 map[string]interface{}{"f1": int64(1)}, 549 WithTime(time.Unix(0, 123)), WithEncoding(Protobuf)) 550 551 assert.NoError(t, err) 552 553 t.Logf("pb point: %s", pt.Pretty()) 554 return pt 555 }(), 556 expect: `abc f1=1i 123`, 557 }, 558 559 { 560 name: "pb-point-with-binary-data", 561 prec: PrecNS, 562 pt: func() *Point { 563 pt, err := NewPoint("abc", 564 map[string]string{"t1": "v1"}, 565 map[string]interface{}{"f1": []byte("abc123")}, 566 WithTime(time.Unix(0, 1)), WithEncoding(Protobuf)) 567 568 assert.NoError(t, err) 569 570 t.Logf("pt: %s", pt.Pretty()) 571 572 return pt 573 }(), 574 expect: `abc,t1=v1 f1="YWJjMTIz"b 1`, 575 }, 576 577 { 578 name: `string-field-with-newline`, 579 prec: PrecNS, 580 pt: NewPointV2(`abc`, append(NewTags(map[string]string{"tag1": "v1"}), 581 NewKVs(map[string]any{"f1": `message 582 with 583 new 584 line`})...), WithTime(time.Unix(0, 123))), 585 expect: `abc,tag1=v1 f1="message 586 with 587 new 588 line" 123`, 589 }, 590 591 { 592 name: "lp-point-with-array-field", 593 prec: PrecNS, 594 pt: func() *Point { 595 var kvs KVs 596 kvs = kvs.Add("arr", 597 MustNewAnyArray(1, 3.14, 1.414, "hello"), 598 false, true) 599 pt := NewPointV2("abc", kvs, WithTime(time.Unix(0, 123))) 600 601 return pt 602 }(), 603 expect: `abc arr=[1i,3.14,1.414,"hello"] 123`, 604 }, 605 } 606 607 for _, tc := range cases { 608 t.Run(tc.name, func(t *T.T) { 609 t.Logf("pt: %s", tc.pt.Pretty()) 610 611 assert.Equal(t, tc.expect, tc.pt.LineProto(tc.prec)) 612 613 // _, err := influxm.ParsePointsWithPrecision([]byte(tc.expect), time.Now(), "n") 614 }) 615 } 616 } 617 618 func TestPBJSON(t *T.T) { 619 t.Run("pbjson", func(t *T.T) { 620 EnableDictField = true 621 EnableMixedArrayField = true 622 defer func() { 623 EnableDictField = false 624 EnableMixedArrayField = false 625 }() 626 627 pt := NewPointV2(`abc`, NewKVs(map[string]any{ 628 "i": 1234567890, 629 "u": uint64(1234567890), 630 "f": 3.14, 631 "s": "hello", 632 "bool": false, 633 "d": []byte("hello world"), 634 "int-arr": MustNewIntArray([]int{1, 2, 3}...), 635 "mixed-arr": MustNewAnyArray(1, 2.0, "hello", false), 636 })) 637 638 kvs := KVs(pt.pt.Fields) 639 kvs = kvs.MustAddTag(`t1`, `v1`). 640 MustAddKV(NewKV(`f2`, 3.14, WithKVUnit("kb"), WithKVType(COUNT))) 641 pt.pt.Fields = kvs 642 643 j, _ := pt.PBJson() 644 t.Logf("raw: %s", string(j)) 645 646 jpt := MustFromPBJson(j) 647 648 assert.True(t, pt.Equal(jpt)) 649 650 j, _ = pt.PBJsonPretty() 651 t.Logf("pretty:\n%s", string(j)) 652 653 jpt = MustFromPBJson(j) 654 assert.True(t, pt.Equal(jpt)) 655 }) 656 } 657 658 func TestPointPB(t *T.T) { 659 t.Run(`valid-types`, func(t *T.T) { 660 pt := NewPointV2(`abc`, NewKVs(map[string]any{ 661 "f1": uint64(123), 662 "f2": uint64(math.MaxUint64), 663 "f3": int64(123), 664 "f4": false, 665 "f5": true, 666 "f6": "hello", 667 "f7": []byte("world"), 668 "f8": struct{}{}, // user-defined 669 "f9": nil, 670 "f10": 3.14, 671 }), WithTime(time.Unix(0, 123)), WithKeySorted(true)) 672 673 kvs := KVs(pt.pt.Fields) 674 sort.Sort(kvs) 675 pt.pt.Fields = kvs 676 677 j := fmt.Sprintf(`{ 678 "name": "%s", 679 "fields": [ 680 { "key": "%s", "u": "123" }, 681 { "key": "%s", "u": "%d" }, 682 { "key": "%s", "i": "123" }, 683 { "key": "%s", "b": false }, 684 { "key": "%s", "b": true }, 685 { "key": "%s", "s": "%s" }, 686 { "key": "%s", "d": "%s" }, 687 { "key": "%s" }, 688 { "key": "%s" }, 689 { "key": "%s", "f": "%f" } 690 ], "time":"123"}`, 691 `abc`, 692 `f1`, 693 `f2`, uint64(math.MaxUint64), 694 `f3`, 695 `f4`, 696 `f5`, 697 `f6`, `hello`, 698 `f7`, b64([]byte(`world`)), 699 `f8`, 700 `f9`, 701 `f10`, float64(3.14)) 702 703 expect := MustFromPBJson([]byte(j)) 704 kvs = KVs(expect.pt.Fields) 705 sort.Sort(kvs) 706 expect.pt.Fields = kvs 707 708 cfg := GetCfg() 709 defer PutCfg(cfg) 710 chk := checker{cfg: cfg} 711 expect = chk.check(expect) 712 expect.SetFlag(Pcheck) 713 expect.pt.Warns = chk.warns 714 715 assert.Equal(t, expect.Pretty(), pt.Pretty(), "got\n%s\nexpect\n%s", expect.Pretty(), pt.Pretty()) 716 717 t.Logf("pt: %s", pt.Pretty()) 718 }) 719 } 720 721 func TestLPPoint(t *T.T) { 722 t.Run(`uint`, func(t *T.T) { 723 pt := NewPointV2(`abc`, NewKVs(map[string]any{"f1": uint64(123)}), WithTime(time.Unix(0, 123))) 724 assert.Equal(t, `abc f1=123u 123`, pt.MustLPPoint().String()) 725 726 // max-int64 is ok 727 pt = NewPointV2(`abc`, NewKVs(map[string]any{"f1": uint64(math.MaxInt64)}), WithTime(time.Unix(0, 123))) 728 assert.Equal(t, fmt.Sprintf(`abc f1=%du 123`, math.MaxInt64), pt.MustLPPoint().String()) 729 730 // max-int64 + 1 not ok 731 pt = NewPointV2(`abc`, NewKVs(map[string]any{ 732 "f1": uint64(math.MaxInt64 + 1), 733 "f2": "foo", 734 }), WithTime(time.Unix(0, 123))) 735 assert.Equal(t, `abc f1=9223372036854775808u,f2="foo" 123`, pt.MustLPPoint().String()) 736 737 t.Logf("lp: %s", pt.MustLPPoint().String()) 738 }) 739 740 t.Run(`nil`, func(t *T.T) { 741 // max-int64 + 1 not ok 742 pt := NewPointV2(`abc`, NewKVs(map[string]any{"f1": 123, "f2": nil}), WithTime(time.Unix(0, 123))) 743 assert.Equal(t, `abc f1=123i 123`, pt.MustLPPoint().String()) 744 745 t.Logf("lp: %s", pt.MustLPPoint().String()) 746 }) 747 748 t.Run(`struct`, func(t *T.T) { 749 // max-int64 + 1 not ok 750 pt := NewPointV2(`abc`, NewKVs(map[string]any{"f1": 123, "f2": struct{}{}}), WithTime(time.Unix(0, 123))) 751 assert.Equal(t, `abc f1=123i 123`, pt.MustLPPoint().String()) 752 753 t.Logf("lp: %s", pt.MustLPPoint().String()) 754 }) 755 } 756 757 func TestFields(t *T.T) { 758 cases := []struct { 759 name string 760 pt *Point 761 expect map[string]interface{} 762 }{ 763 { 764 name: "basic-lp-point", 765 766 pt: func() *Point { 767 x, err := NewPoint("abc", nil, 768 map[string]interface{}{ 769 "i8": int8(1), 770 "u8": uint8(1), 771 "i16": int16(1), 772 "u16": uint16(1), 773 "i32": int32(1), 774 "u32": uint32(1), 775 "i64": int64(1), 776 "u64": uint64(1), 777 "f32": float32(1.0), 778 "f64": float64(1.0), 779 "bool_1": false, 780 "bool_2": true, 781 "str": "hello", 782 "data": []byte("abc123"), 783 "nil": nil, 784 "udf": struct{}{}, 785 }) 786 assert.NoError(t, err) 787 return x 788 }(), 789 790 expect: map[string]interface{}{ 791 "i8": int64(1), 792 "u8": uint64(1), 793 "i16": int64(1), 794 "u16": uint64(1), 795 "i32": int64(1), 796 "u32": uint64(1), 797 "i64": int64(1), 798 "u64": uint64(1), 799 "f32": float32(1.0), 800 "f64": float64(1.0), 801 "bool_1": false, 802 "nil": nil, 803 "udf": nil, 804 "data": []byte("abc123"), 805 "bool_2": true, 806 "str": "hello", 807 }, 808 }, 809 810 { 811 name: "basic-pb-point", 812 813 pt: func() *Point { 814 x, err := NewPoint("abc", nil, 815 map[string]interface{}{ 816 "bool_1": false, 817 "bool_2": true, 818 "data": []byte("abc123"), 819 "f32": float32(1.0), 820 "f64": float64(1.0), 821 "i16": int16(1), 822 "i32": int32(1), 823 "i64": int64(1), 824 "i8": int8(1), 825 "nil": nil, 826 "str": "hello", 827 "u16": uint16(1), 828 "u32": uint32(1), 829 "u64": uint64(1), 830 "u8": uint8(1), 831 "udf": struct{}{}, 832 }, WithEncoding(Protobuf)) 833 assert.NoError(t, err) 834 return x 835 }(), 836 837 expect: map[string]interface{}{ 838 // "any": someAny, 839 "bool_1": false, 840 "bool_2": true, 841 "data": []byte("abc123"), 842 "f32": float64(1.0), 843 "f64": float64(1.0), 844 "i16": int64(1), 845 "i32": int64(1), 846 "i64": int64(1), 847 "i8": int64(1), 848 "str": "hello", 849 "u16": uint64(1), 850 "u32": uint64(1), 851 "u64": uint64(1), 852 "u8": uint64(1), 853 "nil": nil, 854 "udf": nil, 855 }, 856 }, 857 } 858 859 eopt := eqopt{} 860 for _, tc := range cases { 861 t.Run(tc.name, func(t *T.T) { 862 fs := tc.pt.Fields() 863 assert.True(t, len(fs) > 0) 864 865 eq, reason := eopt.kvsEq(fs, NewKVs(tc.expect)) 866 assert.True(t, eq, "not equal, reason: %s, pt: %s", reason, tc.pt.Pretty()) 867 868 assert.NotNil(t, tc.pt.PBPoint()) 869 assert.NotNil(t, tc.pt.MustLPPoint()) 870 871 eq, reason = eopt.kvsEq(fs, NewKVs(tc.expect)) 872 assert.True(t, eq, "not equal, reason: %s, pt: %s", reason, KVs(tc.pt.pt.Fields).Pretty()) 873 }) 874 } 875 } 876 877 func FuzzPBPointString(f *T.F) { 878 cases := []struct { 879 measurement string 880 tagk string 881 tagv string 882 fieldk string 883 884 i64 int64 885 u64 uint64 886 str string 887 b bool 888 f float64 889 d []byte 890 time int64 891 }{ 892 { 893 measurement: "fuzz", 894 tagk: "tag", 895 tagv: "tval", 896 fieldk: "field", 897 898 i64: int64(1), 899 u64: uint64(123), 900 str: "hello world", 901 b: false, 902 f: 3.14, 903 d: []byte("hello, world"), 904 time: 123, 905 }, 906 } 907 908 for _, tc := range cases { 909 f.Add( 910 tc.measurement, tc.tagk, tc.tagv, tc.fieldk, 911 tc.i64, tc.u64, tc.str, tc.b, tc.f, tc.d, tc.time) 912 } 913 914 f.Fuzz(func(t *T.T, 915 measurement string, 916 tagk string, 917 tagv string, 918 fieldk string, 919 920 i64 int64, 921 u64 uint64, 922 str string, 923 b bool, 924 f float64, 925 d []byte, 926 ts int64, 927 ) { 928 pt, err := NewPoint(measurement, 929 map[string]string{tagk: tagv}, 930 map[string]interface{}{ 931 "i64": i64, 932 "u64": u64, 933 "str": str, 934 "b": b, 935 }, WithTime(time.Unix(0, 123)), WithDotInKey(true), WithEncoding(Protobuf)) 936 937 assert.NoError(t, err) 938 if pt != nil { 939 t.Logf(pt.Pretty()) 940 } 941 }) 942 } 943 944 func TestKey(t *T.T) { 945 cases := []struct { 946 name, key string 947 pt *Point 948 expect any 949 }{ 950 { 951 "basic", 952 `f1`, 953 NewPointV2("abc", NewKVs(map[string]any{"f1": 123})), 954 int64(123), 955 }, 956 957 { 958 "query-tag-no-field", 959 `t1`, 960 NewPointV2("abc", nil, WithExtraTags(map[string]string{"t1": "v1"})), 961 "v1", 962 }, 963 964 { 965 "no-field-query-field-not-found", 966 `f1`, 967 NewPointV2("abc", nil, nil), 968 nil, 969 }, 970 971 { 972 "query-field-not-found", 973 `f1`, 974 NewPointV2("abc", NewKVs(map[string]any{"f2": 123})), 975 nil, 976 }, 977 978 { 979 "query-f32", 980 `f1`, 981 NewPointV2("abc", NewKVs(map[string]any{"f1": float32(3.0)})), 982 float64(3.0), 983 }, 984 985 { 986 "query-f64", 987 `f1`, 988 NewPointV2("abc", NewKVs(map[string]any{"f1": float64(3.14)})), 989 float64(3.14), 990 }, 991 992 { 993 "query-u64", 994 `f1`, 995 NewPointV2("abc", NewKVs(map[string]any{"f1": uint64(3)})), 996 uint64(3), 997 }, 998 999 { 1000 "query-data", 1001 `f1`, 1002 NewPointV2("abc", NewKVs(map[string]any{"f1": []byte("hello")}), WithEncoding(Protobuf)), 1003 []byte("hello"), 1004 }, 1005 1006 { 1007 "query-bool", 1008 `f1`, 1009 NewPointV2("abc", NewKVs(map[string]any{"f1": false})), 1010 false, 1011 }, 1012 } 1013 1014 for _, tc := range cases { 1015 t.Run(tc.name, func(t *T.T) { 1016 t.Logf("%s", tc.pt.Pretty()) 1017 assert.Equal(t, tc.expect, tc.pt.Get(tc.key)) 1018 }) 1019 } 1020 } 1021 1022 func TestPointKeys(t *T.T) { 1023 t.Run("point-keys", func(t *T.T) { 1024 p := NewPointV2("abc", 1025 NewKVs(map[string]any{"f1": "123", "f2": false, "f3": float32(3.14)}), 1026 WithExtraTags(map[string]string{"t1": "t2"})) 1027 keys := p.Keys() 1028 1029 t.Logf("keys:\n%s", keys.Pretty()) 1030 1031 hash1 := keys.Hash() 1032 1033 keys.Add(NewKey(`hello`, D)) 1034 1035 hash2 := keys.Hash() 1036 assert.NotEqual(t, hash1, hash2, "keys:\n%s", keys.Pretty()) 1037 1038 keys.Del(NewKey(`hello`, D)) 1039 1040 hash3 := keys.Hash() 1041 assert.Equal(t, hash1, hash3, "keys: \n%s", keys.Pretty()) 1042 1043 keys.Del(NewKey(`t1`, D)) 1044 1045 hash4 := keys.Hash() 1046 assert.NotEqual(t, hash3, hash4, "keys: \n%s", keys.Pretty()) 1047 1048 t.Logf("keys:\n%s", keys.Pretty()) 1049 }) 1050 1051 t.Run("exist", func(t *T.T) { 1052 p := NewPointV2("abc", NewKVs(map[string]any{"x1": "123"})) 1053 keys := p.Keys() 1054 1055 assert.True(t, keys.Has(NewKey(`x1`, D)), "keys:\n%s", keys.Pretty()) 1056 }) 1057 1058 t.Run("add", func(t *T.T) { 1059 p := NewPointV2("abc", NewKVs(map[string]any{"f1": "123"})) 1060 keys := p.Keys() 1061 1062 h1 := keys.Hash() 1063 1064 // add exist key 1065 keys.Add(NewKey(`f1`, D)) 1066 1067 h2 := keys.Hash() 1068 assert.Equal(t, h1, h2, "keys:\n%s", keys.Pretty()) 1069 }) 1070 1071 t.Run("no-kvs", func(t *T.T) { 1072 p := NewPointV2("abc", nil) 1073 keys := p.Keys() 1074 1075 t.Logf("keys:\n%s", keys.Pretty()) 1076 1077 hash1 := keys.Hash() 1078 1079 keys.Add(NewKey("hello", D)) 1080 1081 hash2 := keys.Hash() 1082 assert.NotEqual(t, hash1, hash2, "keys:\n%s", keys.Pretty()) 1083 1084 keys.Del(NewKey("hello", D)) 1085 1086 hash3 := keys.Hash() 1087 assert.Equal(t, hash1, hash3, "keys: \n%s", keys.Pretty()) 1088 1089 // delete not-exist-key 1090 keys.Del(NewKey("t1", D)) 1091 hash4 := keys.Hash() 1092 assert.Equal(t, hash3, hash4, "keys: \n%s", keys.Pretty()) 1093 assert.True(t, keys.hashed) 1094 1095 t.Logf("keys:\n%s", keys.Pretty()) 1096 }) 1097 } 1098 1099 func TestPointAddKey(t *T.T) { 1100 t.Run("add", func(t *T.T) { 1101 pt := NewPointV2("abc", NewKVs(map[string]any{"f1": 123})) 1102 pt.Add("new-key", "hello") 1103 kvs := KVs(pt.pt.Fields) 1104 assert.True(t, kvs.Has(`new-key`), "fields: %s", kvs.Pretty()) 1105 }) 1106 } 1107 1108 func BenchmarkPointSize(b *T.B) { 1109 b.Run(`basic-pt-size`, func(b *T.B) { 1110 r := NewRander(WithRandText(3)) 1111 pts := r.Rand(1) 1112 1113 for i := 0; i < b.N; i++ { 1114 pts[0].Size() 1115 } 1116 }) 1117 1118 b.Run(`basic-pb-size`, func(b *T.B) { 1119 r := NewRander(WithRandText(3)) 1120 pts := r.Rand(1) 1121 1122 for i := 0; i < b.N; i++ { 1123 pts[0].PBSize() 1124 } 1125 }) 1126 } 1127 1128 func TestPayloadSize(t *T.T) { 1129 t.Run("sizes", func(t *T.T) { 1130 // empty point 1131 pt := NewPointV2(`abc`, nil) 1132 t.Logf("pt size: %d, pb size: %d, lp size: %d", pt.Size(), pt.PBSize(), pt.LPSize()) 1133 1134 // basic point 1135 pt = NewPointV2(`abc`, NewKVs(map[string]any{ 1136 "f1": 123, 1137 "f2": uint64(123), 1138 "f3": false, 1139 "f4": 3.14, 1140 "f5": []byte(`hello`), 1141 })) 1142 t.Logf("pt size: %d, pb size: %d, lp size: %d", pt.Size(), pt.PBSize(), pt.LPSize()) 1143 1144 // large numbers 1145 pt = NewPointV2(`abc`, NewKVs(map[string]any{ 1146 "f1": math.MaxInt64, 1147 "f3": false, 1148 "f5": []byte(strings.Repeat(`hello`, 100)), 1149 "f4": float64(math.MaxFloat64), 1150 "f6": float32(math.MaxFloat32), 1151 "f7": 3.14, 1152 "f9": 3.14159265359, 1153 })) 1154 t.Logf("pt size: %d, pb size: %d, lp size: %d", pt.Size(), pt.PBSize(), pt.LPSize()) 1155 1156 // with kv unit/type 1157 pt = NewPointV2(`abc`, NewKVs(nil). 1158 MustAddKV(NewKV(`f1`, 123, WithKVUnit("MB"), WithKVType(COUNT))). 1159 MustAddTag(`t1`, `v1`)) 1160 t.Logf("pt size: %d, pb size: %d, lp size: %d", pt.Size(), pt.PBSize(), pt.LPSize()) 1161 1162 // rand point 1163 r := NewRander(WithRandText(3)) 1164 pts := r.Rand(10) 1165 for idx, pt := range pts { 1166 t.Logf("[%d] pt size: % 5d, pb size: % 5d, lp size: % 5d", idx, pt.Size(), pt.PBSize(), pt.LPSize()) 1167 } 1168 }) 1169 1170 t.Run("size-of-anypb", func(t *T.T) { 1171 pt := NewPointV2("some", nil) 1172 1173 pt.MustAdd("arr", []string{ 1174 cliutils.CreateRandomString(100), 1175 cliutils.CreateRandomString(100), 1176 }) 1177 t.Logf("s-arr pt size: %d, pbsize: %d\npt: %s", pt.Size(), pt.PBSize(), pt.Pretty()) 1178 1179 pt = NewPointV2("some", nil) 1180 pt.MustAdd("arr", []int{(1), (1)}) 1181 t.Logf("i-arr pt size: %d, pbsize: %d\npt: %s", pt.Size(), pt.PBSize(), pt.Pretty()) 1182 1183 pt = NewPointV2("some", nil) 1184 pt.MustAdd("arr", []bool{false, true}) 1185 t.Logf("b-arr pt size: %d, pbsize: %d\npt: %s", pt.Size(), pt.PBSize(), pt.Pretty()) 1186 }) 1187 1188 t.Run("size-of-large-string-point", func(t *T.T) { 1189 pt := NewPointV2("some", nil) 1190 1191 _32mstr := cliutils.CreateRandomString(1024 * 1024 * 32) 1192 pt.MustAdd("large-string", _32mstr) 1193 1194 enc := GetEncoder(WithEncEncoding(Protobuf)) 1195 defer PutEncoder(enc) 1196 1197 datas, err := enc.Encode([]*Point{pt}) 1198 assert.NoError(t, err) 1199 1200 gz := cliutils.MustGZip(datas[0]) 1201 gz32mb := cliutils.MustGZip([]byte(_32mstr)) 1202 1203 t.Logf("pt size: %d, pbsize: %d/gz: %d, gzraw: %d", pt.Size(), pt.PBSize(), len(gz), len(gz32mb)) 1204 }) 1205 }