77# This file may not be copied, modified, or distributed except according to
88# those terms.
99
10+ {.push raises : [], gcsafe .}
11+
1012import
1113 chronos/ unittest2/ asynctests,
1214 stew/ byteutils,
@@ -26,6 +28,25 @@ createRpcSigsFromNim(RpcClient, JrpcFlavor):
2628 proc rets (s: string ): string
2729 proc invalid (s: int ): string
2830
31+ template checkInvalidRequest (client: untyped , req, expectedErr: string ): untyped =
32+ # check sending `req` terminates the connection with `expectedErr` error
33+ var disconnFut = newFuture [void ]()
34+ client.onDisconnect = proc () {.gcsafe , raises : [].} =
35+ disconnFut.complete ()
36+ let fut1 = client.send (req.toBytes)
37+ let fut2 = client.rets (" foobar" )
38+ waitFor fut1
39+ waitFor disconnFut
40+ try :
41+ discard waitFor fut2
42+ doAssert false
43+ except RpcTransportError as err:
44+ doAssert err.parent != nil
45+ check err.parent.msg == expectedErr
46+ # following requests won't work
47+ expect RpcTransportError :
48+ discard waitFor client.rets (" foobar" )
49+
2950template allTests (client: untyped ) =
3051 test " Successful RPC call" :
3152 let r1 = waitFor client.rets (" foobar" )
@@ -60,109 +81,80 @@ template allTests(client: untyped) =
6081 res.get ()[1 ].error.isNone
6182 res.get ()[2 ].error.isSome
6283
63- test " Request with null id terminates the connection" :
64- # the response will contain a null id
65- var disconnFut = newFuture [void ]()
66- client.onDisconnect = proc () {.gcsafe , raises : [].} =
67- disconnFut.complete ()
68- let fut1 = client.send (""" {"jsonrpc": "2.0", "method": "foobar", "id": null} """ .toBytes)
69- let fut2 = client.rets (" foobar" )
70- waitFor fut1
71- waitFor disconnFut
72- try :
73- discard waitFor fut2
74- doAssert false
75- except RpcTransportError as err:
76- # check it fails with method not found; id=null response
77- check err.parent.msg == """ {"code":-32601,"message":"'foobar' is not a registered RPC method"} """
78- # following requests won't work
79- expect RpcTransportError :
80- discard waitFor client.rets (" foobar" )
81-
82- test " Sending an ambiguous message terminates the connection" :
83- var disconnFut = newFuture [void ]()
84- client.onDisconnect = proc () {.gcsafe , raises : [].} =
85- disconnFut.complete ()
86- let fut1 = client.send (""" {"foo": "boo"} """ .toBytes)
87- let fut2 = client.rets (" foobar" )
88- waitFor fut1
89- waitFor disconnFut
90- try :
91- discard waitFor fut2
92- doAssert false
93- except RpcTransportError as err:
94- # check it fails with parse error; id=null response
95- check err.parent.msg == """ {"code":-32600,"message":"',' expected"} """
96- # following requests won't work
97- expect RpcTransportError :
98- discard waitFor client.rets (" foobar" )
99-
100- test " Sending an ambiguous batch message terminates the connection" :
101- var disconnFut = newFuture [void ]()
102- client.onDisconnect = proc () {.gcsafe , raises : [].} =
103- disconnFut.complete ()
104- let fut1 = client.send (""" [{"foo": "boo"}] """ .toBytes)
105- let fut2 = client.rets (" foobar" )
106- waitFor fut1
107- waitFor disconnFut
108- try :
109- discard waitFor fut2
110- doAssert false
111- except RpcTransportError as err:
112- # check it fails with parse error; id=null response
113- check err.parent.msg == """ {"code":-32600,"message":"',' expected"} """
114- # following requests won't work
115- expect RpcTransportError :
116- discard waitFor client.rets (" foobar" )
117-
118- test " Sending a response with id null terminates the connection" :
119- var disconnFut = newFuture [void ]()
120- client.onDisconnect = proc () {.gcsafe , raises : [].} =
121- disconnFut.complete ()
122- const resp = """ {"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null} """
123- waitFor client.send (resp.toBytes)
124- waitFor disconnFut
125-
126- test " Sending a batch response with id null terminates the connection" :
127- var disconnFut = newFuture [void ]()
128- client.onDisconnect = proc () {.gcsafe , raises : [].} =
129- disconnFut.complete ()
130- const resp = """ [{"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null}] """
131- waitFor client.send (resp.toBytes)
132- waitFor disconnFut
133-
13484 test " Sending an unknown id is ignored" :
135- const resp = """ {"jsonrpc": "2.0", "result ": 7 , "id": 123123} """
136- waitFor client.send (resp .toBytes)
85+ const req = """ {"jsonrpc": "2.0", "method ": "foo" , "id": 123123} """
86+ waitFor client.send (req .toBytes)
13787 # following requests still work
13888 let r1 = waitFor client.rets (" foobar" )
13989 check r1 == " ret foobar"
14090
141- test " Sending a batch with an unknown id is ignored" :
142- const resp = """ [{"jsonrpc": "2.0", "result ": 7 , "id": 123123}] """
143- waitFor client.send (resp .toBytes)
91+ test " Sending an unknown id within a batch is ignored" :
92+ const req = """ [{"jsonrpc": "2.0", "method ": "foo" , "id": 123123}] """
93+ waitFor client.send (req .toBytes)
14494 # following requests still work
14595 let r1 = waitFor client.rets (" foobar" )
14696 check r1 == " ret foobar"
14797
148- test " Sending a string id is ignored " :
149- const resp = """ {"jsonrpc": "2.0", "result ": 7 , "id ": "123123" } """
150- waitFor client.send (resp .toBytes)
98+ test " Sending a notification won't terminate the connection " :
99+ const req = """ {"jsonrpc": "2.0", "method ": "rets" , "params ": ["foo"] } """
100+ waitFor client.send (req .toBytes)
151101 # following requests still work
152102 let r1 = waitFor client.rets (" foobar" )
153103 check r1 == " ret foobar"
154104
155- test " Sending a batch with a string id is ignored " :
156- const resp = """ [ {"jsonrpc": "2.0", "result ": 7 , "id ": "123123"}] """
157- waitFor client.send (resp .toBytes)
105+ test " Sending an invalid notification won't terminate the connection " :
106+ const req = """ {"jsonrpc": "2.0", "method ": "rets" , "params ": [123]} """
107+ waitFor client.send (req .toBytes)
158108 # following requests still work
159109 let r1 = waitFor client.rets (" foobar" )
160110 check r1 == " ret foobar"
161111
112+ test " Sending an ambiguous message terminates the connection" :
113+ # check it fails with parse error; id=null response
114+ const req = """ {"foo": "boo"} """
115+ const expected = """ {"code":-32600,"message":"',' expected"} """
116+ checkInvalidRequest (client, req, expected)
117+
118+ test " Sending an ambiguous batch message terminates the connection" :
119+ const req = """ [{"foo": "boo"}] """
120+ const expected = """ {"code":-32600,"message":"',' expected"} """
121+ checkInvalidRequest (client, req, expected)
122+
123+ test " Sending a null id terminates the connection" :
124+ # note this terminates the connection when receiving the null id response
125+ const req = """ {"jsonrpc": "2.0", "method": "foo", "id": null} """
126+ const expected = """ {"code":-32601,"message":"'foo' is not a registered RPC method"} """
127+ checkInvalidRequest (client, req, expected)
128+
129+ test " Sending a null id within a batch terminates the connection" :
130+ const req = """ [{"jsonrpc": "2.0", "method": "foo", "id": null}] """
131+ const expected = """ {"code":-32601,"message":"'foo' is not a registered RPC method"} """
132+ checkInvalidRequest (client, req, expected)
133+
134+ test " Sending a null id terminates the connection; variant" :
135+ const req = """ {"jsonrpc": "2.0", "method": "rets", "params": ["foo"], "id": null} """
136+ const expected = " Expected response with int `id`, but got `id` = null"
137+ checkInvalidRequest (client, req, expected)
138+
139+ test " Sending a null id within a batch terminates the connection; variant" :
140+ const req = """ [{"jsonrpc": "2.0", "method": "rets", "params": ["foo"], "id": null}] """
141+ const expected = " Expected response with int `id`, but got `id` = null"
142+ checkInvalidRequest (client, req, expected)
143+
144+ test " Sending a string id terminates the connection" :
145+ # note this terminates the connection when receiving the string id response
146+ const req = """ {"jsonrpc": "2.0", "method": "foo", "id": "123123"} """
147+ const expected = """ Expected response with int `id`, but got `id` = "123123" """
148+ checkInvalidRequest (client, req, expected)
149+
150+ test " Sending a string id within a batch terminates the connection" :
151+ const req = """ [{"jsonrpc": "2.0", "method": "foo", "id": "123123"}] """
152+ const expected = """ Expected response with int `id`, but got `id` = "123123" """
153+ checkInvalidRequest (client, req, expected)
154+
162155suite " Test bidirectional socket server/client" :
163156 setup:
164- # XXX Framing.lengthHeaderBE32()
165- const framing = Framing .newLine ()
157+ const framing = Framing .lengthHeaderBE32 ()
166158 var srv = newRpcSocketServer ([" 127.0.0.1:0" ], framing = framing)
167159 var client = newRpcSocketClient (framing = framing)
168160
0 commit comments