Add tests and remove dead code
Peter Bourgon
8 years ago
0 | addsvc/addsvc | |
1 | cover.out | |
2 | ||
3 | # Compiled Object files, Static and Dynamic libs (Shared Objects) | |
4 | *.o | |
5 | *.a | |
6 | *.so | |
7 | ||
8 | # Folders | |
9 | _obj | |
10 | _test | |
11 | _old* | |
12 | ||
13 | # Architecture specific extensions/prefixes | |
14 | *.[568vq] | |
15 | [568vq].out | |
16 | ||
17 | *.cgo1.go | |
18 | *.cgo2.c | |
19 | _cgo_defun.c | |
20 | _cgo_gotypes.go | |
21 | _cgo_export.* | |
22 | ||
23 | _testmain.go | |
24 | ||
25 | *.exe |
101 | 101 | |
102 | 102 | type httpClientOption func(*httpClient) |
103 | 103 | |
104 | func before(f httptransport.BeforeFunc) httpClientOption { | |
105 | return func(c *httpClient) { c.before = append(c.before, f) } | |
104 | func before(funcs ...httptransport.BeforeFunc) httpClientOption { | |
105 | return func(c *httpClient) { c.before = append(c.before, funcs...) } | |
106 | 106 | } |
1 | 1 | |
2 | 2 | import ( |
3 | 3 | "encoding/binary" |
4 | "errors" | |
5 | 4 | "net" |
6 | 5 | "strconv" |
7 | 6 | "time" |
8 | 7 | |
9 | 8 | "github.com/go-kit/kit/log" |
10 | ||
11 | 9 | "github.com/go-kit/kit/tracing/zipkin/_thrift/gen-go/zipkincore" |
12 | 10 | ) |
13 | 11 | |
14 | 12 | var ( |
15 | 13 | // SpanContextKey represents the Span in the request context. |
16 | 14 | SpanContextKey = "Zipkin-Span" |
17 | ||
18 | // ErrSpanNotFound is returned when a Span isn't found in a context. | |
19 | ErrSpanNotFound = errors.New("span not found") | |
20 | 15 | ) |
21 | 16 | |
22 | 17 | // A Span is a named collection of annotations. It represents meaningful |
32 | 27 | parentSpanID int64 |
33 | 28 | |
34 | 29 | annotations []annotation |
35 | //binaryAnnotations []BinaryAnnotation | |
30 | //binaryAnnotations []BinaryAnnotation // TODO | |
36 | 31 | } |
37 | 32 | |
38 | 33 | // NewSpan returns a new Span object ready for use. |
52 | 52 | func AnnotateServer(newSpan NewSpanFunc, c Collector) server.Middleware { |
53 | 53 | return func(e server.Endpoint) server.Endpoint { |
54 | 54 | return func(ctx context.Context, request interface{}) (interface{}, error) { |
55 | span, ok := maybeFromContext(ctx) | |
55 | span, ok := fromContext(ctx) | |
56 | 56 | if !ok { |
57 | 57 | span = newSpan(newID(), newID(), 0) |
58 | 58 | ctx = context.WithValue(ctx, SpanContextKey, span) |
73 | 73 | return func(e client.Endpoint) client.Endpoint { |
74 | 74 | return func(ctx context.Context, request interface{}) (interface{}, error) { |
75 | 75 | var clientSpan *Span |
76 | parentSpan, ok := maybeFromContext(ctx) | |
76 | parentSpan, ok := fromContext(ctx) | |
77 | 77 | if ok { |
78 | 78 | clientSpan = newSpan(parentSpan.TraceID(), newID(), parentSpan.SpanID()) |
79 | 79 | } else { |
105 | 105 | // a child/client span. |
106 | 106 | func ToRequest(newSpan NewSpanFunc) func(ctx context.Context, r *http.Request) context.Context { |
107 | 107 | return func(ctx context.Context, r *http.Request) context.Context { |
108 | span, ok := maybeFromContext(ctx) | |
108 | span, ok := fromContext(ctx) | |
109 | 109 | if !ok { |
110 | 110 | span = newSpan(newID(), newID(), 0) |
111 | 111 | } |
112 | setRequestHeaders(r.Header, span) | |
112 | if id := span.TraceID(); id > 0 { | |
113 | r.Header.Set(traceIDHTTPHeader, strconv.FormatInt(id, 16)) | |
114 | } | |
115 | if id := span.SpanID(); id > 0 { | |
116 | r.Header.Set(spanIDHTTPHeader, strconv.FormatInt(id, 16)) | |
117 | } | |
118 | if id := span.ParentSpanID(); id > 0 { | |
119 | r.Header.Set(parentSpanIDHTTPHeader, strconv.FormatInt(id, 16)) | |
120 | } | |
113 | 121 | return ctx |
114 | 122 | } |
115 | 123 | } |
147 | 155 | return newSpan(traceID, spanID, parentSpanID) |
148 | 156 | } |
149 | 157 | |
150 | // func fromContext(newSpan NewSpanFunc) func(context.Context) *Span { | |
151 | // return func(ctx context.Context) *Span { | |
152 | // if span, ok := maybeFromContext(ctx); ok { | |
153 | // return span | |
154 | // } | |
155 | // return newSpan(newID(), newID(), 0) | |
156 | // } | |
157 | // } | |
158 | ||
159 | //// NewChildSpan creates a new child (client) span. If a span is already | |
160 | //// present in the context, it will be interpreted as the parent. | |
161 | //func NewChildSpan(ctx context.Context, newSpan NewSpanFunc) *Span { | |
162 | // parentSpan, ok := maybeFromContext(ctx) | |
163 | // if !ok { | |
164 | // return newSpan(newID(), newID(), 0) | |
165 | // } | |
166 | // var ( | |
167 | // traceID = parentSpan.TraceID() | |
168 | // spanID = newID() | |
169 | // parentSpanID = parentSpan.SpanID() | |
170 | // ) | |
171 | // return newSpan(traceID, spanID, parentSpanID) | |
172 | //} | |
173 | ||
174 | func setRequestHeaders(h http.Header, s *Span) { | |
175 | if id := s.TraceID(); id > 0 { | |
176 | h.Set(traceIDHTTPHeader, strconv.FormatInt(id, 16)) | |
177 | } | |
178 | if id := s.SpanID(); id > 0 { | |
179 | h.Set(spanIDHTTPHeader, strconv.FormatInt(id, 16)) | |
180 | } | |
181 | if id := s.ParentSpanID(); id > 0 { | |
182 | h.Set(parentSpanIDHTTPHeader, strconv.FormatInt(id, 16)) | |
183 | } | |
184 | } | |
185 | ||
186 | func maybeFromContext(ctx context.Context) (*Span, bool) { | |
158 | func fromContext(ctx context.Context) (*Span, bool) { | |
187 | 159 | val := ctx.Value(SpanContextKey) |
188 | 160 | if val == nil { |
189 | 161 | return nil, false |
195 | 167 | return span, true |
196 | 168 | } |
197 | 169 | |
198 | //func mustGetServerSpan(ctx context.Context, newSpan NewSpanFunc) (*Span, context.Context) { | |
199 | // val := ctx.Value(SpanContextKey) | |
200 | // if val == nil { | |
201 | // span := newSpan(newID(), newID(), 0) | |
202 | // return span, context.WithValue(ctx, SpanContextKey, span) | |
203 | // } | |
204 | // span, ok := val.(*Span) | |
205 | // if !ok { | |
206 | // panic(SpanContextKey + " value isn't a span object") | |
207 | // } | |
208 | // return span, ctx | |
209 | //} | |
210 | ||
211 | 170 | func newID() int64 { |
212 | 171 | // https://github.com/wadey/go-zipkin/blob/46e5f01/trace.go#L183-188 |
213 | 172 | // https://github.com/twitter/zipkin/issues/199 |
0 | package zipkin | |
1 | ||
2 | import ( | |
3 | "net/http" | |
4 | "strconv" | |
5 | "testing" | |
6 | ||
7 | "golang.org/x/net/context" | |
8 | ) | |
9 | ||
10 | func TestFromHTTPToContext(t *testing.T) { | |
11 | const ( | |
12 | hostport = "5.5.5.5:5555" | |
13 | serviceName = "foo-service" | |
14 | methodName = "foo-method" | |
15 | traceID int64 = 12 | |
16 | spanID int64 = 34 | |
17 | parentSpanID int64 = 56 | |
18 | ) | |
19 | ||
20 | r, _ := http.NewRequest("GET", "https://best.horse", nil) | |
21 | r.Header.Set("X-B3-TraceId", strconv.FormatInt(traceID, 16)) | |
22 | r.Header.Set("X-B3-SpanId", strconv.FormatInt(spanID, 16)) | |
23 | r.Header.Set("X-B3-ParentSpanId", strconv.FormatInt(parentSpanID, 16)) | |
24 | ||
25 | sf := MakeNewSpanFunc(hostport, serviceName, methodName) | |
26 | cf := ToContext(sf) | |
27 | ||
28 | ctx := cf(context.Background(), r) | |
29 | val := ctx.Value(SpanContextKey) | |
30 | if val == nil { | |
31 | t.Fatalf("%s returned no value", SpanContextKey) | |
32 | } | |
33 | span, ok := val.(*Span) | |
34 | if !ok { | |
35 | t.Fatalf("%s was not a Span object", SpanContextKey) | |
36 | } | |
37 | ||
38 | if want, have := traceID, span.TraceID(); want != have { | |
39 | t.Errorf("want %d, have %d", want, have) | |
40 | } | |
41 | ||
42 | if want, have := spanID, span.SpanID(); want != have { | |
43 | t.Errorf("want %d, have %d", want, have) | |
44 | } | |
45 | ||
46 | if want, have := parentSpanID, span.ParentSpanID(); want != have { | |
47 | t.Errorf("want %d, have %d", want, have) | |
48 | } | |
49 | } | |
50 | ||
51 | func TestSetRequestHeaders(t *testing.T) { | |
52 | const ( | |
53 | hostport = "4.2.4.2:4242" | |
54 | serviceName = "bar-service" | |
55 | methodName = "bar-method" | |
56 | traceID int64 = 123 | |
57 | spanID int64 = 456 | |
58 | parentSpanID int64 = 789 | |
59 | ) | |
60 | ||
61 | r, _ := http.NewRequest("POST", "http://destroy.horse", nil) | |
62 | setRequestHeaders(r.Header, NewSpan(hostport, serviceName, methodName, traceID, spanID, parentSpanID)) | |
63 | ||
64 | for h, want := range map[string]string{ | |
65 | "X-B3-TraceId": strconv.FormatInt(traceID, 16), | |
66 | "X-B3-SpanId": strconv.FormatInt(spanID, 16), | |
67 | "X-B3-ParentSpanId": strconv.FormatInt(parentSpanID, 16), | |
68 | } { | |
69 | if have := r.Header.Get(h); want != have { | |
70 | t.Errorf("%s: want %s, have %s", h, want, have) | |
71 | } | |
72 | } | |
73 | } |
0 | 0 | package zipkin_test |
1 | 1 | |
2 | 2 | import ( |
3 | "net/http" | |
4 | "reflect" | |
5 | "runtime" | |
6 | "strconv" | |
7 | "strings" | |
3 | 8 | "sync/atomic" |
4 | 9 | "testing" |
5 | 10 | |
6 | 11 | "golang.org/x/net/context" |
7 | 12 | |
13 | "github.com/go-kit/kit/client" | |
8 | 14 | "github.com/go-kit/kit/server" |
9 | 15 | "github.com/go-kit/kit/tracing/zipkin" |
10 | 16 | ) |
17 | ||
18 | func TestToContext(t *testing.T) { | |
19 | const ( | |
20 | hostport = "5.5.5.5:5555" | |
21 | serviceName = "foo-service" | |
22 | methodName = "foo-method" | |
23 | traceID int64 = 12 | |
24 | spanID int64 = 34 | |
25 | parentSpanID int64 = 56 | |
26 | ) | |
27 | ||
28 | r, _ := http.NewRequest("GET", "https://best.horse", nil) | |
29 | r.Header.Set("X-B3-TraceId", strconv.FormatInt(traceID, 16)) | |
30 | r.Header.Set("X-B3-SpanId", strconv.FormatInt(spanID, 16)) | |
31 | r.Header.Set("X-B3-ParentSpanId", strconv.FormatInt(parentSpanID, 16)) | |
32 | ||
33 | newSpan := zipkin.MakeNewSpanFunc(hostport, serviceName, methodName) | |
34 | toContext := zipkin.ToContext(newSpan) | |
35 | ||
36 | ctx := toContext(context.Background(), r) | |
37 | val := ctx.Value(zipkin.SpanContextKey) | |
38 | if val == nil { | |
39 | t.Fatalf("%s returned no value", zipkin.SpanContextKey) | |
40 | } | |
41 | span, ok := val.(*zipkin.Span) | |
42 | if !ok { | |
43 | t.Fatalf("%s was not a Span object", zipkin.SpanContextKey) | |
44 | } | |
45 | ||
46 | for want, haveFunc := range map[int64]func() int64{ | |
47 | traceID: span.TraceID, | |
48 | spanID: span.SpanID, | |
49 | parentSpanID: span.ParentSpanID, | |
50 | } { | |
51 | if have := haveFunc(); want != have { | |
52 | name := runtime.FuncForPC(reflect.ValueOf(haveFunc).Pointer()).Name() | |
53 | name = strings.Split(name, "ยท")[0] | |
54 | toks := strings.Split(name, ".") | |
55 | name = toks[len(toks)-1] | |
56 | t.Errorf("%s: want %d, have %d", name, want, have) | |
57 | } | |
58 | } | |
59 | } | |
60 | ||
61 | func TestToRequest(t *testing.T) { | |
62 | const ( | |
63 | hostport = "5.5.5.5:5555" | |
64 | serviceName = "foo-service" | |
65 | methodName = "foo-method" | |
66 | traceID int64 = 20 | |
67 | spanID int64 = 40 | |
68 | parentSpanID int64 = 90 | |
69 | ) | |
70 | ||
71 | newSpan := zipkin.MakeNewSpanFunc(hostport, serviceName, methodName) | |
72 | span := newSpan(traceID, spanID, parentSpanID) | |
73 | ctx := context.WithValue(context.Background(), zipkin.SpanContextKey, span) | |
74 | r, _ := http.NewRequest("GET", "https://best.horse", nil) | |
75 | ctx = zipkin.ToRequest(newSpan)(ctx, r) | |
76 | ||
77 | for header, wantInt := range map[string]int64{ | |
78 | "X-B3-TraceId": traceID, | |
79 | "X-B3-SpanId": spanID, | |
80 | "X-B3-ParentSpanId": parentSpanID, | |
81 | } { | |
82 | if want, have := strconv.FormatInt(wantInt, 16), r.Header.Get(header); want != have { | |
83 | t.Errorf("%s: want %q, have %q", header, want, have) | |
84 | } | |
85 | } | |
86 | } | |
11 | 87 | |
12 | 88 | func TestAnnotateServer(t *testing.T) { |
13 | 89 | const ( |
23 | 99 | e = func(context.Context, interface{}) (interface{}, error) { return struct{}{}, nil } |
24 | 100 | e = zipkin.AnnotateServer(f, c)(e) |
25 | 101 | |
26 | if want, have := int32(0), int32(c.int32); want != have { | |
102 | if want, have := int32(0), atomic.LoadInt32(&(c.int32)); want != have { | |
27 | 103 | t.Errorf("want %d, have %d", want, have) |
28 | 104 | } |
29 | 105 | if _, err := e(context.Background(), struct{}{}); err != nil { |
30 | 106 | t.Fatal(err) |
31 | 107 | } |
32 | if want, have := int32(1), int32(c.int32); want != have { | |
108 | if want, have := int32(1), atomic.LoadInt32(&(c.int32)); want != have { | |
33 | 109 | t.Errorf("want %d, have %d", want, have) |
34 | 110 | } |
35 | 111 | } |
36 | 112 | |
37 | 113 | func TestAnnotateClient(t *testing.T) { |
38 | t.Skip("not yet implemented") | |
114 | const ( | |
115 | hostport = "192.168.1.100:53" | |
116 | serviceName = "client-service" | |
117 | methodName = "client-method" | |
118 | ) | |
119 | ||
120 | f := zipkin.MakeNewSpanFunc(hostport, serviceName, methodName) | |
121 | c := &countingCollector{} | |
122 | ||
123 | var e client.Endpoint | |
124 | e = func(context.Context, interface{}) (interface{}, error) { return struct{}{}, nil } | |
125 | e = zipkin.AnnotateClient(f, c)(e) | |
126 | ||
127 | if want, have := int32(0), atomic.LoadInt32(&(c.int32)); want != have { | |
128 | t.Errorf("want %d, have %d", want, have) | |
129 | } | |
130 | if _, err := e(context.Background(), struct{}{}); err != nil { | |
131 | t.Fatal(err) | |
132 | } | |
133 | if want, have := int32(1), atomic.LoadInt32(&(c.int32)); want != have { | |
134 | t.Errorf("want %d, have %d", want, have) | |
135 | } | |
39 | 136 | } |
40 | 137 | |
41 | 138 | type countingCollector struct{ int32 } |