github.com/GuanceCloud/cliutils@v1.1.21/point/decode_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 "bytes" 10 "fmt" 11 "strings" 12 T "testing" 13 "time" 14 15 "github.com/stretchr/testify/assert" 16 "github.com/stretchr/testify/require" 17 ) 18 19 func TestLPFieldArray(t *T.T) { 20 t.Run(`decode-lp-array-field`, func(t *T.T) { 21 lp := []byte(`a,t1=v1 arr=["s1","s2"] 123`) 22 23 dec := GetDecoder(WithDecEncoding(LineProtocol)) 24 _, err := dec.Decode(lp) 25 assert.NoErrorf(t, err, "should got no error: %s", err) 26 }) 27 28 t.Run(`encode-lp-array-field`, func(t *T.T) { 29 pt := emptyPoint() 30 31 pt.SetName("abc") 32 pt.SetTime(time.Unix(0, 123)) 33 34 pt.AddKVs(NewKV("i-arr", []int{1, 2, 3})) 35 pt.AddKVs(NewKV("s-arr", []string{"hello", "world"})) 36 pt.AddKVs(NewKV("f-arr", []float64{3.14, 6.18})) 37 pt.AddKVs(NewKV("b-arr", []bool{false, true})) 38 39 t.Logf("lp: %s", pt.LineProto()) 40 }) 41 42 t.Run(`encode-json-array-field`, func(t *T.T) { 43 pt := emptyPoint() 44 45 pt.SetName("abc") 46 pt.SetTime(time.Unix(0, 123)) 47 48 pt.AddKVs(NewKV("i-arr", []int{1, 2, 3})) 49 pt.AddKVs(NewKV("s-arr", []string{"hello", "world"})) 50 pt.AddKVs(NewKV("f-arr", []float64{3.14, 6.18})) 51 pt.AddKVs(NewKV("b-arr", []bool{false, true})) 52 53 enc := GetEncoder(WithEncEncoding(JSON)) 54 defer PutEncoder(enc) 55 56 arr, err := enc.Encode([]*Point{pt}) 57 assert.NoError(t, err) 58 59 t.Logf("lp json: %s", string(arr[0])) 60 }) 61 62 t.Run(`decode-json-array-field`, func(t *T.T) { 63 j := `[{"measurement":"abc","fields":{"b-arr":[false,true],"f-arr":[3.14,6.18],"i-arr":[1,2,3],"s-arr":["hello","world"]},"time":123}]` 64 dec := GetDecoder(WithDecEncoding(JSON)) 65 defer PutDecoder(dec) 66 67 pts, err := dec.Decode([]byte(j)) 68 assert.NoError(t, err) 69 70 for _, pt := range pts { 71 t.Logf("json pt: %s", pt.LineProto()) 72 } 73 }) 74 } 75 76 func TestTimeRound(t *T.T) { 77 t.Run(`decode-time`, func(t *T.T) { 78 pt := NewPointV2("some", nil, WithTime(time.Now())) 79 enc := GetEncoder(WithEncEncoding(Protobuf)) 80 data, err := enc.Encode([]*Point{pt}) 81 assert.NoError(t, err) 82 83 dec := GetDecoder(WithDecEncoding(Protobuf)) 84 pts, err := dec.Decode(data[0]) 85 assert.NoError(t, err) 86 87 assert.Equal(t, pt.Pretty(), pts[0].Pretty()) 88 }) 89 } 90 91 func TestDynamicPrecision(t *T.T) { 92 pts := []*Point{ 93 func() *Point { 94 var kvs KVs 95 kvs = kvs.AddV2("f1", 123, true) 96 return NewPointV2("p1", kvs, WithTimestamp(1716536956)) 97 }(), 98 99 func() *Point { 100 var kvs KVs 101 kvs = kvs.AddV2("f1", 123, true) 102 return NewPointV2("p1", kvs, WithTimestamp(1716536956000)) 103 }(), 104 105 func() *Point { 106 var kvs KVs 107 kvs = kvs.AddV2("f1", 123, true) 108 return NewPointV2("p1", kvs, WithTimestamp(1716536956000000)) 109 }(), 110 111 func() *Point { 112 var kvs KVs 113 kvs = kvs.AddV2("f1", 123, true) 114 return NewPointV2("p1", kvs, WithTimestamp(1716536956000000000)) 115 }(), 116 } 117 118 cases := []struct { 119 name string 120 e Encoding 121 }{ 122 { 123 "line-protocol", 124 LineProtocol, 125 }, 126 127 //{ 128 // "json", 129 // JSON, 130 // }, 131 132 //{ 133 // "pbjson", 134 // PBJSON, 135 // }, 136 137 { 138 "pb", 139 Protobuf, 140 }, 141 } 142 143 for _, tc := range cases { 144 t.Run(tc.name, func(t *T.T) { 145 enc := GetEncoder(WithEncEncoding(tc.e)) 146 defer PutEncoder(enc) 147 148 enc.EncodeV2(pts) 149 buf := make([]byte, 1<<20) // large buffer 150 var ( 151 encBuf []byte 152 ok bool 153 ) 154 155 encBuf, ok = enc.Next(buf) // encode once we should get all the buffer 156 assert.True(t, ok, "enc last error: %s", enc.LastErr()) 157 158 dec := GetDecoder(WithDecEncoding(tc.e)) 159 defer PutDecoder(dec) 160 161 newPts, err := dec.Decode(encBuf, WithPrecision(PrecDyn)) 162 assert.NoError(t, err) 163 for _, pt := range newPts { 164 assert.Equal(t, int64(1716536956000000000), pt.pt.Time) 165 } 166 }) 167 } 168 } 169 170 func TestDecode(t *T.T) { 171 var fnCalled int 172 173 cases := []struct { 174 name string 175 data []byte 176 fn DecodeFn 177 fnErr bool 178 expectLP []string 179 180 opts []DecoderOption 181 ptsOpts []Option 182 183 fail bool 184 }{ 185 { 186 name: "decode-json", 187 data: []byte(`[ { "measurement": "abc", "tags": {"t1": "val1"}, "fields": {"f1": 123, "f2": 3.14}, "time":123} ]`), 188 expectLP: []string{ 189 `abc,t1=val1 f1=123,f2=3.14 123`, 190 }, 191 192 opts: []DecoderOption{WithDecEncoding(JSON)}, 193 }, 194 195 { 196 name: "decode-json-with-precision-s", 197 data: []byte(`[ { "measurement": "abc", "tags": {"t1": "val1"}, "fields": {"f1": 123, "f2": 3.14}, "time":123} ]`), 198 expectLP: []string{ 199 `abc,t1=val1 f1=123,f2=3.14 123000000000`, 200 }, 201 202 opts: []DecoderOption{WithDecEncoding(JSON)}, 203 ptsOpts: []Option{WithPrecision(PrecS)}, 204 }, 205 206 { 207 name: "decode-json-with-precision-ms", 208 data: []byte(`[ { "measurement": "abc", "tags": {"t1": "val1"}, "fields": {"f1": 123, "f2": 3.14}, "time":123} ]`), 209 expectLP: []string{ 210 `abc,t1=val1 f1=123,f2=3.14 123000000`, 211 }, 212 213 opts: []DecoderOption{WithDecEncoding(JSON)}, 214 ptsOpts: []Option{WithPrecision(PrecMS)}, 215 }, 216 217 { 218 name: "decode-json-with-precision-us", 219 data: []byte(`[ { "measurement": "abc", "tags": {"t1": "val1"}, "fields": {"f1": 123, "f2": 3.14}, "time":123} ]`), 220 expectLP: []string{ 221 `abc,t1=val1 f1=123,f2=3.14 123000`, 222 }, 223 224 opts: []DecoderOption{WithDecEncoding(JSON)}, 225 ptsOpts: []Option{WithPrecision(PrecUS)}, 226 }, 227 228 { 229 name: "decode-json-with-precision-m", 230 data: []byte(`[ { "measurement": "abc", "tags": {"t1": "val1"}, "fields": {"f1": 123, "f2": 3.14}, "time":123} ]`), 231 expectLP: []string{ 232 `abc,t1=val1 f1=123,f2=3.14 7380000000000`, 233 }, 234 235 opts: []DecoderOption{WithDecEncoding(JSON)}, 236 ptsOpts: []Option{WithPrecision(PrecM)}, 237 }, 238 239 { 240 name: "decode-json-with-precision-h", 241 data: []byte(`[ { "measurement": "abc", "tags": {"t1": "val1"}, "fields": {"f1": 123, "f2": 3.14}, "time":123} ]`), 242 expectLP: []string{ 243 `abc,t1=val1 f1=123,f2=3.14 442800000000000`, 244 }, 245 246 opts: []DecoderOption{WithDecEncoding(JSON)}, 247 ptsOpts: []Option{WithPrecision(PrecH)}, 248 }, 249 250 { 251 name: "decode-json-with-precision-x", 252 data: []byte(`[ { "measurement": "abc", "tags": {"t1": "val1"}, "fields": {"f1": 123, "f2": 3.14}, "time":123} ]`), 253 expectLP: []string{ 254 `abc,t1=val1 f1=123,f2=3.14 123`, 255 }, 256 257 opts: []DecoderOption{WithDecEncoding(JSON)}, 258 ptsOpts: []Option{WithPrecision(PrecW)}, 259 }, 260 261 { 262 name: "decode-metric-json", 263 data: []byte(`[ { "measurement": "abc", "tags": {"t1": "val1"}, "fields": {"f1": 123, "f2": 3.14, "f-str": "hello"}, "time":123} ]`), 264 expectLP: []string{ 265 `abc,t1=val1 f1=123,f2=3.14 123`, 266 }, 267 ptsOpts: DefaultMetricOptions(), 268 269 opts: []DecoderOption{WithDecEncoding(JSON)}, 270 }, 271 272 { 273 name: "lp", 274 data: []byte(`abc,tag1=v1,tag2=v2 f1=1i,f2=2 123`), 275 expectLP: []string{`abc,tag1=v1,tag2=v2 f1=1i,f2=2 123`}, 276 }, 277 278 { 279 fail: true, 280 name: "invalid-lp", 281 data: []byte(`abc,tag1=v1,tag2=v2 f1=1i,f2=2 123,`), 282 }, 283 284 { 285 name: "pb", 286 data: func() []byte { 287 pt, err := NewPoint("abc", 288 map[string]string{"tag1": "v1", "tag2": "v2"}, 289 map[string]interface{}{"f1": 1, "f2": 2.0}, 290 WithTime(time.Unix(0, 123))) 291 assert.NoError(t, err) 292 293 enc := GetEncoder(WithEncEncoding(Protobuf)) 294 defer PutEncoder(enc) 295 296 data, err := enc.Encode([]*Point{pt}) 297 assert.NoError(t, err) 298 assert.Equal(t, 1, len(data)) 299 return data[0] 300 }(), 301 302 opts: []DecoderOption{WithDecEncoding(Protobuf)}, 303 expectLP: []string{`abc,tag1=v1,tag2=v2 f1=1i,f2=2 123`}, 304 }, 305 306 { 307 fail: true, 308 name: "invalid-pb", 309 data: func() []byte { 310 pt, err := NewPoint("abc", 311 map[string]string{"tag1": "v1", "tag2": "v2"}, 312 map[string]interface{}{"f1": 1, "f2": 2.0}, 313 WithTime(time.Unix(0, 123))) 314 assert.NoError(t, err) 315 316 enc := GetEncoder(WithEncEncoding(Protobuf)) 317 defer PutEncoder(enc) 318 319 data, err := enc.Encode([]*Point{pt}) 320 assert.NoError(t, err) 321 assert.Equal(t, 1, len(data)) 322 return data[0][:len(data[0])/2] // half of pb 323 }(), 324 opts: []DecoderOption{WithDecEncoding(Protobuf)}, 325 }, 326 327 { 328 name: "pb-with-fn", 329 data: func() []byte { 330 pt, err := NewPoint("abc", 331 map[string]string{"tag1": "v1", "tag2": "v2"}, 332 map[string]interface{}{"f1": 1, "f2": 2.0}, 333 WithTime(time.Unix(0, 123))) 334 assert.NoError(t, err) 335 336 enc := GetEncoder(WithEncEncoding(Protobuf)) 337 defer PutEncoder(enc) 338 339 data, err := enc.Encode([]*Point{pt}) 340 assert.NoError(t, err) 341 assert.Equal(t, 1, len(data)) 342 return data[0] 343 }(), 344 345 fn: func(pts []*Point) error { 346 t.Logf("get %d point", len(pts)) 347 fnCalled++ 348 return nil 349 }, 350 351 opts: []DecoderOption{WithDecEncoding(Protobuf)}, 352 353 expectLP: []string{`abc,tag1=v1,tag2=v2 f1=1i,f2=2 123`}, 354 }, 355 356 { 357 name: "pb-with-fn-on-error", 358 data: func() []byte { 359 pt, err := NewPoint("abc", 360 map[string]string{"tag1": "v1", "tag2": "v2"}, 361 map[string]interface{}{"f1": 1, "f2": 2.0}, 362 WithTime(time.Unix(0, 123))) 363 assert.NoError(t, err) 364 365 enc := GetEncoder(WithEncEncoding(Protobuf)) 366 defer PutEncoder(enc) 367 368 data, err := enc.Encode([]*Point{pt}) 369 assert.NoError(t, err) 370 assert.Equal(t, 1, len(data)) 371 return data[0] 372 }(), 373 374 fn: func(pts []*Point) error { 375 fnCalled++ 376 return fmt.Errorf("mocked error") 377 }, 378 fnErr: true, 379 380 opts: []DecoderOption{WithDecEncoding(Protobuf)}, 381 expectLP: []string{`abc,tag1=v1,tag2=v2 f1=1i,f2=2 123`}, 382 }, 383 } 384 385 for _, tc := range cases { 386 t.Run(tc.name, func(t *T.T) { 387 fnCalled = 0 // reset 388 389 opts := []DecoderOption{WithDecFn(tc.fn)} 390 opts = append(opts, tc.opts...) 391 392 dec := GetDecoder(opts...) 393 defer PutDecoder(dec) 394 395 pts, err := dec.Decode(tc.data, tc.ptsOpts...) 396 if tc.fail { 397 assert.Error(t, err, "decode %s got pts: %+#v", tc.data, pts) 398 t.Logf("expect error: %s", err) 399 return 400 } 401 402 if tc.fnErr { 403 assert.Error(t, err) 404 } else { 405 assert.NoError(t, err) 406 } 407 408 assert.Equal(t, len(tc.expectLP), len(pts)) 409 for idx := range pts { 410 assert.Equal(t, tc.expectLP[idx], pts[idx].LineProto()) 411 412 t.Logf("point: %s", pts[idx].Pretty()) 413 } 414 415 if tc.fn != nil { 416 assert.Equal(t, 1, fnCalled) 417 } 418 }) 419 } 420 421 t.Run("decode-pb-json", func(t *T.T) { 422 j := `[ 423 {"name":"abc","fields":[{"key":"f1","i":"123"},{"key":"f2","b":false},{"key":"t1","s":"tv1","is_tag":true},{"key":"t2","s":"tv2","is_tag":true}],"time":"123"} 424 ]` 425 dec := GetDecoder(WithDecEncoding(JSON)) 426 defer PutDecoder(dec) 427 pts, err := dec.Decode([]byte(j), DefaultLoggingOptions()...) 428 require.NoError(t, err) 429 430 for _, pt := range pts { 431 assert.Equal(t, "unknown", pt.Get("status").(string)) 432 433 t.Logf("pt: %s", pt.Pretty()) 434 } 435 }) 436 437 t.Run("decode-bytes-array", func(t *T.T) { 438 var kvs KVs 439 kvs = kvs.Add("f_d_arr", MustNewAnyArray([]byte("hello"), []byte("world")), false, false) 440 pt := NewPointV2("m1", kvs) 441 enc := GetEncoder(WithEncEncoding(LineProtocol)) 442 defer PutEncoder(enc) 443 arr, err := enc.Encode([]*Point{pt}) 444 assert.NoError(t, err) 445 446 t.Logf("lp: %s", arr[0]) 447 448 dec := GetDecoder(WithDecEncoding(LineProtocol)) 449 defer PutDecoder(dec) 450 pts, err := dec.Decode(arr[0]) 451 assert.NoError(t, err) 452 for _, pt := range pts { 453 t.Logf("pt: %s", pt.Pretty()) 454 } 455 }) 456 457 t.Run("decode-with-check", func(t *T.T) { 458 var kvs KVs 459 kvs = kvs.AddV2("f.1", 1.23, false) // f.1 rename to f_1 and key conflict 460 kvs = kvs.AddV2("f_1", 321, false) 461 kvs = kvs.AddV2("tag.1", "some-val", false, WithKVTagSet(true)) 462 463 pt := NewPointV2("m1", kvs, WithTime(time.Unix(0, 123))) 464 465 enc := GetEncoder(WithEncEncoding(Protobuf)) 466 defer PutEncoder(enc) 467 enc.EncodeV2([]*Point{pt}) 468 469 src := make([]byte, 1<<20) 470 src, ok := enc.Next(src) 471 assert.True(t, ok) 472 473 dec := GetDecoder(WithDecEncoding(Protobuf)) 474 475 pts, err := dec.Decode(src, WithDotInKey(false)) // disable dot(.) in key 476 assert.NoError(t, err) 477 assert.Len(t, pts, 1) 478 479 assert.Equal(t, int64(321), pts[0].Get("f_1").(int64)) 480 assert.Equal(t, "some-val", pts[0].Get("tag_1").(string)) 481 482 assert.Len(t, pts[0].pt.Warns, 3) 483 484 t.Logf("pt: %s", pts[0].Pretty()) 485 t.Logf("pt: %s", pts[0].LineProto()) 486 defer PutDecoder(dec) 487 488 // test on easyproto 489 dec = GetDecoder(WithDecEncoding(Protobuf), WithDecEasyproto(true)) 490 pts, err = dec.Decode(src, WithDotInKey(false)) // disable dot(.) in key 491 assert.NoError(t, err) 492 assert.Len(t, pts, 1) 493 494 assert.Equal(t, int64(321), pts[0].Get("f_1").(int64)) 495 assert.Equal(t, "some-val", pts[0].Get("tag_1").(string)) 496 497 assert.Len(t, pts[0].pt.Warns, 3) 498 499 t.Logf("pt: %s", pts[0].Pretty()) 500 t.Logf("pt: %s", pts[0].LineProto()) 501 defer PutDecoder(dec) 502 }) 503 } 504 505 func BenchmarkDecode(b *T.B) { 506 r := NewRander(WithFixedTags(true), WithRandText(3)) 507 pts := r.Rand(1000) 508 509 b.Run("decode-lp", func(b *T.B) { 510 enc := GetEncoder() 511 defer PutEncoder(enc) 512 513 data, _ := enc.Encode(pts) 514 515 d := GetDecoder(WithDecEncoding(LineProtocol)) 516 defer PutDecoder(d) 517 518 b.ResetTimer() 519 for i := 0; i < b.N; i++ { 520 d.Decode(data[0]) 521 } 522 }) 523 524 b.Run("decode-pb", func(b *T.B) { 525 enc := GetEncoder(WithEncEncoding(Protobuf)) 526 defer PutEncoder(enc) 527 528 data, _ := enc.Encode(pts) 529 530 d := GetDecoder(WithDecEncoding(Protobuf)) 531 defer PutDecoder(d) 532 533 b.ResetTimer() 534 for i := 0; i < b.N; i++ { 535 d.Decode(data[0]) 536 } 537 }) 538 539 b.Run("decode-pb-no-check", func(b *T.B) { 540 enc := GetEncoder(WithEncEncoding(Protobuf)) 541 defer PutEncoder(enc) 542 543 data, _ := enc.Encode(pts) 544 545 d := GetDecoder(WithDecEncoding(Protobuf)) 546 defer PutDecoder(d) 547 548 b.ResetTimer() 549 for i := 0; i < b.N; i++ { 550 d.Decode(data[0], WithPrecheck(false)) 551 } 552 }) 553 554 b.Run("decode-pb-with-easyproto", func(b *T.B) { 555 enc := GetEncoder(WithEncEncoding(Protobuf)) 556 defer PutEncoder(enc) 557 558 data, _ := enc.Encode(pts) 559 560 d := GetDecoder(WithDecEncoding(Protobuf), WithDecEasyproto(true)) 561 defer PutDecoder(d) 562 563 b.ResetTimer() 564 for i := 0; i < b.N; i++ { 565 d.Decode(data[0]) 566 } 567 }) 568 569 b.Run("decode-pb-with-easyproto-no-check", func(b *T.B) { 570 enc := GetEncoder(WithEncEncoding(Protobuf)) 571 defer PutEncoder(enc) 572 573 data, _ := enc.Encode(pts) 574 575 d := GetDecoder(WithDecEncoding(Protobuf), WithDecEasyproto(true)) 576 defer PutDecoder(d) 577 578 b.ResetTimer() 579 for i := 0; i < b.N; i++ { 580 d.Decode(data[0], WithPrecheck(false)) 581 } 582 }) 583 584 b.Run("decode-json", func(b *T.B) { 585 enc := GetEncoder(WithEncEncoding(JSON)) 586 defer PutEncoder(enc) 587 588 data, _ := enc.Encode(pts) 589 590 d := GetDecoder(WithDecEncoding(JSON)) 591 defer PutDecoder(d) 592 593 b.ResetTimer() 594 for i := 0; i < b.N; i++ { 595 d.Decode(data[0]) 596 } 597 }) 598 599 b.Run("decode-json-no-check", func(b *T.B) { 600 enc := GetEncoder(WithEncEncoding(JSON)) 601 defer PutEncoder(enc) 602 603 data, _ := enc.Encode(pts) 604 605 d := GetDecoder(WithDecEncoding(JSON)) 606 defer PutDecoder(d) 607 608 b.ResetTimer() 609 for i := 0; i < b.N; i++ { 610 d.Decode(data[0], WithPrecheck(false)) 611 } 612 }) 613 614 b.Run("decode-pbjson-no-check", func(b *T.B) { 615 enc := GetEncoder(WithEncEncoding(JSON)) 616 defer PutEncoder(enc) 617 618 for _, pt := range pts { 619 pt.SetFlag(Ppb) 620 } 621 622 data, _ := enc.Encode(pts) 623 624 d := GetDecoder(WithDecEncoding(JSON)) 625 defer PutDecoder(d) 626 627 b.ResetTimer() 628 for i := 0; i < b.N; i++ { 629 d.Decode(data[0], WithPrecheck(false)) 630 } 631 }) 632 } 633 634 func BenchmarkBytes2String(b *T.B) { 635 repeat := 1 636 raw := []byte("xxxxxxxxxxxxxxxx") 637 638 bytesData := bytes.Repeat(raw, repeat) 639 strData := strings.Repeat(string(raw), repeat) 640 641 str := string(raw) 642 b.Logf("str: %p", &str) 643 b.Logf("bytes: %p", raw) 644 b.Logf("repeat: %p", &repeat) 645 646 b.Logf("str: %p", &strData) 647 b.Logf("bytes: %p", []byte(strData)) 648 649 { 650 y := string(bytesData) 651 _ = y 652 b.Errorf("y: %p, d: %p", &y, bytesData) 653 } 654 655 { 656 b.Errorf("y: %p, d: %p", []byte(strData), &strData) 657 } 658 659 b.Run("bytes2str", func(b *T.B) { 660 for i := 0; i < b.N; i++ { 661 y := string(raw) 662 _ = y 663 } 664 }) 665 666 b.Run("str2bytes", func(b *T.B) { 667 for i := 0; i < b.N; i++ { 668 y := []byte(strData) 669 _ = y 670 } 671 }) 672 }