/**
* Copyright 2015-2017 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 zipkin.internal;
import org.junit.Test;
import zipkin.Constants;
import zipkin.internal.DependencyLinkSpan.Kind;
import static org.assertj.core.api.Assertions.assertThat;
public class DependencyLinkSpanTest {
@Test
public void testToString() {
assertThat(DependencyLinkSpan.builder(0L, 1L, null, 1L).build())
.hasToString("{\"traceId\": \"0000000000000001\", \"id\": \"0000000000000001\", \"kind\": \"UNKNOWN\"}");
assertThat(DependencyLinkSpan.builder(0L, 1L, 1L, 2L).build())
.hasToString("{\"traceId\": \"0000000000000001\", \"parentId\": \"0000000000000001\", \"id\": \"0000000000000002\", \"kind\": \"UNKNOWN\"}");
assertThat(DependencyLinkSpan.builder(0L, 1L, 1L, 2L)
.srService("processor")
.caService("kinesis").build())
.hasToString("{\"traceId\": \"0000000000000001\", \"parentId\": \"0000000000000001\", \"id\": \"0000000000000002\", \"kind\": \"SERVER\", \"service\": \"processor\", \"peerService\": \"kinesis\"}");
// It is invalid to log "ca" without "sr", so marked as unknown
assertThat(DependencyLinkSpan.builder(0L, 1L, 1L, 2L)
.caService("kinesis").build())
.hasToString("{\"traceId\": \"0000000000000001\", \"parentId\": \"0000000000000001\", \"id\": \"0000000000000002\", \"kind\": \"UNKNOWN\"}");
assertThat(DependencyLinkSpan.builder(0L, 1L, 1L, 2L)
.saService("mysql").build())
.hasToString("{\"traceId\": \"0000000000000001\", \"parentId\": \"0000000000000001\", \"id\": \"0000000000000002\", \"kind\": \"CLIENT\", \"peerService\": \"mysql\"}");
// arbitrary 2-sided span
assertThat(DependencyLinkSpan.builder(0L, 1L, 1L, 2L)
.caService("shell-script")
.saService("mysql").build())
.hasToString("{\"traceId\": \"0000000000000001\", \"parentId\": \"0000000000000001\", \"id\": \"0000000000000002\", \"kind\": \"CLIENT\", \"service\": \"shell-script\", \"peerService\": \"mysql\"}");
// 128-bit trace ID
assertThat(DependencyLinkSpan.builder(3L, 1L, null, 1L).build())
.hasToString("{\"traceId\": \"00000000000000030000000000000001\", \"id\": \"0000000000000001\", \"kind\": \"UNKNOWN\"}");
}
@Test
public void parentAndChildApply() {
DependencyLinkSpan span = DependencyLinkSpan.builder(0L, 1L, null, 1L).build();
assertThat(span.parentId).isNull();
assertThat(span.id).isEqualTo(1L);
span = DependencyLinkSpan.builder(0L, 1L, 1L, 2L).build();
assertThat(span.parentId).isEqualTo(1L);
assertThat(span.id).isEqualTo(2L);
}
/** You cannot make a dependency link unless you know the the local or peer service. */
@Test
public void whenNoServiceLabelsExist_kindIsUnknown() {
DependencyLinkSpan span = DependencyLinkSpan.builder(0L, 1L, null, 1L).build();
assertThat(span.kind).isEqualTo(Kind.UNKNOWN);
assertThat(span.peerService).isNull();
assertThat(span.service).isNull();
}
@Test
public void whenOnlyAddressLabelsExist_kindIsClient() {
DependencyLinkSpan span = DependencyLinkSpan.builder(0L, 1L, null, 1L)
.caService("service1")
.saService("service2")
.build();
assertThat(span.kind).isEqualTo(Kind.CLIENT);
assertThat(span.service).isEqualTo("service1");
assertThat(span.peerService).isEqualTo("service2");
}
/** The linker is biased towards server spans, or client spans that know the peer service. */
@Test
public void whenServerLabelsAreMissing_kindIsUnknownAndLabelsAreCleared() {
DependencyLinkSpan span = DependencyLinkSpan.builder(0L, 1L, null, 1L)
.caService("service1")
.build();
assertThat(span.kind).isEqualTo(Kind.UNKNOWN);
assertThat(span.service).isNull();
assertThat(span.peerService).isNull();
}
/** {@link Constants#SERVER_RECV} is only applied when the local span is acting as a server */
@Test
public void whenSrServiceExists_kindIsServer() {
DependencyLinkSpan span = DependencyLinkSpan.builder(0L, 1L, null, 1L)
.srService("service")
.build();
assertThat(span.kind).isEqualTo(Kind.SERVER);
assertThat(span.service).isEqualTo("service");
assertThat(span.peerService).isNull();
}
/**
* {@link Constants#CLIENT_ADDR} indicates the peer, which is a client in the case of a server
* span
*/
@Test
public void whenSrAndCaServiceExists_caIsThePeer() {
DependencyLinkSpan span = DependencyLinkSpan.builder(0L, 1L, null, 1L)
.caService("service1")
.srService("service2")
.build();
assertThat(span.kind).isEqualTo(Kind.SERVER);
assertThat(span.service).isEqualTo("service2");
assertThat(span.peerService).isEqualTo("service1");
}
/**
* {@link Constants#CLIENT_SEND} indicates the peer, which is a client in the case of a server
* span
*/
@Test
public void whenSrAndCsServiceExists_caIsThePeer() {
DependencyLinkSpan span = DependencyLinkSpan.builder(0L, 1L, null, 1L)
.csService("service1")
.srService("service2")
.build();
assertThat(span.kind).isEqualTo(Kind.SERVER);
assertThat(span.service).isEqualTo("service2");
assertThat(span.peerService).isEqualTo("service1");
}
/** {@link Constants#CLIENT_ADDR} is more authoritative than {@link Constants#CLIENT_SEND} */
@Test
public void whenCrAndCaServiceExists_caIsThePeer() {
DependencyLinkSpan span = DependencyLinkSpan.builder(0L, 1L, null, 1L)
.csService("foo")
.caService("service1")
.srService("service2")
.build();
assertThat(span.kind).isEqualTo(Kind.SERVER);
assertThat(span.service).isEqualTo("service2");
assertThat(span.peerService).isEqualTo("service1");
}
@Test
public void specialCasesFinagleLocalSocketLabeling() {
// Finagle labels two sides of the same socket ("ca", "sa") with the local service name.
DependencyLinkSpan span = DependencyLinkSpan.builder(0L, 1L, null, 1L)
.caService("service")
.saService("service")
.build();
// When there's no "sr" annotation, we assume it is a client.
assertThat(span.kind).isEqualTo(Kind.CLIENT);
assertThat(span.service).isNull();
assertThat(span.peerService).isEqualTo("service");
span = DependencyLinkSpan.builder(0L, 1L, null, 1L)
.srService("service")
.caService("service")
.saService("service")
.build();
// When there is an "sr" annotation, we know it is a server
assertThat(span.kind).isEqualTo(Kind.SERVER);
assertThat(span.service).isEqualTo("service");
assertThat(span.peerService).isNull();
}
/** Service links to empty string are confusing and offer no value. */
@Test
public void emptyToNull() {
DependencyLinkSpan.Builder builder = DependencyLinkSpan.builder(0L, 1L, null, 1L)
.caService("")
.csService("")
.saService("")
.srService("");
assertThat(builder.caService).isNull();
assertThat(builder.csService).isNull();
assertThat(builder.saService).isNull();
assertThat(builder.srService).isNull();
}
}