solution: select which kind of upstream to use for native call
This commit is contained in:
@@ -23,7 +23,7 @@ import java.time.Duration
|
||||
|
||||
class TrackAddressSpec extends Specification {
|
||||
|
||||
AvailableChains availableChains = new AvailableChains()
|
||||
AvailableChains availableChains
|
||||
Upstreams upstreams
|
||||
TrackAddress trackAddress
|
||||
|
||||
@@ -37,6 +37,7 @@ class TrackAddressSpec extends Specification {
|
||||
|
||||
|
||||
def setup() {
|
||||
availableChains = new AvailableChains()
|
||||
upstreams = Mock(Upstreams)
|
||||
trackAddress = new TrackAddress(upstreams, availableChains, Schedulers.immediate())
|
||||
}
|
||||
@@ -63,7 +64,7 @@ class TrackAddressSpec extends Specification {
|
||||
def apiMock = new EthereumApiMock(Mock(RpcClient), TestingCommons.objectMapper(), Chain.ETHEREUM)
|
||||
apiMock.answer("eth_getBalance", ["0xe2c8fa8120d813cd0b5e6add120295bf20cfa09f", "latest"], "0x499602D2")
|
||||
_ * upstreams.getUpstream(Chain.ETHEREUM) >> upstreamMock
|
||||
_ * upstreamMock.getApi() >> apiMock
|
||||
_ * upstreamMock.getApi(_) >> apiMock
|
||||
start()
|
||||
when:
|
||||
def flux = trackAddress.getBalance(Mono.just(req))
|
||||
@@ -106,7 +107,7 @@ class TrackAddressSpec extends Specification {
|
||||
apiMock.answerOnce("eth_getBalance", ["0xe2c8fa8120d813cd0b5e6add120295bf20cfa09f", "latest"], "0x499602D2")
|
||||
apiMock.answerOnce("eth_getBalance", ["0xe2c8fa8120d813cd0b5e6add120295bf20cfa09f", "latest"], "0xff98")
|
||||
_ * upstreams.getUpstream(Chain.ETHEREUM) >> upstreamMock
|
||||
_ * upstreamMock.getApi() >> apiMock
|
||||
_ * upstreamMock.getApi(_) >> apiMock
|
||||
_ * upstreamMock.getHead() >> headMock
|
||||
_ * headMock.getFlux() >> blocksBus
|
||||
start()
|
||||
@@ -124,6 +125,7 @@ class TrackAddressSpec extends Specification {
|
||||
.expectNext(exp2)
|
||||
.thenCancel()
|
||||
.verify(Duration.ofSeconds(3))
|
||||
Thread.sleep(50)
|
||||
!trackAddress.isTracked(Chain.ETHEREUM, Address.from(address1))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ class TrackTxSpec extends Specification {
|
||||
apiMock.answer("eth_getBlockByHash", [blockJson.hash.toHex(), false], blockJson)
|
||||
|
||||
_ * upstreams.getUpstream(Chain.ETHEREUM) >> upstreamMock
|
||||
_ * upstreamMock.getApi() >> apiMock
|
||||
_ * upstreamMock.getApi(_) >> apiMock
|
||||
_ * upstreamMock.getHead() >> headMock
|
||||
_ * headMock.getFlux() >> blocksBus
|
||||
_ * headMock.getHead() >> Mono.just(blockHeadJson)
|
||||
@@ -182,7 +182,7 @@ class TrackTxSpec extends Specification {
|
||||
def headBlock = blocks[0]
|
||||
|
||||
_ * upstreams.getUpstream(Chain.ETHEREUM) >> upstreamMock
|
||||
_ * upstreamMock.getApi() >> apiMock
|
||||
_ * upstreamMock.getApi(_) >> apiMock
|
||||
_ * upstreamMock.getHead() >> headMock
|
||||
_ * headMock.getFlux() >> blocksBus
|
||||
_ * headMock.getHead() >> { return Mono.just(headBlock) }
|
||||
|
||||
@@ -45,7 +45,7 @@ class EthereumGrpcTransportSpec extends Specification {
|
||||
|
||||
then:
|
||||
1 * otherSideUpstreams.getUpstream(Chain.ETHEREUM) >> otherSideAggr
|
||||
1 * otherSideAggr.api >> otherSideApi
|
||||
1 * otherSideAggr.getApi(_) >> otherSideApi
|
||||
status.failed == 0
|
||||
status.succeed == 1
|
||||
status.total == 1
|
||||
@@ -90,7 +90,7 @@ class EthereumGrpcTransportSpec extends Specification {
|
||||
|
||||
then:
|
||||
1 * otherSideUpstreams.getUpstream(Chain.ETHEREUM) >> otherSideAggr
|
||||
1 * otherSideAggr.api >> otherSideApi
|
||||
1 * otherSideAggr.getApi(_) >> otherSideApi
|
||||
status.failed == 0
|
||||
status.succeed == 2
|
||||
status.total == 2
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
package io.emeraldpay.dshackle.upstream
|
||||
|
||||
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
||||
import io.emeraldpay.dshackle.test.TestingCommons
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import io.infinitape.etherjar.rpc.DefaultRpcClient
|
||||
import spock.lang.Specification
|
||||
|
||||
class FilteringApiIteratorSpec extends Specification {
|
||||
|
||||
def rpcClient = new DefaultRpcClient(null)
|
||||
def objectMapper = TestingCommons.objectMapper()
|
||||
|
||||
def "Verifies labels"() {
|
||||
setup:
|
||||
def upstreams = [
|
||||
new EthereumUpstream(
|
||||
Chain.ETHEREUM,
|
||||
new EthereumApi(rpcClient, objectMapper, Chain.ETHEREUM),
|
||||
(EthereumWs)null,
|
||||
new UpstreamsConfig.Options(),
|
||||
new NodeDetailsList.NodeDetails(1, UpstreamsConfig.Labels.fromMap([test: "foo"]))
|
||||
),
|
||||
new EthereumUpstream(
|
||||
Chain.ETHEREUM,
|
||||
new EthereumApi(rpcClient, objectMapper, Chain.ETHEREUM),
|
||||
(EthereumWs)null,
|
||||
new UpstreamsConfig.Options(),
|
||||
new NodeDetailsList.NodeDetails(1, UpstreamsConfig.Labels.fromMap([test: "bar"]))
|
||||
),
|
||||
new EthereumUpstream(
|
||||
Chain.ETHEREUM,
|
||||
new EthereumApi(rpcClient, objectMapper, Chain.ETHEREUM),
|
||||
(EthereumWs)null,
|
||||
new UpstreamsConfig.Options(),
|
||||
new NodeDetailsList.NodeDetails(1, UpstreamsConfig.Labels.fromMap([test: "foo", test2: "baz"]))
|
||||
),
|
||||
new EthereumUpstream(
|
||||
Chain.ETHEREUM,
|
||||
new EthereumApi(rpcClient, objectMapper, Chain.ETHEREUM),
|
||||
(EthereumWs)null,
|
||||
new UpstreamsConfig.Options(),
|
||||
new NodeDetailsList.NodeDetails(1, UpstreamsConfig.Labels.fromMap([test: "foo"]))
|
||||
),
|
||||
new EthereumUpstream(
|
||||
Chain.ETHEREUM,
|
||||
new EthereumApi(rpcClient, objectMapper, Chain.ETHEREUM),
|
||||
(EthereumWs)null,
|
||||
new UpstreamsConfig.Options(),
|
||||
new NodeDetailsList.NodeDetails(1, UpstreamsConfig.Labels.fromMap([test: "baz"]))
|
||||
)
|
||||
]
|
||||
def matcher = new Selector.LabelMatcher("test", ["foo"])
|
||||
upstreams.forEach {
|
||||
it.setStatus(UpstreamAvailability.OK)
|
||||
}
|
||||
when:
|
||||
def iter = new FilteringApiIterator(upstreams, 3, 0, matcher)
|
||||
then:
|
||||
iter.hasNext()
|
||||
iter.next() == upstreams[0].api
|
||||
iter.hasNext()
|
||||
iter.next() == upstreams[2].api
|
||||
iter.hasNext()
|
||||
iter.next() == upstreams[3].api
|
||||
!iter.hasNext()
|
||||
|
||||
when:
|
||||
iter = new FilteringApiIterator(upstreams, 2, 1, matcher)
|
||||
then:
|
||||
iter.hasNext()
|
||||
iter.next() == upstreams[2].api
|
||||
iter.hasNext()
|
||||
iter.next() == upstreams[3].api
|
||||
!iter.hasNext()
|
||||
|
||||
when:
|
||||
iter = new FilteringApiIterator(upstreams, 3, 1, matcher)
|
||||
then:
|
||||
iter.hasNext()
|
||||
iter.next() == upstreams[2].api
|
||||
iter.hasNext()
|
||||
iter.next() == upstreams[3].api
|
||||
iter.hasNext()
|
||||
iter.next() == upstreams[0].api
|
||||
!iter.hasNext()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,279 @@
|
||||
package io.emeraldpay.dshackle.upstream
|
||||
|
||||
import io.emeraldpay.api.proto.BlockchainOuterClass
|
||||
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
||||
import spock.lang.Specification
|
||||
|
||||
class SelectorSpec extends Specification {
|
||||
|
||||
private BlockchainOuterClass.LabelSelector.Builder selectLabel1 = BlockchainOuterClass.LabelSelector.newBuilder()
|
||||
.setName("foo").addAllValue(["bar"])
|
||||
private BlockchainOuterClass.Selector selectLabel1Selector = BlockchainOuterClass.Selector.newBuilder()
|
||||
.setLabelSelector(selectLabel1).build()
|
||||
|
||||
private BlockchainOuterClass.LabelSelector.Builder selectLabel2 = BlockchainOuterClass.LabelSelector.newBuilder()
|
||||
.setName("baz").addAllValue(["bar"])
|
||||
private BlockchainOuterClass.Selector selectLabel2Selector = BlockchainOuterClass.Selector.newBuilder()
|
||||
.setLabelSelector(selectLabel2).build()
|
||||
|
||||
def "Convert nothing"() {
|
||||
when:
|
||||
def act = Selector.convertToMatcher(null)
|
||||
then:
|
||||
act.class == Selector.EmptyMatcher
|
||||
}
|
||||
|
||||
def "Convert LABEL match"() {
|
||||
when:
|
||||
def act = Selector.convertToMatcher(
|
||||
selectLabel1Selector
|
||||
)
|
||||
then:
|
||||
act instanceof Selector.LabelMatcher
|
||||
with((Selector.LabelMatcher)act) {
|
||||
name == "foo"
|
||||
values == ["bar"]
|
||||
}
|
||||
}
|
||||
|
||||
def "Convert EXISTS match"() {
|
||||
when:
|
||||
def act = Selector.convertToMatcher(
|
||||
BlockchainOuterClass.Selector.newBuilder()
|
||||
.setExistsSelector(
|
||||
BlockchainOuterClass.ExistsSelector.newBuilder()
|
||||
.setName("foo")
|
||||
).build()
|
||||
)
|
||||
then:
|
||||
act instanceof Selector.ExistsMatcher
|
||||
with((Selector.ExistsMatcher)act) {
|
||||
name == "foo"
|
||||
}
|
||||
}
|
||||
|
||||
def "Convert NOT match"() {
|
||||
when:
|
||||
def act = Selector.convertToMatcher(
|
||||
BlockchainOuterClass.Selector.newBuilder()
|
||||
.setNotSelector(
|
||||
BlockchainOuterClass.NotSelector.newBuilder()
|
||||
.setSelector(selectLabel1Selector).build()
|
||||
)
|
||||
.build()
|
||||
)
|
||||
then:
|
||||
act instanceof Selector.NotMatcher
|
||||
with((Selector.NotMatcher)act) {
|
||||
matcher instanceof Selector.LabelMatcher
|
||||
with((Selector.LabelMatcher)matcher) {
|
||||
name == "foo"
|
||||
values == ["bar"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def "Convert OR match"() {
|
||||
when:
|
||||
def act = Selector.convertToMatcher(
|
||||
BlockchainOuterClass.Selector.newBuilder()
|
||||
.setOrSelector(
|
||||
BlockchainOuterClass.OrSelector.newBuilder()
|
||||
.addAllSelectors([selectLabel1Selector, selectLabel2Selector]).build()
|
||||
)
|
||||
.build()
|
||||
)
|
||||
then:
|
||||
act instanceof Selector.OrMatcher
|
||||
with((Selector.OrMatcher)act) {
|
||||
matchers.size() == 2
|
||||
with((Selector.LabelMatcher)matchers[0]) {
|
||||
name == "foo"
|
||||
values == ["bar"]
|
||||
}
|
||||
with((Selector.LabelMatcher)matchers[1]) {
|
||||
name == "baz"
|
||||
values == ["bar"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def "Convert AND match"() {
|
||||
when:
|
||||
def act = Selector.convertToMatcher(
|
||||
BlockchainOuterClass.Selector.newBuilder()
|
||||
.setAndSelector(
|
||||
BlockchainOuterClass.AndSelector.newBuilder()
|
||||
.addAllSelectors([selectLabel1Selector, selectLabel2Selector]).build()
|
||||
)
|
||||
.build()
|
||||
)
|
||||
then:
|
||||
act instanceof Selector.AndMatcher
|
||||
with((Selector.AndMatcher)act) {
|
||||
matchers.size() == 2
|
||||
with((Selector.LabelMatcher)matchers[0]) {
|
||||
name == "foo"
|
||||
values == ["bar"]
|
||||
}
|
||||
with((Selector.LabelMatcher)matchers[1]) {
|
||||
name == "baz"
|
||||
values == ["bar"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def "Convert LABEL AND NOT LABEl match"() {
|
||||
setup:
|
||||
def label1 = selectLabel1Selector
|
||||
def label2 = selectLabel2Selector
|
||||
def notLabel2 = BlockchainOuterClass.Selector.newBuilder()
|
||||
.setNotSelector(BlockchainOuterClass.NotSelector.newBuilder().setSelector(label2).build())
|
||||
.build()
|
||||
def and = BlockchainOuterClass.AndSelector.newBuilder()
|
||||
.addAllSelectors([
|
||||
label1, notLabel2
|
||||
]).build()
|
||||
when:
|
||||
def act = Selector.convertToMatcher(
|
||||
BlockchainOuterClass.Selector.newBuilder()
|
||||
.setAndSelector(and)
|
||||
.build()
|
||||
)
|
||||
then:
|
||||
act instanceof Selector.AndMatcher
|
||||
with((Selector.AndMatcher)act) {
|
||||
matchers.size() == 2
|
||||
with((Selector.LabelMatcher)matchers[0]) {
|
||||
name == "foo"
|
||||
values == ["bar"]
|
||||
}
|
||||
matchers[1] instanceof Selector.NotMatcher
|
||||
with((Selector.NotMatcher)matchers[1]) {
|
||||
matcher instanceof Selector.LabelMatcher
|
||||
with((Selector.LabelMatcher)matcher) {
|
||||
name == "baz"
|
||||
values == ["bar"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def "LABEL matches single label"() {
|
||||
setup:
|
||||
def matcher = new Selector.LabelMatcher("test", ["foo"])
|
||||
|
||||
expect:
|
||||
matcher.matches(UpstreamsConfig.Labels.fromMap(maps))
|
||||
|
||||
where:
|
||||
maps << [
|
||||
[test: "foo"],
|
||||
[test: "foo", test2: "bar"],
|
||||
[test2: "foo", test: "foo"],
|
||||
]
|
||||
}
|
||||
|
||||
def "LABEL matches one label two values"() {
|
||||
setup:
|
||||
def matcher = new Selector.LabelMatcher("test", ["foo", "bar"])
|
||||
|
||||
expect:
|
||||
matcher.matches(UpstreamsConfig.Labels.fromMap(maps))
|
||||
|
||||
where:
|
||||
maps << [
|
||||
[test: "foo"],
|
||||
[test: "foo", test2: "bar"],
|
||||
[test2: "foo", test: "bar"],
|
||||
]
|
||||
}
|
||||
|
||||
def "AND matches one label"() {
|
||||
setup:
|
||||
def matcher = new Selector.AndMatcher(
|
||||
[
|
||||
new Selector.LabelMatcher("test", ["foo", "bar"])
|
||||
]
|
||||
)
|
||||
|
||||
expect:
|
||||
matcher.matches(UpstreamsConfig.Labels.fromMap(maps))
|
||||
|
||||
where:
|
||||
maps << [
|
||||
[test: "foo"],
|
||||
[test: "foo", test2: "bar"],
|
||||
[test2: "foo", test: "bar"],
|
||||
]
|
||||
}
|
||||
|
||||
def "AND matches two labels"() {
|
||||
setup:
|
||||
def matcher = new Selector.AndMatcher(
|
||||
[
|
||||
new Selector.LabelMatcher("test", ["foo", "bar"]),
|
||||
new Selector.LabelMatcher("test2", ["baz"])
|
||||
]
|
||||
)
|
||||
|
||||
expect:
|
||||
matcher.matches(UpstreamsConfig.Labels.fromMap(maps))
|
||||
|
||||
where:
|
||||
maps << [
|
||||
[test: "foo", test2: "baz"],
|
||||
[test: "foo", test3: "bar", test2: "baz"],
|
||||
[test3: "foo", test: "bar", test2: "baz"],
|
||||
]
|
||||
}
|
||||
|
||||
def "OR matches two labels"() {
|
||||
setup:
|
||||
def matcher = new Selector.OrMatcher(
|
||||
[
|
||||
new Selector.LabelMatcher("test", ["foo", "bar"]),
|
||||
new Selector.LabelMatcher("test2", ["baz"])
|
||||
]
|
||||
)
|
||||
|
||||
expect:
|
||||
matcher.matches(UpstreamsConfig.Labels.fromMap(maps))
|
||||
|
||||
where:
|
||||
maps << [
|
||||
[test: "foo", test2: "baz"],
|
||||
[test: "foo", test3: "bar", test2: "baz"],
|
||||
[test3: "foo", test: "bar", test2: "baz"],
|
||||
[test2: "baz"],
|
||||
[test: "bar"],
|
||||
[test: "foo"],
|
||||
]
|
||||
}
|
||||
|
||||
def "AND NOT matches two labels"() {
|
||||
setup:
|
||||
def matcher = new Selector.AndMatcher(
|
||||
[
|
||||
new Selector.LabelMatcher("test", ["foo", "bar"]),
|
||||
new Selector.NotMatcher(
|
||||
new Selector.LabelMatcher("test2", ["baz"])
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
expect:
|
||||
matcher.matches(UpstreamsConfig.Labels.fromMap(maps))
|
||||
|
||||
where:
|
||||
maps << [
|
||||
[test: "foo", test2: "not_baz"],
|
||||
[test: "foo", test3: "bar", test2: "not_baz"],
|
||||
[test: "foo", test3: "bar"],
|
||||
[test3: "foo", test: "bar", test2: "not_baz"],
|
||||
[test3: "foo", test: "bar"],
|
||||
[test: "bar"],
|
||||
[test: "foo"],
|
||||
]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user