problem: no response from proxy if upstream returned error

fix: #35
This commit is contained in:
Igor Artamonov
2020-07-20 00:30:52 -04:00
parent 1cca38a7bc
commit 8cefcbdb5e
29 changed files with 870 additions and 71 deletions

View File

@@ -18,6 +18,7 @@ package io.emeraldpay.dshackle.quorum
import io.emeraldpay.dshackle.upstream.Upstream
import io.emeraldpay.dshackle.quorum.NotLaggingQuorum
import io.infinitape.etherjar.rpc.RpcException
import spock.lang.Specification
class NotLaggingQuorumSpec extends Specification {
@@ -33,6 +34,7 @@ class NotLaggingQuorumSpec extends Specification {
then:
1 * up.getLag() >> 0
quorum.isResolved()
!quorum.isFailed()
quorum.result == value
}
@@ -47,6 +49,7 @@ class NotLaggingQuorumSpec extends Specification {
then:
1 * up.getLag() >> 1
quorum.isResolved()
!quorum.isFailed()
quorum.result == value
}
@@ -61,5 +64,20 @@ class NotLaggingQuorumSpec extends Specification {
then:
1 * up.getLag() >> 2
!quorum.isResolved()
!quorum.isFailed()
}
def "Fails if no lag and error response received"() {
setup:
def up = Mock(Upstream)
def value = "foo".getBytes()
def quorum = new NotLaggingQuorum(1)
when:
quorum.record(new RpcException(-100, "test error"), up)
then:
1 * up.getLag() >> 1
!quorum.isResolved()
quorum.isFailed()
}
}

View File

@@ -23,6 +23,7 @@ import io.emeraldpay.dshackle.upstream.Selector
import io.emeraldpay.dshackle.upstream.Upstream
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcResponse
import io.infinitape.etherjar.rpc.RpcException
import reactor.core.publisher.Mono
import reactor.test.StepVerifier
import spock.lang.Specification
@@ -60,15 +61,16 @@ class QuorumRpcReaderSpec extends Specification {
def "always-quorum - retry upstream error"() {
setup:
def api = Mock(Reader) {
2 * read(new JsonRpcRequest("eth_test", [])) >>> [
Mono.just(JsonRpcResponse.error(1, "test")),
Mono.just(JsonRpcResponse.ok("1"))
]
}
def up = Mock(Upstream) {
_ * isAvailable() >> true
_ * getRole() >> UpstreamsConfig.UpstreamRole.STANDARD
_ * getApi() >> Mock(Reader) {
2 * read(new JsonRpcRequest("eth_test", [])) >>> [
Mono.just(JsonRpcResponse.error(1, "test")),
Mono.just(JsonRpcResponse.ok("1"))
]
}
_ * getApi() >> api
}
def apis = new FilteredApis(
[up], Selector.empty
@@ -180,18 +182,19 @@ class QuorumRpcReaderSpec extends Specification {
.verify(Duration.ofSeconds(1))
}
def "non-empty-quorum - no result if all failed"() {
def "non-empty-quorum - error if all failed"() {
setup:
def api = Mock(Reader) {
3 * read(new JsonRpcRequest("eth_test", [])) >>> [
Mono.just(JsonRpcResponse.ok("null")),
Mono.just(JsonRpcResponse.error(1, "test")),
Mono.just(JsonRpcResponse.ok("null"))
]
}
def up = Mock(Upstream) {
_ * isAvailable() >> true
_ * getRole() >> UpstreamsConfig.UpstreamRole.STANDARD
_ * getApi() >> Mock(Reader) {
3 * read(new JsonRpcRequest("eth_test", [])) >>> [
Mono.just(JsonRpcResponse.ok("null")),
Mono.just(JsonRpcResponse.error(1, "test")),
Mono.just(JsonRpcResponse.ok("null"))
]
}
_ * getApi() >> api
}
def apis = new FilteredApis(
[up], Selector.empty
@@ -206,7 +209,35 @@ class QuorumRpcReaderSpec extends Specification {
then:
StepVerifier.create(act)
.expectComplete()
.expectError()
.verify(Duration.ofSeconds(2))
}
def "Return error is upstream returned it"() {
setup:
def up = Mock(Upstream) {
_ * getLag() >> 0
_ * isAvailable() >> true
_ * getRole() >> UpstreamsConfig.UpstreamRole.STANDARD
_ * getApi() >> Mock(Reader) {
_ * read(new JsonRpcRequest("eth_test", [])) >>> [
Mono.just(JsonRpcResponse.error(-3010, "test")),
]
}
}
def apis = new FilteredApis(
[up], Selector.empty
)
def reader = new QuorumRpcReader(apis, new NotLaggingQuorum(1))
when:
def act = reader.read(new JsonRpcRequest("eth_test", []))
then:
StepVerifier.create(act)
.expectError()
//TODO verify
//.expectErrorMatches { t -> t instanceof RpcException && t.code == -3010}
.verify(Duration.ofSeconds(1))
}

View File

@@ -63,7 +63,7 @@ class NativeCallSpec extends Specification {
when:
def act = nativeCall.fetch(ctx).block(Duration.ofSeconds(1))
then:
act.payload == "1".bytes
act.result == "1".bytes
}
def "Return error if router denied the requests"() {
@@ -85,12 +85,10 @@ class NativeCallSpec extends Specification {
def act = nativeCall.fetch(ctx) //.block(Duration.ofSeconds(1))
then:
StepVerifier.create(act)
.expectErrorMatches { t ->
t instanceof NativeCall.CallFailure &&
t.id == 15 &&
t.reason instanceof RpcException &&
t.reason.rpcMessage == "Test message"
.expectNextMatches { result ->
result.id == 15 && result.isError()
}
.expectComplete()
.verify(Duration.ofSeconds(1))
}
@@ -109,7 +107,7 @@ class NativeCallSpec extends Specification {
when:
def resp = nativeCall.executeOnRemote(call).block(Duration.ofSeconds(1))
def act = objectMapper.readValue(resp.payload, Object)
def act = objectMapper.readValue(resp.result, Object)
then:
act == "foo"
}
@@ -131,7 +129,10 @@ class NativeCallSpec extends Specification {
def resp = nativeCall.executeOnRemote(call)
then:
StepVerifier.create(resp)
.expectErrorMatches({ t -> t instanceof NativeCall.CallFailure && t.id == 1 })
.expectNextMatches { result ->
result.isError()
}
.expectComplete()
.verify(Duration.ofSeconds(1))
}
@@ -176,7 +177,7 @@ class NativeCallSpec extends Specification {
when:
def resp = nativeCall.buildResponse(
new NativeCall.CallContext<byte[]>(1561, TestingCommons.multistream(TestingCommons.api()), Selector.empty, new AlwaysQuorum(), objectMapper.writeValueAsBytes(json))
new NativeCall.CallResult(1561, objectMapper.writeValueAsBytes(json), null)
)
then:
resp.id == 1561