aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/traceback_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/runtime/traceback_test.go')
-rw-r--r--src/runtime/traceback_test.go70
1 files changed, 70 insertions, 0 deletions
diff --git a/src/runtime/traceback_test.go b/src/runtime/traceback_test.go
index 1dac91311c..d47f4ab745 100644
--- a/src/runtime/traceback_test.go
+++ b/src/runtime/traceback_test.go
@@ -6,6 +6,7 @@ package runtime_test
import (
"bytes"
+ "context"
"fmt"
"internal/abi"
"internal/asan"
@@ -15,6 +16,7 @@ import (
"regexp"
"runtime"
"runtime/debug"
+ "runtime/pprof"
"strconv"
"strings"
"sync"
@@ -882,3 +884,71 @@ func TestSetCgoTracebackNoCgo(t *testing.T) {
t.Fatalf("want %s, got %s\n", want, output)
}
}
+
+func TestTracebackGoroutineLabels(t *testing.T) {
+ t.Setenv("GODEBUG", "tracebacklabels=1")
+ for _, tbl := range []struct {
+ l pprof.LabelSet
+ expTB string
+ }{
+ {l: pprof.Labels("foobar", "baz"), expTB: `{"foobar": "baz"}`},
+ // Make sure the keys are sorted because the runtime/pprof package sorts for consistency
+ {l: pprof.Labels("foobar", "baz", "fizzle", "bit"), expTB: `{"fizzle": "bit", "foobar": "baz"}`},
+ // make sure newlines get escaped
+ {l: pprof.Labels("fizzle", "bit", "foobar", "baz\n"), expTB: `{"fizzle": "bit", "foobar": "baz\n"}`},
+ // make sure null and escape bytes are properly escaped
+ {l: pprof.Labels("fizzle", "b\033it", "foo\"ba\x00r", "baz\n"), expTB: `{"fizzle": "b\x1bit", "foo\"ba\x00r": "baz\n"}`},
+ // verify that simple 16-bit unicode runes are escaped with \u, including a greek upper-case sigma and an arbitrary unicode character.
+ {l: pprof.Labels("fizzle", "\u1234Σ", "fooba\x00r", "baz\n"), expTB: `{"fizzle": "\u1234\u03a3", "fooba\x00r": "baz\n"}`},
+ // verify that 32-bit unicode runes are escaped with \U along with tabs
+ {l: pprof.Labels("fizz\tle", "\U00045678boop", "fooba\x00r", "baz\n"), expTB: `{"fizz\tle": "\U00045678boop", "fooba\x00r": "baz\n"}`},
+ // verify carriage returns and backslashes get escaped along with our nulls, newlines and a 32-bit unicode character
+ {l: pprof.Labels("fiz\\zl\re", "\U00045678boop", "fooba\x00r", "baz\n"), expTB: `{"fiz\\zl\re": "\U00045678boop", "fooba\x00r": "baz\n"}`},
+ } {
+ t.Run(tbl.expTB, func(t *testing.T) {
+ verifyLabels := func() {
+ t.Helper()
+ buf := make([]byte, 1<<10)
+ // We collect the stack only for this goroutine (by passing
+ // false to runtime.Stack). We expect to see the parent's goroutine labels in the traceback.
+ stack := string(buf[:runtime.Stack(buf, false)])
+ if !strings.Contains(stack, "labels:"+tbl.expTB) {
+ t.Errorf("failed to find goroutine labels with labels %s (as %s) got:\n%s\n---", tbl.l, tbl.expTB, stack)
+ }
+ }
+ // Use a clean context so the testing package can add whatever goroutine labels it wants to the testing.T context.
+ lblCtx := pprof.WithLabels(context.Background(), tbl.l)
+ pprof.SetGoroutineLabels(lblCtx)
+ var wg sync.WaitGroup
+ // make sure the labels are visible in a child goroutine
+ wg.Go(verifyLabels)
+ // and in this parent goroutine
+ verifyLabels()
+ wg.Wait()
+ })
+ }
+}
+
+func TestTracebackGoroutineLabelsDisabledGODEBUG(t *testing.T) {
+ t.Setenv("GODEBUG", "tracebacklabels=0")
+ lbls := pprof.Labels("foobar", "baz")
+ verifyLabels := func() {
+ t.Helper()
+ buf := make([]byte, 1<<10)
+ // We collect the stack only for this goroutine (by passing
+ // false to runtime.Stack).
+ stack := string(buf[:runtime.Stack(buf, false)])
+ if strings.Contains(stack, "labels:") {
+ t.Errorf("found goroutine labels with labels %s got:\n%s\n---", lbls, stack)
+ }
+ }
+ // Use a clean context so the testing package can add whatever goroutine labels it wants to the testing.T context.
+ lblCtx := pprof.WithLabels(context.Background(), lbls)
+ pprof.SetGoroutineLabels(lblCtx)
+ var wg sync.WaitGroup
+ // make sure the labels are visible in a child goroutine
+ wg.Go(verifyLabels)
+ // and in this parent goroutine
+ verifyLabels()
+ wg.Wait()
+}