1 /* 2 * Copyright 2017, OpenCensus Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package io.opencensus.implcore.trace.propagation; 18 19 import static com.google.common.truth.Truth.assertThat; 20 import static io.opencensus.implcore.trace.propagation.B3Format.X_B3_FLAGS; 21 import static io.opencensus.implcore.trace.propagation.B3Format.X_B3_PARENT_SPAN_ID; 22 import static io.opencensus.implcore.trace.propagation.B3Format.X_B3_SAMPLED; 23 import static io.opencensus.implcore.trace.propagation.B3Format.X_B3_SPAN_ID; 24 import static io.opencensus.implcore.trace.propagation.B3Format.X_B3_TRACE_ID; 25 26 import io.opencensus.trace.SpanContext; 27 import io.opencensus.trace.SpanId; 28 import io.opencensus.trace.TraceId; 29 import io.opencensus.trace.TraceOptions; 30 import io.opencensus.trace.propagation.SpanContextParseException; 31 import io.opencensus.trace.propagation.TextFormat.Getter; 32 import io.opencensus.trace.propagation.TextFormat.Setter; 33 import java.util.HashMap; 34 import java.util.Map; 35 import javax.annotation.Nullable; 36 import org.junit.Rule; 37 import org.junit.Test; 38 import org.junit.rules.ExpectedException; 39 import org.junit.runner.RunWith; 40 import org.junit.runners.JUnit4; 41 42 /** Unit tests for {@link B3Format}. */ 43 @RunWith(JUnit4.class) 44 public class B3FormatTest { 45 private static final String TRACE_ID_BASE16 = "ff000000000000000000000000000041"; 46 private static final TraceId TRACE_ID = TraceId.fromLowerBase16(TRACE_ID_BASE16); 47 private static final String TRACE_ID_BASE16_EIGHT_BYTES = "0000000000000041"; 48 private static final TraceId TRACE_ID_EIGHT_BYTES = 49 TraceId.fromLowerBase16("0000000000000000" + TRACE_ID_BASE16_EIGHT_BYTES); 50 private static final String SPAN_ID_BASE16 = "ff00000000000041"; 51 private static final SpanId SPAN_ID = SpanId.fromLowerBase16(SPAN_ID_BASE16); 52 private static final byte TRACE_OPTIONS_BYTE = 1; 53 private static final TraceOptions TRACE_OPTIONS = TraceOptions.fromByte(TRACE_OPTIONS_BYTE); 54 private static final Setter<Map<String, String>> setter = 55 new Setter<Map<String, String>>() { 56 @Override 57 public void put(Map<String, String> carrier, String key, String value) { 58 carrier.put(key, value); 59 } 60 }; 61 private static final Getter<Map<String, String>> getter = 62 new Getter<Map<String, String>>() { 63 @Nullable 64 @Override 65 public String get(Map<String, String> carrier, String key) { 66 return carrier.get(key); 67 } 68 }; 69 private final B3Format b3Format = new B3Format(); 70 @Rule public ExpectedException thrown = ExpectedException.none(); 71 72 @Test serialize_SampledContext()73 public void serialize_SampledContext() { 74 Map<String, String> carrier = new HashMap<String, String>(); 75 b3Format.inject(SpanContext.create(TRACE_ID, SPAN_ID, TRACE_OPTIONS), carrier, setter); 76 assertThat(carrier) 77 .containsExactly( 78 X_B3_TRACE_ID, TRACE_ID_BASE16, X_B3_SPAN_ID, SPAN_ID_BASE16, X_B3_SAMPLED, "1"); 79 } 80 81 @Test serialize_NotSampledContext()82 public void serialize_NotSampledContext() { 83 Map<String, String> carrier = new HashMap<String, String>(); 84 b3Format.inject(SpanContext.create(TRACE_ID, SPAN_ID, TraceOptions.DEFAULT), carrier, setter); 85 assertThat(carrier) 86 .containsExactly(X_B3_TRACE_ID, TRACE_ID_BASE16, X_B3_SPAN_ID, SPAN_ID_BASE16); 87 } 88 89 @Test parseMissingSampledAndMissingFlag()90 public void parseMissingSampledAndMissingFlag() throws SpanContextParseException { 91 Map<String, String> headersNotSampled = new HashMap<String, String>(); 92 headersNotSampled.put(X_B3_TRACE_ID, TRACE_ID_BASE16); 93 headersNotSampled.put(X_B3_SPAN_ID, SPAN_ID_BASE16); 94 SpanContext spanContext = SpanContext.create(TRACE_ID, SPAN_ID, TraceOptions.DEFAULT); 95 assertThat(b3Format.extract(headersNotSampled, getter)).isEqualTo(spanContext); 96 } 97 98 @Test parseSampled()99 public void parseSampled() throws SpanContextParseException { 100 Map<String, String> headersSampled = new HashMap<String, String>(); 101 headersSampled.put(X_B3_TRACE_ID, TRACE_ID_BASE16); 102 headersSampled.put(X_B3_SPAN_ID, SPAN_ID_BASE16); 103 headersSampled.put(X_B3_SAMPLED, "1"); 104 assertThat(b3Format.extract(headersSampled, getter)) 105 .isEqualTo(SpanContext.create(TRACE_ID, SPAN_ID, TRACE_OPTIONS)); 106 } 107 108 @Test parseZeroSampled()109 public void parseZeroSampled() throws SpanContextParseException { 110 Map<String, String> headersNotSampled = new HashMap<String, String>(); 111 headersNotSampled.put(X_B3_TRACE_ID, TRACE_ID_BASE16); 112 headersNotSampled.put(X_B3_SPAN_ID, SPAN_ID_BASE16); 113 headersNotSampled.put(X_B3_SAMPLED, "0"); 114 assertThat(b3Format.extract(headersNotSampled, getter)) 115 .isEqualTo(SpanContext.create(TRACE_ID, SPAN_ID, TraceOptions.DEFAULT)); 116 } 117 118 @Test parseFlag()119 public void parseFlag() throws SpanContextParseException { 120 Map<String, String> headersFlagSampled = new HashMap<String, String>(); 121 headersFlagSampled.put(X_B3_TRACE_ID, TRACE_ID_BASE16); 122 headersFlagSampled.put(X_B3_SPAN_ID, SPAN_ID_BASE16); 123 headersFlagSampled.put(X_B3_FLAGS, "1"); 124 assertThat(b3Format.extract(headersFlagSampled, getter)) 125 .isEqualTo(SpanContext.create(TRACE_ID, SPAN_ID, TRACE_OPTIONS)); 126 } 127 128 @Test parseZeroFlag()129 public void parseZeroFlag() throws SpanContextParseException { 130 Map<String, String> headersFlagNotSampled = new HashMap<String, String>(); 131 headersFlagNotSampled.put(X_B3_TRACE_ID, TRACE_ID_BASE16); 132 headersFlagNotSampled.put(X_B3_SPAN_ID, SPAN_ID_BASE16); 133 headersFlagNotSampled.put(X_B3_FLAGS, "0"); 134 assertThat(b3Format.extract(headersFlagNotSampled, getter)) 135 .isEqualTo(SpanContext.create(TRACE_ID, SPAN_ID, TraceOptions.DEFAULT)); 136 } 137 138 @Test parseEightBytesTraceId()139 public void parseEightBytesTraceId() throws SpanContextParseException { 140 Map<String, String> headersEightBytes = new HashMap<String, String>(); 141 headersEightBytes.put(X_B3_TRACE_ID, TRACE_ID_BASE16_EIGHT_BYTES); 142 headersEightBytes.put(X_B3_SPAN_ID, SPAN_ID_BASE16); 143 headersEightBytes.put(X_B3_SAMPLED, "1"); 144 assertThat(b3Format.extract(headersEightBytes, getter)) 145 .isEqualTo(SpanContext.create(TRACE_ID_EIGHT_BYTES, SPAN_ID, TRACE_OPTIONS)); 146 } 147 148 @Test parseEightBytesTraceId_NotSampledSpanContext()149 public void parseEightBytesTraceId_NotSampledSpanContext() throws SpanContextParseException { 150 Map<String, String> headersEightBytes = new HashMap<String, String>(); 151 headersEightBytes.put(X_B3_TRACE_ID, TRACE_ID_BASE16_EIGHT_BYTES); 152 headersEightBytes.put(X_B3_SPAN_ID, SPAN_ID_BASE16); 153 assertThat(b3Format.extract(headersEightBytes, getter)) 154 .isEqualTo(SpanContext.create(TRACE_ID_EIGHT_BYTES, SPAN_ID, TraceOptions.DEFAULT)); 155 } 156 157 @Test parseInvalidTraceId()158 public void parseInvalidTraceId() throws SpanContextParseException { 159 Map<String, String> invalidHeaders = new HashMap<String, String>(); 160 invalidHeaders.put(X_B3_TRACE_ID, "abcdefghijklmnop"); 161 invalidHeaders.put(X_B3_SPAN_ID, SPAN_ID_BASE16); 162 thrown.expect(SpanContextParseException.class); 163 thrown.expectMessage("Invalid input."); 164 b3Format.extract(invalidHeaders, getter); 165 } 166 167 @Test parseInvalidTraceId_Size()168 public void parseInvalidTraceId_Size() throws SpanContextParseException { 169 Map<String, String> invalidHeaders = new HashMap<String, String>(); 170 invalidHeaders.put(X_B3_TRACE_ID, "0123456789abcdef00"); 171 invalidHeaders.put(X_B3_SPAN_ID, SPAN_ID_BASE16); 172 thrown.expect(SpanContextParseException.class); 173 thrown.expectMessage("Invalid input."); 174 b3Format.extract(invalidHeaders, getter); 175 } 176 177 @Test parseMissingTraceId()178 public void parseMissingTraceId() throws SpanContextParseException { 179 Map<String, String> invalidHeaders = new HashMap<String, String>(); 180 invalidHeaders.put(X_B3_SPAN_ID, SPAN_ID_BASE16); 181 thrown.expect(SpanContextParseException.class); 182 thrown.expectMessage("Missing X_B3_TRACE_ID."); 183 b3Format.extract(invalidHeaders, getter); 184 } 185 186 @Test parseInvalidSpanId()187 public void parseInvalidSpanId() throws SpanContextParseException { 188 Map<String, String> invalidHeaders = new HashMap<String, String>(); 189 invalidHeaders.put(X_B3_TRACE_ID, TRACE_ID_BASE16); 190 invalidHeaders.put(X_B3_SPAN_ID, "abcdefghijklmnop"); 191 thrown.expect(SpanContextParseException.class); 192 thrown.expectMessage("Invalid input."); 193 b3Format.extract(invalidHeaders, getter); 194 } 195 196 @Test parseInvalidSpanId_Size()197 public void parseInvalidSpanId_Size() throws SpanContextParseException { 198 Map<String, String> invalidHeaders = new HashMap<String, String>(); 199 invalidHeaders.put(X_B3_TRACE_ID, TRACE_ID_BASE16); 200 invalidHeaders.put(X_B3_SPAN_ID, "0123456789abcdef00"); 201 thrown.expect(SpanContextParseException.class); 202 thrown.expectMessage("Invalid input."); 203 b3Format.extract(invalidHeaders, getter); 204 } 205 206 @Test parseMissingSpanId()207 public void parseMissingSpanId() throws SpanContextParseException { 208 Map<String, String> invalidHeaders = new HashMap<String, String>(); 209 invalidHeaders.put(X_B3_TRACE_ID, TRACE_ID_BASE16); 210 thrown.expect(SpanContextParseException.class); 211 thrown.expectMessage("Missing X_B3_SPAN_ID."); 212 b3Format.extract(invalidHeaders, getter); 213 } 214 215 @Test fields_list()216 public void fields_list() { 217 assertThat(b3Format.fields()) 218 .containsExactly( 219 X_B3_TRACE_ID, X_B3_SPAN_ID, X_B3_PARENT_SPAN_ID, X_B3_SAMPLED, X_B3_FLAGS); 220 } 221 } 222