-
Notifications
You must be signed in to change notification settings - Fork 402
/
run.go
134 lines (115 loc) · 3.09 KB
/
run.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
// Copyright (C) 2021 Storj Labs, Inc.
// See LICENSE for copying information
// Package testmonkit allows attaching monkit monitoring for testing.
//
// It allows to set an environment variable to get a trace per test.
//
// STORJ_TEST_MONKIT=svg
// STORJ_TEST_MONKIT=json
//
// By default, it saves the output the same folder as the test. However, if you wish
// to specify a separate folder, you can specify an absolute directory:
//
// STORJ_TEST_MONKIT=json,svg,dir=/home/user/debug/trace
//
// Note, due to how go tests work, it's not possible to specify a relative directory.
package testmonkit
import (
"bytes"
"context"
"os"
"path/filepath"
"strings"
"testing"
"github.com/spacemonkeygo/monkit/v3"
"github.com/spacemonkeygo/monkit/v3/collect"
"github.com/spacemonkeygo/monkit/v3/present"
)
var mon = monkit.Package()
// Config defines configuration for monkit test output.
type Config struct {
Disabled bool
Dir string
Outputs []string
}
// Run attaches monkit tracing to the ctx where configuration is taken from STORJ_TEST_MONKIT.
func Run(ctx context.Context, tb testing.TB, fn func(ctx context.Context)) {
RunWith(ctx, tb, EnvConfig(tb), fn)
}
// RunWith attaches monkit to the ctx with custom configuration.
func RunWith(parentCtx context.Context, tb testing.TB, cfg Config, fn func(ctx context.Context)) {
if cfg.Disabled {
fn(parentCtx)
return
}
done := mon.Task()(&parentCtx)
spans := collect.CollectSpans(parentCtx, fn)
done(nil)
baseName := sanitizeFileName(tb.Name())
for _, outputType := range cfg.Outputs {
var data bytes.Buffer
var err error
switch outputType {
case "svg":
err = present.SpansToSVG(&data, spans)
case "json":
err = present.SpansToJSON(&data, spans)
}
if err != nil {
tb.Error(err)
}
path := filepath.Join(cfg.Dir, baseName+".test."+outputType)
err = os.WriteFile(path, data.Bytes(), 0644)
if err != nil {
tb.Errorf("failed to write %q: %v", path, err)
}
}
}
var supportedOutputs = map[string]bool{
"svg": true,
"json": true,
}
// EnvConfig loads test monkit configuration from STORJ_TEST_MONKIT environment variable.
func EnvConfig(tb testing.TB) Config {
value := os.Getenv("STORJ_TEST_MONKIT")
if value == "" {
return Config{Disabled: true}
}
cfg := Config{}
for _, tag := range strings.Split(value, ",") {
tokens := strings.SplitN(tag, "=", 2)
if len(tokens) <= 1 {
tag = strings.TrimSpace(tag)
if !supportedOutputs[tag] {
tb.Errorf("testmonkit: unknown output type %q", tag)
continue
}
cfg.Outputs = append(cfg.Outputs, tag)
continue
}
key, value := strings.TrimSpace(tokens[0]), strings.TrimSpace(tokens[1])
switch key {
case "dir":
cfg.Dir = value
case "type":
cfg.Outputs = append(cfg.Outputs, strings.TrimSpace(tag))
default:
tb.Errorf("testmonkit: unhandled key=%q value=%q", key, value)
}
}
return cfg
}
func sanitizeFileName(s string) string {
var b strings.Builder
for _, x := range s {
switch {
case 'a' <= x && x <= 'z':
b.WriteRune(x)
case 'A' <= x && x <= 'Z':
b.WriteRune(x)
case '0' <= x && x <= '9':
b.WriteRune(x)
}
}
return b.String()
}