1 // Copyright 2019 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
18 "golang.org/x/tools/internal/event"
19 "golang.org/x/tools/internal/event/core"
20 "golang.org/x/tools/internal/event/export"
21 "golang.org/x/tools/internal/event/export/metric"
22 "golang.org/x/tools/internal/event/export/ocagent"
23 "golang.org/x/tools/internal/event/keys"
24 "golang.org/x/tools/internal/event/label"
27 const testNodeStr = `{
32 "start_timestamp":"1970-01-01T00:00:00Z"
36 "exporter_version":"0.0.1",
37 "core_library_version":"x/tools"
40 "name":"ocagent-tests"
45 keyDB = keys.NewString("db", "the database name")
46 keyMethod = keys.NewString("method", "a metric grouping key")
47 keyRoute = keys.NewString("route", "another metric grouping key")
49 key1DB = keys.NewString("1_db", "A test string key")
51 key2aAge = keys.NewFloat64("2a_age", "A test float64 key")
52 key2bTTL = keys.NewFloat32("2b_ttl", "A test float32 key")
53 key2cExpiryMS = keys.NewFloat64("2c_expiry_ms", "A test float64 key")
55 key3aRetry = keys.NewBoolean("3a_retry", "A test boolean key")
56 key3bStale = keys.NewBoolean("3b_stale", "Another test boolean key")
58 key4aMax = keys.NewInt("4a_max", "A test int key")
59 key4bOpcode = keys.NewInt8("4b_opcode", "A test int8 key")
60 key4cBase = keys.NewInt16("4c_base", "A test int16 key")
61 key4eChecksum = keys.NewInt32("4e_checksum", "A test int32 key")
62 key4fMode = keys.NewInt64("4f_mode", "A test int64 key")
64 key5aMin = keys.NewUInt("5a_min", "A test uint key")
65 key5bMix = keys.NewUInt8("5b_mix", "A test uint8 key")
66 key5cPort = keys.NewUInt16("5c_port", "A test uint16 key")
67 key5dMinHops = keys.NewUInt32("5d_min_hops", "A test uint32 key")
68 key5eMaxHops = keys.NewUInt64("5e_max_hops", "A test uint64 key")
70 recursiveCalls = keys.NewInt64("recursive_calls", "Number of recursive calls")
71 bytesIn = keys.NewInt64("bytes_in", "Number of bytes in") //, unit.Bytes)
72 latencyMs = keys.NewFloat64("latency", "The latency in milliseconds") //, unit.Milliseconds)
74 metricLatency = metric.HistogramFloat64{
76 Description: "The latency of calls in milliseconds",
77 Keys: []label.Key{keyMethod, keyRoute},
78 Buckets: []float64{0, 5, 10, 25, 50},
81 metricBytesIn = metric.HistogramInt64{
83 Description: "The latency of calls in milliseconds",
84 Keys: []label.Key{keyMethod, keyRoute},
85 Buckets: []int64{0, 10, 50, 100, 500, 1000, 2000},
88 metricRecursiveCalls = metric.Scalar{
90 Description: "The latency of calls in milliseconds",
91 Keys: []label.Key{keyMethod, keyRoute},
95 type testExporter struct {
96 ocagent *ocagent.Exporter
100 func registerExporter() *testExporter {
101 exporter := &testExporter{}
102 cfg := ocagent.Config{
105 Service: "ocagent-tests",
106 Client: &http.Client{Transport: &exporter.sent},
108 cfg.Start, _ = time.Parse(time.RFC3339Nano, "1970-01-01T00:00:00Z")
109 exporter.ocagent = ocagent.Connect(&cfg)
111 metrics := metric.Config{}
112 metricLatency.Record(&metrics, latencyMs)
113 metricBytesIn.Record(&metrics, bytesIn)
114 metricRecursiveCalls.SumInt64(&metrics, recursiveCalls)
116 e := exporter.ocagent.ProcessEvent
117 e = metrics.Exporter(e)
126 func timeFixer(output event.Exporter) event.Exporter {
127 start, _ := time.Parse(time.RFC3339Nano, "1970-01-01T00:00:30Z")
128 at, _ := time.Parse(time.RFC3339Nano, "1970-01-01T00:00:40Z")
129 end, _ := time.Parse(time.RFC3339Nano, "1970-01-01T00:00:50Z")
130 return func(ctx context.Context, ev core.Event, lm label.Map) context.Context {
132 case event.IsStart(ev):
133 ev = core.CloneEvent(ev, start)
134 case event.IsEnd(ev):
135 ev = core.CloneEvent(ev, end)
137 ev = core.CloneEvent(ev, at)
139 return output(ctx, ev, lm)
143 func spanFixer(output event.Exporter) event.Exporter {
144 return func(ctx context.Context, ev core.Event, lm label.Map) context.Context {
145 if event.IsStart(ev) {
146 span := export.GetSpan(ctx)
147 span.ID = export.SpanContext{}
149 return output(ctx, ev, lm)
153 func (e *testExporter) Output(route string) []byte {
155 return e.sent.get(route)
158 func checkJSON(t *testing.T, got, want []byte) {
159 // compare the compact form, to allow for formatting differences
161 if err := json.Compact(g, got); err != nil {
165 if err := json.Compact(w, want); err != nil {
168 if g.String() != w.String() {
169 t.Fatalf("Got:\n%s\nWant:\n%s", g, w)
173 type fakeSender struct {
175 data map[string][]byte
178 func (s *fakeSender) get(route string) []byte {
181 data, found := s.data[route]
183 delete(s.data, route)
188 func (s *fakeSender) RoundTrip(req *http.Request) (*http.Response, error) {
192 s.data = make(map[string][]byte)
194 data, err := ioutil.ReadAll(req.Body)
198 path := req.URL.EscapedPath()
199 if _, found := s.data[path]; found {
200 return nil, fmt.Errorf("duplicate delivery to %v", path)
203 return &http.Response{