tracer_test.go 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. package opentelemetry
  2. import (
  3. "context"
  4. "testing"
  5. "github.com/stretchr/testify/assert"
  6. "github.com/stretchr/testify/require"
  7. "go.opentelemetry.io/otel"
  8. "go.opentelemetry.io/otel/propagation"
  9. "go.opentelemetry.io/otel/trace"
  10. "google.golang.org/grpc/metadata"
  11. )
  12. const (
  13. traceIDStr = "4bf92f3577b34da6a3ce929d0e0e4736"
  14. spanIDStr = "00f067aa0ba902b7"
  15. )
  16. var (
  17. traceID = mustTraceIDFromHex(traceIDStr)
  18. spanID = mustSpanIDFromHex(spanIDStr)
  19. )
  20. func mustTraceIDFromHex(s string) (t trace.TraceID) {
  21. var err error
  22. t, err = trace.TraceIDFromHex(s)
  23. if err != nil {
  24. panic(err)
  25. }
  26. return
  27. }
  28. func mustSpanIDFromHex(s string) (t trace.SpanID) {
  29. var err error
  30. t, err = trace.SpanIDFromHex(s)
  31. if err != nil {
  32. panic(err)
  33. }
  34. return
  35. }
  36. func TestExtractValidTraceContext(t *testing.T) {
  37. stateStr := "key1=value1,key2=value2"
  38. state, err := trace.ParseTraceState(stateStr)
  39. require.NoError(t, err)
  40. tests := []struct {
  41. name string
  42. traceparent string
  43. tracestate string
  44. sc trace.SpanContext
  45. }{
  46. {
  47. name: "not sampled",
  48. traceparent: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00",
  49. sc: trace.NewSpanContext(trace.SpanContextConfig{
  50. TraceID: traceID,
  51. SpanID: spanID,
  52. Remote: true,
  53. }),
  54. },
  55. {
  56. name: "sampled",
  57. traceparent: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01",
  58. sc: trace.NewSpanContext(trace.SpanContextConfig{
  59. TraceID: traceID,
  60. SpanID: spanID,
  61. TraceFlags: trace.FlagsSampled,
  62. Remote: true,
  63. }),
  64. },
  65. {
  66. name: "valid tracestate",
  67. traceparent: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00",
  68. tracestate: stateStr,
  69. sc: trace.NewSpanContext(trace.SpanContextConfig{
  70. TraceID: traceID,
  71. SpanID: spanID,
  72. TraceState: state,
  73. Remote: true,
  74. }),
  75. },
  76. {
  77. name: "invalid tracestate perserves traceparent",
  78. traceparent: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00",
  79. tracestate: "invalid$@#=invalid",
  80. sc: trace.NewSpanContext(trace.SpanContextConfig{
  81. TraceID: traceID,
  82. SpanID: spanID,
  83. Remote: true,
  84. }),
  85. },
  86. {
  87. name: "future version not sampled",
  88. traceparent: "02-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00",
  89. sc: trace.NewSpanContext(trace.SpanContextConfig{
  90. TraceID: traceID,
  91. SpanID: spanID,
  92. Remote: true,
  93. }),
  94. },
  95. {
  96. name: "future version sampled",
  97. traceparent: "02-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01",
  98. sc: trace.NewSpanContext(trace.SpanContextConfig{
  99. TraceID: traceID,
  100. SpanID: spanID,
  101. TraceFlags: trace.FlagsSampled,
  102. Remote: true,
  103. }),
  104. },
  105. {
  106. name: "future version sample bit set",
  107. traceparent: "02-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-09",
  108. sc: trace.NewSpanContext(trace.SpanContextConfig{
  109. TraceID: traceID,
  110. SpanID: spanID,
  111. TraceFlags: trace.FlagsSampled,
  112. Remote: true,
  113. }),
  114. },
  115. {
  116. name: "future version sample bit not set",
  117. traceparent: "02-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-08",
  118. sc: trace.NewSpanContext(trace.SpanContextConfig{
  119. TraceID: traceID,
  120. SpanID: spanID,
  121. Remote: true,
  122. }),
  123. },
  124. {
  125. name: "future version additional data",
  126. traceparent: "02-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00-XYZxsf09",
  127. sc: trace.NewSpanContext(trace.SpanContextConfig{
  128. TraceID: traceID,
  129. SpanID: spanID,
  130. Remote: true,
  131. }),
  132. },
  133. {
  134. name: "B3 format ending in dash",
  135. traceparent: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00-",
  136. sc: trace.NewSpanContext(trace.SpanContextConfig{
  137. TraceID: traceID,
  138. SpanID: spanID,
  139. Remote: true,
  140. }),
  141. },
  142. {
  143. name: "future version B3 format ending in dash",
  144. traceparent: "03-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00-",
  145. sc: trace.NewSpanContext(trace.SpanContextConfig{
  146. TraceID: traceID,
  147. SpanID: spanID,
  148. Remote: true,
  149. }),
  150. },
  151. }
  152. otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{}))
  153. propagator := otel.GetTextMapPropagator()
  154. for _, tt := range tests {
  155. t.Run(tt.name, func(t *testing.T) {
  156. ctx := context.Background()
  157. md := metadata.MD{}
  158. md.Set("traceparent", tt.traceparent)
  159. md.Set("tracestate", tt.tracestate)
  160. _, spanCtx := Extract(ctx, propagator, &md)
  161. assert.Equal(t, tt.sc, spanCtx)
  162. })
  163. }
  164. }
  165. func TestExtractInvalidTraceContext(t *testing.T) {
  166. tests := []struct {
  167. name string
  168. header string
  169. }{
  170. {
  171. name: "wrong version length",
  172. header: "0000-00000000000000000000000000000000-0000000000000000-01",
  173. },
  174. {
  175. name: "wrong trace ID length",
  176. header: "00-ab00000000000000000000000000000000-cd00000000000000-01",
  177. },
  178. {
  179. name: "wrong span ID length",
  180. header: "00-ab000000000000000000000000000000-cd0000000000000000-01",
  181. },
  182. {
  183. name: "wrong trace flag length",
  184. header: "00-ab000000000000000000000000000000-cd00000000000000-0100",
  185. },
  186. {
  187. name: "bogus version",
  188. header: "qw-00000000000000000000000000000000-0000000000000000-01",
  189. },
  190. {
  191. name: "bogus trace ID",
  192. header: "00-qw000000000000000000000000000000-cd00000000000000-01",
  193. },
  194. {
  195. name: "bogus span ID",
  196. header: "00-ab000000000000000000000000000000-qw00000000000000-01",
  197. },
  198. {
  199. name: "bogus trace flag",
  200. header: "00-ab000000000000000000000000000000-cd00000000000000-qw",
  201. },
  202. {
  203. name: "upper case version",
  204. header: "A0-00000000000000000000000000000000-0000000000000000-01",
  205. },
  206. {
  207. name: "upper case trace ID",
  208. header: "00-AB000000000000000000000000000000-cd00000000000000-01",
  209. },
  210. {
  211. name: "upper case span ID",
  212. header: "00-ab000000000000000000000000000000-CD00000000000000-01",
  213. },
  214. {
  215. name: "upper case trace flag",
  216. header: "00-ab000000000000000000000000000000-cd00000000000000-A1",
  217. },
  218. {
  219. name: "zero trace ID and span ID",
  220. header: "00-00000000000000000000000000000000-0000000000000000-01",
  221. },
  222. {
  223. name: "trace-flag unused bits set",
  224. header: "00-ab000000000000000000000000000000-cd00000000000000-09",
  225. },
  226. {
  227. name: "missing options",
  228. header: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7",
  229. },
  230. {
  231. name: "empty options",
  232. header: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-",
  233. },
  234. }
  235. otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{}))
  236. propagator := otel.GetTextMapPropagator()
  237. for _, tt := range tests {
  238. t.Run(tt.name, func(t *testing.T) {
  239. ctx := context.Background()
  240. md := metadata.MD{}
  241. md.Set("traceparent", tt.header)
  242. _, spanCtx := Extract(ctx, propagator, &md)
  243. assert.Equal(t, trace.SpanContext{}, spanCtx)
  244. })
  245. }
  246. }
  247. func TestInjectValidTraceContext(t *testing.T) {
  248. stateStr := "key1=value1,key2=value2"
  249. state, err := trace.ParseTraceState(stateStr)
  250. require.NoError(t, err)
  251. tests := []struct {
  252. name string
  253. traceparent string
  254. tracestate string
  255. sc trace.SpanContext
  256. }{
  257. {
  258. name: "not sampled",
  259. traceparent: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00",
  260. sc: trace.NewSpanContext(trace.SpanContextConfig{
  261. TraceID: traceID,
  262. SpanID: spanID,
  263. Remote: true,
  264. }),
  265. },
  266. {
  267. name: "sampled",
  268. traceparent: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01",
  269. sc: trace.NewSpanContext(trace.SpanContextConfig{
  270. TraceID: traceID,
  271. SpanID: spanID,
  272. TraceFlags: trace.FlagsSampled,
  273. Remote: true,
  274. }),
  275. },
  276. {
  277. name: "unsupported trace flag bits dropped",
  278. traceparent: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01",
  279. sc: trace.NewSpanContext(trace.SpanContextConfig{
  280. TraceID: traceID,
  281. SpanID: spanID,
  282. TraceFlags: 0xff,
  283. Remote: true,
  284. }),
  285. },
  286. {
  287. name: "with tracestate",
  288. traceparent: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00",
  289. tracestate: stateStr,
  290. sc: trace.NewSpanContext(trace.SpanContextConfig{
  291. TraceID: traceID,
  292. SpanID: spanID,
  293. TraceState: state,
  294. Remote: true,
  295. }),
  296. },
  297. }
  298. otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{}))
  299. propagator := otel.GetTextMapPropagator()
  300. for _, tt := range tests {
  301. t.Run(tt.name, func(t *testing.T) {
  302. ctx := context.Background()
  303. ctx = trace.ContextWithRemoteSpanContext(ctx, tt.sc)
  304. want := metadata.MD{}
  305. want.Set("traceparent", tt.traceparent)
  306. if len(tt.tracestate) > 0 {
  307. want.Set("tracestate", tt.tracestate)
  308. }
  309. md := metadata.MD{}
  310. Inject(ctx, propagator, &md)
  311. assert.Equal(t, want, md)
  312. })
  313. }
  314. }
  315. func TestInvalidSpanContextDropped(t *testing.T) {
  316. invalidSC := trace.SpanContext{}
  317. require.False(t, invalidSC.IsValid())
  318. ctx := trace.ContextWithRemoteSpanContext(context.Background(), invalidSC)
  319. otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{}))
  320. propagator := otel.GetTextMapPropagator()
  321. md := metadata.MD{}
  322. Inject(ctx, propagator, &md)
  323. mm := &metadataSupplier{
  324. metadata: &md,
  325. }
  326. assert.Equal(t, "", mm.Get("traceparent"), "injected invalid SpanContext")
  327. }