Files
dshackle/src/test/groovy/io/emeraldpay/dshackle/proxy/ReadRpcJsonSpec.groovy
2021-10-26 23:03:40 -04:00

236 lines
6.8 KiB
Groovy

/**
* Copyright (c) 2020 ETCDEV GmbH
* Copyright (c) 2020 EmeraldPay, Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.emeraldpay.dshackle.proxy
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcResponse
import io.emeraldpay.etherjar.rpc.RpcException
import spock.lang.Specification
class ReadRpcJsonSpec extends Specification {
ReadRpcJson reader = new ReadRpcJson()
def "Get first symbol"() {
expect:
reader.getStartOfJson(input.bytes) == exp.bytes[0]
where:
exp | input
"{" | "{}"
"{" | " { }"
"{" | "\n\n { }"
"[" | " [ { } ] "
}
def "Error for input with many spaces"() {
setup:
def empty = " " * 1000
when:
reader.getStartOfJson((empty + "{}").bytes)
then:
thrown(IllegalArgumentException)
}
def "Error for empty spaces"() {
when:
reader.getStartOfJson("".bytes)
then:
thrown(IllegalArgumentException)
}
def "Get type"() {
expect:
reader.getType(input.bytes) == exp
where:
exp | input
ProxyCall.RpcType.SINGLE | "{}"
ProxyCall.RpcType.SINGLE | " { }"
ProxyCall.RpcType.SINGLE | "\n\n { }"
ProxyCall.RpcType.BATCH | " [ { } ] "
}
def "Error type for invalid input"() {
when:
reader.getType("hello".bytes)
then:
thrown(RpcException)
when:
reader.getType("1".bytes)
then:
thrown(RpcException)
when:
reader.getType("".bytes)
then:
thrown(RpcException)
}
def "Parse basic"() {
when:
def act = reader.apply('{"jsonrpc":"2.0", "method":"net_peerCount", "id":1, "params":[]}'.bytes)
then:
act.type == ProxyCall.RpcType.SINGLE
act.ids.size() == 1
act.ids[0] == 1
act.items.size() == 1
with(act.items[0]) {
id == 0
method == "net_peerCount"
payload.toStringUtf8() == "[]"
}
}
def "Parse basic with string id"() {
when:
def act = reader.apply('{"jsonrpc":"2.0", "method":"net_peerCount", "id":"ggk19K5a", "params":[]}'.bytes)
then:
act.type == ProxyCall.RpcType.SINGLE
act.ids.size() == 1
act.ids[0] == "ggk19K5a"
act.items.size() == 1
with(act.items[0]) {
id == 0
method == "net_peerCount"
payload.toStringUtf8() == "[]"
}
}
def "Parse basic without params"() {
when:
def act = reader.apply('{"jsonrpc":"2.0", "method":"net_peerCount", "id":2}'.bytes)
then:
act.type == ProxyCall.RpcType.SINGLE
act.ids.size() == 1
act.ids[0] == 2
act.items.size() == 1
with(act.items[0]) {
id == 0
method == "net_peerCount"
payload.toStringUtf8() == "[]"
}
}
def "Parse with parameters"() {
when:
def act = reader.apply('{"jsonrpc":"2.0", "method":"net_peerCount", "id":1, "params":["0x015f"]}'.bytes)
then:
act.type == ProxyCall.RpcType.SINGLE
act.ids.size() == 1
act.ids[0] == 1
act.items.size() == 1
with(act.items[0]) {
id == 0
method == "net_peerCount"
payload.toStringUtf8() == '["0x015f"]'
}
}
def "Parse single batch"() {
when:
def act = reader.apply('[{"jsonrpc":"2.0", "method":"net_peerCount", "id":1, "params":[]}]'.bytes)
then:
act.type == ProxyCall.RpcType.BATCH
act.ids.size() == 1
act.ids[0] == 1
act.items.size() == 1
with(act.items[0]) {
id == 0
method == "net_peerCount"
payload.toStringUtf8() == "[]"
}
}
def "Parse multi batch"() {
when:
def act = reader.apply('[{"jsonrpc":"2.0", "method":"net_peerCount", "id":"xdd", "params":[]}, {"jsonrpc":"2.0", "method":"foo_bar", "id":4, "params":[143, false]}]'.bytes)
then:
act.type == ProxyCall.RpcType.BATCH
act.ids.size() == 2
act.ids[0] == "xdd"
act.ids[1] == 4
act.items.size() == 2
with(act.items[0]) {
id == 0
method == "net_peerCount"
payload.toStringUtf8() == "[]"
}
with(act.items[1]) {
id == 1
method == "foo_bar"
payload.toStringUtf8() == '[143,false]'
}
}
def "Error if id is not set"() {
when:
reader.apply('{"jsonrpc":"2.0", "method":"net_peerCount", "params":[]}'.bytes)
then:
def t = thrown(RpcException)
t.code == -32600
t.rpcMessage.toLowerCase() == "id is not set"
}
def "Error if jsonrpc is not set"() {
when:
reader.apply('{"id":2, "method":"net_peerCount", "params":[]}'.bytes)
then:
def t = thrown(RpcException)
t.code == -32600
t.rpcMessage.toLowerCase() == "jsonrpc version is not set"
t.details == new JsonRpcResponse.NumberId(2)
}
def "Error if jsonrpc version is invalid"() {
when:
reader.apply('{"id":2, "jsonrpc":"3.0", "method":"net_peerCount", "params":[]}'.bytes)
then:
def t = thrown(RpcException)
t.code == -32600
t.rpcMessage.toLowerCase() == "unsupported json rpc version: 3.0"
t.details == new JsonRpcResponse.NumberId(2)
}
def "Error if method is not set"() {
when:
reader.apply('{"id":2, "jsonrpc":"2.0", "params":[]}'.bytes)
then:
def t = thrown(RpcException)
t.code == -32600
t.rpcMessage.toLowerCase() == "method is not set"
t.details == new JsonRpcResponse.NumberId(2)
}
def "Error if params is not array"() {
when:
reader.apply('{"id":2, "jsonrpc":"2.0", "method":"test", "params":123}'.bytes)
then:
def t = thrown(RpcException)
t.code == -32600
t.rpcMessage.toLowerCase() == "params must be an array"
t.details == new JsonRpcResponse.NumberId(2)
}
def "Error if json is broken"() {
when:
reader.apply('{"id":2, "method":"net_peerCount", "params"'.bytes)
then:
def t = thrown(RpcException)
t.code == -32700
}
}