github.com/GuanceCloud/cliutils@v1.1.21/point/json_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  	"testing"
    12  	T "testing"
    13  	"time"
    14  
    15  	"github.com/stretchr/testify/assert"
    16  	"github.com/stretchr/testify/require"
    17  )
    18  
    19  func TestJSONPointMarshal(t *T.T) {
    20  	cases := []struct {
    21  		name   string
    22  		p      *Point
    23  		opts   []Option
    24  		expect string
    25  	}{
    26  		{
    27  			name: "basic",
    28  			opts: []Option{WithTime(time.Unix(0, 123))},
    29  			p: func() *Point {
    30  				pt, err := NewPoint("abc",
    31  					map[string]string{"t1": "tv1", "t2": "tv2"},
    32  					map[string]interface{}{"f1": 123, "f2": false},
    33  					WithTime(time.Unix(0, 123)))
    34  				assert.NoError(t, err)
    35  
    36  				pt.SetFlag(Ppb) // setup pb
    37  
    38  				return pt
    39  			}(),
    40  
    41  			expect: fmt.Sprintf(`{
    42  				"name":"%s",
    43  				"fields":[
    44  					{"key":"%s","is_tag": true, "s":"%s"},
    45  					{"key":"%s","is_tag": true, "s":"%s"},
    46  				  {"key":"%s","i":"123"},
    47  				  {"key":"%s","b":false}
    48  				],
    49  				"time":"123"
    50  			}`,
    51  				`abc`,
    52  				`t2`,
    53  				`tv2`,
    54  				`t1`,
    55  				`tv1`,
    56  				`f1`,
    57  				`f2`),
    58  		},
    59  	}
    60  
    61  	for _, tc := range cases {
    62  		t.Run(tc.name, func(t *T.T) {
    63  			j, err := json.Marshal(tc.p)
    64  			assert.NoError(t, err, "marshal %s to json failed: %s, json: %v", tc.p.Pretty(), err, j)
    65  
    66  			t.Logf("json: %s", string(j))
    67  
    68  			var pt Point
    69  			require.NoError(t, json.Unmarshal(j, &pt), "unmarshal %s failed", string(j))
    70  
    71  			var pt2 Point
    72  			require.NoError(t, json.Unmarshal([]byte(tc.expect), &pt2))
    73  
    74  			require.True(t, pt2.Equal(&pt), "deep-not-equal:\n%s\n%s", pt.Pretty(), pt2.Pretty())
    75  
    76  			t.Logf("pt: %+#v, pt.pbPoint: %s", pt2, pt.Pretty())
    77  		})
    78  	}
    79  }
    80  
    81  func TestJSONUnmarshal(t *T.T) {
    82  	t.Run(`unmarshal-point-array`, func(t *T.T) {
    83  		j := `[
    84  {"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"}
    85  ]`
    86  		pts := make([]*Point, 0)
    87  		require.NoError(t, json.Unmarshal([]byte(j), &pts))
    88  		t.Logf("pt: %s", pts[0].Pretty())
    89  	})
    90  }
    91  
    92  func TestJSONPointMarhsal(t *testing.T) {
    93  	var kvs KVs
    94  
    95  	EnableMixedArrayField = true
    96  	defer func() {
    97  		EnableMixedArrayField = false
    98  	}()
    99  
   100  	kvs = kvs.AddV2("f1", 123, false)
   101  	kvs = kvs.AddV2("f2", uint(123), false)
   102  	kvs = kvs.AddV2("f3", "hello", false)
   103  	kvs = kvs.AddV2("f4", []byte("world"), false)
   104  	kvs = kvs.AddV2("f5", false, false)
   105  	kvs = kvs.AddV2("f6", 3.14, false, WithKVUnit("kb"), WithKVType(GAUGE))
   106  	kvs = kvs.AddV2("f7", []int{1, 2, 3, 4, 5}, false)
   107  	kvs = kvs.AddV2("f8", MustNewAnyArray(1.0, 2, uint(3), "hello", []byte("world"), false, 3.14), false)
   108  
   109  	kvs = kvs.AddV2("t1", "some-tag-value", false, WithKVTagSet(true))
   110  
   111  	pt := NewPointV2("json-point", kvs)
   112  
   113  	j, err := json.MarshalIndent(pt, "", "  ")
   114  	assert.NoError(t, err)
   115  
   116  	t.Logf("old json:\n%s", string(j))
   117  
   118  	pt.SetFlag(Ppb)
   119  
   120  	j, err = json.MarshalIndent(pt, "", "  ")
   121  	assert.NoError(t, err)
   122  
   123  	t.Logf("new json:\n%s", string(j))
   124  
   125  	t.Logf("line-protocol:\n%s", pt.LineProto())
   126  }
   127  
   128  func TestJSONPoint2Point(t *T.T) {
   129  	cases := []struct {
   130  		name   string
   131  		p      *JSONPoint
   132  		opts   []Option
   133  		expect string
   134  		fail   bool
   135  	}{
   136  		{
   137  			name: "basic",
   138  			p: &JSONPoint{
   139  				Measurement: "abc",
   140  				Tags:        nil,
   141  				Fields:      map[string]interface{}{"f1": 123, "f2": false},
   142  			},
   143  			opts:   []Option{WithTime(time.Unix(0, 123))},
   144  			expect: "abc f1=123i,f2=false 123",
   145  		},
   146  
   147  		{
   148  			name: "no-fields",
   149  			p: &JSONPoint{
   150  				Measurement: "abc",
   151  				Fields:      nil,
   152  			},
   153  			fail: true,
   154  			opts: []Option{WithTime(time.Unix(0, 123))},
   155  		},
   156  
   157  		{
   158  			name: "no-measurement",
   159  			p: &JSONPoint{
   160  				Measurement: "", // not set
   161  				Tags:        nil,
   162  				Fields:      map[string]interface{}{"f1": 123, "f2": false},
   163  			},
   164  			opts:   []Option{WithTime(time.Unix(0, 123))},
   165  			expect: fmt.Sprintf("%s f1=123i,f2=false 123", DefaultMeasurementName),
   166  		},
   167  	}
   168  
   169  	for _, tc := range cases {
   170  		t.Run(tc.name, func(t *T.T) {
   171  			pt, err := tc.p.Point(tc.opts...)
   172  			if tc.fail {
   173  				assert.Error(t, err)
   174  				t.Logf("expect err: %s", err)
   175  				return
   176  			} else {
   177  				assert.NoError(t, err)
   178  			}
   179  
   180  			assert.Equal(t, tc.expect, pt.LineProto())
   181  		})
   182  	}
   183  
   184  	t.Run("array-field", func(t *T.T) {
   185  		jp := JSONPoint{
   186  			Measurement: "some",
   187  			Fields: map[string]any{
   188  				"f_i_arr": []int{1, 2, 3},
   189  				"f_d_arr": [][]byte{[]byte("hello"), []byte("world")},
   190  			},
   191  		}
   192  
   193  		pt := fromJSONPoint(&jp)
   194  
   195  		t.Logf("pt: %s", pt.Pretty())
   196  
   197  		EnableMixedArrayField = true
   198  		defer func() {
   199  			EnableMixedArrayField = false
   200  		}()
   201  
   202  		j := `{
   203  	"measurement": "some",
   204  	"fields": {
   205  		"f_i_arr": [1,2,3],
   206  		"f_f_arr": [1.0,2.0,3.14],
   207  		"f_mix_arr": [1.0, "string", false, 3]
   208  	}
   209  }`
   210  		// NOTE: simple json do not support:
   211  		//  - signed/unsigned int
   212  		//  - []byte
   213  		var jp2 JSONPoint
   214  		assert.NoError(t, json.Unmarshal([]byte(j), &jp2))
   215  
   216  		t.Logf("jp2 fields: %+#v", jp2.Fields)
   217  
   218  		pt, err := jp2.Point()
   219  		assert.NoError(t, err)
   220  		assert.NotNilf(t, pt.Get("f_i_arr"), "pt: %s", pt.Pretty())
   221  		assert.NotNilf(t, pt.Get("f_f_arr"), "pt: %s", pt.Pretty())
   222  		assert.NotNilf(t, pt.Get("f_mix_arr"), "pt: %s", pt.Pretty())
   223  
   224  		t.Logf("pt: %s", pt.Pretty())
   225  	})
   226  }
   227  
   228  func TestFromJSONPoint(t *T.T) {
   229  	t.Run(`basic`, func(t *T.T) {
   230  		jp := JSONPoint{
   231  			Measurement: "m",
   232  			Tags: map[string]string{
   233  				"t1": "v1",
   234  				"t2": "v2",
   235  			},
   236  			Fields: map[string]any{
   237  				"f1": 1,
   238  				"f2": 3.14,
   239  			},
   240  			Time: 123,
   241  		}
   242  
   243  		pt := fromJSONPoint(&jp)
   244  		assert.Equal(t, "m", pt.Name())
   245  		assert.Equal(t, "v1", pt.Get("t1"))
   246  		assert.Equal(t, "v2", pt.Get("t2"))
   247  		assert.Equal(t, int64(1), pt.Get("f1"))
   248  		assert.Equal(t, 3.14, pt.Get("f2"))
   249  		assert.Equal(t, int64(123), pt.Time().UnixNano())
   250  	})
   251  
   252  	t.Run(`from-raw-json`, func(t *T.T) {
   253  		j := `
   254  {
   255  	"measurement": "m",
   256  	"tags": {
   257  		"t1": "v1",
   258  		"t2": "v2"
   259  	},
   260  	"fields": {
   261  		"f1": 1,
   262  		"f2": 3.14
   263  	},
   264  
   265  	"time": 123
   266  }
   267  `
   268  
   269  		var pt Point
   270  		assert.NoError(t, json.Unmarshal([]byte(j), &pt))
   271  
   272  		assert.Equal(t, "m", pt.Name())
   273  		assert.Equal(t, "v1", pt.Get("t1"))
   274  		assert.Equal(t, "v2", pt.Get("t2"))
   275  		assert.Equal(t, 1.0, pt.Get("f1")) // NOTE: here 1 in json unmarshaled as float
   276  		assert.Equal(t, 3.14, pt.Get("f2"))
   277  		assert.Equal(t, int64(123), pt.Time().UnixNano())
   278  	})
   279  }