You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

268 lines
7.4 KiB

  1. // Copyright 2018, OpenCensus Authors
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package tracecontext
  15. import (
  16. "fmt"
  17. "net/http"
  18. "reflect"
  19. "strings"
  20. "testing"
  21. "go.opencensus.io/trace"
  22. "go.opencensus.io/trace/tracestate"
  23. )
  24. var (
  25. tpHeader = "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01"
  26. traceID = trace.TraceID{75, 249, 47, 53, 119, 179, 77, 166, 163, 206, 146, 157, 14, 14, 71, 54}
  27. spanID = trace.SpanID{0, 240, 103, 170, 11, 169, 2, 183}
  28. traceOpt = trace.TraceOptions(1)
  29. oversizeValue = strings.Repeat("a", maxTracestateLen/2)
  30. oversizeEntry1 = tracestate.Entry{Key: "foo", Value: oversizeValue}
  31. oversizeEntry2 = tracestate.Entry{Key: "hello", Value: oversizeValue}
  32. entry1 = tracestate.Entry{Key: "foo", Value: "bar"}
  33. entry2 = tracestate.Entry{Key: "hello", Value: "world example"}
  34. oversizeTs, _ = tracestate.New(nil, oversizeEntry1, oversizeEntry2)
  35. defaultTs, _ = tracestate.New(nil, nil...)
  36. nonDefaultTs, _ = tracestate.New(nil, entry1, entry2)
  37. )
  38. func TestHTTPFormat_FromRequest(t *testing.T) {
  39. tests := []struct {
  40. name string
  41. header string
  42. wantSc trace.SpanContext
  43. wantOk bool
  44. }{
  45. {
  46. name: "future version",
  47. header: "02-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01",
  48. wantSc: trace.SpanContext{
  49. TraceID: trace.TraceID{75, 249, 47, 53, 119, 179, 77, 166, 163, 206, 146, 157, 14, 14, 71, 54},
  50. SpanID: trace.SpanID{0, 240, 103, 170, 11, 169, 2, 183},
  51. TraceOptions: trace.TraceOptions(1),
  52. },
  53. wantOk: true,
  54. },
  55. {
  56. name: "zero trace ID and span ID",
  57. header: "00-00000000000000000000000000000000-0000000000000000-01",
  58. wantSc: trace.SpanContext{},
  59. wantOk: false,
  60. },
  61. {
  62. name: "valid header",
  63. header: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01",
  64. wantSc: trace.SpanContext{
  65. TraceID: trace.TraceID{75, 249, 47, 53, 119, 179, 77, 166, 163, 206, 146, 157, 14, 14, 71, 54},
  66. SpanID: trace.SpanID{0, 240, 103, 170, 11, 169, 2, 183},
  67. TraceOptions: trace.TraceOptions(1),
  68. },
  69. wantOk: true,
  70. },
  71. {
  72. name: "missing options",
  73. header: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7",
  74. wantSc: trace.SpanContext{},
  75. wantOk: false,
  76. },
  77. {
  78. name: "empty options",
  79. header: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-",
  80. wantSc: trace.SpanContext{},
  81. wantOk: false,
  82. },
  83. }
  84. f := &HTTPFormat{}
  85. for _, tt := range tests {
  86. t.Run(tt.name, func(t *testing.T) {
  87. req, _ := http.NewRequest("GET", "http://example.com", nil)
  88. req.Header.Set("traceparent", tt.header)
  89. gotSc, gotOk := f.SpanContextFromRequest(req)
  90. if !reflect.DeepEqual(gotSc, tt.wantSc) {
  91. t.Errorf("HTTPFormat.FromRequest() gotSc = %v, want %v", gotSc, tt.wantSc)
  92. }
  93. if gotOk != tt.wantOk {
  94. t.Errorf("HTTPFormat.FromRequest() gotOk = %v, want %v", gotOk, tt.wantOk)
  95. }
  96. })
  97. }
  98. }
  99. func TestHTTPFormat_ToRequest(t *testing.T) {
  100. tests := []struct {
  101. sc trace.SpanContext
  102. wantHeader string
  103. }{
  104. {
  105. sc: trace.SpanContext{
  106. TraceID: trace.TraceID{75, 249, 47, 53, 119, 179, 77, 166, 163, 206, 146, 157, 14, 14, 71, 54},
  107. SpanID: trace.SpanID{0, 240, 103, 170, 11, 169, 2, 183},
  108. TraceOptions: trace.TraceOptions(1),
  109. },
  110. wantHeader: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01",
  111. },
  112. }
  113. for _, tt := range tests {
  114. t.Run(tt.wantHeader, func(t *testing.T) {
  115. f := &HTTPFormat{}
  116. req, _ := http.NewRequest("GET", "http://example.com", nil)
  117. f.SpanContextToRequest(tt.sc, req)
  118. h := req.Header.Get("traceparent")
  119. if got, want := h, tt.wantHeader; got != want {
  120. t.Errorf("HTTPFormat.ToRequest() header = %v, want %v", got, want)
  121. }
  122. })
  123. }
  124. }
  125. func TestHTTPFormatTracestate_FromRequest(t *testing.T) {
  126. scWithNonDefaultTracestate := trace.SpanContext{
  127. TraceID: traceID,
  128. SpanID: spanID,
  129. TraceOptions: traceOpt,
  130. Tracestate: nonDefaultTs,
  131. }
  132. scWithDefaultTracestate := trace.SpanContext{
  133. TraceID: traceID,
  134. SpanID: spanID,
  135. TraceOptions: traceOpt,
  136. Tracestate: defaultTs,
  137. }
  138. tests := []struct {
  139. name string
  140. tpHeader string
  141. tsHeader string
  142. wantSc trace.SpanContext
  143. wantOk bool
  144. }{
  145. {
  146. name: "tracestate invalid entries delimiter",
  147. tpHeader: tpHeader,
  148. tsHeader: "foo=bar;hello=world",
  149. wantSc: scWithDefaultTracestate,
  150. wantOk: true,
  151. },
  152. {
  153. name: "tracestate invalid key-value delimiter",
  154. tpHeader: tpHeader,
  155. tsHeader: "foo=bar,hello-world",
  156. wantSc: scWithDefaultTracestate,
  157. wantOk: true,
  158. },
  159. {
  160. name: "tracestate invalid value character",
  161. tpHeader: tpHeader,
  162. tsHeader: "foo=bar,hello=world example \u00a0 ",
  163. wantSc: scWithDefaultTracestate,
  164. wantOk: true,
  165. },
  166. {
  167. name: "tracestate blank key-value",
  168. tpHeader: tpHeader,
  169. tsHeader: "foo=bar, ",
  170. wantSc: scWithDefaultTracestate,
  171. wantOk: true,
  172. },
  173. {
  174. name: "tracestate oversize header",
  175. tpHeader: tpHeader,
  176. tsHeader: fmt.Sprintf("foo=%s,hello=%s", oversizeValue, oversizeValue),
  177. wantSc: scWithDefaultTracestate,
  178. wantOk: true,
  179. },
  180. {
  181. name: "tracestate valid",
  182. tpHeader: tpHeader,
  183. tsHeader: "foo=bar , hello=world example",
  184. wantSc: scWithNonDefaultTracestate,
  185. wantOk: true,
  186. },
  187. }
  188. f := &HTTPFormat{}
  189. for _, tt := range tests {
  190. t.Run(tt.name, func(t *testing.T) {
  191. req, _ := http.NewRequest("GET", "http://example.com", nil)
  192. req.Header.Set("traceparent", tt.tpHeader)
  193. req.Header.Set("tracestate", tt.tsHeader)
  194. gotSc, gotOk := f.SpanContextFromRequest(req)
  195. if !reflect.DeepEqual(gotSc, tt.wantSc) {
  196. t.Errorf("HTTPFormat.FromRequest() gotTs = %v, want %v", gotSc.Tracestate, tt.wantSc.Tracestate)
  197. }
  198. if gotOk != tt.wantOk {
  199. t.Errorf("HTTPFormat.FromRequest() gotOk = %v, want %v", gotOk, tt.wantOk)
  200. }
  201. })
  202. }
  203. }
  204. func TestHTTPFormatTracestate_ToRequest(t *testing.T) {
  205. tests := []struct {
  206. name string
  207. sc trace.SpanContext
  208. wantHeader string
  209. }{
  210. {
  211. name: "valid span context with default tracestate",
  212. sc: trace.SpanContext{
  213. TraceID: traceID,
  214. SpanID: spanID,
  215. TraceOptions: traceOpt,
  216. },
  217. wantHeader: "",
  218. },
  219. {
  220. name: "valid span context with non default tracestate",
  221. sc: trace.SpanContext{
  222. TraceID: traceID,
  223. SpanID: spanID,
  224. TraceOptions: traceOpt,
  225. Tracestate: nonDefaultTs,
  226. },
  227. wantHeader: "foo=bar,hello=world example",
  228. },
  229. {
  230. name: "valid span context with oversize tracestate",
  231. sc: trace.SpanContext{
  232. TraceID: traceID,
  233. SpanID: spanID,
  234. TraceOptions: traceOpt,
  235. Tracestate: oversizeTs,
  236. },
  237. wantHeader: "",
  238. },
  239. }
  240. for _, tt := range tests {
  241. t.Run(tt.name, func(t *testing.T) {
  242. f := &HTTPFormat{}
  243. req, _ := http.NewRequest("GET", "http://example.com", nil)
  244. f.SpanContextToRequest(tt.sc, req)
  245. h := req.Header.Get("tracestate")
  246. if got, want := h, tt.wantHeader; got != want {
  247. t.Errorf("HTTPFormat.ToRequest() tracestate header = %v, want %v", got, want)
  248. }
  249. })
  250. }
  251. }