Detect and send node version in api (#445)
This commit is contained in:
@@ -20,6 +20,7 @@ import io.emeraldpay.dshackle.monitoring.accesslog.AccessHandlerHttp
|
||||
import io.emeraldpay.dshackle.rpc.NativeCall
|
||||
import io.emeraldpay.dshackle.rpc.NativeSubscribe
|
||||
import io.emeraldpay.dshackle.upstream.Selector
|
||||
import io.emeraldpay.dshackle.upstream.Upstream
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.json.RequestJson
|
||||
import io.micrometer.core.instrument.Counter
|
||||
import reactor.core.publisher.Flux
|
||||
@@ -85,7 +86,7 @@ class WebsocketHandlerSpec extends Specification {
|
||||
|
||||
def "Respond to a single call"() {
|
||||
setup:
|
||||
def response = new NativeCall.CallResult(0, null, '{"foo": 1}'.bytes, null, null, "test", null, null)
|
||||
def response = new NativeCall.CallResult(0, null, '{"foo": 1}'.bytes, null, null, new Upstream.UpstreamSettingsData("test"), null, null)
|
||||
|
||||
def nativeCall = Mock(NativeCall) {
|
||||
1 * it.nativeCallResult(_) >> Flux.fromIterable([response])
|
||||
|
||||
@@ -120,14 +120,10 @@ class NativeCallSpec extends Specification {
|
||||
setup:
|
||||
def quorum = new AlwaysQuorum()
|
||||
|
||||
def ups = Mock(Upstream) {
|
||||
_ * nodeId() >> (byte) 1
|
||||
}
|
||||
|
||||
def nativeCall = nativeCall()
|
||||
nativeCall.requestReaderFactory = Mock(RequestReaderFactory) {
|
||||
1 * create(_) >> Mock(RequestReader) {
|
||||
1 * read(_) >> Mono.just(new RequestReader.Result("\"foo\"".bytes, null, 1, ups, null))
|
||||
1 * read(_) >> Mono.just(new RequestReader.Result("\"foo\"".bytes, null, 1, new Upstream.UpstreamSettingsData((byte)1, "test", "v"), null))
|
||||
}
|
||||
}
|
||||
def call = new NativeCall.ValidCallContext(1, 10, TestingCommons.multistream(TestingCommons.api()), Selector.empty, quorum,
|
||||
@@ -250,7 +246,7 @@ class NativeCallSpec extends Specification {
|
||||
|
||||
when:
|
||||
def resp = nativeCall.buildResponse(
|
||||
new NativeCall.CallResult(1561, 10, objectMapper.writeValueAsBytes(json), null, new ResponseSigner.Signature("sig1".bytes, "test", 100), "test", null, null)
|
||||
new NativeCall.CallResult(1561, 10, objectMapper.writeValueAsBytes(json), null, new ResponseSigner.Signature("sig1".bytes, "test", 100), new Upstream.UpstreamSettingsData("test"), null, null)
|
||||
)
|
||||
then:
|
||||
resp.id == 1561
|
||||
@@ -597,9 +593,6 @@ class NativeCallSpec extends Specification {
|
||||
|
||||
def "Decorate eth_newFilter result"() {
|
||||
setup:
|
||||
def ups = Mock(Upstream) {
|
||||
_ * nodeId() >> (byte)255
|
||||
}
|
||||
def quorum = new AlwaysQuorum()
|
||||
def methods = new ManagedCallMethods(
|
||||
new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET, false),
|
||||
@@ -616,7 +609,7 @@ class NativeCallSpec extends Specification {
|
||||
def nativeCall = nativeCall(multistreamHolder)
|
||||
nativeCall.requestReaderFactory = Mock(RequestReaderFactory) {
|
||||
1 * create(_) >> Mock(RequestReader) {
|
||||
1 * read(_) >> Mono.just(new RequestReader.Result("\"0xab\"".bytes, null, 1, ups, null))
|
||||
1 * read(_) >> Mono.just(new RequestReader.Result("\"0xab\"".bytes, null, 1, new Upstream.UpstreamSettingsData((byte) 255, "", ""), null))
|
||||
}
|
||||
}
|
||||
def call = new NativeCall.ValidCallContext(1, 10, multistream, Selector.empty, quorum,
|
||||
@@ -633,9 +626,6 @@ class NativeCallSpec extends Specification {
|
||||
|
||||
def "Decorate eth_newFilter result with short nodeId"() {
|
||||
setup:
|
||||
def ups = Mock(Upstream) {
|
||||
_ * nodeId() >> (byte)1
|
||||
}
|
||||
def quorum = new AlwaysQuorum()
|
||||
def methods = new ManagedCallMethods(
|
||||
new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET, false),
|
||||
@@ -652,7 +642,7 @@ class NativeCallSpec extends Specification {
|
||||
def nativeCall = nativeCall(multistreamHolder)
|
||||
nativeCall.requestReaderFactory = Mock(RequestReaderFactory) {
|
||||
1 * create(_) >> Mock(RequestReader) {
|
||||
1 * read(_) >> Mono.just(new RequestReader.Result("\"0xab\"".bytes, null, 1, ups, null))
|
||||
1 * read(_) >> Mono.just(new RequestReader.Result("\"0xab\"".bytes, null, 1, new Upstream.UpstreamSettingsData((byte) 1, "", ""), null))
|
||||
}
|
||||
}
|
||||
def call = new NativeCall.ValidCallContext(1, 10, multistream, Selector.empty, quorum,
|
||||
|
||||
@@ -74,7 +74,7 @@ class GenericUpstreamMock extends GenericUpstream {
|
||||
ChainConfig.default(),
|
||||
new ConnectorFactoryMock(api, new EthereumHeadMock()),
|
||||
io.emeraldpay.dshackle.upstream.starknet.StarknetChainSpecific.INSTANCE.&validator,
|
||||
io.emeraldpay.dshackle.upstream.starknet.StarknetChainSpecific.INSTANCE.&labelDetector,
|
||||
io.emeraldpay.dshackle.upstream.starknet.StarknetChainSpecific.INSTANCE.&upstreamSettingsDetector,
|
||||
io.emeraldpay.dshackle.upstream.starknet.StarknetChainSpecific.INSTANCE.&lowerBoundBlockDetector,
|
||||
)
|
||||
this.ethereumHeadMock = this.getHead() as EthereumHeadMock
|
||||
|
||||
@@ -76,7 +76,7 @@ class FilteredApisSpec extends Specification {
|
||||
ChainsConfig.ChainConfig.default(),
|
||||
connectorFactory,
|
||||
cs.&validator,
|
||||
cs.&labelDetector,
|
||||
cs.&upstreamSettingsDetector,
|
||||
cs.&lowerBoundBlockDetector
|
||||
)
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ class EthereumDirectReaderSpec extends Specification {
|
||||
|
||||
String hash1 = "0x40d15edaff9acdabd2a1c96fd5f683b3300aad34e7015f34def3c56ba8a7ffb5"
|
||||
String address1 = "0xe0aadb0a012dbcdc529c4c743d3e0385a0b54d3d"
|
||||
Upstream resolver = TestingCommons.upstream()
|
||||
Upstream.UpstreamSettingsData data = new Upstream.UpstreamSettingsData("test")
|
||||
|
||||
def "Reads block by hash"() {
|
||||
setup:
|
||||
@@ -54,7 +54,7 @@ class EthereumDirectReaderSpec extends Specification {
|
||||
1 * create(_) >> Mock(RequestReader) {
|
||||
1 * read(new ChainRequest("eth_getBlockByHash", new ListParams([hash1, false]))) >> Mono.just(
|
||||
new RequestReader.Result(
|
||||
Global.objectMapper.writeValueAsBytes(json), null, 1, resolver, null)
|
||||
Global.objectMapper.writeValueAsBytes(json), null, 1, data, null)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -81,7 +81,7 @@ class EthereumDirectReaderSpec extends Specification {
|
||||
1 * create(_) >> Mock(RequestReader) {
|
||||
1 * read(new ChainRequest("eth_getBlockByHash", new ListParams([hash1, false]))) >> Mono.just(
|
||||
new RequestReader.Result(
|
||||
Global.objectMapper.writeValueAsBytes(null), null, 1, resolver, null
|
||||
Global.objectMapper.writeValueAsBytes(null), null, 1, data, null
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -114,7 +114,7 @@ class EthereumDirectReaderSpec extends Specification {
|
||||
1 * create(_) >> Mock(RequestReader) {
|
||||
1 * read(new ChainRequest("eth_getBlockByNumber", new ListParams(["0x64", false]))) >> Mono.just(
|
||||
new RequestReader.Result(
|
||||
Global.objectMapper.writeValueAsBytes(json), null, 1, resolver, null
|
||||
Global.objectMapper.writeValueAsBytes(json), null, 1, data, null
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -146,7 +146,7 @@ class EthereumDirectReaderSpec extends Specification {
|
||||
1 * create(_) >> Mock(RequestReader) {
|
||||
1 * read(new ChainRequest("eth_getLogs", new ListParams([Map.of("blockHash", hash1)]))) >> Mono.just(
|
||||
new RequestReader.Result(
|
||||
Global.objectMapper.writeValueAsBytes([json]), null, 1, resolver, null
|
||||
Global.objectMapper.writeValueAsBytes([json]), null, 1, data, null
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -179,7 +179,7 @@ class EthereumDirectReaderSpec extends Specification {
|
||||
1 * create(_) >> Mock(RequestReader) {
|
||||
1 * read(new ChainRequest("eth_getTransactionByHash", new ListParams([hash1]))) >> Mono.just(
|
||||
new RequestReader.Result(
|
||||
Global.objectMapper.writeValueAsBytes(json), null, 1, resolver, null
|
||||
Global.objectMapper.writeValueAsBytes(json), null, 1, data, null
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -212,7 +212,7 @@ class EthereumDirectReaderSpec extends Specification {
|
||||
1 * create(_) >> Mock(RequestReader) {
|
||||
1 * read(new ChainRequest("eth_getTransactionReceipt", new ListParams([hash1]))) >> Mono.just(
|
||||
new RequestReader.Result(
|
||||
Global.objectMapper.writeValueAsBytes(json), null, 1, resolver, null
|
||||
Global.objectMapper.writeValueAsBytes(json), null, 1, data, null
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -246,7 +246,7 @@ class EthereumDirectReaderSpec extends Specification {
|
||||
1 * create(_) >> Mock(RequestReader) {
|
||||
1 * read(new ChainRequest("eth_getTransactionReceipt", new ListParams([hash1]))) >> Mono.just(
|
||||
new RequestReader.Result(
|
||||
Global.objectMapper.writeValueAsBytes(json), null, 1, resolver, null
|
||||
Global.objectMapper.writeValueAsBytes(json), null, 1, data, null
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -271,7 +271,7 @@ class EthereumDirectReaderSpec extends Specification {
|
||||
1 * create(_) >> Mock(RequestReader) {
|
||||
1 * read(new ChainRequest("eth_getTransactionByHash", new ListParams([hash1]))) >> Mono.just(
|
||||
new RequestReader.Result(
|
||||
Global.objectMapper.writeValueAsBytes(null), null, 1, resolver, null
|
||||
Global.objectMapper.writeValueAsBytes(null), null, 1, data, null
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -301,7 +301,7 @@ class EthereumDirectReaderSpec extends Specification {
|
||||
1 * create(_) >> Mock(RequestReader) {
|
||||
1 * read(new ChainRequest("eth_getBalance", new ListParams([address1, "latest"]))) >> Mono.just(
|
||||
new RequestReader.Result(
|
||||
Global.objectMapper.writeValueAsBytes("0x100"), null, 1, resolver, null
|
||||
Global.objectMapper.writeValueAsBytes("0x100"), null, 1, data, null
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -332,7 +332,7 @@ class EthereumDirectReaderSpec extends Specification {
|
||||
1 * create(_) >> Mock(RequestReader) {
|
||||
1 * read(new ChainRequest("eth_getBalance", new ListParams([address1, "0xa8c9bb"]))) >> Mono.just(
|
||||
new RequestReader.Result(
|
||||
Global.objectMapper.writeValueAsBytes("0x100"), null, 1, resolver, null
|
||||
Global.objectMapper.writeValueAsBytes("0x100"), null, 1, data, null
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -361,7 +361,7 @@ class EthereumDirectReaderSpec extends Specification {
|
||||
}
|
||||
def result = Mono.just(
|
||||
new RequestReader.Result(
|
||||
Global.objectMapper.writeValueAsBytes(json), null, 1, resolver, null)
|
||||
Global.objectMapper.writeValueAsBytes(json), null, 1, data, null)
|
||||
)
|
||||
EthereumDirectReader ethereumDirectReader = new EthereumDirectReader(
|
||||
Stub(Multistream), Caches.default(), new CurrentBlockCache(), calls, TestingCommons.tracerMock()
|
||||
@@ -401,7 +401,7 @@ class EthereumDirectReaderSpec extends Specification {
|
||||
}
|
||||
def result = Mono.just(
|
||||
new RequestReader.Result(
|
||||
Global.objectMapper.writeValueAsBytes(json), null, 1, resolver, null)
|
||||
Global.objectMapper.writeValueAsBytes(json), null, 1, data, null)
|
||||
)
|
||||
EthereumDirectReader ethereumDirectReader = new EthereumDirectReader(
|
||||
Stub(Multistream), Caches.default(), new CurrentBlockCache(), calls, TestingCommons.tracerMock()
|
||||
|
||||
@@ -15,7 +15,7 @@ import spock.lang.Specification
|
||||
|
||||
import java.time.Duration
|
||||
|
||||
class EthereumLabelsDetectorSpec extends Specification {
|
||||
class EthereumUpstreamSettingsDetectorSpec extends Specification {
|
||||
|
||||
def "Detect labels"() {
|
||||
setup:
|
||||
@@ -27,7 +27,7 @@ class EthereumLabelsDetectorSpec extends Specification {
|
||||
answer("eth_getBalance", ["0x0000000000000000000000000000000000000000", "0x2710"], "")
|
||||
}
|
||||
)
|
||||
def detector = new EthereumLabelsDetector(up.getIngressReader(), Chain.ETHEREUM__MAINNET)
|
||||
def detector = new EthereumUpstreamSettingsDetector(up, Chain.ETHEREUM__MAINNET)
|
||||
|
||||
when:
|
||||
def act = detector.detectLabels()
|
||||
@@ -51,7 +51,7 @@ class EthereumLabelsDetectorSpec extends Specification {
|
||||
def "No any label"() {
|
||||
setup:
|
||||
def up = Mock(DefaultUpstream) {
|
||||
1 * getIngressReader() >> Mock(Reader) {
|
||||
4 * getIngressReader() >> Mock(Reader) {
|
||||
1 * read(new ChainRequest("web3_clientVersion", new ListParams())) >>
|
||||
Mono.just(new ChainResponse('no/v1.19.3+e8ac1da4/linux-x64/dotnet7.0.8'.getBytes(), null))
|
||||
1 * read(new ChainRequest("eth_blockNumber", new ListParams())) >>
|
||||
@@ -62,7 +62,7 @@ class EthereumLabelsDetectorSpec extends Specification {
|
||||
Mono.just(new ChainResponse("".getBytes(), null))
|
||||
}
|
||||
}
|
||||
def detector = new EthereumLabelsDetector(up.getIngressReader(), Chain.ETHEREUM__MAINNET)
|
||||
def detector = new EthereumUpstreamSettingsDetector(up, Chain.ETHEREUM__MAINNET)
|
||||
when:
|
||||
def act = detector.detectLabels()
|
||||
then:
|
||||
@@ -70,4 +70,22 @@ class EthereumLabelsDetectorSpec extends Specification {
|
||||
.expectComplete()
|
||||
.verify(Duration.ofSeconds(1))
|
||||
}
|
||||
|
||||
def "Detect client version"() {
|
||||
setup:
|
||||
def up = Mock(DefaultUpstream) {
|
||||
2 * getIngressReader() >> Mock(Reader) {
|
||||
1 * read(new ChainRequest("web3_clientVersion", new ListParams())) >>
|
||||
Mono.just(new ChainResponse('"Erigon/v1.12.0-stable-e501b3b0/linux-amd64/go1.20.3"'.getBytes(), null))
|
||||
}
|
||||
}
|
||||
def detector = new EthereumUpstreamSettingsDetector(up, Chain.ETHEREUM__MAINNET)
|
||||
when:
|
||||
def act = detector.detectClientVersion()
|
||||
then:
|
||||
StepVerifier.create(act)
|
||||
.expectNext("Erigon/v1.12.0-stable-e501b3b0/linux-amd64/go1.20.3")
|
||||
.expectComplete()
|
||||
.verify(Duration.ofSeconds(1))
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,8 @@ import io.emeraldpay.api.proto.BlockchainOuterClass.NativeCallReplyItem
|
||||
import io.emeraldpay.api.proto.BlockchainOuterClass.NativeCallRequest
|
||||
import io.emeraldpay.dshackle.config.MainConfig
|
||||
import io.emeraldpay.dshackle.upstream.MultistreamHolder
|
||||
import io.emeraldpay.dshackle.upstream.UNKNOWN_CLIENT_VERSION
|
||||
import io.emeraldpay.dshackle.upstream.Upstream
|
||||
import io.emeraldpay.dshackle.upstream.signature.ResponseSigner
|
||||
import io.emeraldpay.dshackle.upstream.stream.Chunk
|
||||
import org.junit.jupiter.api.Test
|
||||
@@ -31,7 +33,7 @@ class NativeCallTest {
|
||||
),
|
||||
) {
|
||||
on { nativeCallResult(request) } doReturn Flux.just(
|
||||
NativeCall.CallResult.ok(1, null, "0x1".toByteArray(), null, "id", null),
|
||||
NativeCall.CallResult.ok(1, null, "0x1".toByteArray(), null, Upstream.UpstreamSettingsData("id"), null),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -39,6 +41,7 @@ class NativeCallTest {
|
||||
.expectNext(
|
||||
NativeCallReplyItem.newBuilder()
|
||||
.setUpstreamId("id")
|
||||
.setUpstreamNodeVersion(UNKNOWN_CLIENT_VERSION)
|
||||
.setId(1)
|
||||
.setSucceed(true)
|
||||
.setPayload(ByteString.copyFrom("0x1".toByteArray()))
|
||||
@@ -60,7 +63,7 @@ class NativeCallTest {
|
||||
),
|
||||
) {
|
||||
on { nativeCallResult(request) } doReturn Flux.just(
|
||||
NativeCall.CallResult(1, null, null, NativeCall.CallError(50001, "message", null, null, "upId"), null, null),
|
||||
NativeCall.CallResult(1, null, null, NativeCall.CallError(50001, "message", null, null, Upstream.UpstreamSettingsData("upId")), null, null),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -69,6 +72,7 @@ class NativeCallTest {
|
||||
NativeCallReplyItem.newBuilder()
|
||||
.setUpstreamId("upId")
|
||||
.setId(1)
|
||||
.setUpstreamNodeVersion(UNKNOWN_CLIENT_VERSION)
|
||||
.setSucceed(false)
|
||||
.setErrorMessage("message")
|
||||
.setItemErrorCode(50001)
|
||||
@@ -95,7 +99,7 @@ class NativeCallTest {
|
||||
),
|
||||
) {
|
||||
on { nativeCallResult(request) } doReturn Flux.just(
|
||||
NativeCall.CallResult.ok(1, null, "".toByteArray(), null, "upId", null, chunks),
|
||||
NativeCall.CallResult.ok(1, null, "".toByteArray(), null, Upstream.UpstreamSettingsData("upId"), null, chunks),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -104,6 +108,7 @@ class NativeCallTest {
|
||||
NativeCallReplyItem.newBuilder()
|
||||
.setUpstreamId("upId")
|
||||
.setId(1)
|
||||
.setUpstreamNodeVersion(UNKNOWN_CLIENT_VERSION)
|
||||
.setChunked(true)
|
||||
.setSucceed(true)
|
||||
.setPayload(ByteString.copyFrom("0x1".toByteArray()))
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
package io.emeraldpay.dshackle.upstream.near
|
||||
|
||||
import io.emeraldpay.dshackle.reader.ChainReader
|
||||
import io.emeraldpay.dshackle.upstream.ChainRequest
|
||||
import io.emeraldpay.dshackle.upstream.ChainResponse
|
||||
import io.emeraldpay.dshackle.upstream.Upstream
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.ListParams
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.mockito.kotlin.doReturn
|
||||
import org.mockito.kotlin.mock
|
||||
import reactor.core.publisher.Mono
|
||||
import reactor.test.StepVerifier
|
||||
|
||||
class NearUpstreamSettingsDetectorTest {
|
||||
|
||||
@Test
|
||||
fun `detect client version`() {
|
||||
val reader = mock<ChainReader> {
|
||||
on { read(ChainRequest("status", ListParams())) } doReturn
|
||||
Mono.just(
|
||||
ChainResponse(
|
||||
"""
|
||||
{
|
||||
"version": {
|
||||
"build": "1.38.1",
|
||||
"rustc_version": "1.75.0",
|
||||
"version": "1.38.1"
|
||||
}
|
||||
}
|
||||
""".trimIndent().toByteArray(),
|
||||
null,
|
||||
),
|
||||
)
|
||||
}
|
||||
val up = mock<Upstream> {
|
||||
on { getIngressReader() } doReturn reader
|
||||
}
|
||||
|
||||
val detector = NearUpstreamSettingsDetector(up)
|
||||
|
||||
StepVerifier.create(detector.detectClientVersion())
|
||||
.expectNext("1.38.1")
|
||||
.expectComplete()
|
||||
.verify()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package io.emeraldpay.dshackle.upstream.solana
|
||||
|
||||
import io.emeraldpay.dshackle.reader.ChainReader
|
||||
import io.emeraldpay.dshackle.upstream.ChainCallError
|
||||
import io.emeraldpay.dshackle.upstream.ChainRequest
|
||||
import io.emeraldpay.dshackle.upstream.ChainResponse
|
||||
import io.emeraldpay.dshackle.upstream.UNKNOWN_CLIENT_VERSION
|
||||
import io.emeraldpay.dshackle.upstream.Upstream
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.ListParams
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.mockito.kotlin.doReturn
|
||||
import org.mockito.kotlin.mock
|
||||
import reactor.core.publisher.Mono
|
||||
import reactor.test.StepVerifier
|
||||
|
||||
class SolanaUpstreamSettingsDetectorTest {
|
||||
|
||||
@Test
|
||||
fun `detect client version`() {
|
||||
val reader = mock<ChainReader> {
|
||||
on { read(ChainRequest("getVersion", ListParams())) } doReturn
|
||||
Mono.just(
|
||||
ChainResponse(
|
||||
"""
|
||||
{
|
||||
"feature-set": 2891131721,
|
||||
"solana-core": "1.16.7"
|
||||
}
|
||||
""".trimIndent().toByteArray(),
|
||||
null,
|
||||
),
|
||||
)
|
||||
}
|
||||
val up = mock<Upstream> {
|
||||
on { getIngressReader() } doReturn reader
|
||||
}
|
||||
|
||||
val detector = SolanaUpstreamSettingsDetector(up)
|
||||
|
||||
StepVerifier.create(detector.detectClientVersion())
|
||||
.expectNext("1.16.7")
|
||||
.expectComplete()
|
||||
.verify()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `unknown client if there is an error`() {
|
||||
val reader = mock<ChainReader> {
|
||||
on { read(ChainRequest("getVersion", ListParams())) } doReturn
|
||||
Mono.just(
|
||||
ChainResponse(
|
||||
null,
|
||||
ChainCallError(
|
||||
1,
|
||||
"message",
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
val up = mock<Upstream> {
|
||||
on { getIngressReader() } doReturn reader
|
||||
}
|
||||
|
||||
val detector = SolanaUpstreamSettingsDetector(up)
|
||||
|
||||
StepVerifier.create(detector.detectClientVersion())
|
||||
.expectNext(UNKNOWN_CLIENT_VERSION)
|
||||
.expectComplete()
|
||||
.verify()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user