You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

221 lines
5.2 KiB

  1. package rpcserver
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "net/http"
  6. "strconv"
  7. "testing"
  8. "github.com/stretchr/testify/assert"
  9. amino "github.com/tendermint/go-amino"
  10. cmn "github.com/tendermint/tendermint/libs/common"
  11. )
  12. func TestParseJSONMap(t *testing.T) {
  13. assert := assert.New(t)
  14. input := []byte(`{"value":"1234","height":22}`)
  15. // naive is float,string
  16. var p1 map[string]interface{}
  17. err := json.Unmarshal(input, &p1)
  18. if assert.Nil(err) {
  19. h, ok := p1["height"].(float64)
  20. if assert.True(ok, "%#v", p1["height"]) {
  21. assert.EqualValues(22, h)
  22. }
  23. v, ok := p1["value"].(string)
  24. if assert.True(ok, "%#v", p1["value"]) {
  25. assert.EqualValues("1234", v)
  26. }
  27. }
  28. // preloading map with values doesn't help
  29. tmp := 0
  30. p2 := map[string]interface{}{
  31. "value": &cmn.HexBytes{},
  32. "height": &tmp,
  33. }
  34. err = json.Unmarshal(input, &p2)
  35. if assert.Nil(err) {
  36. h, ok := p2["height"].(float64)
  37. if assert.True(ok, "%#v", p2["height"]) {
  38. assert.EqualValues(22, h)
  39. }
  40. v, ok := p2["value"].(string)
  41. if assert.True(ok, "%#v", p2["value"]) {
  42. assert.EqualValues("1234", v)
  43. }
  44. }
  45. // preload here with *pointers* to the desired types
  46. // struct has unknown types, but hard-coded keys
  47. tmp = 0
  48. p3 := struct {
  49. Value interface{} `json:"value"`
  50. Height interface{} `json:"height"`
  51. }{
  52. Height: &tmp,
  53. Value: &cmn.HexBytes{},
  54. }
  55. err = json.Unmarshal(input, &p3)
  56. if assert.Nil(err) {
  57. h, ok := p3.Height.(*int)
  58. if assert.True(ok, "%#v", p3.Height) {
  59. assert.Equal(22, *h)
  60. }
  61. v, ok := p3.Value.(*cmn.HexBytes)
  62. if assert.True(ok, "%#v", p3.Value) {
  63. assert.EqualValues([]byte{0x12, 0x34}, *v)
  64. }
  65. }
  66. // simplest solution, but hard-coded
  67. p4 := struct {
  68. Value cmn.HexBytes `json:"value"`
  69. Height int `json:"height"`
  70. }{}
  71. err = json.Unmarshal(input, &p4)
  72. if assert.Nil(err) {
  73. assert.EqualValues(22, p4.Height)
  74. assert.EqualValues([]byte{0x12, 0x34}, p4.Value)
  75. }
  76. // so, let's use this trick...
  77. // dynamic keys on map, and we can deserialize to the desired types
  78. var p5 map[string]*json.RawMessage
  79. err = json.Unmarshal(input, &p5)
  80. if assert.Nil(err) {
  81. var h int
  82. err = json.Unmarshal(*p5["height"], &h)
  83. if assert.Nil(err) {
  84. assert.Equal(22, h)
  85. }
  86. var v cmn.HexBytes
  87. err = json.Unmarshal(*p5["value"], &v)
  88. if assert.Nil(err) {
  89. assert.Equal(cmn.HexBytes{0x12, 0x34}, v)
  90. }
  91. }
  92. }
  93. func TestParseJSONArray(t *testing.T) {
  94. assert := assert.New(t)
  95. input := []byte(`["1234",22]`)
  96. // naive is float,string
  97. var p1 []interface{}
  98. err := json.Unmarshal(input, &p1)
  99. if assert.Nil(err) {
  100. v, ok := p1[0].(string)
  101. if assert.True(ok, "%#v", p1[0]) {
  102. assert.EqualValues("1234", v)
  103. }
  104. h, ok := p1[1].(float64)
  105. if assert.True(ok, "%#v", p1[1]) {
  106. assert.EqualValues(22, h)
  107. }
  108. }
  109. // preloading map with values helps here (unlike map - p2 above)
  110. tmp := 0
  111. p2 := []interface{}{&cmn.HexBytes{}, &tmp}
  112. err = json.Unmarshal(input, &p2)
  113. if assert.Nil(err) {
  114. v, ok := p2[0].(*cmn.HexBytes)
  115. if assert.True(ok, "%#v", p2[0]) {
  116. assert.EqualValues([]byte{0x12, 0x34}, *v)
  117. }
  118. h, ok := p2[1].(*int)
  119. if assert.True(ok, "%#v", p2[1]) {
  120. assert.EqualValues(22, *h)
  121. }
  122. }
  123. }
  124. func TestParseJSONRPC(t *testing.T) {
  125. assert := assert.New(t)
  126. demo := func(height int, name string) {}
  127. call := NewRPCFunc(demo, "height,name")
  128. cdc := amino.NewCodec()
  129. cases := []struct {
  130. raw string
  131. height int64
  132. name string
  133. fail bool
  134. }{
  135. // should parse
  136. {`["7", "flew"]`, 7, "flew", false},
  137. {`{"name": "john", "height": "22"}`, 22, "john", false},
  138. // defaults
  139. {`{"name": "solo", "unused": "stuff"}`, 0, "solo", false},
  140. // should fail - wrong types/length
  141. {`["flew", 7]`, 0, "", true},
  142. {`[7,"flew",100]`, 0, "", true},
  143. {`{"name": -12, "height": "fred"}`, 0, "", true},
  144. }
  145. for idx, tc := range cases {
  146. i := strconv.Itoa(idx)
  147. data := []byte(tc.raw)
  148. vals, err := jsonParamsToArgs(call, cdc, data, 0)
  149. if tc.fail {
  150. assert.NotNil(err, i)
  151. } else {
  152. assert.Nil(err, "%s: %+v", i, err)
  153. if assert.Equal(2, len(vals), i) {
  154. assert.Equal(tc.height, vals[0].Int(), i)
  155. assert.Equal(tc.name, vals[1].String(), i)
  156. }
  157. }
  158. }
  159. }
  160. func TestParseURI(t *testing.T) {
  161. demo := func(height int, name string) {}
  162. call := NewRPCFunc(demo, "height,name")
  163. cdc := amino.NewCodec()
  164. cases := []struct {
  165. raw []string
  166. height int64
  167. name string
  168. fail bool
  169. }{
  170. // can parse numbers unquoted and strings quoted
  171. {[]string{"7", `"flew"`}, 7, "flew", false},
  172. {[]string{"22", `"john"`}, 22, "john", false},
  173. {[]string{"-10", `"bob"`}, -10, "bob", false},
  174. // can parse numbers quoted, too
  175. {[]string{`"7"`, `"flew"`}, 7, "flew", false},
  176. {[]string{`"-10"`, `"bob"`}, -10, "bob", false},
  177. // cant parse strings uquoted
  178. {[]string{`"-10"`, `bob`}, -10, "bob", true},
  179. }
  180. for idx, tc := range cases {
  181. i := strconv.Itoa(idx)
  182. // data := []byte(tc.raw)
  183. url := fmt.Sprintf(
  184. "test.com/method?height=%v&name=%v",
  185. tc.raw[0], tc.raw[1])
  186. req, err := http.NewRequest("GET", url, nil)
  187. assert.NoError(t, err)
  188. vals, err := httpParamsToArgs(call, cdc, req)
  189. if tc.fail {
  190. assert.NotNil(t, err, i)
  191. } else {
  192. assert.Nil(t, err, "%s: %+v", i, err)
  193. if assert.Equal(t, 2, len(vals), i) {
  194. assert.Equal(t, tc.height, vals[0].Int(), i)
  195. assert.Equal(t, tc.name, vals[1].String(), i)
  196. }
  197. }
  198. }
  199. }