package rocks.inspectit.agent.java.sdk.opentracing.internal.impl;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasEntry;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
import org.mockito.Mock;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import io.opentracing.References;
import io.opentracing.Span;
import io.opentracing.SpanContext;
import rocks.inspectit.agent.java.sdk.opentracing.Timer;
import rocks.inspectit.shared.all.testbase.TestBase;
/**
* @author Ivan Senic
*
*/
@SuppressWarnings("PMD")
public class SpanBuilderImplTest extends TestBase {
@Mock
Timer timer;
@Mock
TracerImpl tracer;
@BeforeMethod
public void init() {
when(tracer.getTimer()).thenReturn(timer);
}
public static class Start extends SpanBuilderImplTest {
Random random = new Random();
@Test
public void base() {
String op = "operation";
long currentTime = System.currentTimeMillis();
long nano1 = random.nextLong();
long nano2 = nano1 + random.nextInt(5000);
when(timer.getCurrentTimeMicroseconds()).thenReturn(currentTime);
when(timer.getCurrentNanoTime()).thenReturn(nano1).thenReturn(nano2);
SpanBuilderImpl builder = new SpanBuilderImpl(tracer, op);
SpanImpl span = builder.start();
assertThat(span.getOperationName(), is(op));
assertThat(span.getStartTimeMicros(), is(currentTime));
assertThat(span.context().getId(), is(span.context().getParentId()));
assertThat(span.context().getReferenceType(), is(nullValue()));
// for duration finish
span.finish();
assertThat(span.getDuration(), is((nano2 - nano1) / 1000.0d));
// verify tracer passed
verify(tracer).spanStarted(span);
verify(tracer).spanEnded(span);
verify(tracer, atLeastOnce()).getTimer();
verify(timer).getCurrentTimeMicroseconds();
verify(timer, times(2)).getCurrentNanoTime();
verifyNoMoreInteractions(tracer, timer);
}
@Test
public void operationNull() {
when(timer.getCurrentTimeMicroseconds()).thenReturn(System.currentTimeMillis());
SpanBuilderImpl builder = new SpanBuilderImpl(tracer, null);
SpanImpl span = builder.start();
assertThat(span.getOperationName(), is(nullValue()));
}
@Test
public void parent() {
when(timer.getCurrentTimeMicroseconds()).thenReturn(System.currentTimeMillis());
SpanContextImpl parent = new SpanContextImpl(1, 2, 3, null, Collections.<String, String> singletonMap("key", "value"));
SpanBuilderImpl builder = new SpanBuilderImpl(tracer, null).addReference(References.FOLLOWS_FROM, parent);
SpanImpl span = builder.start();
assertThat(span.context().getParentId(), is(parent.getId()));
assertThat(span.context().getTraceId(), is(parent.getTraceId()));
assertThat(span.context().getReferenceType(), is(References.FOLLOWS_FROM));
Map<String, String> contextBaggage = mapFromEntryIterator(span.context().baggageItems());
assertThat(contextBaggage.size(), is(1));
assertThat(contextBaggage, hasEntry("key", "value"));
// assert baggage of the builder as well
Map<String, String> builderBaggage = mapFromEntryIterator(builder.baggageItems());
assertThat(builderBaggage.size(), is(1));
assertThat(builderBaggage, hasEntry("key", "value"));
}
@Test
public void twoParents() {
when(timer.getCurrentTimeMicroseconds()).thenReturn(System.currentTimeMillis());
SpanContextImpl parent1 = new SpanContextImpl(1, 2, 3, null, Collections.<String, String> singletonMap("key1", "value1"));
SpanContextImpl parent2 = new SpanContextImpl(4, 5, 6, null, Collections.<String, String> singletonMap("key2", "value2"));
SpanBuilderImpl builder = new SpanBuilderImpl(tracer, null).asChildOf(parent1).asChildOf(parent2);
SpanImpl span = builder.start();
// first parent is trace responsible
assertThat(span.context().getParentId(), is(parent1.getId()));
assertThat(span.context().getTraceId(), is(parent1.getTraceId()));
assertThat(span.context().getReferenceType(), is(References.CHILD_OF));
// baggage is taken from both parents
Map<String, String> contextBaggage = mapFromEntryIterator(span.context().baggageItems());
assertThat(contextBaggage.size(), is(2));
assertThat(contextBaggage, hasEntry("key1", "value1"));
assertThat(contextBaggage, hasEntry("key2", "value2"));
// assert baggage of the builder as well
Map<String, String> builderBaggage = mapFromEntryIterator(builder.baggageItems());
assertThat(builderBaggage.size(), is(2));
assertThat(builderBaggage, hasEntry("key1", "value1"));
assertThat(builderBaggage, hasEntry("key2", "value2"));
}
@Test
public void twoParentsOneNotOurImpl() {
when(timer.getCurrentTimeMicroseconds()).thenReturn(System.currentTimeMillis());
SpanContext parent1 = mock(SpanContext.class);
SpanContextImpl parent2 = new SpanContextImpl(4, 5, 6, null, Collections.<String, String> singletonMap("key2", "value2"));
SpanBuilderImpl builder = new SpanBuilderImpl(tracer, null).asChildOf(parent1).asChildOf(parent2);
SpanImpl span = builder.start();
// first parent is trace responsible
assertThat(span.context().getParentId(), is(parent2.getId()));
assertThat(span.context().getTraceId(), is(parent2.getTraceId()));
assertThat(span.context().getReferenceType(), is(References.CHILD_OF));
// baggage is taken from both parents
Map<String, String> contextBaggage = mapFromEntryIterator(span.context().baggageItems());
assertThat(contextBaggage.size(), is(1));
assertThat(contextBaggage, hasEntry("key2", "value2"));
// assert baggage of the builder as well
Map<String, String> builderBaggage = mapFromEntryIterator(builder.baggageItems());
assertThat(builderBaggage.size(), is(1));
assertThat(builderBaggage, hasEntry("key2", "value2"));
}
@Test
public void parentNull() {
when(timer.getCurrentTimeMicroseconds()).thenReturn(System.currentTimeMillis());
Span parent = null;
SpanBuilderImpl builder = new SpanBuilderImpl(tracer, null).asChildOf(parent);
SpanImpl span = builder.start();
assertThat(span.context().getId(), is(span.context().getParentId()));
assertThat(span.context().getReferenceType(), is(nullValue()));
}
@Test
public void parentContextNull() {
when(timer.getCurrentTimeMicroseconds()).thenReturn(System.currentTimeMillis());
SpanContextImpl parent = null;
SpanBuilderImpl builder = new SpanBuilderImpl(tracer, null).asChildOf(parent);
SpanImpl span = builder.start();
assertThat(span.context().getId(), is(span.context().getParentId()));
assertThat(span.context().getReferenceType(), is(nullValue()));
}
@Test
public void parentWrongReference() {
when(timer.getCurrentTimeMicroseconds()).thenReturn(System.currentTimeMillis());
SpanContextImpl parent = SpanContextImpl.build();
parent.setBaggageItem("key", "value");
SpanBuilderImpl builder = new SpanBuilderImpl(tracer, null).addReference("some_reference", parent);
SpanImpl span = builder.start();
assertThat(span.context().getId(), is(span.context().getParentId()));
assertThat(span.context().getReferenceType(), is(nullValue()));
assertThat(span.context().getBaggageItem("key"), is("value"));
}
@Test
public void noReport() {
when(timer.getCurrentTimeMicroseconds()).thenReturn(System.currentTimeMillis());
SpanBuilderImpl builder = new SpanBuilderImpl(tracer, null).doNotReport();
SpanImpl span = builder.start();
assertThat(span.isReport(), is(false));
}
@Test
public void selfStartTime() {
long micros = 1422l;
SpanBuilderImpl builder = new SpanBuilderImpl(tracer, null).withStartTimestamp(micros);
SpanImpl span = builder.start();
assertThat(span.getStartTimeMicros(), is(micros));
verifyZeroInteractions(timer);
}
@Test
public void booleanTag() {
when(timer.getCurrentTimeMicroseconds()).thenReturn(System.currentTimeMillis());
SpanBuilderImpl builder = new SpanBuilderImpl(tracer, null).withTag("key", false);
SpanImpl span = builder.start();
assertThat(span.getTags().size(), is(1));
assertThat(span.getTags(), hasEntry("key", String.valueOf(false)));
}
@Test
public void numberTag() {
when(timer.getCurrentTimeMicroseconds()).thenReturn(System.currentTimeMillis());
SpanBuilderImpl builder = new SpanBuilderImpl(tracer, null).withTag("key", 5l);
SpanImpl span = builder.start();
assertThat(span.getTags().size(), is(1));
assertThat(span.getTags(), hasEntry("key", String.valueOf(5L)));
}
@Test
public void stringTag() {
when(timer.getCurrentTimeMicroseconds()).thenReturn(System.currentTimeMillis());
SpanBuilderImpl builder = new SpanBuilderImpl(tracer, null).withTag("key", "value");
SpanImpl span = builder.start();
assertThat(span.getTags().size(), is(1));
assertThat(span.getTags(), hasEntry("key", "value"));
}
}
private static <K, V> Map<K, V> mapFromEntryIterator(Iterable<Entry<K, V>> i) {
Map<K, V> map = new HashMap<K, V>();
for (Entry<K, V> e : i) {
map.put(e.getKey(), e.getValue());
}
return map;
}
}