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.

503 lines
17 KiB

  1. package jsonrpc
  2. import (
  3. "fmt"
  4. "io/ioutil"
  5. "net/http"
  6. "net/http/httptest"
  7. "net/url"
  8. "os"
  9. "testing"
  10. "time"
  11. "github.com/onsi/gomega"
  12. )
  13. // needed to retrieve requests that arrived at httpServer for further investigation
  14. var requestChan = make(chan *RequestData, 1)
  15. // the request datastructure that can be retrieved for test assertions
  16. type RequestData struct {
  17. request *http.Request
  18. body string
  19. }
  20. // set the response body the httpServer should return for the next request
  21. var responseBody = ""
  22. var httpServer *httptest.Server
  23. // start the testhttp server and stop it when tests are finished
  24. func TestMain(m *testing.M) {
  25. httpServer = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  26. data, _ := ioutil.ReadAll(r.Body)
  27. defer r.Body.Close()
  28. // put request and body to channel for the client to investigate them
  29. requestChan <- &RequestData{r, string(data)}
  30. fmt.Fprintf(w, responseBody)
  31. }))
  32. defer httpServer.Close()
  33. os.Exit(m.Run())
  34. }
  35. func TestSimpleRpcCallHeaderCorrect(t *testing.T) {
  36. gomega.RegisterTestingT(t)
  37. rpcClient := NewRPCClient(httpServer.URL)
  38. rpcClient.Call("add", 1, 2)
  39. req := (<-requestChan).request
  40. gomega.Expect(req.Method).To(gomega.Equal("POST"))
  41. gomega.Expect(req.Header.Get("Content-Type")).To(gomega.Equal("application/json"))
  42. gomega.Expect(req.Header.Get("Accept")).To(gomega.Equal("application/json"))
  43. }
  44. // test if the structure of an rpc request is built correctly validate the data that arrived on the server
  45. func TestRpcJsonRequestStruct(t *testing.T) {
  46. gomega.RegisterTestingT(t)
  47. rpcClient := NewRPCClient(httpServer.URL)
  48. rpcClient.SetAutoIncrementID(false)
  49. rpcClient.Call("add", 1, 2)
  50. body := (<-requestChan).body
  51. gomega.Expect(body).To(gomega.Equal(`{"jsonrpc":"2.0","method":"add","params":[1,2],"id":0}`))
  52. rpcClient.Call("setName", "alex")
  53. body = (<-requestChan).body
  54. gomega.Expect(body).To(gomega.Equal(`{"jsonrpc":"2.0","method":"setName","params":["alex"],"id":0}`))
  55. rpcClient.Call("setPerson", "alex", 33, "Germany")
  56. body = (<-requestChan).body
  57. gomega.Expect(body).To(gomega.Equal(`{"jsonrpc":"2.0","method":"setPerson","params":["alex",33,"Germany"],"id":0}`))
  58. rpcClient.Call("setPersonObject", Person{"alex", 33, "Germany"})
  59. body = (<-requestChan).body
  60. gomega.Expect(body).To(gomega.Equal(`{"jsonrpc":"2.0","method":"setPersonObject","params":[{"name":"alex","age":33,"country":"Germany"}],"id":0}`))
  61. rpcClient.Call("getDate")
  62. body = (<-requestChan).body
  63. gomega.Expect(body).To(gomega.Equal(`{"jsonrpc":"2.0","method":"getDate","id":0}`))
  64. rpcClient.Call("setAnonymStruct", struct {
  65. Name string `json:"name"`
  66. Age int `json:"age"`
  67. }{"Alex", 33})
  68. body = (<-requestChan).body
  69. gomega.Expect(body).To(gomega.Equal(`{"jsonrpc":"2.0","method":"setAnonymStruct","params":[{"name":"Alex","age":33}],"id":0}`))
  70. }
  71. // test if the structure of an rpc request is built correctly validate the data that arrived on the server
  72. func TestRpcJsonRequestStructWithNamedParams(t *testing.T) {
  73. gomega.RegisterTestingT(t)
  74. rpcClient := NewRPCClient(httpServer.URL)
  75. rpcClient.SetAutoIncrementID(false)
  76. rpcClient.CallNamed("myMethod", map[string]interface{}{
  77. "arrayOfInts": []int{1, 2, 3},
  78. "arrayOfStrings": []string{"A", "B", "C"},
  79. "bool": true,
  80. "int": 1,
  81. "number": 1.2,
  82. "string": "boogaloo",
  83. "subObject": map[string]interface{}{"foo": "bar"},
  84. })
  85. body := (<-requestChan).body
  86. gomega.Expect(body).To(gomega.Equal(`{"jsonrpc":"2.0","method":"myMethod","params":{"arrayOfInts":[1,2,3],"arrayOfStrings":["A","B","C"],"bool":true,"int":1,"number":1.2,"string":"boogaloo","subObject":{"foo":"bar"}},"id":0}`))
  87. }
  88. func TestRpcJsonResponseStruct(t *testing.T) {
  89. gomega.RegisterTestingT(t)
  90. rpcClient := NewRPCClient(httpServer.URL)
  91. rpcClient.SetAutoIncrementID(false)
  92. responseBody = `{"jsonrpc":"2.0","result":3,"id":0}`
  93. response, _ := rpcClient.Call("test") // Call param does not matter, since response does not depend on request
  94. <-requestChan
  95. var int64Result int64
  96. int64Result, _ = response.GetInt64()
  97. gomega.Expect(int64Result).To(gomega.Equal(int64(3)))
  98. responseBody = `{"jsonrpc":"2.0","result":3,"id":0}`
  99. response, _ = rpcClient.Call("test") // Call param does not matter, since response does not depend on request
  100. <-requestChan
  101. var intResult int
  102. intResult, _ = response.GetInt()
  103. gomega.Expect(intResult).To(gomega.Equal(3))
  104. responseBody = `{"jsonrpc":"2.0","result":3.3,"id":0}`
  105. response, _ = rpcClient.Call("test") // Call param does not matter, since response does not depend on request
  106. <-requestChan
  107. _, err := response.GetInt()
  108. gomega.Expect(err).To(gomega.Not(gomega.Equal(nil)))
  109. responseBody = `{"jsonrpc":"2.0","result":false,"id":0}`
  110. response, _ = rpcClient.Call("test") // Call param does not matter, since response does not depend on request
  111. <-requestChan
  112. _, err = response.GetInt()
  113. gomega.Expect(err).To(gomega.Not(gomega.Equal(nil)))
  114. responseBody = `{"jsonrpc":"2.0","result": 3.7,"id":0}`
  115. response, _ = rpcClient.Call("test") // Call param does not matter, since response does not depend on request
  116. <-requestChan
  117. var float64Result float64
  118. float64Result, _ = response.GetFloat64()
  119. gomega.Expect(float64Result).To(gomega.Equal(3.7))
  120. responseBody = `{"jsonrpc":"2.0","result": "1.3","id":0}`
  121. response, _ = rpcClient.Call("test") // Call param does not matter, since response does not depend on request
  122. <-requestChan
  123. _, err = response.GetFloat64()
  124. gomega.Expect(err).To(gomega.Not(gomega.Equal(nil)))
  125. responseBody = `{"jsonrpc":"2.0","result": true,"id":0}`
  126. response, _ = rpcClient.Call("test") // Call param does not matter, since response does not depend on request
  127. <-requestChan
  128. var boolResult bool
  129. boolResult, _ = response.GetBool()
  130. gomega.Expect(boolResult).To(gomega.Equal(true))
  131. responseBody = `{"jsonrpc":"2.0","result": 0,"id":0}`
  132. response, _ = rpcClient.Call("test") // Call param does not matter, since response does not depend on request
  133. <-requestChan
  134. _, err = response.GetBool()
  135. gomega.Expect(err).To(gomega.Not(gomega.Equal(nil)))
  136. responseBody = `{"jsonrpc":"2.0","result": "alex","id":0}`
  137. response, _ = rpcClient.Call("test") // Call param does not matter, since response does not depend on request
  138. <-requestChan
  139. var stringResult string
  140. stringResult, _ = response.GetString()
  141. gomega.Expect(stringResult).To(gomega.Equal("alex"))
  142. responseBody = `{"jsonrpc":"2.0","result": 123,"id":0}`
  143. response, _ = rpcClient.Call("test") // Call param does not matter, since response does not depend on request
  144. <-requestChan
  145. _, err = response.GetString()
  146. gomega.Expect(err).To(gomega.Not(gomega.Equal(nil)))
  147. responseBody = `{"jsonrpc":"2.0","result": {"name": "alex", "age": 33, "country": "Germany"},"id":0}`
  148. response, _ = rpcClient.Call("test") // Call param does not matter, since response does not depend on request
  149. <-requestChan
  150. var person Person
  151. response.GetObject(&person)
  152. gomega.Expect(person).To(gomega.Equal(Person{"alex", 33, "Germany"}))
  153. responseBody = `{"jsonrpc":"2.0","result": 3,"id":0}`
  154. response, _ = rpcClient.Call("test") // Call param does not matter, since response does not depend on request
  155. <-requestChan
  156. var number int
  157. response.GetObject(&number)
  158. gomega.Expect(int(number)).To(gomega.Equal(3))
  159. responseBody = `{"jsonrpc":"2.0","result": [{"name": "alex", "age": 33, "country": "Germany"}, {"name": "Ferolaz", "age": 333, "country": "Azeroth"}],"id":0}`
  160. response, _ = rpcClient.Call("test") // Call param does not matter, since response does not depend on request
  161. <-requestChan
  162. var personArray = []Person{}
  163. response.GetObject(&personArray)
  164. gomega.Expect(personArray).To(gomega.Equal([]Person{{"alex", 33, "Germany"}, {"Ferolaz", 333, "Azeroth"}}))
  165. responseBody = `{"jsonrpc":"2.0","result": [1, 2, 3],"id":0}`
  166. response, _ = rpcClient.Call("test") // Call param does not matter, since response does not depend on request
  167. <-requestChan
  168. var intArray []int
  169. response.GetObject(&intArray)
  170. gomega.Expect(intArray).To(gomega.Equal([]int{1, 2, 3}))
  171. }
  172. func TestResponseErrorWorks(t *testing.T) {
  173. gomega.RegisterTestingT(t)
  174. rpcClient := NewRPCClient(httpServer.URL)
  175. rpcClient.SetAutoIncrementID(false)
  176. responseBody = `{"jsonrpc":"2.0","error": {"code": -123, "message": "something wrong"},"id":0}`
  177. response, _ := rpcClient.Call("test") // Call param does not matter, since response does not depend on request
  178. <-requestChan
  179. gomega.Expect(*response.Error).To(gomega.Equal(RPCError{-123, "something wrong", nil}))
  180. }
  181. func TestNotifyWorks(t *testing.T) {
  182. gomega.RegisterTestingT(t)
  183. rpcClient := NewRPCClient(httpServer.URL)
  184. rpcClient.Notification("test", 10)
  185. <-requestChan
  186. rpcClient.Notification("test", Person{"alex", 33, "Germany"})
  187. <-requestChan
  188. rpcClient.Notification("test", 10, 20, "alex")
  189. body := (<-requestChan).body
  190. gomega.Expect(body).To(gomega.Equal(`{"jsonrpc":"2.0","method":"test","params":[10,20,"alex"]}`))
  191. }
  192. func TestNewRPCRequestObject(t *testing.T) {
  193. gomega.RegisterTestingT(t)
  194. rpcClient := NewRPCClient(httpServer.URL)
  195. req := rpcClient.NewRPCRequestObject("add", 1, 2)
  196. gomega.Expect(req).To(gomega.Equal(&RPCRequest{
  197. JSONRPC: "2.0",
  198. ID: 0,
  199. Method: "add",
  200. Params: []interface{}{1, 2},
  201. }))
  202. req = rpcClient.NewRPCRequestObject("getDate")
  203. gomega.Expect(req).To(gomega.Equal(&RPCRequest{
  204. JSONRPC: "2.0",
  205. ID: 1,
  206. Method: "getDate",
  207. Params: nil,
  208. }))
  209. req = rpcClient.NewRPCRequestObject("getPerson", Person{"alex", 33, "germany"})
  210. gomega.Expect(req).To(gomega.Equal(&RPCRequest{
  211. JSONRPC: "2.0",
  212. ID: 2,
  213. Method: "getPerson",
  214. Params: []interface{}{Person{"alex", 33, "germany"}},
  215. }))
  216. }
  217. func TestNewRPCNotificationObject(t *testing.T) {
  218. gomega.RegisterTestingT(t)
  219. rpcClient := NewRPCClient(httpServer.URL)
  220. req := rpcClient.NewRPCNotificationObject("add", 1, 2)
  221. gomega.Expect(req).To(gomega.Equal(&RPCNotification{
  222. JSONRPC: "2.0",
  223. Method: "add",
  224. Params: []interface{}{1, 2},
  225. }))
  226. req = rpcClient.NewRPCNotificationObject("getDate")
  227. gomega.Expect(req).To(gomega.Equal(&RPCNotification{
  228. JSONRPC: "2.0",
  229. Method: "getDate",
  230. Params: nil,
  231. }))
  232. req = rpcClient.NewRPCNotificationObject("getPerson", Person{"alex", 33, "germany"})
  233. gomega.Expect(req).To(gomega.Equal(&RPCNotification{
  234. JSONRPC: "2.0",
  235. Method: "getPerson",
  236. Params: []interface{}{Person{"alex", 33, "germany"}},
  237. }))
  238. }
  239. func TestBatchRequestWorks(t *testing.T) {
  240. gomega.RegisterTestingT(t)
  241. rpcClient := NewRPCClient(httpServer.URL)
  242. rpcClient.SetCustomHeader("Test", "test")
  243. req1 := rpcClient.NewRPCRequestObject("test1", "alex")
  244. rpcClient.Batch(req1)
  245. req := <-requestChan
  246. body := req.body
  247. gomega.Expect(req.request.Header.Get("Test")).To(gomega.Equal("test"))
  248. gomega.Expect(body).To(gomega.Equal(`[{"jsonrpc":"2.0","method":"test1","params":["alex"],"id":0}]`))
  249. notify1 := rpcClient.NewRPCNotificationObject("test2", "alex")
  250. rpcClient.Batch(notify1)
  251. body = (<-requestChan).body
  252. gomega.Expect(body).To(gomega.Equal(`[{"jsonrpc":"2.0","method":"test2","params":["alex"]}]`))
  253. rpcClient.Batch(req1, notify1)
  254. body = (<-requestChan).body
  255. gomega.Expect(body).To(gomega.Equal(`[{"jsonrpc":"2.0","method":"test1","params":["alex"],"id":0},{"jsonrpc":"2.0","method":"test2","params":["alex"]}]`))
  256. requests := []interface{}{req1, notify1}
  257. rpcClient.Batch(requests...)
  258. body = (<-requestChan).body
  259. gomega.Expect(body).To(gomega.Equal(`[{"jsonrpc":"2.0","method":"test1","params":["alex"],"id":0},{"jsonrpc":"2.0","method":"test2","params":["alex"]}]`))
  260. invalid := &Person{"alex", 33, "germany"}
  261. _, err := rpcClient.Batch(invalid, notify1)
  262. gomega.Expect(err).To(gomega.Not(gomega.Equal(nil)))
  263. }
  264. func TestBatchResponseWorks(t *testing.T) {
  265. gomega.RegisterTestingT(t)
  266. rpcClient := NewRPCClient(httpServer.URL)
  267. responseBody = `[{"jsonrpc":"2.0","result": 1,"id":0},{"jsonrpc":"2.0","result": 2,"id":1},{"jsonrpc":"2.0","result": 3,"id":3}]`
  268. req1 := rpcClient.NewRPCRequestObject("test1", 1)
  269. req2 := rpcClient.NewRPCRequestObject("test2", 2)
  270. req3 := rpcClient.NewRPCRequestObject("test3", 3)
  271. responses, _ := rpcClient.Batch(req1, req2, req3)
  272. <-requestChan
  273. resp2, _ := responses.GetResponseOf(req2)
  274. res2, _ := resp2.GetInt()
  275. gomega.Expect(res2).To(gomega.Equal(2))
  276. }
  277. func TestIDIncremtWorks(t *testing.T) {
  278. gomega.RegisterTestingT(t)
  279. rpcClient := NewRPCClient(httpServer.URL)
  280. rpcClient.SetAutoIncrementID(true) // default
  281. rpcClient.Call("test1", 1, 2)
  282. body := (<-requestChan).body
  283. gomega.Expect(body).To(gomega.Equal(`{"jsonrpc":"2.0","method":"test1","params":[1,2],"id":0}`))
  284. rpcClient.Call("test2", 1, 2)
  285. body = (<-requestChan).body
  286. gomega.Expect(body).To(gomega.Equal(`{"jsonrpc":"2.0","method":"test2","params":[1,2],"id":1}`))
  287. rpcClient.SetNextID(10)
  288. rpcClient.Call("test3", 1, 2)
  289. body = (<-requestChan).body
  290. gomega.Expect(body).To(gomega.Equal(`{"jsonrpc":"2.0","method":"test3","params":[1,2],"id":10}`))
  291. rpcClient.Call("test4", 1, 2)
  292. body = (<-requestChan).body
  293. gomega.Expect(body).To(gomega.Equal(`{"jsonrpc":"2.0","method":"test4","params":[1,2],"id":11}`))
  294. rpcClient.SetAutoIncrementID(false)
  295. rpcClient.Call("test5", 1, 2)
  296. body = (<-requestChan).body
  297. gomega.Expect(body).To(gomega.Equal(`{"jsonrpc":"2.0","method":"test5","params":[1,2],"id":12}`))
  298. rpcClient.Call("test6", 1, 2)
  299. body = (<-requestChan).body
  300. gomega.Expect(body).To(gomega.Equal(`{"jsonrpc":"2.0","method":"test6","params":[1,2],"id":12}`))
  301. }
  302. func TestRequestIDUpdateWorks(t *testing.T) {
  303. gomega.RegisterTestingT(t)
  304. rpcClient := NewRPCClient(httpServer.URL)
  305. rpcClient.SetAutoIncrementID(true) // default
  306. req1 := rpcClient.NewRPCRequestObject("test", 1, 2, 3)
  307. req2 := rpcClient.NewRPCRequestObject("test", 1, 2, 3)
  308. gomega.Expect(int(req1.ID)).To(gomega.Equal(0))
  309. gomega.Expect(int(req2.ID)).To(gomega.Equal(1))
  310. rpcClient.UpdateRequestID(req1)
  311. rpcClient.UpdateRequestID(req2)
  312. gomega.Expect(int(req1.ID)).To(gomega.Equal(2))
  313. gomega.Expect(int(req2.ID)).To(gomega.Equal(3))
  314. rpcClient.UpdateRequestID(req2)
  315. rpcClient.UpdateRequestID(req1)
  316. gomega.Expect(int(req1.ID)).To(gomega.Equal(5))
  317. gomega.Expect(int(req2.ID)).To(gomega.Equal(4))
  318. rpcClient.UpdateRequestID(req1)
  319. rpcClient.UpdateRequestID(req1)
  320. gomega.Expect(int(req1.ID)).To(gomega.Equal(7))
  321. gomega.Expect(int(req2.ID)).To(gomega.Equal(4))
  322. rpcClient.SetAutoIncrementID(false)
  323. rpcClient.UpdateRequestID(req2)
  324. rpcClient.UpdateRequestID(req1)
  325. gomega.Expect(int(req1.ID)).To(gomega.Equal(8))
  326. gomega.Expect(int(req2.ID)).To(gomega.Equal(8))
  327. rpcClient.SetAutoIncrementID(false)
  328. }
  329. func TestBasicAuthentication(t *testing.T) {
  330. gomega.RegisterTestingT(t)
  331. rpcClient := NewRPCClient(httpServer.URL)
  332. rpcClient.SetBasicAuth("alex", "secret")
  333. rpcClient.Call("add", 1, 2)
  334. req := (<-requestChan).request
  335. gomega.Expect(req.Header.Get("Authorization")).To(gomega.Equal("Basic YWxleDpzZWNyZXQ="))
  336. rpcClient.SetBasicAuth("", "")
  337. rpcClient.Call("add", 1, 2)
  338. req = (<-requestChan).request
  339. gomega.Expect(req.Header.Get("Authorization")).NotTo(gomega.Equal("Basic YWxleDpzZWNyZXQ="))
  340. }
  341. func TestCustomHeaders(t *testing.T) {
  342. gomega.RegisterTestingT(t)
  343. rpcClient := NewRPCClient(httpServer.URL)
  344. rpcClient.SetCustomHeader("Test", "success")
  345. rpcClient.Call("add", 1, 2)
  346. req := (<-requestChan).request
  347. gomega.Expect(req.Header.Get("Test")).To(gomega.Equal("success"))
  348. rpcClient.SetCustomHeader("Test2", "success2")
  349. rpcClient.Call("add", 1, 2)
  350. req = (<-requestChan).request
  351. gomega.Expect(req.Header.Get("Test")).To(gomega.Equal("success"))
  352. gomega.Expect(req.Header.Get("Test2")).To(gomega.Equal("success2"))
  353. rpcClient.UnsetCustomHeader("Test")
  354. rpcClient.Call("add", 1, 2)
  355. req = (<-requestChan).request
  356. gomega.Expect(req.Header.Get("Test")).NotTo(gomega.Equal("success"))
  357. gomega.Expect(req.Header.Get("Test2")).To(gomega.Equal("success2"))
  358. }
  359. func TestCustomHTTPClient(t *testing.T) {
  360. gomega.RegisterTestingT(t)
  361. rpcClient := NewRPCClient(httpServer.URL)
  362. proxyURL, _ := url.Parse("http://proxy:8080")
  363. transport := &http.Transport{Proxy: http.ProxyURL(proxyURL)}
  364. httpClient := &http.Client{
  365. Timeout: 5 * time.Second,
  366. Transport: transport,
  367. }
  368. rpcClient.SetHTTPClient(httpClient)
  369. rpcClient.Call("add", 1, 2)
  370. // req := (<-requestChan).request
  371. // TODO: what to test here?
  372. }
  373. type Person struct {
  374. Name string `json:"name"`
  375. Age int `json:"age"`
  376. Country string `json:"country"`
  377. }
  378. func TestReadmeExamples(t *testing.T) {
  379. gomega.RegisterTestingT(t)
  380. rpcClient := NewRPCClient(httpServer.URL)
  381. rpcClient.SetAutoIncrementID(false)
  382. rpcClient.Call("getDate")
  383. body := (<-requestChan).body
  384. gomega.Expect(body).To(gomega.Equal(`{"jsonrpc":"2.0","method":"getDate","id":0}`))
  385. rpcClient.Call("addNumbers", 1, 2)
  386. body = (<-requestChan).body
  387. gomega.Expect(body).To(gomega.Equal(`{"jsonrpc":"2.0","method":"addNumbers","params":[1,2],"id":0}`))
  388. rpcClient.Call("createPerson", "Alex", 33, "Germany")
  389. body = (<-requestChan).body
  390. gomega.Expect(body).To(gomega.Equal(`{"jsonrpc":"2.0","method":"createPerson","params":["Alex",33,"Germany"],"id":0}`))
  391. rpcClient.Call("createPerson", Person{"Alex", 33, "Germany"})
  392. body = (<-requestChan).body
  393. gomega.Expect(body).To(gomega.Equal(`{"jsonrpc":"2.0","method":"createPerson","params":[{"name":"Alex","age":33,"country":"Germany"}],"id":0}`))
  394. rpcClient.Call("createPersonsWithRole", []Person{{"Alex", 33, "Germany"}, {"Barney", 38, "Germany"}}, []string{"Admin", "User"})
  395. body = (<-requestChan).body
  396. gomega.Expect(body).To(gomega.Equal(`{"jsonrpc":"2.0","method":"createPersonsWithRole","params":[[{"name":"Alex","age":33,"country":"Germany"},{"name":"Barney","age":38,"country":"Germany"}],["Admin","User"]],"id":0}`))
  397. }