Fixing sc function (#1983)
- Removed an unnecessary child span; the parent span was never ended - Added tests
This commit is contained in:
committed by
GitHub
parent
e17ae7445a
commit
b876551a78
@@ -18,6 +18,7 @@ package org.springframework.cloud.sleuth.brave;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import brave.test.IntegrationTestSpanHandler;
|
||||
@@ -27,6 +28,8 @@ import org.springframework.cloud.sleuth.brave.bridge.BraveAccessor;
|
||||
import org.springframework.cloud.sleuth.exporter.FinishedSpan;
|
||||
import org.springframework.cloud.sleuth.test.TestSpanHandler;
|
||||
|
||||
import static org.assertj.core.api.BDDAssertions.then;
|
||||
|
||||
public class BraveTestSpanHandler implements TestSpanHandler {
|
||||
|
||||
final brave.test.TestSpanHandler spans;
|
||||
@@ -81,6 +84,33 @@ public class BraveTestSpanHandler implements TestSpanHandler {
|
||||
return BraveAccessor.finishedSpan(this.spans.get(index));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void assertAllSpansWereFinishedOrAbandoned(Queue<Span> createdSpans) {
|
||||
List<FinishedSpan> finishedSpans = reportedSpans();
|
||||
then(finishedSpans).as("There should be that many finished spans as many created ones")
|
||||
.hasSize(createdSpans.size());
|
||||
// finished -> a,b,c ; created -> b,c,d => matchedFinished = b,c
|
||||
List<FinishedSpan> matchedFinishedSpans = finishedSpans.stream()
|
||||
.filter(f -> createdSpans.stream().anyMatch(cs -> f.getSpanId().equals(cs.context().spanId())))
|
||||
.collect(Collectors.toList());
|
||||
// finished -> a,b,c ; created -> b,c,d => matchedCreated = b,c
|
||||
List<Span> matchedCreatedSpans = createdSpans.stream()
|
||||
.filter(cs -> finishedSpans.stream().anyMatch(f -> cs.context().spanId().equals(f.getSpanId())))
|
||||
.collect(Collectors.toList());
|
||||
// finished -> a,b,c ; created -> b,c,d => missingFinished = a
|
||||
List<FinishedSpan> missingFinishedSpans = finishedSpans.stream()
|
||||
.filter(f -> matchedFinishedSpans.stream().noneMatch(m -> m.getSpanId().equals(f.getSpanId())))
|
||||
.collect(Collectors.toList());
|
||||
// finished -> a,b,c ; created -> b,c,d => missingCreated = d
|
||||
List<Span> missingCreatedSpans = createdSpans.stream().filter(
|
||||
f -> matchedCreatedSpans.stream().noneMatch(m -> m.context().spanId().equals(f.context().spanId())))
|
||||
.collect(Collectors.toList());
|
||||
if (!missingFinishedSpans.isEmpty() || !missingCreatedSpans.isEmpty()) {
|
||||
throw new AssertionError("There were unmatched created spans " + missingCreatedSpans
|
||||
+ " and/or finished span " + missingFinishedSpans);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<FinishedSpan> iterator() {
|
||||
return reportedSpans().iterator();
|
||||
|
||||
@@ -26,6 +26,8 @@ import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.cloud.function.context.FunctionCatalog;
|
||||
import org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry.FunctionInvocationWrapper;
|
||||
import org.springframework.cloud.sleuth.test.TestSpanHandler;
|
||||
import org.springframework.cloud.sleuth.test.TestTracer;
|
||||
import org.springframework.cloud.sleuth.test.TestTracingBeanPostProcessor;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.messaging.Message;
|
||||
@@ -49,10 +51,13 @@ public abstract class TraceFunctionAroundWrapperTests {
|
||||
FunctionCatalog catalog = context.getBean(FunctionCatalog.class);
|
||||
FunctionInvocationWrapper function = catalog.lookup("greeter");
|
||||
function.setSkipOutputConversion(true);
|
||||
|
||||
Message<?> result = (Message<?>) function.get();
|
||||
|
||||
assertThat(result.getPayload()).isEqualTo("hello");
|
||||
assertThat(spanHandler.reportedSpans().size()).isEqualTo(2);
|
||||
assertThat(((String) result.getHeaders().get("b3"))).contains(spanHandler.get(0).getTraceId());
|
||||
spanHandler.assertAllSpansWereFinishedOrAbandoned(context.getBean(TestTracer.class).createdSpans());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,10 +71,13 @@ public abstract class TraceFunctionAroundWrapperTests {
|
||||
FunctionCatalog catalog = context.getBean(FunctionCatalog.class);
|
||||
FunctionInvocationWrapper function = catalog.lookup("uppercase");
|
||||
function.setSkipOutputConversion(true);
|
||||
|
||||
Message<?> result = (Message<?>) function.apply(MessageBuilder.withPayload("hello").build());
|
||||
|
||||
assertThat(result.getPayload()).isEqualTo("HELLO");
|
||||
assertThat(spanHandler.reportedSpans().size()).isEqualTo(3);
|
||||
assertThat(((String) result.getHeaders().get("b3"))).contains(spanHandler.get(0).getTraceId());
|
||||
spanHandler.assertAllSpansWereFinishedOrAbandoned(context.getBean(TestTracer.class).createdSpans());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,6 +96,11 @@ public abstract class TraceFunctionAroundWrapperTests {
|
||||
return v -> v.toUpperCase();
|
||||
}
|
||||
|
||||
@Bean
|
||||
static TestTracingBeanPostProcessor testTracerBeanPostProcessor() {
|
||||
return new TestTracingBeanPostProcessor();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2013-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.sleuth.test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.cloud.sleuth.Span;
|
||||
import org.springframework.cloud.sleuth.TraceContext;
|
||||
import org.springframework.cloud.sleuth.propagation.Propagator;
|
||||
|
||||
/**
|
||||
* {@link Propagator} that stores information about started spans.
|
||||
*/
|
||||
public class TestPropagator implements Propagator {
|
||||
|
||||
private final Propagator delegate;
|
||||
|
||||
private final TestTracer testTracer;
|
||||
|
||||
public TestPropagator(Propagator delegate, TestTracer testTracer) {
|
||||
this.delegate = delegate;
|
||||
this.testTracer = testTracer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> fields() {
|
||||
return this.delegate.fields();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <C> void inject(TraceContext context, C carrier, Setter<C> setter) {
|
||||
this.delegate.inject(context, carrier, setter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <C> Span.Builder extract(C carrier, Getter<C> getter) {
|
||||
return new TestSpanBuilder(this.delegate.extract(carrier, getter), this.testTracer);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright 2013-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.sleuth.test;
|
||||
|
||||
import org.springframework.cloud.sleuth.Span;
|
||||
import org.springframework.cloud.sleuth.TraceContext;
|
||||
|
||||
class TestSpanBuilder implements Span.Builder {
|
||||
|
||||
private final Span.Builder delegate;
|
||||
|
||||
private final TestTracer testTracer;
|
||||
|
||||
TestSpanBuilder(Span.Builder delegate, TestTracer testTracer) {
|
||||
this.delegate = delegate;
|
||||
this.testTracer = testTracer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Span.Builder setParent(TraceContext context) {
|
||||
delegate.setParent(context);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Span.Builder setNoParent() {
|
||||
delegate.setNoParent();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Span.Builder name(String name) {
|
||||
delegate.name(name);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Span.Builder event(String value) {
|
||||
delegate.event(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Span.Builder tag(String key, String value) {
|
||||
delegate.tag(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Span.Builder error(Throwable throwable) {
|
||||
delegate.error(throwable);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Span.Builder kind(Span.Kind spanKind) {
|
||||
delegate.kind(spanKind);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Span.Builder remoteServiceName(String remoteServiceName) {
|
||||
delegate.remoteServiceName(remoteServiceName);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Span start() {
|
||||
Span span = delegate.start();
|
||||
this.testTracer.createdSpans.add(span);
|
||||
return span;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.springframework.cloud.sleuth.test;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
|
||||
import org.springframework.cloud.sleuth.Span;
|
||||
import org.springframework.cloud.sleuth.exporter.FinishedSpan;
|
||||
@@ -35,4 +36,6 @@ public interface TestSpanHandler extends Iterable<FinishedSpan> {
|
||||
|
||||
FinishedSpan get(int index);
|
||||
|
||||
void assertAllSpansWereFinishedOrAbandoned(Queue<Span> createdSpans);
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright 2013-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.sleuth.test;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
|
||||
import org.springframework.cloud.sleuth.BaggageInScope;
|
||||
import org.springframework.cloud.sleuth.ScopedSpan;
|
||||
import org.springframework.cloud.sleuth.Span;
|
||||
import org.springframework.cloud.sleuth.SpanCustomizer;
|
||||
import org.springframework.cloud.sleuth.TraceContext;
|
||||
import org.springframework.cloud.sleuth.Tracer;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
public class TestTracer implements Tracer, AutoCloseable {
|
||||
|
||||
private final Tracer delegate;
|
||||
|
||||
final Queue<Span> createdSpans = new LinkedList<>();
|
||||
|
||||
public TestTracer(Tracer delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getAllBaggage() {
|
||||
return delegate.getAllBaggage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaggageInScope getBaggage(String name) {
|
||||
return delegate.getBaggage(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaggageInScope getBaggage(TraceContext traceContext, String name) {
|
||||
return delegate.getBaggage(traceContext, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaggageInScope createBaggage(String name) {
|
||||
return delegate.createBaggage(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaggageInScope createBaggage(String name, String value) {
|
||||
return delegate.createBaggage(name, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Span nextSpan() {
|
||||
Span span = delegate.nextSpan();
|
||||
this.createdSpans.add(span);
|
||||
return span;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Span nextSpan(Span parent) {
|
||||
Span span = delegate.nextSpan(parent);
|
||||
this.createdSpans.add(span);
|
||||
return span;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpanInScope withSpan(Span span) {
|
||||
return delegate.withSpan(span);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScopedSpan startScopedSpan(String name) {
|
||||
return delegate.startScopedSpan(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Span.Builder spanBuilder() {
|
||||
return new TestSpanBuilder(delegate.spanBuilder(), this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public SpanCustomizer currentSpanCustomizer() {
|
||||
return delegate.currentSpanCustomizer();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Span currentSpan() {
|
||||
return delegate.currentSpan();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
this.createdSpans.clear();
|
||||
}
|
||||
|
||||
public Queue<Span> createdSpans() {
|
||||
return createdSpans;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2013-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.sleuth.test;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.cloud.sleuth.Tracer;
|
||||
import org.springframework.cloud.sleuth.propagation.Propagator;
|
||||
|
||||
/**
|
||||
* Wraps all tracing related components into test representations. That way additional
|
||||
* assertions can take place.
|
||||
*/
|
||||
public class TestTracingBeanPostProcessor implements BeanPostProcessor {
|
||||
|
||||
TestTracer testTracer;
|
||||
|
||||
@Override
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
if (bean instanceof Tracer && !(bean instanceof TestTracer)) {
|
||||
this.testTracer = new TestTracer((Tracer) bean);
|
||||
return this.testTracer;
|
||||
}
|
||||
else if (bean instanceof Propagator && !(bean instanceof TestPropagator)) {
|
||||
return new TestPropagator((Propagator) bean, this.testTracer);
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user