private void verifyDurationBetweenLowerAndUpperBounds(Span span, long beforeCompletionCallNanoTime, long afterCompletionCallNanoTime) { long durationLowerBound = beforeCompletionCallNanoTime - span.getSpanStartTimeNanos(); long durationUpperBound = afterCompletionCallNanoTime - span.getSpanStartTimeNanos(); assertThat(span.getDurationNanos()).isNotNull(); assertThat(span.getDurationNanos()).isBetween(durationLowerBound, durationUpperBound); }
@Test public void public_constructor_calculates_start_time_nanos_if_passed_null() { // given long startTimeEpochMicrosUsed = 42; long nanosBeforeCall = System.nanoTime(); long epochMicrosBeforeCall = TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis()); // when Span span = new Span(traceId, parentSpanId, spanId, spanName, true, userId, spanPurpose, startTimeEpochMicrosUsed, null, 41L, null, null); long epochMicrosAfterCall = TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis()); long nanosAfterCall = System.nanoTime(); // then long lowerBound = calculateNanoStartTimeFromSpecifiedEpochMicrosStartTime(startTimeEpochMicrosUsed, epochMicrosBeforeCall, nanosBeforeCall); long upperBound = calculateNanoStartTimeFromSpecifiedEpochMicrosStartTime(startTimeEpochMicrosUsed, epochMicrosAfterCall, nanosAfterCall); assertThat(span.getSpanStartTimeNanos()).isBetween(lowerBound, upperBound); }
@Test public void complete_method_should_complete_the_span_with_correct_duration() throws InterruptedException { for (int i = 0; i < 10; i++) { // given Span validSpan = Span.generateRootSpanForNewTrace(spanName, spanPurpose).build(); assertThat(validSpan.isCompleted()).isFalse(); // when Thread.sleep((long) (Math.random() * 10)); long beforeCompleteNanoTime = System.nanoTime(); validSpan.complete(); long afterCompleteNanoTime = System.nanoTime(); // then assertThat(validSpan.isCompleted()).isTrue(); long lowerBoundDuration = beforeCompleteNanoTime - validSpan.getSpanStartTimeNanos(); long upperBoundDuration = afterCompleteNanoTime - validSpan.getSpanStartTimeNanos(); assertThat(validSpan.getDurationNanos()).isBetween(lowerBoundDuration, upperBoundDuration); } }
@Test public void fromHttpServletRequestOrCreateRootSpan_returns_new_root_span_if_traceId_is_missing_from_headers() { // given: no trace ID in headers, but user ID exists given(request.getHeader(ALT_USER_ID_HEADER_KEY)).willReturn(altUserId); // when: creating Span object from HTTP request using fromHttpServletRequestOrCreateRootSpan long beforeCallNanos = System.nanoTime(); Span newSpan = HttpSpanFactory.fromHttpServletRequestOrCreateRootSpan(request, USER_ID_HEADER_KEYS); long afterCallNanos = System.nanoTime(); // then: ensure root span object is created even though there was no trace ID header, and the returned span contains the expected user ID assertThat(newSpan).isNotNull(); assertThat(newSpan.getParentSpanId()).isNull(); assertThat(newSpan.getUserId()).isEqualTo(altUserId); assertThat(newSpan.getSpanStartTimeNanos()).isBetween(beforeCallNanos, afterCallNanos); assertThat(newSpan.isCompleted()).isFalse(); assertThat(newSpan.getSpanPurpose()).isEqualTo(SpanPurpose.SERVER); }
@Test public void builder_build_ignores_passed_in_spanStartTimeNanos_if_spanStartTimeEpochMicros_is_null() { // given Span.Builder builder = Span .newBuilder("stuff", SpanPurpose.LOCAL_ONLY) .withSpanStartTimeNanos(42L) .withSpanStartTimeEpochMicros(null); // when long beforeNanos = System.nanoTime(); long beforeEpochMicros = TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis()); Span span = builder.build(); long afterNanos = System.nanoTime(); long afterEpochMicros = TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis()); // then assertThat(span.getSpanStartTimeNanos()).isBetween(beforeNanos, afterNanos); assertThat(span.getSpanStartTimeEpochMicros()).isBetween(beforeEpochMicros, afterEpochMicros); }
@Test public void public_constructor_works_as_expected_for_completed_span() { // when Span span = new Span( traceId, parentSpanId, spanId, spanName, sampleableForFullyCompleteSpan, userId, spanPurposeForFullyCompletedSpan, startTimeEpochMicrosForFullyCompleteSpan, startTimeNanosForFullyCompleteSpan, durationNanosForFullyCompletedSpan, tags, annotations ); // then assertThat(span.getTraceId()).isEqualTo(traceId); assertThat(span.getParentSpanId()).isEqualTo(parentSpanId); assertThat(span.getSpanId()).isEqualTo(spanId); assertThat(span.getSpanName()).isEqualTo(spanName); assertThat(span.isSampleable()).isEqualTo(sampleableForFullyCompleteSpan); assertThat(span.getUserId()).isEqualTo(userId); assertThat(span.getSpanStartTimeEpochMicros()).isEqualTo(startTimeEpochMicrosForFullyCompleteSpan); assertThat(span.getSpanStartTimeNanos()).isEqualTo(startTimeNanosForFullyCompleteSpan); assertThat(span.getSpanPurpose()).isEqualTo(spanPurposeForFullyCompletedSpan); assertThat(span.isCompleted()).isTrue(); assertThat(span.getDurationNanos()).isEqualTo(durationNanosForFullyCompletedSpan); assertThat(span.getTags()).isEqualTo(tags); assertThat(span.getTimestampedAnnotations()).isEqualTo(annotations); }
@Test public void public_constructor_works_as_expected_for_incomplete_span() { // when Span span = new Span( traceId, parentSpanId, spanId, spanName, sampleableForFullyCompleteSpan, userId, spanPurposeForFullyCompletedSpan, startTimeEpochMicrosForFullyCompleteSpan, startTimeNanosForFullyCompleteSpan, null, tags, annotations ); // then assertThat(span.getTraceId()).isEqualTo(traceId); assertThat(span.getParentSpanId()).isEqualTo(parentSpanId); assertThat(span.getSpanId()).isEqualTo(spanId); assertThat(span.getSpanName()).isEqualTo(spanName); assertThat(span.isSampleable()).isEqualTo(sampleableForFullyCompleteSpan); assertThat(span.getUserId()).isEqualTo(userId); assertThat(span.getSpanStartTimeEpochMicros()).isEqualTo(startTimeEpochMicrosForFullyCompleteSpan); assertThat(span.getSpanStartTimeNanos()).isEqualTo(startTimeNanosForFullyCompleteSpan); assertThat(span.getSpanPurpose()).isEqualTo(spanPurposeForFullyCompletedSpan); assertThat(span.isCompleted()).isFalse(); assertThat(span.getDurationNanos()).isNull(); assertThat(span.getTags()).isEqualTo(tags); assertThat(span.getTimestampedAnnotations()).isEqualTo(annotations); }
public static void verifySpanDeepEquals( Span spanToVerify, Span expectedSpan, boolean allowStartTimeNanosFudgeFactor ) { assertThat(spanToVerify.getSpanStartTimeEpochMicros()).isEqualTo(expectedSpan.getSpanStartTimeEpochMicros()); if (allowStartTimeNanosFudgeFactor) { assertThat(spanToVerify.getSpanStartTimeNanos()) .isCloseTo(expectedSpan.getSpanStartTimeNanos(), Offset.offset(TimeUnit.MILLISECONDS.toNanos(1))); } else { assertThat(spanToVerify.getSpanStartTimeNanos()).isEqualTo(expectedSpan.getSpanStartTimeNanos()); } assertThat(spanToVerify.isCompleted()).isEqualTo(expectedSpan.isCompleted()); assertThat(spanToVerify.getTraceId()).isEqualTo(expectedSpan.getTraceId()); assertThat(spanToVerify.getSpanId()).isEqualTo(expectedSpan.getSpanId()); assertThat(spanToVerify.getParentSpanId()).isEqualTo(expectedSpan.getParentSpanId()); assertThat(spanToVerify.getSpanName()).isEqualTo(expectedSpan.getSpanName()); assertThat(spanToVerify.isSampleable()).isEqualTo(expectedSpan.isSampleable()); assertThat(spanToVerify.getUserId()).isEqualTo(expectedSpan.getUserId()); assertThat(spanToVerify.getDurationNanos()).isEqualTo(expectedSpan.getDurationNanos()); assertThat(spanToVerify.getSpanPurpose()).isEqualTo(expectedSpan.getSpanPurpose()); assertThat(spanToVerify.getTags()).isEqualTo(expectedSpan.getTags()); assertThat(spanToVerify.getTimestampedAnnotations()).isEqualTo(expectedSpan.getTimestampedAnnotations()); }
@Test public void fromHttpServletRequestOrCreateRootSpan_pulls_from_headers_if_available() { // given: a set of standard Span header values given(request.getHeader(TraceHeaders.TRACE_ID)).willReturn(sampleTraceID); given(request.getHeader(TraceHeaders.TRACE_SAMPLED)).willReturn(Boolean.TRUE.toString()); given(request.getHeader(TraceHeaders.SPAN_ID)).willReturn(sampleSpanID); given(request.getHeader(TraceHeaders.PARENT_SPAN_ID)).willReturn(sampleParentSpanID); given(request.getHeader(USER_ID_HEADER_KEY)).willReturn(userId); // when: creating Span object from HTTP request using fromHttpServletRequestOrCreateRootSpan long beforeCallNanos = System.nanoTime(); Span goodSpan = HttpSpanFactory.fromHttpServletRequestOrCreateRootSpan(request, USER_ID_HEADER_KEYS); long afterCallNanos = System.nanoTime(); // then: ensure Span object gets identical values from corresponding headers assertThat(goodSpan.getTraceId()).isEqualTo(sampleTraceID); assertThat(goodSpan.isSampleable()).isTrue(); assertThat(goodSpan.getSpanId()).isEqualTo(sampleSpanID); assertThat(goodSpan.getParentSpanId()).isEqualTo(sampleParentSpanID); assertThat(goodSpan.getUserId()).isEqualTo(userId); assertThat(goodSpan.getSpanStartTimeNanos()).isBetween(beforeCallNanos, afterCallNanos); assertThat(goodSpan.isCompleted()).isFalse(); assertThat(goodSpan.getSpanPurpose()).isEqualTo(SpanPurpose.SERVER); }
@Test public void fromHttpServletRequest_creates_span_with_all_values_if_all_values_available_from_request_headers() { // given: a set of standard Span header values given(request.getHeader(TraceHeaders.TRACE_ID)).willReturn(sampleTraceID); given(request.getHeader(TraceHeaders.TRACE_SAMPLED)).willReturn(Boolean.FALSE.toString()); given(request.getHeader(TraceHeaders.SPAN_ID)).willReturn(sampleSpanID); given(request.getHeader(TraceHeaders.PARENT_SPAN_ID)).willReturn(sampleParentSpanID); given(request.getHeader(USER_ID_HEADER_KEY)).willReturn(userId); // when: creating Span object from HTTP request long beforeCallNanos = System.nanoTime(); Span goodSpan = HttpSpanFactory.fromHttpServletRequest(request, USER_ID_HEADER_KEYS); long afterCallNanos = System.nanoTime(); // then: ensure Span object gets identical values from corresponding headers assertThat(goodSpan.getTraceId()).isEqualTo(sampleTraceID); assertThat(goodSpan.isSampleable()).isFalse(); assertThat(goodSpan.getSpanId()).isEqualTo(sampleSpanID); assertThat(goodSpan.getParentSpanId()).isEqualTo(sampleParentSpanID); assertThat(goodSpan.getUserId()).isEqualTo(userId); assertThat(goodSpan.getSpanStartTimeNanos()).isBetween(beforeCallNanos, afterCallNanos); assertThat(goodSpan.isCompleted()).isFalse(); assertThat(goodSpan.getSpanPurpose()).isEqualTo(SpanPurpose.SERVER); }
@Test public void fromHttpServletRequest_pulls_from_alt_user_id_if_specified_in_header_and_primary_is_missing() { // given: a set of standard Span header values with the alt user ID header specified instead of the primary given(request.getHeader(TraceHeaders.TRACE_ID)).willReturn(sampleTraceID); given(request.getHeader(TraceHeaders.TRACE_SAMPLED)).willReturn(Boolean.TRUE.toString()); given(request.getHeader(TraceHeaders.SPAN_ID)).willReturn(sampleSpanID); given(request.getHeader(TraceHeaders.PARENT_SPAN_ID)).willReturn(sampleParentSpanID); given(request.getHeader(ALT_USER_ID_HEADER_KEY)).willReturn(altUserId); // when: creating Span object from HTTP request long beforeCallNanos = System.nanoTime(); Span goodSpan = HttpSpanFactory.fromHttpServletRequest(request, USER_ID_HEADER_KEYS); long afterCallNanos = System.nanoTime(); // then: ensure Span object gets identical values from corresponding headers assertThat(goodSpan.getTraceId()).isEqualTo(sampleTraceID); assertThat(goodSpan.isSampleable()).isTrue(); assertThat(goodSpan.getSpanId()).isEqualTo(sampleSpanID); assertThat(goodSpan.getParentSpanId()).isEqualTo(sampleParentSpanID); assertThat(goodSpan.getUserId()).isEqualTo(altUserId); assertThat(goodSpan.getSpanStartTimeNanos()).isBetween(beforeCallNanos, afterCallNanos); assertThat(goodSpan.isCompleted()).isFalse(); assertThat(goodSpan.getSpanPurpose()).isEqualTo(SpanPurpose.SERVER); }
@Test public void fromHttpServletRequest_creates_span_with_all_values_minus_user_id_if_user_id_list_is_not_passed_in() { // given: a set of standard Span header values given(request.getHeader(TraceHeaders.TRACE_ID)).willReturn(sampleTraceID); given(request.getHeader(TraceHeaders.TRACE_SAMPLED)).willReturn(Boolean.FALSE.toString()); given(request.getHeader(TraceHeaders.SPAN_ID)).willReturn(sampleSpanID); given(request.getHeader(TraceHeaders.PARENT_SPAN_ID)).willReturn(sampleParentSpanID); given(request.getHeader(USER_ID_HEADER_KEY)).willReturn(userId); // when: creating Span object from HTTP request long beforeCallNanos = System.nanoTime(); Span goodSpan = HttpSpanFactory.fromHttpServletRequest(request, null); long afterCallNanos = System.nanoTime(); // then: ensure Span object gets identical values from corresponding headers assertThat(goodSpan.getTraceId()).isEqualTo(sampleTraceID); assertThat(goodSpan.isSampleable()).isFalse(); assertThat(goodSpan.getSpanId()).isEqualTo(sampleSpanID); assertThat(goodSpan.getParentSpanId()).isEqualTo(sampleParentSpanID); assertThat(goodSpan.getUserId()).isNull(); assertThat(goodSpan.getSpanStartTimeNanos()).isBetween(beforeCallNanos, afterCallNanos); assertThat(goodSpan.isCompleted()).isFalse(); assertThat(goodSpan.getSpanPurpose()).isEqualTo(SpanPurpose.SERVER); }
assertThat(span.getParentSpanId()).isNull(); assertThat(span.getSpanStartTimeEpochMicros()).isBetween(beforeEpochMicros, afterEpochMicros); assertThat(span.getSpanStartTimeNanos()).isBetween(beforeNanoTime, afterNanoTime); assertThat(span.isCompleted()).isFalse(); assertThat(span.getDurationNanos()).isNull();
assertThat(result.getSpanPurpose()).isEqualTo(spanPurpose); assertThat(result.getSpanStartTimeEpochMicros()).isBetween(beforeCallEpochMicros, afterCallEpochMicros); assertThat(result.getSpanStartTimeNanos()).isBetween(beforeCallNanos, afterCallNanos); assertThat(result.getDurationNanos()).isNull(); assertThat(result.isCompleted()).isFalse();
assertThat(result.getSpanPurpose()).isEqualTo(spanPurpose); assertThat(result.getSpanStartTimeEpochMicros()).isBetween(beforeCallEpochMicros, afterCallEpochMicros); assertThat(result.getSpanStartTimeNanos()).isBetween(beforeCallNanos, afterCallNanos); assertThat(result.isCompleted()).isFalse(); assertThat(result.getDurationNanos()).isNull();
assertThat(span.getParentSpanId()).isNull(); assertThat(span.getSpanStartTimeEpochMicros()).isBetween(beforeEpochMicros, afterEpochMicros); assertThat(span.getSpanStartTimeNanos()).isBetween(beforeNanoTime, afterNanoTime); assertThat(span.isCompleted()).isFalse(); assertThat(span.getDurationNanos()).isNull();
assertThat(childSpan.getSpanStartTimeNanos()).isBetween(beforeCallNanos, afterCallNanos); assertThat(childSpan.isCompleted()).isFalse(); assertThat(childSpan.getDurationNanos()).isNull();
assertThat(subspan.getParentSpanId()).isNull(); assertThat(subspan.getSpanStartTimeEpochMicros()).isBetween(beforeEpochMicros, afterEpochMicros); assertThat(subspan.getSpanStartTimeNanos()).isBetween(beforeNanoTime, afterNanoTime); assertThat(subspan.isCompleted()).isFalse(); assertThat(subspan.getDurationNanos()).isNull();
assertThat(span.getParentSpanId()).isEqualTo(parentSpan.getSpanId()); assertThat(span.getSpanStartTimeEpochMicros()).isBetween(beforeEpochMicros, afterEpochMicros); assertThat(span.getSpanStartTimeNanos()).isBetween(beforeNanoTime, afterNanoTime); assertThat(span.isCompleted()).isFalse(); assertThat(span.getDurationNanos()).isNull();
assertThat(span.getParentSpanId()).isEqualTo(parentSpan.getSpanId()); assertThat(span.getSpanStartTimeEpochMicros()).isBetween(beforeEpochMicros, afterEpochMicros); assertThat(span.getSpanStartTimeNanos()).isBetween(beforeNanoTime, afterNanoTime); assertThat(span.isCompleted()).isFalse(); assertThat(span.getDurationNanos()).isNull();