operation_test.go 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. // Copyright (c) 2017 Arista Networks, Inc.
  2. // Use of this source code is governed by the Apache License 2.0
  3. // that can be found in the COPYING file.
  4. package gnmi
  5. import (
  6. "bytes"
  7. "io/ioutil"
  8. "os"
  9. "testing"
  10. "notabug.org/themusicgod1/goarista/test"
  11. "github.com/golang/protobuf/proto"
  12. "github.com/golang/protobuf/ptypes/any"
  13. pb "github.com/openconfig/gnmi/proto/gnmi"
  14. )
  15. func TestNewSetRequest(t *testing.T) {
  16. pathFoo := &pb.Path{
  17. Element: []string{"foo"},
  18. Elem: []*pb.PathElem{{Name: "foo"}},
  19. }
  20. pathCli := &pb.Path{
  21. Origin: "cli",
  22. }
  23. testCases := map[string]struct {
  24. setOps []*Operation
  25. exp pb.SetRequest
  26. }{
  27. "delete": {
  28. setOps: []*Operation{{Type: "delete", Path: []string{"foo"}}},
  29. exp: pb.SetRequest{Delete: []*pb.Path{pathFoo}},
  30. },
  31. "update": {
  32. setOps: []*Operation{{Type: "update", Path: []string{"foo"}, Val: "true"}},
  33. exp: pb.SetRequest{
  34. Update: []*pb.Update{{
  35. Path: pathFoo,
  36. Val: &pb.TypedValue{
  37. Value: &pb.TypedValue_JsonIetfVal{JsonIetfVal: []byte("true")}},
  38. }},
  39. },
  40. },
  41. "replace": {
  42. setOps: []*Operation{{Type: "replace", Path: []string{"foo"}, Val: "true"}},
  43. exp: pb.SetRequest{
  44. Replace: []*pb.Update{{
  45. Path: pathFoo,
  46. Val: &pb.TypedValue{
  47. Value: &pb.TypedValue_JsonIetfVal{JsonIetfVal: []byte("true")}},
  48. }},
  49. },
  50. },
  51. "cli-replace": {
  52. setOps: []*Operation{{Type: "replace", Path: []string{"cli"},
  53. Val: "hostname foo\nip routing"}},
  54. exp: pb.SetRequest{
  55. Replace: []*pb.Update{{
  56. Path: pathCli,
  57. Val: &pb.TypedValue{
  58. Value: &pb.TypedValue_AsciiVal{AsciiVal: "hostname foo\nip routing"}},
  59. }},
  60. },
  61. },
  62. }
  63. for name, tc := range testCases {
  64. t.Run(name, func(t *testing.T) {
  65. got, err := newSetRequest(tc.setOps)
  66. if err != nil {
  67. t.Fatal(err)
  68. }
  69. if diff := test.Diff(tc.exp, *got); diff != "" {
  70. t.Errorf("unexpected diff: %s", diff)
  71. }
  72. })
  73. }
  74. }
  75. func TestStrUpdateVal(t *testing.T) {
  76. anyBytes, err := proto.Marshal(&pb.ModelData{Name: "foobar"})
  77. if err != nil {
  78. t.Fatal(err)
  79. }
  80. anyMessage := &any.Any{TypeUrl: "gnmi/ModelData", Value: anyBytes}
  81. anyString := proto.CompactTextString(anyMessage)
  82. for name, tc := range map[string]struct {
  83. update *pb.Update
  84. exp string
  85. }{
  86. "JSON Value": {
  87. update: &pb.Update{
  88. Value: &pb.Value{
  89. Value: []byte(`{"foo":"bar"}`),
  90. Type: pb.Encoding_JSON}},
  91. exp: `{
  92. "foo": "bar"
  93. }`,
  94. },
  95. "JSON_IETF Value": {
  96. update: &pb.Update{
  97. Value: &pb.Value{
  98. Value: []byte(`{"foo":"bar"}`),
  99. Type: pb.Encoding_JSON_IETF}},
  100. exp: `{
  101. "foo": "bar"
  102. }`,
  103. },
  104. "BYTES Value": {
  105. update: &pb.Update{
  106. Value: &pb.Value{
  107. Value: []byte{0xde, 0xad},
  108. Type: pb.Encoding_BYTES}},
  109. exp: "3q0=",
  110. },
  111. "PROTO Value": {
  112. update: &pb.Update{
  113. Value: &pb.Value{
  114. Value: []byte{0xde, 0xad},
  115. Type: pb.Encoding_PROTO}},
  116. exp: "3q0=",
  117. },
  118. "ASCII Value": {
  119. update: &pb.Update{
  120. Value: &pb.Value{
  121. Value: []byte("foobar"),
  122. Type: pb.Encoding_ASCII}},
  123. exp: "foobar",
  124. },
  125. "INVALID Value": {
  126. update: &pb.Update{
  127. Value: &pb.Value{
  128. Value: []byte("foobar"),
  129. Type: pb.Encoding(42)}},
  130. exp: "foobar",
  131. },
  132. "StringVal": {
  133. update: &pb.Update{Val: &pb.TypedValue{
  134. Value: &pb.TypedValue_StringVal{StringVal: "foobar"}}},
  135. exp: "foobar",
  136. },
  137. "IntVal": {
  138. update: &pb.Update{Val: &pb.TypedValue{
  139. Value: &pb.TypedValue_IntVal{IntVal: -42}}},
  140. exp: "-42",
  141. },
  142. "UintVal": {
  143. update: &pb.Update{Val: &pb.TypedValue{
  144. Value: &pb.TypedValue_UintVal{UintVal: 42}}},
  145. exp: "42",
  146. },
  147. "BoolVal": {
  148. update: &pb.Update{Val: &pb.TypedValue{
  149. Value: &pb.TypedValue_BoolVal{BoolVal: true}}},
  150. exp: "true",
  151. },
  152. "BytesVal": {
  153. update: &pb.Update{Val: &pb.TypedValue{
  154. Value: &pb.TypedValue_BytesVal{BytesVal: []byte{0xde, 0xad}}}},
  155. exp: "3q0=",
  156. },
  157. "FloatVal": {
  158. update: &pb.Update{Val: &pb.TypedValue{
  159. Value: &pb.TypedValue_FloatVal{FloatVal: 3.14}}},
  160. exp: "3.14",
  161. },
  162. "DecimalVal": {
  163. update: &pb.Update{Val: &pb.TypedValue{
  164. Value: &pb.TypedValue_DecimalVal{
  165. DecimalVal: &pb.Decimal64{Digits: 314, Precision: 2},
  166. }}},
  167. exp: "3.14",
  168. },
  169. "LeafListVal": {
  170. update: &pb.Update{Val: &pb.TypedValue{
  171. Value: &pb.TypedValue_LeaflistVal{
  172. LeaflistVal: &pb.ScalarArray{Element: []*pb.TypedValue{
  173. &pb.TypedValue{Value: &pb.TypedValue_BoolVal{BoolVal: true}},
  174. &pb.TypedValue{Value: &pb.TypedValue_AsciiVal{AsciiVal: "foobar"}},
  175. }},
  176. }}},
  177. exp: "[true, foobar]",
  178. },
  179. "AnyVal": {
  180. update: &pb.Update{Val: &pb.TypedValue{
  181. Value: &pb.TypedValue_AnyVal{AnyVal: anyMessage}}},
  182. exp: anyString,
  183. },
  184. "JsonVal": {
  185. update: &pb.Update{Val: &pb.TypedValue{
  186. Value: &pb.TypedValue_JsonVal{JsonVal: []byte(`{"foo":"bar"}`)}}},
  187. exp: `{
  188. "foo": "bar"
  189. }`,
  190. },
  191. "JsonIetfVal": {
  192. update: &pb.Update{Val: &pb.TypedValue{
  193. Value: &pb.TypedValue_JsonIetfVal{JsonIetfVal: []byte(`{"foo":"bar"}`)}}},
  194. exp: `{
  195. "foo": "bar"
  196. }`,
  197. },
  198. "AsciiVal": {
  199. update: &pb.Update{Val: &pb.TypedValue{
  200. Value: &pb.TypedValue_AsciiVal{AsciiVal: "foobar"}}},
  201. exp: "foobar",
  202. },
  203. } {
  204. t.Run(name, func(t *testing.T) {
  205. got := StrUpdateVal(tc.update)
  206. if got != tc.exp {
  207. t.Errorf("Expected: %q Got: %q", tc.exp, got)
  208. }
  209. })
  210. }
  211. }
  212. func TestExtractJSON(t *testing.T) {
  213. jsonFile, err := ioutil.TempFile("", "extractJSON")
  214. if err != nil {
  215. t.Fatal(err)
  216. }
  217. defer os.Remove(jsonFile.Name())
  218. if _, err := jsonFile.Write([]byte(`"jsonFile"`)); err != nil {
  219. jsonFile.Close()
  220. t.Fatal(err)
  221. }
  222. if err := jsonFile.Close(); err != nil {
  223. t.Fatal(err)
  224. }
  225. for val, exp := range map[string][]byte{
  226. jsonFile.Name(): []byte(`"jsonFile"`),
  227. "foobar": []byte(`"foobar"`),
  228. `"foobar"`: []byte(`"foobar"`),
  229. "Val: true": []byte(`"Val: true"`),
  230. "host42": []byte(`"host42"`),
  231. "42": []byte("42"),
  232. "-123.43": []byte("-123.43"),
  233. "0xFFFF": []byte("0xFFFF"),
  234. // Int larger than can fit in 32 bits should be quoted
  235. "0x8000000000": []byte(`"0x8000000000"`),
  236. "-0x8000000000": []byte(`"-0x8000000000"`),
  237. "true": []byte("true"),
  238. "false": []byte("false"),
  239. "null": []byte("null"),
  240. "{true: 42}": []byte("{true: 42}"),
  241. "[]": []byte("[]"),
  242. } {
  243. t.Run(val, func(t *testing.T) {
  244. got := extractJSON(val)
  245. if !bytes.Equal(exp, got) {
  246. t.Errorf("Unexpected diff. Expected: %q Got: %q", exp, got)
  247. }
  248. })
  249. }
  250. }