Switch no response error to null or separate errors (#210)

This commit is contained in:
KirillPamPam
2023-05-22 17:57:32 +04:00
committed by GitHub
parent 72c4f1192b
commit 4f21cb995d
22 changed files with 779 additions and 151 deletions

View File

@@ -289,4 +289,33 @@ class QuorumRpcReaderSpec extends Specification {
.verify(Duration.ofSeconds(1))
}
def "Error if no upstreams"() {
setup:
def api = Stub(Reader)
def up = Mock(Upstream) {
_ * getId() >> "id1"
_ * isAvailable() >> false
_ * getRole() >> UpstreamsConfig.UpstreamRole.PRIMARY
_ * getIngressReader() >> api
}
def apis = new FilteredApis(
Chain.ETHEREUM,
[up], Selector.empty
)
def reader = new QuorumRpcReader(apis, new AlwaysQuorum(), Stub(Tracer))
when:
def act = reader.read(new JsonRpcRequest("eth_test", []))
.map {
new String(it.value)
}
then:
StepVerifier.create(act)
.expectErrorMatches { t ->
t instanceof RpcException && t.rpcMessage == "No response for method eth_test. Cause - Upstream is not available" && t.error.code == 1
}
.verify(Duration.ofSeconds(4))
}
}

View File

@@ -25,6 +25,7 @@ import io.emeraldpay.dshackle.Global
import io.emeraldpay.dshackle.config.CacheConfig
import io.emeraldpay.dshackle.config.MainConfig
import io.emeraldpay.dshackle.quorum.AlwaysQuorum
import io.emeraldpay.dshackle.quorum.QuorumReader
import io.emeraldpay.dshackle.quorum.QuorumReaderFactory
import io.emeraldpay.dshackle.quorum.QuorumRpcReader
import io.emeraldpay.dshackle.reader.Reader
@@ -52,6 +53,7 @@ import spock.lang.Ignore
import spock.lang.Specification
import java.time.Duration
import java.util.concurrent.atomic.AtomicInteger
class NativeCallSpec extends Specification {
@@ -131,7 +133,7 @@ class NativeCallSpec extends Specification {
def nativeCall = nativeCall()
nativeCall.quorumReaderFactory = Mock(QuorumReaderFactory) {
1 * create(_, _, _, _) >> Mock(Reader) {
1 * create(_, _, _, _) >> Mock(QuorumReader) {
1 * read(_) >> Mono.just(new QuorumRpcReader.Result("\"foo\"".bytes, null, 1, Collections.singletonList(ups), null))
}
}
@@ -152,7 +154,8 @@ class NativeCallSpec extends Specification {
def nativeCall = nativeCall()
nativeCall.quorumReaderFactory = Mock(QuorumReaderFactory) {
1 * create(_, _, _, _) >> Mock(Reader) {
1 * create(_, _, _, _) >> Mock(QuorumReader) {
1 * attempts() >> new AtomicInteger(1)
1 * read(new JsonRpcRequest("eth_test", [], 10)) >> Mono.empty()
}
}
@@ -176,7 +179,7 @@ class NativeCallSpec extends Specification {
def nativeCall = nativeCall()
nativeCall.quorumReaderFactory = Mock(QuorumReaderFactory) {
1 * create(_, _, _, _) >> Mock(Reader) {
1 * create(_, _, _, _) >> Mock(QuorumReader) {
1 * read(new JsonRpcRequest("eth_test", [], 10)) >> Mono.error(
new JsonRpcException(JsonRpcResponse.Id.from(12), new JsonRpcError(-32123, "Foo Bar", "Foo Bar Baz"), true)
)
@@ -613,7 +616,7 @@ class NativeCallSpec extends Specification {
}
def nativeCall = nativeCall(multistreamHolder)
nativeCall.quorumReaderFactory = Mock(QuorumReaderFactory) {
1 * create(_, _, _, _) >> Mock(Reader) {
1 * create(_, _, _, _) >> Mock(QuorumReader) {
1 * read(_) >> Mono.just(new QuorumRpcReader.Result("\"0xab\"".bytes, null, 1, Collections.singletonList(ups), null))
}
}
@@ -648,7 +651,7 @@ class NativeCallSpec extends Specification {
}
def nativeCall = nativeCall(multistreamHolder)
nativeCall.quorumReaderFactory = Mock(QuorumReaderFactory) {
1 * create(_, _, _, _) >> Mock(Reader) {
1 * create(_, _, _, _) >> Mock(QuorumReader) {
1 * read(_) >> Mono.just(new QuorumRpcReader.Result("\"0xab\"".bytes, null, 1, Collections.singletonList(ups), null))
}
}

View File

@@ -33,6 +33,8 @@ import spock.lang.Specification
import java.time.Duration
import static java.util.List.of
class FilteredApisSpec extends Specification {
def ethereumTargets = new DefaultEthereumMethods(Chain.ETHEREUM)
@@ -194,6 +196,29 @@ class FilteredApisSpec extends Specification {
.expectNext(ups[2], ups[3], ups[4], ups[5], ups[0], ups[1])
.expectComplete()
.verify(Duration.ofSeconds(1))
act.attempts().get() == 6
}
def "FilteredApis is requested 3 times"() {
setup:
def apis = (0..5).collect {
new EthereumApiStub(it)
}
def ups = apis.collect {
TestingCommons.upstream(it)
}
when:
def act = new FilteredApis(Chain.ETHEREUM, ups, Selector.empty, 2, 1, 0)
act.request(3)
then:
StepVerifier.create(act)
.expectNext(ups[2], ups[3], ups[4])
.then {
act.resolve()
}
.expectComplete()
.verify(Duration.ofSeconds(1))
act.attempts().get() == 3
}
def "Start with offset - 5 items"() {
@@ -330,4 +355,207 @@ class FilteredApisSpec extends Specification {
.expectComplete()
.verify(Duration.ofSeconds(1))
}
def "No upstreams if they all are unavailable"() {
setup:
List<Upstream> ups = [
Mock(Upstream) {
_ * getRole() >> UpstreamsConfig.UpstreamRole.PRIMARY
_ * isAvailable() >> false
_ * getId() >> "id1"
_ * getStatus() >> UpstreamAvailability.SYNCING
},
Mock(Upstream) {
_ * getId() >> "id2"
_ * getRole() >> UpstreamsConfig.UpstreamRole.PRIMARY
_ * isAvailable() >> false
_ * getStatus() >> UpstreamAvailability.SYNCING
}
]
when:
def act = new FilteredApis(Chain.ETHEREUM, ups, Selector.empty)
act.request(1)
then:
StepVerifier.create(act)
.expectNextCount(0)
.expectComplete()
.verify(Duration.ofSeconds(5))
act.upstreamsMatchesResponse() != null
act.upstreamsMatchesResponse().getFullCause() == "id1 - Upstream is not available; id2 - Upstream is not available"
act.upstreamsMatchesResponse().getCause("").cause == "Upstream is not available"
}
def "No upstreams if they all are not matched"() {
setup:
List<Upstream> ups = [
Mock(Upstream) {
_ * getRole() >> UpstreamsConfig.UpstreamRole.PRIMARY
_ * isAvailable() >> true
_ * getId() >> "id1"
_ * getStatus() >> UpstreamAvailability.OK
_ * getLabels() >> of(UpstreamsConfig.Labels.fromMap(Map.of("node", "archive")))
},
Mock(Upstream) {
_ * getId() >> "id2"
_ * getRole() >> UpstreamsConfig.UpstreamRole.PRIMARY
_ * isAvailable() >> true
_ * getStatus() >> UpstreamAvailability.OK
_ * getLabels() >> of(UpstreamsConfig.Labels.fromMap(Map.of("node", "archive")))
}
]
when:
def act = new FilteredApis(Chain.ETHEREUM, ups, new Selector.LabelMatcher("node", of("test")))
act.request(1)
then:
StepVerifier.create(act)
.expectNextCount(0)
.expectComplete()
.verify(Duration.ofSeconds(5))
act.upstreamsMatchesResponse() != null
act.upstreamsMatchesResponse().getFullCause() == "id1 - No label `node` with values [test]; id2 - No label `node` with values [test]"
act.upstreamsMatchesResponse().getCause("").cause == "No label `node` with values [test]"
}
def "No upstreams if they all are not matched by first matcher"() {
setup:
List<Upstream> ups = [
Mock(Upstream) {
_ * getRole() >> UpstreamsConfig.UpstreamRole.PRIMARY
_ * isAvailable() >> false
_ * getId() >> "id1"
_ * getStatus() >> UpstreamAvailability.OK
_ * getHead() >> Mock(Head) {
_ * getCurrentHeight() >> 100000
}
_ * getLabels() >> of(
UpstreamsConfig.Labels.fromMap(
Map.of("node", "archive", "type", "super")
)
)
},
Mock(Upstream) {
_ * getId() >> "id2"
_ * getRole() >> UpstreamsConfig.UpstreamRole.PRIMARY
_ * isAvailable() >> false
_ * getHead() >> Mock(Head) {
_ * getCurrentHeight() >> 100000
}
_ * getStatus() >> UpstreamAvailability.OK
_ * getLabels() >> of(UpstreamsConfig.Labels.fromMap(Map.of("node", "archive")))
}
]
when:
def act = new FilteredApis(
Chain.ETHEREUM, ups,
new Selector.MultiMatcher(
of(
new Selector.HeightMatcher(100000000),
)
)
)
act.request(1)
then:
StepVerifier.create(act)
.expectNextCount(0)
.expectComplete()
.verify(Duration.ofSeconds(5))
act.upstreamsMatchesResponse() != null
act.upstreamsMatchesResponse().getFullCause() == "id1 - Upstream is not available; Upstream height 100000 is less than 100000000; id2 - Upstream is not available; Upstream height 100000 is less than 100000000"
act.upstreamsMatchesResponse().getCause("eth_getTransactionByHash").cause == null
act.upstreamsMatchesResponse().getCause("eth_getTransactionByHash").shouldReturnNull
}
def "No upstreams if they all are not matched and return null cause"() {
setup:
List<Upstream> ups = [
Mock(Upstream) {
_ * getRole() >> UpstreamsConfig.UpstreamRole.PRIMARY
_ * isAvailable() >> false
_ * getId() >> "id1"
_ * getStatus() >> UpstreamAvailability.OK
_ * getHead() >> Mock(Head) {
_ * getCurrentHeight() >> 100000
}
_ * getLabels() >> of(
UpstreamsConfig.Labels.fromMap(
Map.of("node", "archive", "type", "super")
)
)
},
Mock(Upstream) {
_ * getId() >> "id2"
_ * getRole() >> UpstreamsConfig.UpstreamRole.PRIMARY
_ * isAvailable() >> false
_ * getHead() >> Mock(Head) {
_ * getCurrentHeight() >> 100000
}
_ * getStatus() >> UpstreamAvailability.OK
_ * getLabels() >> of(UpstreamsConfig.Labels.fromMap(Map.of("node", "archive")))
}
]
when:
def act = new FilteredApis(
Chain.ETHEREUM, ups,
new Selector.MultiMatcher(
of(
new Selector.HeightMatcher(100000000),
)
)
)
act.request(1)
then:
StepVerifier.create(act)
.expectNextCount(0)
.expectComplete()
.verify(Duration.ofSeconds(5))
act.upstreamsMatchesResponse() != null
act.upstreamsMatchesResponse().getFullCause() == "id1 - Upstream is not available; Upstream height 100000 is less than 100000000; id2 - Upstream is not available; Upstream height 100000 is less than 100000000"
act.upstreamsMatchesResponse().getCause("other") == null
}
def "Second upstream if first is not matched"() {
setup:
def up = Mock(Upstream) {
_ * getId() >> "id2"
_ * getRole() >> UpstreamsConfig.UpstreamRole.PRIMARY
_ * isAvailable() >> true
_ * getHead() >> Mock(Head) {
_ * getCurrentHeight() >> 100000001
}
_ * getStatus() >> UpstreamAvailability.OK
_ * getLabels() >> of(UpstreamsConfig.Labels.fromMap(Map.of("node", "test")))
}
List<Upstream> ups = [
Mock(Upstream) {
_ * getRole() >> UpstreamsConfig.UpstreamRole.PRIMARY
_ * isAvailable() >> true
_ * getId() >> "id1"
_ * getStatus() >> UpstreamAvailability.OK
_ * getHead() >> Mock(Head) {
_ * getCurrentHeight() >> 100000
}
_ * getLabels() >> of(UpstreamsConfig.Labels.fromMap(Map.of("node", "archive")))
}, up
]
when:
def act = new FilteredApis(
Chain.ETHEREUM, ups,
new Selector.MultiMatcher(
of(
new Selector.HeightMatcher(100000000),
new Selector.LabelMatcher("node", of("test"))
)
)
)
act.request(1)
then:
StepVerifier.create(act)
.expectNext(up)
.then {
act.resolve()
}
.expectComplete()
.verify(Duration.ofSeconds(5))
act.upstreamsMatchesResponse() == null
}
}

View File

@@ -178,9 +178,12 @@ class SelectorSpec extends Specification {
def "LABEL matches single label"() {
setup:
def matcher = new Selector.LabelMatcher("test", ["foo"])
def up = Mock(Upstream) {
1 * getLabels() >> [UpstreamsConfig.Labels.fromMap(maps)]
}
expect:
matcher.matches(UpstreamsConfig.Labels.fromMap(maps))
matcher.matches(up)
where:
maps << [
@@ -193,9 +196,12 @@ class SelectorSpec extends Specification {
def "LABEL matches one label two values"() {
setup:
def matcher = new Selector.LabelMatcher("test", ["foo", "bar"])
def up = Mock(Upstream) {
1 * getLabels() >> [UpstreamsConfig.Labels.fromMap(maps)]
}
expect:
matcher.matches(UpstreamsConfig.Labels.fromMap(maps))
matcher.matches(up)
where:
maps << [
@@ -212,9 +218,12 @@ class SelectorSpec extends Specification {
new Selector.LabelMatcher("test", ["foo", "bar"])
]
)
def up = Mock(Upstream) {
1 * getLabels() >> [UpstreamsConfig.Labels.fromMap(maps)]
}
expect:
matcher.matches(UpstreamsConfig.Labels.fromMap(maps))
matcher.matches(up)
where:
maps << [
@@ -232,9 +241,12 @@ class SelectorSpec extends Specification {
new Selector.LabelMatcher("test2", ["baz"])
]
)
def up = Mock(Upstream) {
1 * getLabels() >> [UpstreamsConfig.Labels.fromMap(maps)]
}
expect:
matcher.matches(UpstreamsConfig.Labels.fromMap(maps))
matcher.matches(up)
where:
maps << [
@@ -252,9 +264,12 @@ class SelectorSpec extends Specification {
new Selector.LabelMatcher("test2", ["baz"])
]
)
def up = Mock(Upstream) {
1 * getLabels() >> [UpstreamsConfig.Labels.fromMap(maps)]
}
expect:
matcher.matches(UpstreamsConfig.Labels.fromMap(maps))
matcher.matches(up)
where:
maps << [
@@ -277,9 +292,12 @@ class SelectorSpec extends Specification {
)
]
)
def up = Mock(Upstream) {
1 * getLabels() >> [UpstreamsConfig.Labels.fromMap(maps)]
}
expect:
matcher.matches(UpstreamsConfig.Labels.fromMap(maps))
matcher.matches(up)
where:
maps << [

View File

@@ -5,9 +5,9 @@ import io.emeraldpay.dshackle.Global
import io.emeraldpay.dshackle.cache.Caches
import io.emeraldpay.dshackle.cache.CurrentBlockCache
import io.emeraldpay.dshackle.data.DefaultContainer
import io.emeraldpay.dshackle.quorum.QuorumReader
import io.emeraldpay.dshackle.quorum.QuorumReaderFactory
import io.emeraldpay.dshackle.quorum.QuorumRpcReader
import io.emeraldpay.dshackle.reader.Reader
import io.emeraldpay.dshackle.test.TestingCommons
import io.emeraldpay.dshackle.upstream.ApiSource
import io.emeraldpay.dshackle.upstream.Head
@@ -56,7 +56,7 @@ class EthereumDirectReaderSpec extends Specification {
up, Caches.default(), new CurrentBlockCache(), calls, TestingCommons.tracerMock()
)
reader.quorumReaderFactory = Mock(QuorumReaderFactory) {
1 * create(_, _, _, _) >> Mock(Reader) {
1 * create(_, _, _, _,) >> Mock(QuorumReader) {
1 * read(new JsonRpcRequest("eth_getBlockByHash", [hash1, false])) >> Mono.just(
new QuorumRpcReader.Result(
Global.objectMapper.writeValueAsBytes(json), null, 1, resolvers, null)
@@ -86,7 +86,7 @@ class EthereumDirectReaderSpec extends Specification {
up, Caches.default(), new CurrentBlockCache(), calls, TestingCommons.tracerMock()
)
reader.quorumReaderFactory = Mock(QuorumReaderFactory) {
1 * create(_, _, _, _) >> Mock(Reader) {
1 * create(_, _, _, _) >> Mock(QuorumReader) {
1 * read(new JsonRpcRequest("eth_getBlockByHash", [hash1, false])) >> Mono.just(
new QuorumRpcReader.Result(
Global.objectMapper.writeValueAsBytes(null), null, 1, resolvers, null
@@ -124,7 +124,7 @@ class EthereumDirectReaderSpec extends Specification {
up, Caches.default(), new CurrentBlockCache(), calls, TestingCommons.tracerMock()
)
reader.quorumReaderFactory = Mock(QuorumReaderFactory) {
1 * create(_, _, _, _) >> Mock(Reader) {
1 * create(_, _, _, _) >> Mock(QuorumReader) {
1 * read(new JsonRpcRequest("eth_getBlockByNumber", ["0x64", false])) >> Mono.just(
new QuorumRpcReader.Result(
Global.objectMapper.writeValueAsBytes(json), null, 1, resolvers, null
@@ -160,7 +160,7 @@ class EthereumDirectReaderSpec extends Specification {
up, Caches.default(), new CurrentBlockCache(), calls, TestingCommons.tracerMock()
)
reader.quorumReaderFactory = Mock(QuorumReaderFactory) {
1 * create(_, _, _, _) >> Mock(Reader) {
1 * create(_, _, _, _) >> Mock(QuorumReader) {
1 * read(new JsonRpcRequest("eth_getTransactionByHash", [hash1])) >> Mono.just(
new QuorumRpcReader.Result(
Global.objectMapper.writeValueAsBytes(json), null, 1, resolvers, null
@@ -196,7 +196,7 @@ class EthereumDirectReaderSpec extends Specification {
up, Caches.default(), new CurrentBlockCache(), calls, TestingCommons.tracerMock()
)
reader.quorumReaderFactory = Mock(QuorumReaderFactory) {
1 * create(_, _, _, _) >> Mock(Reader) {
1 * create(_, _, _, _) >> Mock(QuorumReader) {
1 * read(new JsonRpcRequest("eth_getTransactionReceipt", [hash1])) >> Mono.just(
new QuorumRpcReader.Result(
Global.objectMapper.writeValueAsBytes(json), null, 1, new ArrayList<Byte>(), null
@@ -233,7 +233,7 @@ class EthereumDirectReaderSpec extends Specification {
up, caches, new CurrentBlockCache(), calls, TestingCommons.tracerMock()
)
reader.quorumReaderFactory = Mock(QuorumReaderFactory) {
1 * create(_, _, _, _) >> Mock(Reader) {
1 * create(_, _, _, _) >> Mock(QuorumReader) {
1 * read(new JsonRpcRequest("eth_getTransactionReceipt", [hash1])) >> Mono.just(
new QuorumRpcReader.Result(
Global.objectMapper.writeValueAsBytes(json), null, 1, new ArrayList<Byte>(), null
@@ -261,7 +261,7 @@ class EthereumDirectReaderSpec extends Specification {
up, Caches.default(), new CurrentBlockCache(), calls, TestingCommons.tracerMock()
)
reader.quorumReaderFactory = Mock(QuorumReaderFactory) {
1 * create(_, _, _, _) >> Mock(Reader) {
1 * create(_, _, _, _) >> Mock(QuorumReader) {
1 * read(new JsonRpcRequest("eth_getTransactionByHash", [hash1])) >> Mono.just(
new QuorumRpcReader.Result(
Global.objectMapper.writeValueAsBytes(null), null, 1, resolvers, null
@@ -292,7 +292,7 @@ class EthereumDirectReaderSpec extends Specification {
up, Caches.default(), new CurrentBlockCache(), calls, TestingCommons.tracerMock()
)
reader.quorumReaderFactory = Mock(QuorumReaderFactory) {
1 * create(_, _, _, _) >> Mock(Reader) {
1 * create(_, _, _, _) >> Mock(QuorumReader) {
1 * read(new JsonRpcRequest("eth_getBalance", [address1, "latest"])) >> Mono.just(
new QuorumRpcReader.Result(
Global.objectMapper.writeValueAsBytes("0x100"), null, 1, resolvers, null
@@ -324,7 +324,7 @@ class EthereumDirectReaderSpec extends Specification {
up, Caches.default(), new CurrentBlockCache(), calls, TestingCommons.tracerMock()
)
reader.quorumReaderFactory = Mock(QuorumReaderFactory) {
1 * create(_, _, _, _) >> Mock(Reader) {
1 * create(_, _, _, _) >> Mock(QuorumReader) {
1 * read(new JsonRpcRequest("eth_getBalance", [address1, "0xa8c9bb"])) >> Mono.just(
new QuorumRpcReader.Result(
Global.objectMapper.writeValueAsBytes("0x100"), null, 1, resolvers, null
@@ -365,11 +365,11 @@ class EthereumDirectReaderSpec extends Specification {
up, Caches.default(), new CurrentBlockCache(), calls, TestingCommons.tracerMock()
)
ethereumDirectReader.quorumReaderFactory = Mock(QuorumReaderFactory) {
2 * create(_, _, _, _) >> Mock(Reader) {
2 * create(_, _, _, _) >> Mock(QuorumReader) {
2 * read(new JsonRpcRequest("eth_getBlockByHash", [hash1, false])) >>>
[Mono.error(new RuntimeException()), Mono.error(new RuntimeException())]
}
1 * create(_, _, _, _) >> Mock(Reader) {
1 * create(_, _, _, _) >> Mock(QuorumReader) {
1 * read(new JsonRpcRequest("eth_getBlockByHash", [hash1, false])) >> result
}
}
@@ -408,11 +408,11 @@ class EthereumDirectReaderSpec extends Specification {
up, Caches.default(), new CurrentBlockCache(), calls, TestingCommons.tracerMock()
)
ethereumDirectReader.quorumReaderFactory = Mock(QuorumReaderFactory) {
2 * create(_, _, _, _) >> Mock(Reader) {
2 * create(_, _, _, _) >> Mock(QuorumReader) {
2 * read(new JsonRpcRequest("eth_getBlockByNumber", ["0x64", false])) >>>
[Mono.error(new RuntimeException()), Mono.error(new RuntimeException())]
}
1 * create(_, _, _, _) >> Mock(Reader) {
1 * create(_, _, _, _) >> Mock(QuorumReader) {
1 * read(new JsonRpcRequest("eth_getBlockByNumber", ["0x64", false])) >> result
}
}
@@ -442,7 +442,7 @@ class EthereumDirectReaderSpec extends Specification {
up, Caches.default(), new CurrentBlockCache(), calls, TestingCommons.tracerMock()
)
reader.quorumReaderFactory = Mock(QuorumReaderFactory) {
4 * create(_, _, _, _) >> Mock(Reader) {
4 * create(_, _, _, _) >> Mock(QuorumReader) {
4 * read(new JsonRpcRequest("eth_getBalance", [address1, "latest"])) >>>
[Mono.error(new RuntimeException()), Mono.error(new RuntimeException()),
Mono.error(new RuntimeException()), Mono.error(new RuntimeException())]

View File

@@ -37,7 +37,7 @@ class CollectSpanConfigTest {
appCtx.getBean(SpanConfig::class.java)
}
assertThrows(NoSuchBeanDefinitionException::class.java) {
appCtx.getBean(ErrorSpanHandler::class.java)
appCtx.getBean(ProviderSpanHandler::class.java)
}
assertThrows(NoSuchBeanDefinitionException::class.java) {
appCtx.getBean(ServerSpansInterceptor::class.java)
@@ -72,7 +72,7 @@ class CollectSpanConfigTest {
appCtx.getBean(SpanConfig::class.java)
}
assertDoesNotThrow {
appCtx.getBean(ErrorSpanHandler::class.java)
appCtx.getBean(ProviderSpanHandler::class.java)
}
assertDoesNotThrow {
appCtx.getBean(ServerSpansInterceptor::class.java)
@@ -113,7 +113,7 @@ class CollectSpanConfigTest {
appCtx.getBean(SpanConfig::class.java)
}
assertThrows(NoSuchBeanDefinitionException::class.java) {
appCtx.getBean(ErrorSpanHandler::class.java)
appCtx.getBean(ProviderSpanHandler::class.java)
}
assertThrows(NoSuchBeanDefinitionException::class.java) {
appCtx.getBean(ServerSpansInterceptor::class.java)

View File

@@ -5,16 +5,20 @@ import brave.handler.SpanHandler
import brave.propagation.TraceContext
import com.fasterxml.jackson.module.kotlin.readValue
import io.emeraldpay.dshackle.commons.SPAN_ERROR
import io.emeraldpay.dshackle.commons.SPAN_NO_RESPONSE_MESSAGE
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Test
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.MethodSource
import org.mockito.Mockito
import org.mockito.Mockito.`when`
import org.springframework.cloud.sleuth.Span
import org.springframework.cloud.sleuth.brave.bridge.BraveTraceContext
class ErrorSpanHandlerTest {
class ProviderSpanHandlerTest {
private val mapper = SpanConfig().spanMapper()
private val spanExportableList = listOf(ErrorSpanExportable(), NoResponseSpanExportable())
private val ctx = TraceContext.newBuilder()
.traceId(1223324)
.spanId(234235)
@@ -48,13 +52,11 @@ class ErrorSpanHandlerTest {
assertEquals("", result)
}
@Test
fun `span with length of traceId greater than 20 and with parentId is collected`() {
val spanId = "f7e83f2b69ec684d"
@ParameterizedTest
@MethodSource("spans")
fun `span with length of traceId greater than 20 and with parentId is collected`(span: MutableSpan) {
val currentSpan = Mockito.mock(Span::class.java)
val handler = spanHandler()
val span = span("6666632728347823749827349723985", spanId)
.apply { parentId("f7e83f2b69ec682d") }
`when`(currentSpan.context()).thenReturn(BraveTraceContext(ctx))
@@ -92,5 +94,25 @@ class ErrorSpanHandlerTest {
tag(SPAN_ERROR, "true")
}
private fun spanHandler() = ErrorSpanHandler(mapper)
companion object {
@JvmStatic
fun spans() = listOf(
MutableSpan()
.apply {
traceId("6666632728347823749827349723985")
id("f7e83f2b69ec682d")
tag(SPAN_ERROR, "true")
parentId("f7e83f2b69ec682d")
},
MutableSpan()
.apply {
traceId("6666632728347823749827349723985")
id("f7e83f2b69ec111d")
parentId("f7e83f2b69ec682d")
tag(SPAN_NO_RESPONSE_MESSAGE, "noResp")
}
)
}
private fun spanHandler() = ProviderSpanHandler(mapper, spanExportableList)
}