/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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
*
* http://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.apache.camel.opentracing;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import io.opentracing.Span;
import io.opentracing.mock.MockSpan;
import io.opentracing.mock.MockTracer;
import io.opentracing.mock.MockTracer.Propagator;
import io.opentracing.tag.Tags;
import org.apache.camel.CamelContext;
import org.apache.camel.test.junit4.CamelTestSupport;
public class CamelOpenTracingTestSupport extends CamelTestSupport {
private MockTracer tracer;
private SpanTestData[] testdata;
public CamelOpenTracingTestSupport(SpanTestData[] testdata) {
this.testdata = testdata;
}
@Override
protected void doPostSetup() throws Exception {
tracer.reset();
}
@Override
protected CamelContext createCamelContext() throws Exception {
CamelContext context = super.createCamelContext();
tracer = new MockTracer(Propagator.TEXT_MAP);
OpenTracingTracer ottracer = new OpenTracingTracer();
ottracer.setTracer(tracer);
ottracer.init(context);
return context;
}
protected MockTracer getTracer() {
return tracer;
}
protected void verify() {
verify(false);
}
protected void verify(boolean async) {
assertEquals("Incorrect number of spans", testdata.length, tracer.finishedSpans().size());
verifySameTrace();
List<MockSpan> spans = tracer.finishedSpans();
if (async) {
final List<MockSpan> unsortedSpans = spans;
spans = Arrays.asList(testdata).stream()
.map(td -> findSpan(td, unsortedSpans)).distinct().collect(Collectors.toList());
assertEquals("Incorrect number of spans after sorting", testdata.length, spans.size());
}
for (int i = 0; i < testdata.length; i++) {
verifySpan(i, testdata, spans);
}
}
protected MockSpan findSpan(SpanTestData testdata, List<MockSpan> spans) {
return spans.stream().filter(s -> s.operationName().equals(testdata.getOperation())
&& s.tags().get("camel.uri").equals(testdata.getUri())
&& s.tags().get(Tags.SPAN_KIND.getKey()).equals(testdata.getKind())).findFirst().orElse(null);
}
protected void verifySpan(int index, SpanTestData[] testdata, List<MockSpan> spans) {
MockSpan span = spans.get(index);
SpanTestData td = testdata[index];
String component = (String) span.tags().get(Tags.COMPONENT.getKey());
assertNotNull(component);
assertEquals(td.getLabel(),
SpanDecorator.CAMEL_COMPONENT + URI.create((String) td.getUri()).getScheme(),
component);
assertEquals(td.getLabel(), td.getUri(), span.tags().get("camel.uri"));
// If span associated with TestSEDASpanDecorator, check that pre/post tags have been defined
if ("camel-seda".equals(component)) {
assertTrue(span.tags().containsKey("pre"));
assertTrue(span.tags().containsKey("post"));
}
assertEquals(td.getLabel(), td.getOperation(), span.operationName());
assertEquals(td.getLabel(), td.getKind(),
span.tags().get(Tags.SPAN_KIND.getKey()));
if (td.getParentId() != -1) {
assertEquals(td.getLabel(),
spans.get(td.getParentId()).context().spanId(),
span.parentId());
}
if (!td.getLogMessages().isEmpty()) {
assertEquals("Number of log messages", td.getLogMessages().size(), span.logEntries().size());
for (int i = 0; i < td.getLogMessages().size(); i++) {
assertEquals(td.getLogMessages().get(i), span.logEntries().get(i).fields().get("message"));
}
}
}
protected void verifySameTrace() {
assertEquals(1, tracer.finishedSpans().stream().map(s -> s.context().traceId()).distinct().count());
}
protected void verifyTraceSpanNumbers(int numOfTraces, int numSpansPerTrace) {
Map<Long, List<Span>> traces = new HashMap<Long, List<Span>>();
// Sort spans into separate traces
for (int i = 0; i < getTracer().finishedSpans().size(); i++) {
List<Span> spans = traces.get(getTracer().finishedSpans().get(i).context().traceId());
if (spans == null) {
spans = new ArrayList<Span>();
traces.put(getTracer().finishedSpans().get(i).context().traceId(), spans);
}
spans.add(getTracer().finishedSpans().get(i));
}
assertEquals(numOfTraces, traces.size());
for (Map.Entry<Long, List<Span>> spans : traces.entrySet()) {
assertEquals(numSpansPerTrace, spans.getValue().size());
}
}
}