Skip to content

Commit fbaea3c

Browse files
ALmost there
1 parent 42d3428 commit fbaea3c

File tree

5 files changed

+231
-40
lines changed

5 files changed

+231
-40
lines changed

spring-cloud-sleuth-instrumentation/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/TraceFunctionAroundWrapper.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@
2525
import org.apache.commons.logging.Log;
2626
import org.apache.commons.logging.LogFactory;
2727
import org.reactivestreams.Publisher;
28+
import reactor.core.publisher.Flux;
29+
import reactor.core.publisher.Mono;
30+
2831
import org.springframework.cloud.context.scope.refresh.RefreshScopeRefreshedEvent;
2932
import org.springframework.cloud.function.context.catalog.FunctionAroundWrapper;
3033
import org.springframework.cloud.function.context.catalog.FunctionTypeUtils;
@@ -39,9 +42,6 @@
3942
import org.springframework.messaging.support.MessageBuilder;
4043
import org.springframework.messaging.support.MessageHeaderAccessor;
4144

42-
import reactor.core.publisher.Flux;
43-
import reactor.core.publisher.Mono;
44-
4545
/**
4646
* Trace representation of a {@link FunctionAroundWrapper}.
4747
*

spring-cloud-sleuth-instrumentation/src/test/java/org/springframework/cloud/sleuth/instrument/messaging/TraceFunctionAroundWrapperTests.java

Lines changed: 220 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,18 @@
1616

1717
package org.springframework.cloud.sleuth.instrument.messaging;
1818

19+
import java.time.Duration;
1920
import java.util.Collections;
2021
import java.util.List;
22+
import java.util.function.Consumer;
2123
import java.util.function.Function;
2224
import java.util.function.Supplier;
2325

2426
import com.fasterxml.jackson.databind.ObjectMapper;
27+
import org.junit.jupiter.api.Disabled;
2528
import org.junit.jupiter.api.Test;
26-
import org.mockito.Answers;
27-
import org.mockito.BDDMockito;
29+
import reactor.core.publisher.Flux;
30+
import reactor.core.publisher.Mono;
2831

2932
import org.springframework.cloud.function.context.FunctionRegistration;
3033
import org.springframework.cloud.function.context.FunctionType;
@@ -33,93 +36,204 @@
3336
import org.springframework.cloud.function.context.config.JsonMessageConverter;
3437
import org.springframework.cloud.function.json.JacksonMapper;
3538
import org.springframework.cloud.sleuth.Span;
36-
import org.springframework.cloud.sleuth.TraceContext;
3739
import org.springframework.cloud.sleuth.Span.Builder;
40+
import org.springframework.cloud.sleuth.TraceContext;
3841
import org.springframework.cloud.sleuth.propagation.Propagator;
39-
import org.springframework.cloud.sleuth.propagation.Propagator.Getter;
40-
import org.springframework.cloud.sleuth.propagation.Propagator.Setter;
4142
import org.springframework.cloud.sleuth.tracer.SimpleTracer;
4243
import org.springframework.core.convert.support.DefaultConversionService;
43-
import org.springframework.integration.support.MessageBuilder;
4444
import org.springframework.messaging.Message;
4545
import org.springframework.messaging.converter.CompositeMessageConverter;
46+
import org.springframework.messaging.support.MessageBuilder;
4647
import org.springframework.mock.env.MockEnvironment;
4748

4849
import static org.assertj.core.api.Assertions.assertThat;
4950
import static org.assertj.core.api.BDDAssertions.then;
5051

5152
class TraceFunctionAroundWrapperTests {
52-
53+
5354
CompositeMessageConverter messageConverter = new CompositeMessageConverter(
5455
Collections.singletonList(new JsonMessageConverter(new JacksonMapper(new ObjectMapper()))));
55-
56+
5657
SimpleFunctionRegistry catalog = new SimpleFunctionRegistry(new DefaultConversionService(), messageConverter,
5758
new JacksonMapper(new ObjectMapper()));
5859

5960
SimpleTracer tracer = new SimpleTracer();
60-
61+
6162
MockEnvironment mockEnvironment = mockEnvironment();
6263

63-
TraceFunctionAroundWrapper wrapper = new TraceFunctionAroundWrapper(mockEnvironment, tracer, testPropagator(),
64+
TraceFunctionAroundWrapper wrapper = new TraceFunctionAroundWrapper(mockEnvironment, tracer, testPropagator(),
6465
new MessageHeaderPropagatorSetter(), new MessageHeaderPropagatorGetter()) {
6566
@Override
6667
MessageAndSpan getMessageAndSpans(Message<?> resultMessage, String name, Span spanFromMessage) {
6768
return new MessageAndSpan(resultMessage, spanFromMessage);
6869
}
6970
};
7071

71-
/**
72-
* @return
73-
*/
7472
private Propagator testPropagator() {
7573
return new Propagator() {
76-
74+
7775
@Override
7876
public <C> void inject(TraceContext context, C carrier, Setter<C> setter) {
7977
setter.set(carrier, "superHeader", "test");
8078
}
81-
79+
8280
@Override
8381
public List<String> fields() {
8482
return Collections.singletonList("superHeader");
8583
}
86-
84+
8785
@Override
8886
public <C> Builder extract(C carrier, Getter<C> getter) {
89-
Builder builder = BDDMockito.mock(Builder.class, Answers.RETURNS_SELF);
90-
BDDMockito.given(builder.start()).willReturn(tracer.nextSpan());
91-
return builder;
87+
return tracer.spanBuilder();
9288
}
9389
};
9490
}
95-
91+
9692
@Test
9793
void test_tracing_with_supplier() {
9894
FunctionRegistration<Greeter> registration = new FunctionRegistration<>(new Greeter(), "greeter")
9995
.type(FunctionType.of(Greeter.class));
10096
catalog.register(registration);
10197
FunctionInvocationWrapper function = catalog.lookup("greeter");
102-
98+
10399
Message<?> result = (Message<?>) wrapper.apply(null, function);
104-
100+
105101
assertThat(result.getPayload()).isEqualTo("hello");
106102
assertThat(tracer.getOnlySpan().name).isEqualTo("greeter");
107103
}
108-
104+
109105
@Test
110106
void test_tracing_with_function() {
111-
FunctionRegistration<GreeterFunction> registration = new FunctionRegistration<>(new GreeterFunction(), "greeter")
112-
.type(FunctionType.of(GreeterFunction.class));
107+
FunctionRegistration<GreeterFunction> registration = new FunctionRegistration<>(new GreeterFunction(),
108+
"greeter").type(FunctionType.of(GreeterFunction.class));
113109
catalog.register(registration);
114110
FunctionInvocationWrapper function = catalog.lookup("greeter");
115-
116-
Message<?> result = (Message<?>) wrapper.apply(MessageBuilder
117-
.withPayload("hello").setHeader("superHeader", "someValue").build(), function);
118-
111+
112+
Message<?> result = (Message<?>) wrapper
113+
.apply(MessageBuilder.withPayload("hello").setHeader("superHeader", "someValue").build(), function);
114+
119115
assertThat(result.getPayload()).isEqualTo("HELLO");
116+
assertThat(tracer.spans).hasSize(3);
117+
assertThat(tracer.spans.get(0).name).isEqualTo("handle");
118+
assertThat(tracer.spans.get(1).name).isEqualTo("greeter");
119+
assertThat(tracer.spans.get(2).name).isEqualTo("send");
120+
}
121+
122+
@Test
123+
void test_tracing_with_consumer() {
124+
GreeterConsumer consumer = new GreeterConsumer();
125+
FunctionRegistration<GreeterConsumer> registration = new FunctionRegistration<>(consumer, "greeter")
126+
.type(FunctionType.of(GreeterConsumer.class));
127+
catalog.register(registration);
128+
FunctionInvocationWrapper function = catalog.lookup("greeter");
129+
130+
wrapper.apply(MessageBuilder.withPayload("hello").setHeader("superHeader", "someValue").build(), function);
131+
132+
assertThat(consumer.result).isEqualTo("HELLO");
133+
assertThat(tracer.spans).hasSize(2);
134+
assertThat(tracer.spans.get(0).name).isEqualTo("handle");
135+
assertThat(tracer.spans.get(1).name).isEqualTo("greeter");
136+
}
137+
138+
@Disabled("TODO: don't we want to support this?")
139+
@Test
140+
void should_trace_when_reactive_mono_supplier() {
141+
FunctionRegistration<ReactiveMonoGreeter> registration = new FunctionRegistration<>(new ReactiveMonoGreeter(),
142+
"greeter").type(FunctionType.of(ReactiveMonoGreeter.class));
143+
catalog.register(registration);
144+
FunctionInvocationWrapper function = catalog.lookup("greeter");
145+
146+
Message<?> result = ((Mono<Message<?>>) wrapper.apply(null, function)).block(Duration.ofSeconds(5));
147+
148+
assertThat(result.getPayload()).isEqualTo("hello");
120149
assertThat(tracer.getOnlySpan().name).isEqualTo("greeter");
121150
}
122151

152+
@Test
153+
void should_trace_when_reactive_mono_function() {
154+
FunctionRegistration<ReactiveMonoGreeterFunction> registration = new FunctionRegistration<>(
155+
new ReactiveMonoGreeterFunction(), "greeter").type(FunctionType.of(ReactiveMonoGreeterFunction.class));
156+
catalog.register(registration);
157+
FunctionInvocationWrapper function = catalog.lookup("greeter");
158+
159+
Message<?> result = ((Mono<Message<?>>) wrapper.apply(
160+
Mono.just(MessageBuilder.withPayload("hello").setHeader("superHeader", "someValue").build()), function))
161+
.block(Duration.ofSeconds(5));
162+
163+
assertThat(result.getPayload()).isEqualTo("HELLO");
164+
assertThat(tracer.spans).hasSize(3);
165+
assertThat(tracer.spans.get(0).name).isEqualTo("handle");
166+
assertThat(tracer.spans.get(1).name).isEqualTo("greeter");
167+
assertThat(tracer.spans.get(2).name).isEqualTo("send");
168+
}
169+
170+
@Disabled("TODO: don't we want to support this?")
171+
@Test
172+
void should_trace_when_reactive_mono_consumer() {
173+
ReactiveMonoGreeterConsumer consumer = new ReactiveMonoGreeterConsumer();
174+
FunctionRegistration<ReactiveMonoGreeterConsumer> registration = new FunctionRegistration<>(consumer, "greeter")
175+
.type(FunctionType.of(ReactiveMonoGreeterConsumer.class));
176+
catalog.register(registration);
177+
FunctionInvocationWrapper function = catalog.lookup("greeter");
178+
179+
wrapper.apply(Mono.just(MessageBuilder.withPayload("hello").setHeader("superHeader", "someValue").build()),
180+
function);
181+
182+
assertThat(consumer.result).isEqualTo("HELLO");
183+
assertThat(tracer.spans).hasSize(2);
184+
assertThat(tracer.spans.get(0).name).isEqualTo("handle");
185+
assertThat(tracer.spans.get(1).name).isEqualTo("greeter");
186+
}
187+
188+
@Disabled("TODO: don't we want to support this?")
189+
@Test
190+
void should_trace_when_reactive_flux_supplier() {
191+
FunctionRegistration<ReactiveFluxGreeter> registration = new FunctionRegistration<>(new ReactiveFluxGreeter(),
192+
"greeter").type(FunctionType.of(ReactiveFluxGreeter.class));
193+
catalog.register(registration);
194+
FunctionInvocationWrapper function = catalog.lookup("greeter");
195+
196+
Message<?> result = ((Flux<Message<?>>) wrapper.apply(null, function)).blockFirst(Duration.ofSeconds(5));
197+
198+
assertThat(result.getPayload()).isEqualTo("hello");
199+
assertThat(tracer.getOnlySpan().name).isEqualTo("greeter");
200+
}
201+
202+
@Test
203+
void should_trace_when_reactive_flux_function() {
204+
FunctionRegistration<ReactiveFluxGreeterFunction> registration = new FunctionRegistration<>(
205+
new ReactiveFluxGreeterFunction(), "greeter").type(FunctionType.of(ReactiveFluxGreeterFunction.class));
206+
catalog.register(registration);
207+
FunctionInvocationWrapper function = catalog.lookup("greeter");
208+
209+
Message<?> result = ((Flux<Message<?>>) wrapper.apply(
210+
Flux.just(MessageBuilder.withPayload("hello").setHeader("superHeader", "someValue").build()), function))
211+
.blockFirst(Duration.ofSeconds(5));
212+
213+
assertThat(result.getPayload()).isEqualTo("HELLO");
214+
assertThat(tracer.spans).hasSize(3);
215+
assertThat(tracer.spans.get(0).name).isEqualTo("handle");
216+
assertThat(tracer.spans.get(1).name).isEqualTo("greeter");
217+
assertThat(tracer.spans.get(2).name).isEqualTo("send");
218+
}
219+
220+
@Test
221+
void should_trace_when_reactive_flux_consumer() {
222+
ReactiveFluxGreeterConsumer consumer = new ReactiveFluxGreeterConsumer();
223+
FunctionRegistration<ReactiveFluxGreeterConsumer> registration = new FunctionRegistration<>(consumer, "greeter")
224+
.type(FunctionType.of(ReactiveFluxGreeterConsumer.class));
225+
catalog.register(registration);
226+
FunctionInvocationWrapper function = catalog.lookup("greeter");
227+
228+
wrapper.apply(Flux.just(MessageBuilder.withPayload("hello").setHeader("superHeader", "someValue").build()),
229+
function);
230+
231+
assertThat(consumer.result).isEqualTo("HELLO");
232+
assertThat(tracer.spans).hasSize(2);
233+
assertThat(tracer.spans.get(0).name).isEqualTo("handle");
234+
assertThat(tracer.spans.get(1).name).isEqualTo("greeter");
235+
}
236+
123237
@Test
124238
void should_clear_cache_on_refresh() {
125239
TraceFunctionAroundWrapper wrapper = new TraceFunctionAroundWrapper(null, null, null, null, null);
@@ -160,7 +274,7 @@ void should_point_to_proper_destination_when_working_with_remapped_functions() {
160274

161275
assertThat(wrapper.outputDestination("marcin")).isEqualTo("bob");
162276
}
163-
277+
164278
private MockEnvironment mockEnvironment() {
165279
MockEnvironment mockEnvironment = new MockEnvironment();
166280
mockEnvironment.setProperty("spring.cloud.stream.bindings.greeter-in-0.destination", "oleg");
@@ -176,14 +290,87 @@ public String get() {
176290
}
177291

178292
}
179-
293+
180294
private static class GreeterFunction implements Function<String, String> {
181-
295+
182296
@Override
183297
public String apply(String in) {
184298
return in.toUpperCase();
185299
}
186-
300+
301+
}
302+
303+
private static class GreeterConsumer implements Consumer<String> {
304+
305+
String result;
306+
307+
@Override
308+
public void accept(String in) {
309+
this.result = in.toUpperCase();
310+
}
311+
312+
}
313+
314+
private static class ReactiveMonoGreeter implements Supplier<Mono<Message<String>>> {
315+
316+
@Override
317+
public Mono<Message<String>> get() {
318+
return Mono.just(MessageBuilder.withPayload("hello").build());
319+
}
320+
321+
}
322+
323+
private static class ReactiveMonoGreeterFunction implements Function<Mono<Message<String>>, Mono<Message<String>>> {
324+
325+
@Override
326+
public Mono<Message<String>> apply(Mono<Message<String>> in) {
327+
return in.map(s -> MessageBuilder.fromMessage(s).withPayload(s.getPayload().toUpperCase()).build());
328+
}
329+
330+
}
331+
332+
private static class ReactiveMonoGreeterConsumer implements Consumer<Mono<Message<String>>> {
333+
334+
String result;
335+
336+
@Override
337+
public void accept(Mono<Message<String>> in) {
338+
in.map(s -> s.getPayload().toUpperCase()).doOnNext(s -> {
339+
result = s;
340+
}).subscribe();
341+
}
342+
343+
}
344+
345+
private static class ReactiveFluxGreeter implements Supplier<Flux<Message<String>>> {
346+
347+
@Override
348+
public Flux<Message<String>> get() {
349+
return Flux.just(MessageBuilder.withPayload("hello").build());
350+
}
351+
352+
}
353+
354+
private static class ReactiveFluxGreeterFunction implements Function<Flux<Message<String>>, Flux<Message<String>>> {
355+
356+
@Override
357+
public Flux<Message<String>> apply(Flux<Message<String>> in) {
358+
return in.map(s -> MessageBuilder.fromMessage(s).withPayload(s.getPayload().toUpperCase()).build());
359+
}
360+
361+
}
362+
363+
private static class ReactiveFluxGreeterConsumer implements Consumer<Flux<Message<String>>> {
364+
365+
String result;
366+
367+
@Override
368+
public void accept(Flux<Message<String>> in) {
369+
in.map(s -> s.getPayload().toUpperCase()).doOnNext(s -> {
370+
result = s;
371+
}).subscribe();
372+
}
373+
187374
}
188375

189376
}

spring-cloud-sleuth-instrumentation/src/test/java/org/springframework/cloud/sleuth/tracer/SimpleSpan.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ public class SimpleSpan implements Span {
5454

5555
public boolean noOp;
5656

57+
public Span parent;
58+
5759
@Override
5860
public boolean isNoop() {
5961
return this.noOp;

spring-cloud-sleuth-instrumentation/src/test/java/org/springframework/cloud/sleuth/tracer/SimpleTracer.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,9 @@ public class SimpleTracer implements Tracer {
4343

4444
@Override
4545
public Span nextSpan(Span parent) {
46-
return new SimpleSpan();
46+
SimpleSpan span = nextSpan();
47+
span.parent = parent;
48+
return span;
4749
}
4850

4951
public SimpleSpan getOnlySpan() {

0 commit comments

Comments
 (0)