github.com/GuanceCloud/cliutils@v1.1.21/lineproto/lp_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 lineproto
     7  
     8  import (
     9  	"fmt"
    10  	"runtime"
    11  	"strings"
    12  	"testing"
    13  	"time"
    14  
    15  	"github.com/GuanceCloud/cliutils"
    16  	"github.com/GuanceCloud/cliutils/testutil"
    17  	influxdb "github.com/influxdata/influxdb1-client/v2"
    18  )
    19  
    20  func TestUnsafeBytesToString(t *testing.T) {
    21  	runes := []byte{'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!'}
    22  	fmt.Printf("%p\n", runes)
    23  	s := unsafeBytesToString(runes)
    24  	runes = []byte{'g', 'o', 'l', 'a', 'n', 'g'}
    25  	fmt.Printf("%p\n", runes)
    26  	runtime.GC()
    27  	testutil.Equals(t, s, "hello world!")
    28  }
    29  
    30  func TestInterfaceToValue(t *testing.T) {
    31  	ints := []interface{}{
    32  		-5,
    33  		int8(-5),
    34  		int16(-5),
    35  		int32(-5),
    36  		int64(-5),
    37  
    38  		uint(5),
    39  		uint8(5),
    40  		uint16(5),
    41  		uint32(5),
    42  		uint64(5),
    43  
    44  		float32(3.14),
    45  		3.14,
    46  
    47  		true,
    48  		"hello world",
    49  		[]byte{'f', 'o', 'o'},
    50  
    51  		[]string{"hello", "world"},
    52  		map[string]int{"foo": 333333, "bar": 44444},
    53  
    54  		struct {
    55  			Name string
    56  			Age  int
    57  		}{"foobar", 16},
    58  	}
    59  
    60  	for _, i := range ints {
    61  		v, ok := InterfaceToValue(i)
    62  		if !ok {
    63  			t.Errorf("can not new value from interface: %T, %v", i, i)
    64  		}
    65  		t.Logf("%T, %v -> %v", i, i, v)
    66  	}
    67  }
    68  
    69  func TestPointString(t *testing.T) {
    70  	tags := map[string]string{
    71  		"t1": cliutils.CreateRandomString(100),
    72  		"t2": cliutils.CreateRandomString(100),
    73  	}
    74  	fields := map[string]interface{}{
    75  		"f1": int64(1024),
    76  		"f2": 1024.2048,
    77  		"f3": cliutils.CreateRandomString(128),
    78  	}
    79  
    80  	pt, _ := NewPoint("foobar", tags, fields, time.Now())
    81  	line, err := pt.String()
    82  	if err != nil {
    83  		t.Fatal(err)
    84  	}
    85  	t.Logf("[%s]\n", line)
    86  }
    87  
    88  func TestParse(t *testing.T) {
    89  	lines := `
    90  
    91  
    92  error,t1=tag1,t2=tag2 f1=1.0,f2=2i,f3="abc"
    93     view,t1=tag2,t2=tag2 f1=1.0,f2=2i,f3="abc" 1625823259000000000
    94   resource,t1=tag3,t2=tag2 f1=1.0,f2=2i,f3="abc" 1621239130
    95    long_task,t1=tag4,t2=tag2 f1=1.0,f2=2i,f3="abc"
    96   action,t1=tag5,t2=tag2 f1=1.0,f2=2i,f3="abc"
    97  
    98  
    99  
   100  `
   101  
   102  	pts, err := Parse([]byte(lines), DefaultOption)
   103  	if err != nil {
   104  		t.Error(err)
   105  	}
   106  
   107  	if len(pts) != 5 {
   108  		t.Errorf("expected %d points, actually get %d points", 5, len(pts))
   109  	}
   110  
   111  	for _, pt := range pts {
   112  		t.Logf("%+#v", pt)
   113  	}
   114  }
   115  
   116  func BenchmarkParse(b *testing.B) {
   117  	cases := []struct {
   118  		name       string
   119  		data       []byte
   120  		opt        *Option
   121  		optSetters []OptionSetter
   122  	}{
   123  		{
   124  			name: "parse-multi-short",
   125  			data: []byte(strings.Join([]string{
   126  				`foo,tag1=val1,tag2=val2 x=1,y="hello" 1625823259000000`,
   127  				`foo,tag1=val1,tag2=val2 x=1,y="hello" 1625823259000000`,
   128  				`foo,tag1=val1,tag2=val2 x=1,y="hello" 1625823259000000`,
   129  				`foo,tag1=val1,tag2=val2 x=1,y="hello" 1625823259000000`,
   130  			}, "\n")),
   131  			opt:        &Option{PrecisionV2: Microsecond},
   132  			optSetters: []OptionSetter{WithPrecisionV2(Microsecond)},
   133  		},
   134  
   135  		{
   136  			name: "parse-multi-long-with-32k-field",
   137  			data: []byte(strings.Join([]string{
   138  				fmt.Sprintf(`foo,tag1=%s,tag2=%s f1=1,f2="%s",f3=3i 1625823259000000`, cliutils.CreateRandomString(100), cliutils.CreateRandomString(100), cliutils.CreateRandomString(32*1024)),
   139  				fmt.Sprintf(`foo,tag1=%s,tag2=%s f1=1,f2="%s",f3=3i 1625823259000000`, cliutils.CreateRandomString(100), cliutils.CreateRandomString(100), cliutils.CreateRandomString(32*1024)),
   140  				fmt.Sprintf(`foo,tag1=%s,tag2=%s f1=1,f2="%s",f3=3i 1625823259000000`, cliutils.CreateRandomString(100), cliutils.CreateRandomString(100), cliutils.CreateRandomString(32*1024)),
   141  				fmt.Sprintf(`foo,tag1=%s,tag2=%s f1=1,f2="%s",f3=3i 1625823259000000`, cliutils.CreateRandomString(100), cliutils.CreateRandomString(100), cliutils.CreateRandomString(32*1024)),
   142  			}, "\n")),
   143  			opt:        &Option{PrecisionV2: Microsecond},
   144  			optSetters: []OptionSetter{WithPrecisionV2(Microsecond)},
   145  		},
   146  	}
   147  
   148  	for _, tc := range cases {
   149  		b.Run(tc.name+"-New", func(b *testing.B) {
   150  			for i := 0; i < b.N; i++ {
   151  				pts, err := ParseWithOptionSetter(tc.data, tc.optSetters...)
   152  				if err != nil {
   153  					b.Errorf("Parse: %s", err.Error())
   154  				}
   155  				_ = pts
   156  			}
   157  		})
   158  
   159  		b.Run(tc.name+"-Old", func(b *testing.B) {
   160  			for i := 0; i < b.N; i++ {
   161  				pts, err := ParsePoints(tc.data, tc.opt)
   162  				if err != nil {
   163  					b.Errorf("Parse: %s", err.Error())
   164  				}
   165  				_ = pts
   166  			}
   167  		})
   168  	}
   169  }
   170  
   171  func TestNewLineEncoder(t *testing.T) {
   172  	cases := []struct {
   173  		name string
   174  		pts  []struct {
   175  			measurement string
   176  			tags        map[string]string
   177  			fields      map[string]interface{}
   178  			time        time.Time
   179  		}
   180  		opt *Option
   181  	}{
   182  		{
   183  			name: "encode-multi-short",
   184  			opt:  &Option{PrecisionV2: Microsecond},
   185  			pts: []struct {
   186  				measurement string
   187  				tags        map[string]string
   188  				fields      map[string]interface{}
   189  				time        time.Time
   190  			}{
   191  				{
   192  					measurement: "foo",
   193  					tags: map[string]string{
   194  						"t2": cliutils.CreateRandomString(100),
   195  						"t1": cliutils.CreateRandomString(100),
   196  					},
   197  					fields: map[string]interface{}{
   198  						"f3": int64(1024),
   199  						"f1": 1024.2048,
   200  						"f2": cliutils.CreateRandomString(128),
   201  					},
   202  					time: time.Now(),
   203  				},
   204  				{
   205  					measurement: "foo2",
   206  					tags: map[string]string{
   207  						"aaa": cliutils.CreateRandomString(110),
   208  						"AAA": cliutils.CreateRandomString(110),
   209  					},
   210  					fields: map[string]interface{}{
   211  						"f1": int64(1024),
   212  						"f5": 1024.2048,
   213  						"f3": cliutils.CreateRandomString(138),
   214  					},
   215  					time: time.Now(),
   216  				},
   217  
   218  				{
   219  					measurement: "foo3",
   220  					tags: map[string]string{
   221  						"t31": cliutils.CreateRandomString(100),
   222  						"t22": cliutils.CreateRandomString(120),
   223  					},
   224  					fields: map[string]interface{}{
   225  						"f1":   int64(1024),
   226  						"f222": 1024.2048,
   227  						"f3":   cliutils.CreateRandomString(148),
   228  					},
   229  					time: time.Now(),
   230  				},
   231  			},
   232  		},
   233  	}
   234  
   235  	encoder := NewLineEncoder()
   236  
   237  	var point *Point
   238  	for _, tc := range cases {
   239  		for _, pt := range tc.pts {
   240  			newPoint, err := NewPoint(pt.measurement,
   241  				pt.tags,
   242  				pt.fields,
   243  				pt.time)
   244  			if err != nil {
   245  				t.Fatal(err)
   246  			}
   247  			point = newPoint
   248  
   249  			err = encoder.AppendPoint(newPoint)
   250  			if err != nil {
   251  				t.Fatal(err)
   252  			}
   253  
   254  			bts, _ := encoder.Bytes()
   255  			fmt.Println(len(bts))
   256  		}
   257  	}
   258  
   259  	chars, _ := encoder.Bytes()
   260  
   261  	fmt.Println(string(chars))
   262  
   263  	lineBytes, err := encoder.BytesWithoutLn()
   264  	if err != nil {
   265  		t.Fatal(err)
   266  	}
   267  
   268  	fmt.Printf("[%s]\n", lineBytes)
   269  
   270  	encoder.SetBuffer(chars[807:])
   271  	if err := encoder.AppendPoint(point); err != nil {
   272  		t.Fatal(err)
   273  	}
   274  
   275  	chars, _ = encoder.Bytes()
   276  
   277  	fmt.Println(string(chars))
   278  
   279  	encoder = NewLineEncoder()
   280  	chars, err = encoder.Bytes()
   281  	if err != nil {
   282  		t.Fatal(err)
   283  	}
   284  	fmt.Println(chars)
   285  	str, err := encoder.UnsafeString()
   286  	if err != nil {
   287  		t.Fatal(err)
   288  	}
   289  	fmt.Printf("%q\n", str)
   290  }
   291  
   292  func TestEncode(t *testing.T) {
   293  	cases := []struct {
   294  		name string
   295  		pts  []struct {
   296  			measurement string
   297  			tags        map[string]string
   298  			fields      map[string]interface{}
   299  			time        time.Time
   300  		}
   301  		opt *Option
   302  	}{
   303  		{
   304  			name: "encode-multi-short",
   305  			opt:  &Option{PrecisionV2: Microsecond},
   306  			pts: []struct {
   307  				measurement string
   308  				tags        map[string]string
   309  				fields      map[string]interface{}
   310  				time        time.Time
   311  			}{
   312  				{
   313  					measurement: "foo",
   314  					tags: map[string]string{
   315  						"tttttt": "",
   316  						"t1":     cliutils.CreateRandomString(100),
   317  						"t2":     cliutils.CreateRandomString(100),
   318  					},
   319  					fields: map[string]interface{}{
   320  						"f1": int64(1024),
   321  						"f2": 1024.2048,
   322  						"f3": cliutils.CreateRandomString(128),
   323  						"f4": "",
   324  					},
   325  					time: time.Now(),
   326  				},
   327  				{
   328  					measurement: "foo2",
   329  					tags: map[string]string{
   330  						"tttt": "",
   331  						"t1":   cliutils.CreateRandomString(100),
   332  						"t2":   cliutils.CreateRandomString(100),
   333  					},
   334  					fields: map[string]interface{}{
   335  						"ffff": "",
   336  						"f1":   int64(1024),
   337  						"f2":   1024.2048,
   338  						"f3":   cliutils.CreateRandomString(128),
   339  					},
   340  					time: time.Now(),
   341  				},
   342  			},
   343  		},
   344  	}
   345  
   346  	for _, tc := range cases {
   347  		t.Run(tc.name+"-New", func(t *testing.T) {
   348  			pts := make([]*Point, 0, len(tc.pts))
   349  			for _, pt := range tc.pts {
   350  				newPoint, err := NewPoint(pt.measurement,
   351  					pt.tags,
   352  					pt.fields,
   353  					pt.time)
   354  				if err != nil {
   355  					t.Error(err)
   356  					return
   357  				}
   358  
   359  				pts = append(pts, newPoint)
   360  			}
   361  
   362  			lines, err := Encode(pts)
   363  			if err != nil {
   364  				t.Error(err)
   365  			} else {
   366  				t.Logf("[%s]", string(lines))
   367  			}
   368  		})
   369  	}
   370  }
   371  
   372  func BenchmarkEncode(b *testing.B) {
   373  	cases := []struct {
   374  		name string
   375  		pts  []struct {
   376  			measurement string
   377  			tags        map[string]string
   378  			fields      map[string]interface{}
   379  			time        time.Time
   380  		}
   381  		opt *Option
   382  	}{
   383  		{
   384  			name: "encode-multi-short",
   385  			opt:  &Option{PrecisionV2: Microsecond},
   386  			pts: []struct {
   387  				measurement string
   388  				tags        map[string]string
   389  				fields      map[string]interface{}
   390  				time        time.Time
   391  			}{
   392  				{
   393  					measurement: "foo",
   394  					tags: map[string]string{
   395  						"t1": cliutils.CreateRandomString(100),
   396  						"t2": cliutils.CreateRandomString(100),
   397  					},
   398  					fields: map[string]interface{}{
   399  						"f1": int64(1024),
   400  						"f2": 1024.2048,
   401  						"f3": cliutils.CreateRandomString(128),
   402  					},
   403  					time: time.Now(),
   404  				},
   405  			},
   406  		},
   407  
   408  		{
   409  			name: "encode-multi-long-with-32k-fields",
   410  			opt:  &Option{PrecisionV2: Microsecond},
   411  			pts: []struct {
   412  				measurement string
   413  				tags        map[string]string
   414  				fields      map[string]interface{}
   415  				time        time.Time
   416  			}{
   417  				{
   418  					measurement: "foo",
   419  					tags: map[string]string{
   420  						"t1": cliutils.CreateRandomString(100),
   421  						"t2": cliutils.CreateRandomString(100),
   422  					},
   423  					fields: map[string]interface{}{
   424  						"f1": int64(1024),
   425  						"f2": 1024.2048,
   426  						"f3": cliutils.CreateRandomString(1024),
   427  						"f4": cliutils.CreateRandomString(32 * 1024),
   428  					},
   429  					time: time.Now(),
   430  				},
   431  
   432  				{
   433  					measurement: "foo",
   434  					tags: map[string]string{
   435  						"t1": cliutils.CreateRandomString(100),
   436  						"t2": cliutils.CreateRandomString(100),
   437  					},
   438  					fields: map[string]interface{}{
   439  						"f1": int64(1024),
   440  						"f2": 1024.2048,
   441  						"f3": cliutils.CreateRandomString(1024),
   442  						"f4": cliutils.CreateRandomString(32 * 1024),
   443  					},
   444  					time: time.Now(),
   445  				},
   446  
   447  				{
   448  					measurement: "foo",
   449  					tags: map[string]string{
   450  						"t1": cliutils.CreateRandomString(100),
   451  						"t2": cliutils.CreateRandomString(100),
   452  					},
   453  					fields: map[string]interface{}{
   454  						"f1": int64(1024),
   455  						"f2": 1024.2048,
   456  						"f3": cliutils.CreateRandomString(1024),
   457  						"f4": cliutils.CreateRandomString(32 * 1024),
   458  					},
   459  					time: time.Now(),
   460  				},
   461  			},
   462  		},
   463  	}
   464  
   465  	for _, tc := range cases {
   466  		b.Run(tc.name+"-New", func(b *testing.B) {
   467  			encoder := NewLineEncoder()
   468  
   469  			for i := 0; i < b.N; i++ {
   470  				for _, pt := range tc.pts {
   471  					newPoint, err := NewPoint(pt.measurement,
   472  						pt.tags,
   473  						pt.fields,
   474  						pt.time)
   475  					if err != nil {
   476  						b.Error(err)
   477  						return
   478  					}
   479  					encoder.Reset()
   480  					_ = encoder.AppendPoint(newPoint)
   481  					_, err = encoder.Bytes()
   482  					if err != nil {
   483  						b.Error(err)
   484  						return
   485  					}
   486  				}
   487  			}
   488  		})
   489  
   490  		b.Run(tc.name+"-Old", func(b *testing.B) {
   491  			for i := 0; i < b.N; i++ {
   492  				for _, pt := range tc.pts {
   493  					oldPoint, err := influxdb.NewPoint(pt.measurement,
   494  						pt.tags,
   495  						pt.fields,
   496  						pt.time)
   497  					if err != nil {
   498  						b.Error(err)
   499  						return
   500  					}
   501  
   502  					_ = oldPoint.String()
   503  				}
   504  			}
   505  		})
   506  	}
   507  }
   508  
   509  func TestLineEncoderBytesWithoutLn(t *testing.T) {
   510  	cases := []struct {
   511  		name string
   512  		pts  []struct {
   513  			measurement string
   514  			tags        map[string]string
   515  			fields      map[string]interface{}
   516  			time        time.Time
   517  		}
   518  		opt *Option
   519  	}{
   520  		{
   521  			name: "encode-multi-short",
   522  			opt:  &Option{PrecisionV2: Microsecond},
   523  			pts: []struct {
   524  				measurement string
   525  				tags        map[string]string
   526  				fields      map[string]interface{}
   527  				time        time.Time
   528  			}{
   529  				{
   530  					measurement: "foo",
   531  					tags: map[string]string{
   532  						"t2": cliutils.CreateRandomString(100),
   533  						"t1": cliutils.CreateRandomString(100),
   534  					},
   535  					fields: map[string]interface{}{
   536  						"f3": int64(1024),
   537  						"f1": 1024.2048,
   538  						"f2": cliutils.CreateRandomString(128),
   539  					},
   540  					time: time.Now(),
   541  				},
   542  				{
   543  					measurement: "foo2",
   544  					tags: map[string]string{
   545  						"aaa": cliutils.CreateRandomString(110),
   546  						"AAA": cliutils.CreateRandomString(110),
   547  					},
   548  					fields: map[string]interface{}{
   549  						"f1": int64(1024),
   550  						"f5": 1024.2048,
   551  						"f3": cliutils.CreateRandomString(138),
   552  					},
   553  					time: time.Now(),
   554  				},
   555  
   556  				{
   557  					measurement: "foo3",
   558  					tags: map[string]string{
   559  						"t31": cliutils.CreateRandomString(100),
   560  						"t22": cliutils.CreateRandomString(120),
   561  					},
   562  					fields: map[string]interface{}{
   563  						"f1":   int64(1024),
   564  						"f222": 1024.2048,
   565  						"f3":   cliutils.CreateRandomString(148),
   566  					},
   567  					time: time.Now(),
   568  				},
   569  			},
   570  		},
   571  	}
   572  
   573  	for _, tc := range cases {
   574  		t.Run(tc.name, func(t *testing.T) {
   575  			encoder := NewLineEncoder()
   576  
   577  			for _, pt := range tc.pts {
   578  				encoder.Reset()
   579  				point, _ := NewPoint(pt.measurement, pt.tags, pt.fields, pt.time)
   580  				if err := encoder.AppendPoint(point); err != nil {
   581  					t.Fatal(err)
   582  				}
   583  				line, err := encoder.BytesWithoutLn()
   584  				if err != nil {
   585  					t.Fatal(err)
   586  				}
   587  
   588  				t.Logf("%q\n", string(line))
   589  			}
   590  		})
   591  	}
   592  }