@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 equals_returns_true_and_hashCode_same_if_all_fields_are_equal() { // given Span fullSpan1 = createFilledOutSpan(true); Span fullSpan2 = createFilledOutSpan(true); // expect assertThat(fullSpan1.equals(fullSpan2)).isTrue(); assertThat(fullSpan1.hashCode()).isEqualTo(fullSpan2.hashCode()); }
public static void verifySpanEqualsDeserializedValues(Span span, Map<String, ?> deserializedValues) { assertThat(nullSafeStringValueOf(span.getSpanStartTimeEpochMicros())).isEqualTo(deserializedValues.get(SpanParser.START_TIME_EPOCH_MICROS_FIELD)); assertThat(span.isCompleted()).isEqualTo(deserializedValues.containsKey(SpanParser.DURATION_NANOS_FIELD)); assertThat(nullSafeStringValueOf(span.getTraceId())).isEqualTo(deserializedValues.get(SpanParser.TRACE_ID_FIELD)); assertThat(nullSafeStringValueOf(span.getSpanId())).isEqualTo(deserializedValues.get(SpanParser.SPAN_ID_FIELD)); assertThat(nullSafeStringValueOf(span.getParentSpanId())).isEqualTo(deserializedValues.get(SpanParser.PARENT_SPAN_ID_FIELD)); assertThat(nullSafeStringValueOf(span.getSpanName())).isEqualTo(deserializedValues.get(SpanParser.SPAN_NAME_FIELD)); assertThat(nullSafeStringValueOf(span.isSampleable())).isEqualTo(deserializedValues.get(SpanParser.SAMPLEABLE_FIELD)); assertThat(nullSafeStringValueOf(span.getUserId())).isEqualTo(deserializedValues.get(SpanParser.USER_ID_FIELD)); assertThat(nullSafeStringValueOf(span.getDurationNanos())).isEqualTo(nullSafeStringValueOf(deserializedValues.get(SpanParser.DURATION_NANOS_FIELD))); assertThat(nullSafeStringValueOf(span.getSpanPurpose())).isEqualTo(nullSafeStringValueOf(deserializedValues.get(SpanParser.SPAN_PURPOSE_FIELD)));
@DataProvider(value = { "SERVER", "CLIENT", "LOCAL_ONLY", "UNKNOWN" }, splitBy = "\\|") @Test public void newBuilder_with_copy_arg_returns_exact_copy(SpanPurpose spanPurpose) { // given Span origSpan = createFilledOutSpan(true); Whitebox.setInternalState(origSpan, "spanPurpose", spanPurpose); assertThat(origSpan.getSpanPurpose()).isEqualTo(spanPurpose); // when Span copySpan = Span.newBuilder(origSpan).build(); // then verifySpanDeepEquals(copySpan, origSpan, false); }
@Test public void fromKeyValueString_should_function_properly_for_non_completed_spans() { // given: valid, non-completed span and key/value string from Span.fromKeyValueString() Span validSpan = Span.generateRootSpanForNewTrace(spanName, spanPurpose).build(); String keyValStr = SpanParser.convertSpanToKeyValueFormat(validSpan); assertThat(validSpan.isCompleted()).isFalse(); // when: fromKeyValueString is called Span spanFromKeyValStr = SpanParser.fromKeyValueString(keyValStr); // then: the original span and the fromKeyValueString() span values should be exactly the same verifySpanDeepEquals(spanFromKeyValStr, validSpan, true); }
@Test public void convertSpanToJSON_should_function_properly_for_non_completed_spans() throws IOException { // given: valid span and JSON string from SpanParser.convertSpanToJSON() Span validSpan = Span.generateRootSpanForNewTrace(spanName, spanPurpose).build(); String json = SpanParser.convertSpanToJSON(validSpan); assertThat(validSpan.isCompleted()).isFalse(); assertThat(validSpan.getDurationNanos()).isNull(); // when: jackson is used to deserialize that JSON Map<String, Object> spanValuesFromJackson = objectMapper.readValue(json, new TypeReference<Map<String, Object>>() {}); // then: the original span and jackson's span values should be exactly the same verifySpanEqualsDeserializedValues(validSpan, spanValuesFromJackson); }
@Before public void beforeMethod() { resetTracing(); }
busyWaitForNanos(delayNanos);
@Test public void fromJson_should_function_properly_for_non_completed_spans() { // given: valid, non-completed span and JSON string from SpanParser.convertSpanToJSON() Span validSpan = Span.generateRootSpanForNewTrace(spanName, spanPurpose).build(); String json = SpanParser.convertSpanToJSON(validSpan); assertThat(validSpan.isCompleted()).isFalse(); // when: fromJson is called Span spanFromJson = SpanParser.fromJSON(json); // then: the original span and the fromJson() span values should be exactly the same verifySpanDeepEquals(spanFromJson, validSpan, true); }
@Test public void convertSpanToJSON_should_function_properly_for_completed_spans() throws IOException { // given: valid span and completed, and JSON string from SpanParser.convertSpanToJSON() Span validSpan = Span.generateRootSpanForNewTrace(spanName, spanPurpose).build(); completeSpan(validSpan); assertThat(validSpan.isCompleted()).isTrue(); assertThat(validSpan.getDurationNanos()).isNotNull(); String json = SpanParser.convertSpanToJSON(validSpan); // when: jackson is used to deserialize that JSON Map<String, Object> spanValuesFromJackson = objectMapper.readValue(json, new TypeReference<Map<String, Object>>() {}); // then: the original span and jackson's span values should be exactly the same verifySpanEqualsDeserializedValues(validSpan, spanValuesFromJackson); }
@After public void afterMethod() { resetTracing(); }
@Test public void equals_returns_false_and_hashCode_different_if_tags_are_different() { // given Span fullSpan1 = createFilledOutSpan(true); Span fullSpan2 = createFilledOutSpan(true); fullSpan1.putTag("key-" + UUID.randomUUID().toString(), UUID.randomUUID().toString()); // expect assertThat(fullSpan1.equals(fullSpan2)).isFalse(); assertThat(fullSpan1.hashCode()).isNotEqualTo(fullSpan2.hashCode()); }
@Test public void fromKeyValueString_delegates_to_span_parser() { // given Span span = Span.newBuilder("foo", SpanPurpose.CLIENT) .withTag("blahtag", UUID.randomUUID().toString()) .build(); String keyValueStr = span.toKeyValueString(); // when Span result = span.fromKeyValueString(keyValueStr); // then verifySpanDeepEquals(result, span, true); }
@Test public void convertSpanToKeyValueFormat_should_function_properly_for_non_completed_spans() { // given: valid span and key/value string from SpanParser.convertSpanToKeyValueFormat() Span validSpan = Span.generateRootSpanForNewTrace(spanName, spanPurpose).build(); assertThat(validSpan.isCompleted()).isFalse(); String keyValueStr = SpanParser.convertSpanToKeyValueFormat(validSpan); // when: the string is deserialized into a map Map<String, Object> deserializedValues = deserializeKeyValueSpanString(keyValueStr); // then: the original span and deserialized map values should be exactly the same verifySpanEqualsDeserializedValues(validSpan, deserializedValues); }
@Test public void equals_returns_false_and_hashCode_different_if_other_is_not_a_Span() { // given Span span = createFilledOutSpan(true); String notASpan = "notASpan"; // expect //noinspection EqualsBetweenInconvertibleTypes assertThat(span.equals(notASpan)).isFalse(); assertThat(span.hashCode()).isNotEqualTo(notASpan.hashCode()); }
@Test public void convertSpanToKeyValueFormat_and_fromKeyValueString_escapes_and_unescapes_tag_keys_as_expected() { // given String unescapedTagKey = "fookey=blah withspaceandequals,andcomma"; String tagValue = UUID.randomUUID().toString(); Span span = Span.newBuilder("someSpan", SpanPurpose.CLIENT) .withTag(unescapedTagKey, tagValue) .build(); String expectedEscapedTagKey = "fookey\\u003Dblah\\u0020withspaceandequals\\u002Candcomma"; // when String keyValueStr = SpanParser.convertSpanToKeyValueFormat(span); // then assertThat(keyValueStr).contains("," + SpanParser.KEY_VALUE_TAG_PREFIX + expectedEscapedTagKey + "=\"" + tagValue + "\""); // and when Span deserialized = SpanParser.fromKeyValueString(keyValueStr); // then verifySpanDeepEquals(deserialized, span, true); } }
@Test public void complete_should_reset_cached_json() throws IOException { // given Span validSpan = Span.generateRootSpanForNewTrace(spanName, spanPurpose).build(); String uuidString = UUID.randomUUID().toString(); Whitebox.setInternalState(validSpan, "cachedJsonRepresentation", uuidString); // when String beforeCompleteJson = validSpan.toJSON(); completeSpan(validSpan); // then String afterCompleteJson = validSpan.toJSON(); assertThat(afterCompleteJson).isNotEqualTo(beforeCompleteJson); assertThat(afterCompleteJson).isNotEqualTo(uuidString); Map<String, Object> spanValuesFromJackson = objectMapper.readValue(afterCompleteJson, new TypeReference<Map<String, Object>>() { }); verifySpanEqualsDeserializedValues(validSpan, spanValuesFromJackson); }
@Test public void toString_delegates_to_toJSON() { // given: span with all values filled in Span span = createFilledOutSpan(true); // when: toString is called on that span String toStringVal = span.toString(); // then: it has the same value as toJSON() assertThat(toStringVal).isEqualTo(span.toJSON()); }
@Test public void fromJSON_delegates_to_span_parser() { // given Span span = Span.newBuilder("foo", SpanPurpose.CLIENT) .withTag("blahtag", UUID.randomUUID().toString()) .build(); String json = span.toJSON(); // when Span result = span.fromJSON(json); // then verifySpanDeepEquals(result, span, true); }
@Test public void convertSpanToKeyValueFormat_should_function_properly_for_completed_spans() { // given: valid span and completed, and key/value string from SpanParser.convertSpanToKeyValueFormat() Span validSpan = Span.generateRootSpanForNewTrace(spanName, spanPurpose).build(); completeSpan(validSpan); assertThat(validSpan.isCompleted()).isTrue(); String keyValueStr = SpanParser.convertSpanToKeyValueFormat(validSpan); // when: the string is deserialized into a map Map<String, Object> deserializedValues = deserializeKeyValueSpanString(keyValueStr); // then: the original span and deserialized map values should be exactly the same verifySpanEqualsDeserializedValues(validSpan, deserializedValues); }