github.com/aristanetworks/goarista@v0.0.0-20240514173732-cca2755bbd44/elasticsearch/json_test.go (about)

     1  // Copyright (c) 2018 Arista Networks, Inc.  All rights reserved.
     2  // Arista Networks, Inc. Confidential and Proprietary.
     3  // Subject to Arista Networks, Inc.'s EULA.
     4  // FOR INTERNAL USE ONLY. NOT FOR DISTRIBUTION.
     5  
     6  package elasticsearch
     7  
     8  import (
     9  	"encoding/json"
    10  	"reflect"
    11  	"testing"
    12  
    13  	"github.com/aristanetworks/goarista/gnmi"
    14  	pb "github.com/openconfig/gnmi/proto/gnmi"
    15  )
    16  
    17  func stringToGNMIPath(path string) *pb.Path {
    18  	p, _ := gnmi.ParseGNMIElements(gnmi.SplitPath(path))
    19  	return p
    20  }
    21  
    22  func gnmiUpdate(path string, value *pb.TypedValue) *pb.Update {
    23  	return &pb.Update{
    24  		Path: stringToGNMIPath(path),
    25  		Val:  value,
    26  	}
    27  }
    28  
    29  func toPtr(val interface{}) interface{} {
    30  	switch tv := val.(type) {
    31  	case string:
    32  		return &tv
    33  	case int:
    34  		i64 := int64(tv)
    35  		return &i64
    36  	case bool:
    37  		return &tv
    38  	case float64:
    39  		return &tv
    40  	default:
    41  		return &tv
    42  	}
    43  }
    44  
    45  func TestDataConversion(t *testing.T) {
    46  	cases := []struct {
    47  		in   *pb.Notification
    48  		data []Data
    49  	}{
    50  		{
    51  			in: &pb.Notification{
    52  				Timestamp: 123,
    53  				Prefix:    stringToGNMIPath("foo"),
    54  				Update: []*pb.Update{
    55  					gnmiUpdate("String", &pb.TypedValue{Value: &pb.TypedValue_StringVal{
    56  						StringVal: "hello"}}),
    57  					gnmiUpdate("Int", &pb.TypedValue{Value: &pb.TypedValue_IntVal{
    58  						IntVal: -123}}),
    59  					gnmiUpdate("Bool", &pb.TypedValue{Value: &pb.TypedValue_BoolVal{
    60  						BoolVal: true}}),
    61  				}},
    62  			data: []Data{
    63  				Data{
    64  					Timestamp:   123,
    65  					DatasetID:   "0",
    66  					Path:        "/foo/String",
    67  					Key:         []byte("/String"),
    68  					KeyString:   toPtr("/String").(*string),
    69  					ValueString: toPtr("hello").(*string)},
    70  				Data{
    71  					Timestamp: 123,
    72  					DatasetID: "0",
    73  					Path:      "/foo/Int",
    74  					Key:       []byte("/Int"),
    75  					KeyString: toPtr("/Int").(*string),
    76  					ValueLong: toPtr(-123).(*int64)},
    77  				Data{
    78  					Timestamp: 123,
    79  					DatasetID: "0",
    80  					Path:      "/foo/Bool",
    81  					Key:       []byte("/Bool"),
    82  					KeyString: toPtr("/Bool").(*string),
    83  					ValueBool: toPtr(true).(*bool)},
    84  			},
    85  		},
    86  		{
    87  			in: &pb.Notification{
    88  				Timestamp: 234,
    89  				Prefix:    stringToGNMIPath("bar"),
    90  				Update: []*pb.Update{
    91  					gnmiUpdate("Decimal", &pb.TypedValue{Value: &pb.TypedValue_DecimalVal{
    92  						DecimalVal: &pb.Decimal64{Digits: -123, Precision: 2}}}),
    93  				}},
    94  			data: []Data{
    95  				Data{
    96  					Timestamp:   234,
    97  					DatasetID:   "0",
    98  					Path:        "/bar/Decimal",
    99  					Key:         []byte("/Decimal"),
   100  					KeyString:   toPtr("/Decimal").(*string),
   101  					ValueDouble: toPtr(-1.23).(*float64)},
   102  			},
   103  		},
   104  		{
   105  			in: &pb.Notification{
   106  				Timestamp: 345,
   107  				Prefix:    stringToGNMIPath("baz"),
   108  				Update: []*pb.Update{
   109  					gnmiUpdate("Leaflist", &pb.TypedValue{Value: &pb.TypedValue_LeaflistVal{
   110  						LeaflistVal: &pb.ScalarArray{Element: []*pb.TypedValue{}}}}),
   111  				}},
   112  			data: []Data{
   113  				Data{
   114  					Timestamp: 345,
   115  					DatasetID: "0",
   116  					Path:      "/baz/Leaflist",
   117  					Key:       []byte("/Leaflist"),
   118  					KeyString: toPtr("/Leaflist").(*string),
   119  					Value:     []*field{}},
   120  			},
   121  		},
   122  		{
   123  			in: &pb.Notification{
   124  				Timestamp: 345,
   125  				Prefix:    stringToGNMIPath("baz"),
   126  				Update: []*pb.Update{
   127  					gnmiUpdate("Leaflist", &pb.TypedValue{Value: &pb.TypedValue_LeaflistVal{
   128  						LeaflistVal: &pb.ScalarArray{Element: []*pb.TypedValue{
   129  							&pb.TypedValue{Value: &pb.TypedValue_StringVal{StringVal: "hello"}},
   130  							&pb.TypedValue{Value: &pb.TypedValue_IntVal{IntVal: -123}},
   131  							&pb.TypedValue{Value: &pb.TypedValue_BoolVal{BoolVal: true}},
   132  						}}}}),
   133  				}},
   134  			data: []Data{
   135  				Data{
   136  					Timestamp: 345,
   137  					DatasetID: "0",
   138  					Path:      "/baz/Leaflist",
   139  					Key:       []byte("/Leaflist"),
   140  					KeyString: toPtr("/Leaflist").(*string),
   141  					Value: []*field{
   142  						&field{String: toPtr("hello").(*string)},
   143  						&field{Long: toPtr(-123).(*int64)},
   144  						&field{Bool: toPtr(true).(*bool)}}},
   145  			},
   146  		},
   147  		{
   148  			// JsonVal -> ValueString
   149  			in: &pb.Notification{
   150  				Timestamp: 456,
   151  				Prefix:    stringToGNMIPath("foo"),
   152  				Update: []*pb.Update{gnmiUpdate("bar",
   153  					&pb.TypedValue{Value: &pb.TypedValue_JsonVal{
   154  						//JsonVal: []byte(`[ {"json": "val"}]`)}})}},
   155  						JsonVal: []byte("67")}})}},
   156  			data: []Data{
   157  				Data{
   158  					Timestamp:   456,
   159  					DatasetID:   "0",
   160  					Path:        "/foo/bar",
   161  					Key:         []byte("/bar"),
   162  					KeyString:   toPtr("/bar").(*string),
   163  					ValueDouble: toPtr(float64(67)).(*float64)},
   164  			},
   165  		},
   166  		{
   167  			// JsonIetfVal -> ValueString
   168  			in: &pb.Notification{
   169  				Timestamp: 456,
   170  				Prefix:    stringToGNMIPath("foo"),
   171  				Update: []*pb.Update{gnmiUpdate("bar",
   172  					&pb.TypedValue{Value: &pb.TypedValue_JsonIetfVal{
   173  						JsonIetfVal: []byte("67")}})}},
   174  			data: []Data{
   175  				Data{
   176  					Timestamp:   456,
   177  					DatasetID:   "0",
   178  					Path:        "/foo/bar",
   179  					Key:         []byte("/bar"),
   180  					KeyString:   toPtr("/bar").(*string),
   181  					ValueDouble: toPtr(float64(67)).(*float64)},
   182  			},
   183  		},
   184  	}
   185  	for _, tc := range cases {
   186  		maps, err := NotificationToMaps("0", tc.in)
   187  		if err != nil {
   188  			t.Fatalf("issue converting %v to data map. Err: %v", tc.in, err)
   189  		}
   190  		if len(maps) != len(tc.data) {
   191  			t.Fatalf("number of output notifications (%d) does not match expected %d",
   192  				len(maps), len(tc.data))
   193  		}
   194  		byteArr, err := json.Marshal(maps)
   195  		if err != nil {
   196  			t.Fatalf("error while trying to marshal map: %v", err)
   197  		}
   198  
   199  		data := []Data{}
   200  		json.Unmarshal(byteArr, &data)
   201  
   202  		if !reflect.DeepEqual(data, tc.data) {
   203  			gotPretty, _ := json.MarshalIndent(data, "", " ")
   204  			wantPretty, _ := json.MarshalIndent(tc.data, "", " ")
   205  			t.Fatalf("reflect struct array mismatch!\n Got: %+v\n Want: %+v",
   206  				string(gotPretty), string(wantPretty))
   207  		}
   208  	}
   209  }