github.com/GuanceCloud/cliutils@v1.1.21/point/kvs_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  	"math"
    10  	"sort"
    11  	T "testing"
    12  
    13  	"github.com/stretchr/testify/assert"
    14  )
    15  
    16  func TestTrim(t *T.T) {
    17  	t.Run("trim-field", func(t *T.T) {
    18  		var kvs KVs
    19  		kvs = kvs.Add("f0", 1.23, false, false)
    20  		kvs = kvs.AddTag("t1", "v1")
    21  		kvs = kvs.Add("f1", -123, false, false)
    22  		kvs = kvs.Add("f2", uint64(123), false, false)
    23  		kvs = kvs.Add("f3", "hello", false, false)
    24  		kvs = kvs.Add("f4", []byte("world"), false, false)
    25  		kvs = kvs.Add("f5", false, false, false)
    26  
    27  		kvs = kvs.TrimFields(1)
    28  
    29  		assert.Lenf(t, kvs, 2, "go kvs: %s", kvs.Pretty())
    30  		assert.NotNil(t, kvs.Get("f0"))
    31  		assert.NotNil(t, kvs.Get("t1"))
    32  	})
    33  
    34  	t.Run("point-pool-kv-reuse", func(t *T.T) {
    35  		pp := NewReservedCapPointPool(1000)
    36  		SetPointPool(pp)
    37  		defer ClearPointPool()
    38  
    39  		i := 0
    40  		var kvs KVs
    41  
    42  		kvs = kvs.Add("f0", 1.23, false, false)
    43  		kvs = kvs.AddTag("t1", "v1")
    44  
    45  		for {
    46  			kvs = kvs.TrimFields(0)
    47  
    48  			assert.Lenf(t, kvs, 1, "go kvs: %s", kvs.Pretty())
    49  
    50  			kvs = kvs.Add("f-1", 123, false, false)
    51  
    52  			if pp.(*ReservedCapPointPool).chanGet() > 0 {
    53  				t.Logf("[%d] %s", i, pp)
    54  				break
    55  			}
    56  			i++
    57  		}
    58  	})
    59  
    60  	t.Run("trim-field-under-point-pool", func(t *T.T) {
    61  		pp := NewReservedCapPointPool(1000)
    62  		SetPointPool(pp)
    63  		defer ClearPointPool()
    64  
    65  		for loop := 0; loop < 2; loop++ {
    66  			var kvs KVs
    67  			kvs = kvs.Add("f0", 1.23, false, false)
    68  			kvs = kvs.AddTag("t1", "v1")
    69  			kvs = kvs.Add("f1", -123, false, false)
    70  			kvs = kvs.Add("f2", uint64(123), false, false)
    71  			kvs = kvs.Add("f3", "hello", false, false)
    72  			kvs = kvs.Add("f4", []byte("world"), false, false)
    73  			kvs = kvs.Add("f5", false, false, false)
    74  
    75  			kvs = kvs.TrimFields(2)
    76  
    77  			assert.Lenf(t, kvs, 3 /* 2 fields  + 1 tag */, "go kvs: %s", kvs.Pretty())
    78  			assert.NotNil(t, kvs.Get("f0"))
    79  			assert.NotNil(t, kvs.Get("f1"))
    80  			assert.NotNil(t, kvs.Get("t1"))
    81  
    82  			kvs = kvs.Add("f-2", 123, false, false)
    83  			kvs = kvs.Add("f-3", 123, false, false)
    84  			kvs = kvs.Add("f-4", 123, false, false)
    85  			_ = kvs.Add("f-5", 123, false, false)
    86  		}
    87  
    88  		// XXX: why set loop to 1, the kvReused == 0?
    89  		assert.True(t, pp.(*ReservedCapPointPool).chanGet() > 0)
    90  
    91  		t.Logf("point-pool: %s", pp)
    92  	})
    93  
    94  	t.Run("trim-tag", func(t *T.T) {
    95  		var kvs KVs
    96  		kvs = kvs.Add("f0", 1.23, false, false)
    97  		kvs = kvs.AddTag("t1", "v1")
    98  		kvs = kvs.AddTag("t2", "v1")
    99  		kvs = kvs.AddTag("t3", "v1")
   100  		kvs = kvs.Add("f1", -123, false, false)
   101  
   102  		kvs = kvs.TrimTags(1)
   103  
   104  		assert.Lenf(t, kvs, 3, "go kvs: %s", kvs.Pretty())
   105  		assert.NotNil(t, kvs.Get("t1"))
   106  	})
   107  
   108  	t.Run("trim-tag-under-point-pool", func(t *T.T) {
   109  		pp := NewReservedCapPointPool(2)
   110  		SetPointPool(pp)
   111  		defer ClearPointPool()
   112  
   113  		for loop := 0; loop < 2; loop++ {
   114  			var kvs KVs
   115  
   116  			kvs = kvs.Add("f0", 1.23, false, false)
   117  			kvs = kvs.AddTag("t1", "v1")
   118  			kvs = kvs.AddTag("t2", "v1")
   119  			kvs = kvs.Add("f1", -123, false, false)
   120  
   121  			kvs = kvs.TrimTags(1)
   122  
   123  			assert.Lenf(t, kvs, 3 /* 2 fields  + 1 tag */, "go kvs: %s", kvs.Pretty())
   124  
   125  			assert.NotNil(t, kvs.Get("f0"))
   126  			assert.NotNil(t, kvs.Get("f1"))
   127  			assert.NotNil(t, kvs.Get("f1"))
   128  
   129  			kvs = kvs.Add("f-2", 123, false, false)
   130  			kvs = kvs.Add("f-3", 123, false, false)
   131  			kvs = kvs.Add("f-4", 123, false, false)
   132  			_ = kvs.Add("f-5", 123, false, false)
   133  		}
   134  
   135  		// XXX: why set loop to 1, the kvReused == 0?
   136  		assert.True(t, pp.(*ReservedCapPointPool).chanGet() > 0)
   137  
   138  		t.Logf("point-pool: %s", pp.(*ReservedCapPointPool).String())
   139  	})
   140  }
   141  
   142  func BenchmarkKVsTrim(b *T.B) {
   143  	b.Run("trim", func(b *T.B) {
   144  		pp := NewReservedCapPointPool(1000)
   145  		SetPointPool(pp)
   146  		defer func() {
   147  			ClearPointPool()
   148  			b.Logf("point pool: %s", pp)
   149  		}()
   150  
   151  		for i := 0; i < b.N; i++ {
   152  			var kvs KVs
   153  			kvs = kvs.Add("f0", 1.23, false, false)
   154  			kvs = kvs.AddTag("t1", "v1")
   155  			kvs = kvs.Add("f1", -123, false, false)
   156  			kvs = kvs.Add("f2", uint64(123), false, false)
   157  
   158  			kvs = kvs.TrimFields(1)
   159  
   160  			kvs = kvs.Add("f-2", 123, false, false)
   161  			kvs = kvs.Add("f-3", 123, false, false)
   162  			kvs = kvs.Add("f-4", 123, false, false)
   163  			_ = kvs.Add("f-5", 123, false, false)
   164  		}
   165  	})
   166  
   167  	b.Run("del", func(b *T.B) {
   168  		pp := NewReservedCapPointPool(1000)
   169  		SetPointPool(pp)
   170  		defer func() {
   171  			ClearPointPool()
   172  			b.Logf("point pool: %s", pp)
   173  		}()
   174  
   175  		for i := 0; i < b.N; i++ {
   176  			var kvs KVs
   177  			kvs = kvs.Add("f0", 1.23, false, false)
   178  			kvs = kvs.AddTag("t1", "v1")
   179  			kvs = kvs.Add("f1", -123, false, false)
   180  			kvs = kvs.Add("f2", uint64(123), false, false)
   181  
   182  			kvs = kvs.Del("f2")
   183  
   184  			kvs = kvs.Add("f-2", 123, false, false)
   185  			kvs = kvs.Add("f-3", 123, false, false)
   186  			kvs = kvs.Add("f-4", 123, false, false)
   187  			_ = kvs.Add("f-5", 123, false, false)
   188  		}
   189  	})
   190  }
   191  
   192  func TestKVsAdd(t *T.T) {
   193  	t.Run("basic", func(t *T.T) {
   194  		var kvs KVs
   195  		kvs.Add("f1", 123, false, false)
   196  
   197  		assert.Len(t, kvs, 0)
   198  
   199  		kvs = kvs.Add("f1", 123, false, false)
   200  		assert.Len(t, kvs, 1)
   201  	})
   202  
   203  	t.Run("add-v2", func(t *T.T) {
   204  		var kvs KVs
   205  		kvs = kvs.AddV2("f1", 123, false, WithKVUnit("dollar"), WithKVType(GAUGE))
   206  		kvs = kvs.AddV2("cap", 123, false, WithKVUnit("bytes"), WithKVType(COUNT))
   207  
   208  		t.Logf("kvs: %s", kvs.Pretty())
   209  	})
   210  }
   211  
   212  func TestKVsReset(t *T.T) {
   213  	t.Run("reset", func(t *T.T) {
   214  		var kvs KVs
   215  		kvs = kvs.Add("f0", 1.23, false, false)
   216  		kvs = kvs.Add("f1", -123, false, false)
   217  		kvs = kvs.Add("f2", uint64(123), false, false)
   218  		kvs = kvs.Add("f3", "hello", false, false)
   219  		kvs = kvs.Add("f4", []byte("world"), false, false)
   220  		kvs = kvs.Add("f5", false, false, false)
   221  
   222  		kvs.ResetFull()
   223  
   224  		assert.Equal(t, "", kvs[0].Key)
   225  		assert.Equal(t, 0.0, kvs[0].Raw().(float64))
   226  
   227  		assert.Equal(t, int64(0), kvs[1].Raw().(int64))
   228  		assert.Equal(t, uint64(0), kvs[2].Raw().(uint64))
   229  		assert.Equal(t, "", kvs[3].Raw().(string))
   230  		assert.Len(t, kvs[4].Raw().([]byte), 0)
   231  		assert.False(t, kvs[5].Raw().(bool))
   232  	})
   233  }
   234  
   235  func TestNewKVs(t *T.T) {
   236  	t.Run("add-tag", func(t *T.T) {
   237  		kvs := NewKVs(map[string]any{"f1": 123})
   238  
   239  		kvs = kvs.AddTag(`t1`, `v1`)
   240  		assert.Equal(t, `v1`, kvs.Get(`t1`).GetS())
   241  		assert.Equal(t, 1, kvs.TagCount())
   242  
   243  		// add new tag t2
   244  		kvs = kvs.Add(`t2`, `v2`, true, true)
   245  		assert.Equal(t, `v2`, kvs.Get(`t2`).GetS())
   246  		assert.Equal(t, 2, kvs.TagCount())
   247  
   248  		// replace t2's value v3
   249  		kvs = kvs.Add(`t2`, `v3`, true, true)
   250  		assert.Equal(t, `v3`, kvs.Get(`t2`).GetS())
   251  		assert.Equal(t, 2, kvs.TagCount())
   252  
   253  		// invalid tag value(must be []byte/string), switch to field
   254  		kvs = kvs.Add(`tag-as-field`, 123, true, true)
   255  		assert.Equal(t, int64(123), kvs.Get(`tag-as-field`).GetI())
   256  		assert.Equal(t, 2, kvs.TagCount())
   257  
   258  		// invalid tag override exist
   259  		kvs = kvs.Add(`t2`, false, true, true)
   260  		assert.Equal(t, false, kvs.Get(`t2`).GetB())
   261  		assert.Equal(t, 1, kvs.TagCount())
   262  	})
   263  
   264  	t.Run(`new-empty`, func(t *T.T) {
   265  		kvs := NewKVs(nil)
   266  		assert.Equal(t, 0, len(kvs))
   267  	})
   268  
   269  	t.Run(`new-invalid-float`, func(t *T.T) {
   270  		kvs := NewKVs(map[string]any{
   271  			"f1": math.NaN(),
   272  			"f2": math.Inf(1),
   273  		})
   274  
   275  		assert.Equal(t, 2, len(kvs))
   276  	})
   277  
   278  	t.Run(`new-all-types`, func(t *T.T) {
   279  		kvs := NewKVs(map[string]any{
   280  			"f1": 123,
   281  			"f2": uint64(123),
   282  			"f3": 3.14,
   283  			"f4": "hello",
   284  			"f5": []byte(`world`),
   285  			"f6": false,
   286  			"f7": true,
   287  		})
   288  		assert.Equal(t, 7, len(kvs))
   289  
   290  		assert.Equal(t, int64(123), kvs.Get(`f1`).GetI())
   291  		assert.Equal(t, uint64(123), kvs.Get(`f2`).GetU())
   292  		assert.Equal(t, 3.14, kvs.Get(`f3`).GetF())
   293  		assert.Equal(t, `hello`, kvs.Get(`f4`).GetS())
   294  		assert.Equal(t, []byte(`world`), kvs.Get(`f5`).GetD())
   295  		assert.Equal(t, false, kvs.Get(`f6`).GetB())
   296  		assert.Equal(t, true, kvs.Get(`f7`).GetB())
   297  
   298  		t.Logf("kvs:\n%s", kvs.Pretty())
   299  	})
   300  
   301  	t.Run(`add-kv`, func(t *T.T) {
   302  		kvs := NewKVs(nil)
   303  
   304  		kvs = kvs.MustAddKV(NewKV(`t1`, false, WithKVTagSet(true))) // set tag failed on bool value
   305  		kvs = kvs.MustAddKV(NewKV(`t2`, "v1", WithKVTagSet(true)))
   306  		kvs = kvs.MustAddKV(NewKV(`t3`, []byte("v2"), WithKVTagSet(true)))
   307  
   308  		kvs = kvs.MustAddKV(NewKV(`f1`, "foo"))
   309  		kvs = kvs.MustAddKV(NewKV(`f2`, 123, WithKVUnit("MB"), WithKVType(COUNT)))
   310  		kvs = kvs.MustAddKV(NewKV(`f3`, 3.14, WithKVUnit("some"), WithKVType(GAUGE)))
   311  
   312  		assert.Equal(t, 6, len(kvs))
   313  
   314  		t.Logf("kvs:\n%s", kvs.Pretty())
   315  	})
   316  
   317  	// any update to kvs should keep them sorted
   318  	t.Run(`test-not-sorted`, func(t *T.T) {
   319  		kvs := NewKVs(nil)
   320  
   321  		assert.True(t, sort.IsSorted(kvs)) // empty kvs sorted
   322  
   323  		kvs = kvs.Add(`f2`, false, false, false)
   324  		kvs = kvs.Add(`f1`, 123, false, false)
   325  		kvs = kvs.Add(`f0`, 123, false, false)
   326  		kvs = kvs.MustAddTag(`t1`, "v1")
   327  
   328  		assert.False(t, sort.IsSorted(kvs))
   329  
   330  		kvs = kvs.Del(`f1`)
   331  		assert.False(t, sort.IsSorted(kvs))
   332  
   333  		kvs = kvs.MustAddKV(NewKV(`f3`, 3.14))
   334  		assert.False(t, sort.IsSorted(kvs))
   335  
   336  		t.Logf("kvs:\n%s", kvs.Pretty())
   337  
   338  		sort.Sort(kvs)
   339  		assert.True(t, sort.IsSorted(kvs))
   340  		assert.Len(t, kvs, 4)
   341  	})
   342  
   343  	t.Run(`test-del3`, func(t *T.T) {
   344  		pp := NewReservedCapPointPool(1000)
   345  
   346  		SetPointPool(pp)
   347  		defer ClearPointPool()
   348  
   349  		var kvs KVs
   350  
   351  		defer func() {
   352  			for _, kv := range kvs {
   353  				pp.PutKV(kv)
   354  			}
   355  		}()
   356  
   357  		kvs = kvs.Add(`f1`, false, false, false)
   358  		kvs = kvs.Add(`f2`, 123, false, false)
   359  		kvs = kvs.Add(`f3`, 123, false, false)
   360  
   361  		t.Logf("kvs:\n%s", kvs.Pretty())
   362  		kvs = kvs.Del(`f1`)
   363  		t.Logf("kvs:\n%s", kvs.Pretty())
   364  
   365  		t.Logf("pt pool: %s", pp)
   366  	})
   367  
   368  	t.Run(`test-del-on-pt-pool`, func(t *T.T) {
   369  		pp := NewReservedCapPointPool(1000)
   370  
   371  		SetPointPool(pp)
   372  		defer ClearPointPool()
   373  
   374  		var kvs KVs
   375  
   376  		defer func() {
   377  			for _, kv := range kvs {
   378  				pp.PutKV(kv)
   379  			}
   380  		}()
   381  
   382  		kvs = kvs.Add(`f1`, false, false, false)
   383  		kvs = kvs.Add(`f2`, 123, false, false)
   384  		kvs = kvs.Add(`f3`, 123, false, false)
   385  
   386  		t.Logf("kvs:\n%s", kvs.Pretty())
   387  		kvs = kvs.Del(`f1`)
   388  		t.Logf("kvs:\n%s", kvs.Pretty())
   389  
   390  		t.Logf("pt pool: %s", pp)
   391  	})
   392  
   393  	t.Run(`test-update-on-kvs`, func(t *T.T) {
   394  		pt := NewPointV2("ptname", nil)
   395  
   396  		pt.pt.Fields = KVs(pt.pt.Fields).Add("f1", 1.23, false, false)
   397  
   398  		t.Logf("point: %s", pt.Pretty())
   399  
   400  		assert.NotNil(t, pt.Get("f1"))
   401  	})
   402  
   403  	t.Run("array-int-value", func(t *T.T) {
   404  		var kvs KVs
   405  		kvs = kvs.Add("f_arr", MustNewAnyArray(1, 2, 3), false, false)
   406  		assert.Equal(t, []any{int64(1), int64(2), int64(3)}, kvs.Get("f_arr").Raw())
   407  		t.Logf("kvs: %s", kvs.Pretty())
   408  	})
   409  
   410  	t.Run("array-bytes-value", func(t *T.T) {
   411  		var kvs KVs
   412  		kvs = kvs.Add("f_arr", MustNewAnyArray([]byte("hello"), []byte("world")), false, false)
   413  		assert.Equal(t, []any{[]byte("hello"), []byte("world")}, kvs.Get("f_arr").Raw())
   414  		t.Logf("kvs: %s", kvs.Pretty())
   415  
   416  		pt := NewPointV2("some", kvs)
   417  
   418  		t.Logf("pt pretty: %s", pt.Pretty())
   419  		t.Logf("pt lineproto: %s", pt.LineProto())
   420  	})
   421  
   422  	t.Run("array-float-value", func(t *T.T) {
   423  		kvs := NewKVs(map[string]any{
   424  			"f_arr": []float64{1.0, 2.0},
   425  		})
   426  		t.Logf("kvs: %s", kvs.Pretty())
   427  	})
   428  
   429  	t.Run("array-bytes-value", func(t *T.T) {
   430  		kvs := NewKVs(map[string]any{
   431  			"f_arr": [][]byte{[]byte("hello"), []byte("world")},
   432  		})
   433  		t.Logf("kvs: %s", kvs.Pretty())
   434  	})
   435  }
   436  
   437  func TestKVsDel(t *T.T) {
   438  	t.Run("del", func(t *T.T) {
   439  		var kvs KVs
   440  
   441  		kvs = kvs.Add(`f1`, false, false, false)
   442  		kvs = kvs.Add(`f2`, 123, false, false)
   443  		kvs = kvs.Add(`f3`, 123, false, false)
   444  
   445  		kvs = kvs.Del(`f1`)
   446  		assert.Len(t, kvs, 2)
   447  		kvs = kvs.Del(`f3`)
   448  		assert.Len(t, kvs, 1)
   449  		assert.NotNil(t, kvs.Get(`f2`))
   450  	})
   451  
   452  	t.Run(`del-on-point-pool`, func(t *T.T) {
   453  		var kvs KVs
   454  
   455  		pp := NewReservedCapPointPool(1000)
   456  		SetPointPool(pp)
   457  		defer func() {
   458  			ClearPointPool()
   459  		}()
   460  
   461  		kvs = kvs.Add(`f1`, false, false, false)
   462  		kvs = kvs.Add(`f2`, 123, false, false)
   463  		kvs = kvs.Add(`f3`, 123, false, false)
   464  
   465  		kvs = kvs.Del(`f1`)
   466  		assert.Len(t, kvs, 2)
   467  		kvs = kvs.Del(`f3`)
   468  
   469  		assert.Len(t, kvs, 1)
   470  		assert.NotNil(t, kvs.Get(`f2`))
   471  
   472  		_ = kvs.Add(`f-x`, 123, false, false)
   473  
   474  		assert.True(t, pp.(*ReservedCapPointPool).poolGet() > 0)
   475  		assert.True(t, pp.(*ReservedCapPointPool).poolPut() == 0) // chan is 1000, not put to pool
   476  
   477  		assert.True(t, pp.(*ReservedCapPointPool).chanGet() > 0)
   478  		assert.True(t, pp.(*ReservedCapPointPool).chanPut() > 0)
   479  
   480  		t.Logf("point pool: %s", pp.(*ReservedCapPointPool).String())
   481  	})
   482  }
   483  
   484  func BenchmarkKVsDel(b *T.B) {
   485  	addTestKVs := func(kvs KVs) KVs {
   486  		kvs = kvs.Add(`f1`, false, false, false)
   487  		kvs = kvs.Add(`f2`, 123, false, false)
   488  		kvs = kvs.Add(`f3`, "some string", false, false)
   489  		kvs = kvs.Add(`f4`, []byte("hello world"), false, false)
   490  		kvs = kvs.Add(`f5`, 3.14, false, false)
   491  		kvs = kvs.Add(`f6`, uint(8), false, false)
   492  
   493  		return kvs
   494  	}
   495  
   496  	b.Run("del-on-slice-Delete", func(b *T.B) {
   497  		for i := 0; i < b.N; i++ {
   498  			var kvs KVs
   499  			kvs = addTestKVs(kvs)
   500  			_ = kvs.Del(`f1`)
   501  		}
   502  	})
   503  
   504  	b.Run("del-on-slice-Delete-with-point-pool", func(b *T.B) {
   505  		pp := NewReservedCapPointPool(1000)
   506  		SetPointPool(pp)
   507  		defer func() {
   508  			b.Logf("point pool: %s", pp.(*ReservedCapPointPool).String())
   509  			ClearPointPool()
   510  		}()
   511  
   512  		for i := 0; i < b.N; i++ {
   513  			var kvs KVs
   514  			kvs = addTestKVs(kvs)
   515  			_ = kvs.Del(`f1`)
   516  		}
   517  	})
   518  
   519  	b.Run("del-on-new-slice", func(b *T.B) {
   520  		del := func(kvs KVs, k string) KVs {
   521  			var keep KVs // new slice
   522  			for _, f := range kvs {
   523  				if f.Key != k {
   524  					keep = append(keep, f)
   525  				}
   526  			}
   527  			return keep
   528  		}
   529  
   530  		for i := 0; i < b.N; i++ {
   531  			var kvs KVs
   532  			kvs = addTestKVs(kvs)
   533  			_ = del(kvs, `f1`)
   534  		}
   535  	})
   536  }