solution: JSON RPC client that treats result as raw

This commit is contained in:
Igor Artamonov
2020-05-09 22:47:19 -04:00
parent 0ef46b2980
commit a539ad3b84
8 changed files with 626 additions and 0 deletions

View File

@@ -0,0 +1,59 @@
/**
* 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.upstream.rpcclient
import io.emeraldpay.dshackle.test.TestingCommons
import org.mockserver.integration.ClientAndServer
import org.mockserver.model.HttpRequest
import org.mockserver.model.HttpResponse
import spock.lang.Specification
class JsonRpcClientSpec extends Specification {
ClientAndServer mockServer
JsonRpcClient client
def setup() {
mockServer = ClientAndServer.startClientAndServer(18332);
client = new JsonRpcClient("localhost:18332", TestingCommons.objectMapper(), null)
}
def cleanup() {
mockServer.stop()
}
def "Make a request"() {
setup:
def resp = '{' +
' "jsonrpc": "2.0",' +
' "result": "0x98de45",' +
' "error": null,' +
' "id": 15' +
'}'
mockServer.when(
HttpRequest.request()
).respond(
HttpResponse.response(resp)
)
when:
def act = client.execute(new JsonRpcRequest("test", [])).block()
then:
act.error == null
new String(act.result) == '"0x98de45"'
}
}

View File

@@ -0,0 +1,179 @@
/**
* 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.upstream.rpcclient
import spock.lang.Specification
class JsonRpcParserSpec extends Specification {
JsonRpcParser parser = new JsonRpcParser()
def "Parse just result"() {
setup:
def json = '{"result": "Hello world!"}'
when:
def act = parser.parse(json.getBytes())
then:
act.error == null
new String(act.result) == '"Hello world!"'
}
def "Parse string response"() {
setup:
// 0 8 16 32 35
def json = '{"jsonrpc": "2.0", "id": 1, "result": "Hello world!"}'
when:
def act = parser.parse(json.getBytes())
then:
act.error == null
new String(act.result) == '"Hello world!"'
}
def "Parse string response when result starts first"() {
setup:
// 0 8 16 32 35
def json = '{"result": "Hello world!", "jsonrpc": "2.0", "id": 1}'
when:
def act = parser.parse(json.getBytes())
then:
act.error == null
new String(act.result) == '"Hello world!"'
}
def "Parse bool response"() {
setup:
// 0 8 16 32
def json = '{"jsonrpc": "2.0", "id": 1, "result": false}'
when:
def act = parser.parse(json.getBytes())
then:
act.error == null
new String(act.result) == 'false'
}
def "Parse bool response when id is last"() {
setup:
// 0 8 16 32
def json = '{"jsonrpc": "2.0", "result": false, "id": 1}'
when:
def act = parser.parse(json.getBytes())
then:
act.error == null
new String(act.result) == 'false'
}
def "Parse int response"() {
setup:
// 0 8 16 32
def json = '{"jsonrpc": "2.0", "id": 1, "result": 100}'
when:
def act = parser.parse(json.getBytes())
then:
act.error == null
new String(act.result) == '100'
}
def "Parse null response"() {
setup:
// 0 8 16 32
def json = '{"jsonrpc": "2.0", "id": 1, "result": null}'
when:
def act = parser.parse(json.getBytes())
then:
act.error == null
new String(act.result) == 'null'
}
def "Parse object response"() {
setup:
// 0 8 16 32
def json = '{"jsonrpc": "2.0", "id": 1, "result": {"hash": "0x00000", "foo": false, "bar": 1}}'
when:
def act = parser.parse(json.getBytes())
then:
act.error == null
new String(act.result) == '{"hash": "0x00000", "foo": false, "bar": 1}'
}
def "Parse object response with null error"() {
setup:
// 0 8 16 32
def json = '{"jsonrpc": "2.0", "id": 1, "result": {"hash": "0x00000", "foo": false, "bar": 1}, "error": null}'
when:
def act = parser.parse(json.getBytes())
then:
act.error == null
new String(act.result) == '{"hash": "0x00000", "foo": false, "bar": 1}'
}
def "Parse object response if null error comes first"() {
setup:
// 0 8 16 32
def json = '{"jsonrpc": "2.0", "id": 1, "error": null, "result": {"hash": "0x00000", "foo": false, "bar": 1}}'
when:
def act = parser.parse(json.getBytes())
then:
act.error == null
new String(act.result) == '{"hash": "0x00000", "foo": false, "bar": 1}'
}
def "Parse object response with extra spaces"() {
setup:
// 0 8 16 32
def json = '{"jsonrpc": "2.0", "result" : {"hash": "0x00000", "foo": false , "bar":1} , "id": 1}'
when:
def act = parser.parse(json.getBytes())
then:
act.error == null
new String(act.result) == '{"hash": "0x00000", "foo": false , "bar":1}'
}
def "Parse complex object response"() {
setup:
// 0 8 16 32
def json = '{"jsonrpc": "2.0", "id": 1, "result": {"hash": "0x00000", "foo": {"bar": 1, "baz": 2}}}'
when:
def act = parser.parse(json.getBytes())
then:
act.error == null
new String(act.result) == '{"hash": "0x00000", "foo": {"bar": 1, "baz": 2}}'
}
def "Parse array response"() {
setup:
// 0 8 16 32
def json = '{"jsonrpc": "2.0", "id": 1, "result": [1, 2, false]}'
when:
def act = parser.parse(json.getBytes())
then:
act.error == null
new String(act.result) == '[1, 2, false]'
}
def "Parse error"() {
setup:
// 0 8 16 32
def json = '{"jsonrpc": "2.0", "id": 1, "result": null, "error": {"code": -1111, "message": "test"}}'
when:
def act = parser.parse(json.getBytes())
then:
act.error != null
act.error.code == -1111
act.error.message == "test"
act.result == null
}
}

View File

@@ -0,0 +1,59 @@
/**
* 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.upstream.rpcclient
import io.emeraldpay.dshackle.test.TestingCommons
import spock.lang.Specification
class JsonRpcRequestSpec extends Specification {
def "Serialize empty params"() {
setup:
def req = new JsonRpcRequest("test_foo", [])
when:
def act = req.toJson(TestingCommons.objectMapper())
then:
new String(act) == '{"jsonrpc":"2.0","id":1,"method":"test_foo","params":[]}'
}
def "Serialize single param"() {
setup:
def req = new JsonRpcRequest("test_foo", ["0x0000"])
when:
def act = req.toJson(TestingCommons.objectMapper())
then:
new String(act) == '{"jsonrpc":"2.0","id":1,"method":"test_foo","params":["0x0000"]}'
}
def "Serialize two params"() {
setup:
def req = new JsonRpcRequest("test_foo", ["0x0000", false])
when:
def act = req.toJson(TestingCommons.objectMapper())
then:
new String(act) == '{"jsonrpc":"2.0","id":1,"method":"test_foo","params":["0x0000",false]}'
}
def "Same requests are equal"() {
setup:
def req1 = new JsonRpcRequest("test_foo", ["0x0000", false])
def req2 = new JsonRpcRequest("test_foo", ["0x0000", false])
when:
def act = req1.equals(req2)
then:
act == true
}
}

View File

@@ -0,0 +1,31 @@
/**
* 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.upstream.rpcclient
import spock.lang.Specification
class JsonRpcResponseSpec extends Specification {
def "Same responses are equal"() {
setup:
def resp1 = new JsonRpcResponse("\"hello\"".bytes, null)
def resp2 = new JsonRpcResponse("\"hello\"".bytes, null)
when:
def act = resp1.equals(resp2)
then:
act == true
}
}