4020e9e2ce
Some tests do not use testplanet and hence testmonkit should be reusable. Change-Id: If6b7194a199d9ffba5eb1a91f38d3a792f883336
135 lines
3.1 KiB
Go
135 lines
3.1 KiB
Go
// 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()
|
|
}
|