solution: select which kind of upstream to use for native call

This commit is contained in:
Igor Artamonov
2019-08-02 23:46:58 -04:00
parent 2c5551d818
commit 22c2294983
19 changed files with 607 additions and 94 deletions

View File

@@ -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))
}
}

View File

@@ -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) }

View File

@@ -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

View File

@@ -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()
}
}

View File

@@ -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"],
]
}
}