/** * Copyright 2015 The OpenZipkin 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 * * 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 io.zipkin.query; import io.zipkin.Annotation; import io.zipkin.BinaryAnnotation; import io.zipkin.Endpoint; import io.zipkin.Span; import io.zipkin.Trace; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import java.util.stream.Stream; import org.junit.Before; import org.junit.Test; import static io.zipkin.Constants.CLIENT_RECV; import static io.zipkin.Constants.CLIENT_SEND; import static io.zipkin.Constants.SERVER_RECV; import static io.zipkin.Constants.SERVER_SEND; import static java.util.Arrays.asList; import static java.util.Collections.emptyMap; import static org.assertj.core.api.Assertions.assertThat; public abstract class ZipkinQueryTest { private final Charset UTF_8 = Charset.forName("UTF-8"); protected abstract ZipkinQuery query(); protected abstract void reload(Iterable<Span> spans); @Before public void load() { List<Span> spans = new ArrayList<>(); spans.addAll(trace1.spans()); spans.addAll(trace5.spans()); reload(spans); } Endpoint web = Endpoint.builder() .ipv4(0x7f000001 /* 127.0.0.1 */) .port((short) 8080) .serviceName("web").build(); Endpoint app = Endpoint.builder(web) .port((short) 9411) .serviceName("app").build(); Endpoint db = Endpoint.builder(web) .port((short) 3306) .serviceName("db").build(); Annotation webSR = Annotation.builder().timestamp(10).value(SERVER_RECV).host(web).build(); BinaryAnnotation httpUri = BinaryAnnotation.builder() .key("http.uri").value("/foo".getBytes()) .type(BinaryAnnotation.Type.STRING).host(web).build(); Annotation webSS = Annotation.builder(webSR).timestamp(21).value(SERVER_SEND).build(); BinaryAnnotation httpResponse = BinaryAnnotation.builder() .key("http.responseCode").value(new byte[] {0, (byte) 200}) .type(BinaryAnnotation.Type.I16).host(web).build(); List<Span> collection1 = asList( Span.builder() .traceId(1L) .name("GET") .id(1L) .annotations(asList(webSR)) .binaryAnnotations(asList(httpUri)) .build(), Span.builder() .traceId(1L) .name("/foo") .id(1L) .annotations(asList(webSS)) .binaryAnnotations(asList(httpResponse)) .build() ); long afterWebSS = webSS.timestamp() + 1; Annotation webCS = Annotation.builder().timestamp(12).value(CLIENT_SEND).host(web).build(); Annotation webCR = Annotation.builder(webCS).timestamp(20).value(CLIENT_RECV).build(); List<Span> collection2 = asList( Span.builder() .traceId(1L) .name("GET Book") .id(2L) .parentId(1L) .annotations(asList(webCS)) .binaryAnnotations(asList()) .build(), Span.builder() .traceId(1L) .name("GET Book") .id(2L) .parentId(1L) .annotations(asList(webCR)) .binaryAnnotations(asList()) .build() ); Annotation appSR = Annotation.builder().timestamp(14).value(SERVER_RECV).host(app).build(); Annotation appSS = Annotation.builder(appSR).timestamp(18).value(SERVER_SEND).build(); List<Span> collection3 = asList( Span.builder() .traceId(1L) .name("GET Book") .id(2L) .parentId(1L) .annotations(asList(appSR)) .binaryAnnotations(asList()) .build(), Span.builder() .traceId(1L) .name("GET Book") .id(2L) .parentId(1L) .annotations(asList(appSS)) .binaryAnnotations(asList()) .build() ); Annotation dbSR = Annotation.builder().timestamp(13).value(SERVER_RECV).host(db).build(); Annotation dbSS = Annotation.builder(dbSR).timestamp(15).value(SERVER_SEND).build(); List<Span> collection4 = asList( Span.builder() .traceId(1L) .name("QUERY BOOK") .id(3L) .parentId(2L) .annotations(asList(dbSR)) .binaryAnnotations(asList()) .build(), Span.builder() .traceId(1L) .name("QUERY BOOK") .id(3L) .parentId(2L) .annotations(asList(dbSS)) .binaryAnnotations(asList()) .build() ); Annotation dbSR2 = Annotation.builder(dbSR).timestamp(20).build(); Annotation dbSS2 = Annotation.builder(dbSS).timestamp(21).build(); List<Span> collection5 = asList( Span.builder() .traceId(5L) .name("QUERY EGG") .id(7L) .parentId(6L) .annotations(asList(dbSR2)) .binaryAnnotations(asList()) .build(), Span.builder() .traceId(5L) .name("QUERY EGG") .id(7L) .parentId(6L) .annotations(asList(dbSS2)) .binaryAnnotations(asList()) .build() ); Trace trace1 = Trace.create(Stream.of(collection1, collection2, collection3, collection4) .flatMap(List::stream).collect(Collectors.toList())); Trace trace5 = Trace.create(collection5); @Test(expected = IllegalStateException.class) public void getTraces_null_service_name() { query().getTraces(QueryRequest.builder() .spanName("span") .annotations(asList()) .binaryAnnotations(emptyMap()) .endTs(afterWebSS) .limit(100).build()); } @Test public void getTraces_span_name() { assertThat(query().getTraces(QueryRequest.builder() .serviceName("db") .spanName("QUERY EGG") .annotations(asList()) .binaryAnnotations(emptyMap()) .endTs(afterWebSS) .limit(100).build())).containsExactly(trace5); } @Test public void getTraces_service_name() { assertThat(query().getTraces(QueryRequest.builder() .serviceName("db") .spanName("QUERY EGG") .annotations(asList()) .binaryAnnotations(emptyMap()) .endTs(afterWebSS) .limit(100).build())).containsExactly(trace5); } @Test public void getTraces_annotation_name() { assertThat(query().getTraces(QueryRequest.builder() .serviceName("web") .annotations(asList(SERVER_SEND)) .binaryAnnotations(emptyMap()) .endTs(afterWebSS) .limit(100).build())).containsExactly(trace1); } @Test public void getTraces_annotation_name_and_value() { Map<String, String> binaryAnnotations = new LinkedHashMap<>(); binaryAnnotations.put(httpUri.key(), new String(httpUri.value(), UTF_8)); // NOTE: Thrift accepts the whole struct, but scala impl only pays attention to key and id assertThat(query().getTraces(QueryRequest.builder() .serviceName("web") .annotations(asList()) .binaryAnnotations(binaryAnnotations) .endTs(afterWebSS) .limit(100).build())).containsExactly(trace1); } @Test public void getTracesByIds() { assertThat(query().getTracesByIds(asList(1L, 3L), true)) .containsExactly(trace1); } @Test public void getSpanNames() { assertThat(query().getSpanNames("db")) .containsExactly("QUERY BOOK", "QUERY EGG"); } @Test public void getSpanNames_null() { assertThat(query().getSpanNames(null)) .isEmpty(); } @Test public void getSpanNames_notFound() { assertThat(query().getSpanNames("booboo")) .isEmpty(); } @Test public void getServiceNames() { assertThat(query().getServiceNames()) .containsExactly("web", "app", "db"); } }