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 }