123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678 |
- package stack
- import (
- "bufio"
- "bytes"
- "errors"
- "io/ioutil"
- "reflect"
- "strings"
- "testing"
- )
- func TestParseDump1(t *testing.T) {
-
-
-
- long := strings.Repeat("a", bufio.MaxScanTokenSize+1)
- data := []string{
- long,
- "panic: reflect.Set: value of type",
- "",
- "goroutine 1 [running]:",
- "github.com/cockroachdb/cockroach/storage/engine._Cfunc_DBIterSeek()",
- " ??:0 +0x6d",
- "gopkg.in/yaml%2ev2.handleErr(0xc208033b20)",
- " /gopath/src/gopkg.in/yaml.v2/yaml.go:153 +0xc6",
- "reflect.Value.assignTo(0x570860, 0xc20803f3e0, 0x15)",
- " /goroot/src/reflect/value.go:2125 +0x368",
- "main.main()",
- " /gopath/src/notabug.org/themusicgod1/panicparse/stack/stack.go:428 +0x27",
- "",
- }
- extra := &bytes.Buffer{}
- c, err := ParseDump(bytes.NewBufferString(strings.Join(data, "\n")), extra, true)
- if err != nil {
- t.Fatal(err)
- }
- compareString(t, long+"\npanic: reflect.Set: value of type\n\n", extra.String())
- expected := []*Goroutine{
- {
- Signature: Signature{
- State: "running",
- Stack: Stack{
- Calls: []Call{
- {
- SrcPath: "??",
- Func: Func{Raw: "github.com/cockroachdb/cockroach/storage/engine._Cfunc_DBIterSeek"},
- },
- {
- SrcPath: "/gopath/src/gopkg.in/yaml.v2/yaml.go",
- Line: 153,
- Func: Func{Raw: "gopkg.in/yaml%2ev2.handleErr"},
- Args: Args{Values: []Arg{{Value: 0xc208033b20}}},
- },
- {
- SrcPath: "/goroot/src/reflect/value.go",
- Line: 2125,
- Func: Func{Raw: "reflect.Value.assignTo"},
- Args: Args{Values: []Arg{{Value: 0x570860}, {Value: 0xc20803f3e0}, {Value: 0x15}}},
- },
- {
- SrcPath: "/gopath/src/notabug.org/themusicgod1/panicparse/stack/stack.go",
- Line: 428,
- Func: Func{Raw: "main.main"},
- },
- },
- },
- },
- ID: 1,
- First: true,
- },
- }
- for i := range expected {
- expected[i].updateLocations(c.GOROOT, c.localgoroot, c.GOPATHs)
- }
- compareGoroutines(t, expected, c.Goroutines)
- }
- func TestParseDumpLongWait(t *testing.T) {
-
- data := []string{
- "panic: bleh",
- "",
- "goroutine 1 [chan send, 100 minutes]:",
- "gopkg.in/yaml%2ev2.handleErr(0xc208033b20)",
- " /gopath/src/gopkg.in/yaml.v2/yaml.go:153 +0xc6",
- "",
- "goroutine 2 [chan send, locked to thread]:",
- "gopkg.in/yaml%2ev2.handleErr(0xc208033b21)",
- " /gopath/src/gopkg.in/yaml.v2/yaml.go:153 +0xc6",
- "",
- "goroutine 3 [chan send, 101 minutes, locked to thread]:",
- "gopkg.in/yaml%2ev2.handleErr(0xc208033b22)",
- " /gopath/src/gopkg.in/yaml.v2/yaml.go:153 +0xc6",
- "",
- }
- extra := &bytes.Buffer{}
- c, err := ParseDump(bytes.NewBufferString(strings.Join(data, "\n")), extra, true)
- if err != nil {
- t.Fatal(err)
- }
- compareString(t, "panic: bleh\n\n", extra.String())
- expected := []*Goroutine{
- {
- Signature: Signature{
- State: "chan send",
- SleepMin: 100,
- SleepMax: 100,
- Stack: Stack{
- Calls: []Call{
- {
- SrcPath: "/gopath/src/gopkg.in/yaml.v2/yaml.go",
- Line: 153,
- Func: Func{Raw: "gopkg.in/yaml%2ev2.handleErr"},
- Args: Args{Values: []Arg{{Value: 0xc208033b20}}},
- },
- },
- },
- },
- ID: 1,
- First: true,
- },
- {
- Signature: Signature{
- State: "chan send",
- Locked: true,
- Stack: Stack{
- Calls: []Call{
- {
- SrcPath: "/gopath/src/gopkg.in/yaml.v2/yaml.go",
- Line: 153,
- Func: Func{Raw: "gopkg.in/yaml%2ev2.handleErr"},
- Args: Args{Values: []Arg{{Value: 0xc208033b21, Name: "#1"}}},
- },
- },
- },
- },
- ID: 2,
- },
- {
- Signature: Signature{
- State: "chan send",
- SleepMin: 101,
- SleepMax: 101,
- Stack: Stack{
- Calls: []Call{
- {
- SrcPath: "/gopath/src/gopkg.in/yaml.v2/yaml.go",
- Line: 153,
- Func: Func{Raw: "gopkg.in/yaml%2ev2.handleErr"},
- Args: Args{Values: []Arg{{Value: 0xc208033b22, Name: "#2"}}},
- },
- },
- },
- Locked: true,
- },
- ID: 3,
- },
- }
- for i := range expected {
- expected[i].updateLocations(c.GOROOT, c.localgoroot, c.GOPATHs)
- }
- compareGoroutines(t, expected, c.Goroutines)
- }
- func TestParseDumpAsm(t *testing.T) {
- data := []string{
- "panic: reflect.Set: value of type",
- "",
- "goroutine 16 [garbage collection]:",
- "runtime.switchtoM()",
- "\t/goroot/src/runtime/asm_amd64.s:198 fp=0xc20cfb80d8 sp=0xc20cfb80d0",
- "",
- }
- extra := &bytes.Buffer{}
- c, err := ParseDump(bytes.NewBufferString(strings.Join(data, "\n")), extra, false)
- if err != nil {
- t.Fatal(err)
- }
- expected := []*Goroutine{
- {
- Signature: Signature{
- State: "garbage collection",
- Stack: Stack{
- Calls: []Call{
- {
- SrcPath: "/goroot/src/runtime/asm_amd64.s",
- Line: 198,
- Func: Func{Raw: "runtime.switchtoM"},
- },
- },
- },
- },
- ID: 16,
- First: true,
- },
- }
- compareGoroutines(t, expected, c.Goroutines)
- compareString(t, "panic: reflect.Set: value of type\n\n", extra.String())
- }
- func TestParseDumpLineErr(t *testing.T) {
- data := []string{
- "panic: reflect.Set: value of type",
- "",
- "goroutine 1 [running]:",
- "notabug.org/themusicgod1/panicparse/stack/stack.recurseType()",
- "\t/gopath/src/notabug.org/themusicgod1/panicparse/stack/stack.go:12345678901234567890",
- "",
- }
- extra := &bytes.Buffer{}
- c, err := ParseDump(bytes.NewBufferString(strings.Join(data, "\n")), extra, false)
- compareErr(t, errors.New("failed to parse int on line: \"/gopath/src/notabug.org/themusicgod1/panicparse/stack/stack.go:12345678901234567890\""), err)
- expected := []*Goroutine{
- {
- Signature: Signature{
- State: "running",
- Stack: Stack{Calls: []Call{{Func: Func{Raw: "notabug.org/themusicgod1/panicparse/stack/stack.recurseType"}}}},
- },
- ID: 1,
- First: true,
- },
- }
- for i := range expected {
- expected[i].updateLocations(c.GOROOT, c.localgoroot, c.GOPATHs)
- }
- compareGoroutines(t, expected, c.Goroutines)
- }
- func TestParseDumpValueErr(t *testing.T) {
- data := []string{
- "panic: reflect.Set: value of type",
- "",
- "goroutine 1 [running]:",
- "notabug.org/themusicgod1/panicparse/stack/stack.recurseType(123456789012345678901)",
- "\t/gopath/src/notabug.org/themusicgod1/panicparse/stack/stack.go:9",
- "",
- }
- extra := &bytes.Buffer{}
- c, err := ParseDump(bytes.NewBufferString(strings.Join(data, "\n")), extra, false)
- compareErr(t, errors.New("failed to parse int on line: \"notabug.org/themusicgod1/panicparse/stack/stack.recurseType(123456789012345678901)\""), err)
- expected := []*Goroutine{
- {
- Signature: Signature{State: "running"},
- ID: 1,
- First: true,
- },
- }
- for i := range expected {
- expected[i].updateLocations(c.GOROOT, c.localgoroot, c.GOPATHs)
- }
- compareGoroutines(t, expected, c.Goroutines)
- }
- func TestParseDumpOrderErr(t *testing.T) {
- data := []string{
- "panic: reflect.Set: value of type",
- "",
- "goroutine 16 [garbage collection]:",
- " /gopath/src/gopkg.in/yaml.v2/yaml.go:153 +0xc6",
- "runtime.switchtoM()",
- "\t/goroot/src/runtime/asm_amd64.s:198 fp=0xc20cfb80d8 sp=0xc20cfb80d0",
- "",
- }
- extra := &bytes.Buffer{}
- c, err := ParseDump(bytes.NewBufferString(strings.Join(data, "\n")), extra, false)
- compareErr(t, errors.New("unexpected order on line: \"/gopath/src/gopkg.in/yaml.v2/yaml.go:153 +0xc6\""), err)
- expected := []*Goroutine{
- {
- Signature: Signature{State: "garbage collection"},
- ID: 16,
- First: true,
- },
- }
- compareGoroutines(t, expected, c.Goroutines)
- compareString(t, "panic: reflect.Set: value of type\n\n", extra.String())
- }
- func TestParseDumpElided(t *testing.T) {
- data := []string{
- "panic: reflect.Set: value of type",
- "",
- "goroutine 16 [garbage collection]:",
- "notabug.org/themusicgod1/panicparse/stack/stack.recurseType(0x7f4fa9a3ec70, 0xc208062580, 0x7f4fa9a3e818, 0x50a820, 0xc20803a8a0)",
- "\t/gopath/src/notabug.org/themusicgod1/panicparse/stack/stack.go:53 +0x845 fp=0xc20cfc66d8 sp=0xc20cfc6470",
- "...additional frames elided...",
- "created by testing.RunTests",
- "\t/goroot/src/testing/testing.go:555 +0xa8b",
- "",
- }
- extra := &bytes.Buffer{}
- c, err := ParseDump(bytes.NewBufferString(strings.Join(data, "\n")), extra, false)
- if err != nil {
- t.Fatal(err)
- }
- expected := []*Goroutine{
- {
- Signature: Signature{
- State: "garbage collection",
- Stack: Stack{
- Calls: []Call{
- {
- SrcPath: "/gopath/src/notabug.org/themusicgod1/panicparse/stack/stack.go",
- Line: 53,
- Func: Func{Raw: "notabug.org/themusicgod1/panicparse/stack/stack.recurseType"},
- Args: Args{
- Values: []Arg{
- {Value: 0x7f4fa9a3ec70},
- {Value: 0xc208062580},
- {Value: 0x7f4fa9a3e818},
- {Value: 0x50a820},
- {Value: 0xc20803a8a0},
- },
- },
- },
- },
- Elided: true,
- },
- CreatedBy: Call{
- SrcPath: "/goroot/src/testing/testing.go",
- Line: 555,
- Func: Func{Raw: "testing.RunTests"},
- },
- },
- ID: 16,
- First: true,
- },
- }
- compareGoroutines(t, expected, c.Goroutines)
- compareString(t, "panic: reflect.Set: value of type\n\n", extra.String())
- }
- func TestParseDumpSysCall(t *testing.T) {
- data := []string{
- "panic: reflect.Set: value of type",
- "",
- "goroutine 5 [syscall]:",
- "runtime.notetsleepg(0x918100, 0xffffffffffffffff, 0x1)",
- "\t/goroot/src/runtime/lock_futex.go:201 +0x52 fp=0xc208018f68 sp=0xc208018f40",
- "runtime.signal_recv(0x0)",
- "\t/goroot/src/runtime/sigqueue.go:109 +0x135 fp=0xc208018fa0 sp=0xc208018f68",
- "os/signal.loop()",
- "\t/goroot/src/os/signal/signal_unix.go:21 +0x1f fp=0xc208018fe0 sp=0xc208018fa0",
- "runtime.goexit()",
- "\t/goroot/src/runtime/asm_amd64.s:2232 +0x1 fp=0xc208018fe8 sp=0xc208018fe0",
- "created by os/signal.init·1",
- "\t/goroot/src/os/signal/signal_unix.go:27 +0x35",
- "",
- }
- extra := &bytes.Buffer{}
- c, err := ParseDump(bytes.NewBufferString(strings.Join(data, "\n")), extra, false)
- if err != nil {
- t.Fatal(err)
- }
- expected := []*Goroutine{
- {
- Signature: Signature{
- State: "syscall",
- Stack: Stack{
- Calls: []Call{
- {
- SrcPath: "/goroot/src/runtime/lock_futex.go",
- Line: 201,
- Func: Func{Raw: "runtime.notetsleepg"},
- Args: Args{
- Values: []Arg{
- {Value: 0x918100},
- {Value: 0xffffffffffffffff},
- {Value: 0x1},
- },
- },
- },
- {
- SrcPath: "/goroot/src/runtime/sigqueue.go",
- Line: 109,
- Func: Func{Raw: "runtime.signal_recv"},
- Args: Args{
- Values: []Arg{{}},
- },
- },
- {
- SrcPath: "/goroot/src/os/signal/signal_unix.go",
- Line: 21,
- Func: Func{Raw: "os/signal.loop"},
- },
- {
- SrcPath: "/goroot/src/runtime/asm_amd64.s",
- Line: 2232,
- Func: Func{Raw: "runtime.goexit"},
- },
- },
- },
- CreatedBy: Call{
- SrcPath: "/goroot/src/os/signal/signal_unix.go",
- Line: 27,
- Func: Func{Raw: "os/signal.init·1"},
- },
- },
- ID: 5,
- First: true,
- },
- }
- compareGoroutines(t, expected, c.Goroutines)
- compareString(t, "panic: reflect.Set: value of type\n\n", extra.String())
- }
- func TestParseDumpUnavail(t *testing.T) {
- data := []string{
- "panic: reflect.Set: value of type",
- "",
- "goroutine 24 [running]:",
- "\tgoroutine running on other thread; stack unavailable",
- "created by notabug.org/themusicgod1/panicparse/stack.New",
- "\t/gopath/src/notabug.org/themusicgod1/panicparse/stack/stack.go:131 +0x381",
- "",
- }
- extra := &bytes.Buffer{}
- c, err := ParseDump(bytes.NewBufferString(strings.Join(data, "\n")), extra, false)
- if err != nil {
- t.Fatal(err)
- }
- expected := []*Goroutine{
- {
- Signature: Signature{
- State: "running",
- Stack: Stack{
- Calls: []Call{{SrcPath: "<unavailable>"}},
- },
- CreatedBy: Call{
- SrcPath: "/gopath/src/notabug.org/themusicgod1/panicparse/stack/stack.go",
- Line: 131,
- Func: Func{Raw: "notabug.org/themusicgod1/panicparse/stack.New"},
- },
- },
- ID: 24,
- First: true,
- },
- }
- compareGoroutines(t, expected, c.Goroutines)
- compareString(t, "panic: reflect.Set: value of type\n\n", extra.String())
- }
- func TestParseDumpNoOffset(t *testing.T) {
- data := []string{
- "panic: runtime error: index out of range",
- "",
- "goroutine 37 [runnable]:",
- "notabug.org/themusicgod1/panicparse/stack.func·002()",
- " /gopath/src/notabug.org/themusicgod1/panicparse/stack/stack.go:110",
- "created by notabug.org/themusicgod1/panicparse/stack.New",
- " /gopath/src/notabug.org/themusicgod1/panicparse/stack/stack.go:113 +0x43b",
- "",
- }
- c, err := ParseDump(bytes.NewBufferString(strings.Join(data, "\n")), ioutil.Discard, false)
- if err != nil {
- t.Fatal(err)
- }
- expectedGR := []*Goroutine{
- {
- Signature: Signature{
- State: "runnable",
- Stack: Stack{
- Calls: []Call{
- {
- SrcPath: "/gopath/src/notabug.org/themusicgod1/panicparse/stack/stack.go",
- Line: 110,
- Func: Func{Raw: "notabug.org/themusicgod1/panicparse/stack.func·002"},
- },
- },
- },
- CreatedBy: Call{
- SrcPath: "/gopath/src/notabug.org/themusicgod1/panicparse/stack/stack.go",
- Line: 113,
- Func: Func{Raw: "notabug.org/themusicgod1/panicparse/stack.New"},
- },
- },
- ID: 37,
- First: true,
- },
- }
- compareGoroutines(t, expectedGR, c.Goroutines)
- }
- func TestParseDumpJunk(t *testing.T) {
-
- data := []string{
- "panic: reflect.Set: value of type",
- "",
- "goroutine 1 [running]:",
- "junk",
- }
- c, err := ParseDump(bytes.NewBufferString(strings.Join(data, "\n")), ioutil.Discard, false)
- if err != nil {
- t.Fatal(err)
- }
- expectedGR := []*Goroutine{
- {
- Signature: Signature{State: "running"},
- ID: 1,
- First: true,
- },
- }
- compareGoroutines(t, expectedGR, c.Goroutines)
- }
- func TestParseDumpCCode(t *testing.T) {
- data := []string{
- "SIGQUIT: quit",
- "PC=0x43f349",
- "",
- "goroutine 0 [idle]:",
- "runtime.epollwait(0x4, 0x7fff671c7118, 0xffffffff00000080, 0x0, 0xffffffff0028c1be, 0x0, 0x0, 0x0, 0x0, 0x0, ...)",
- " /goroot/src/runtime/sys_linux_amd64.s:400 +0x19",
- "runtime.netpoll(0x901b01, 0x0)",
- " /goroot/src/runtime/netpoll_epoll.go:68 +0xa3",
- "findrunnable(0xc208012000)",
- " /goroot/src/runtime/proc.c:1472 +0x485",
- "schedule()",
- " /goroot/src/runtime/proc.c:1575 +0x151",
- "runtime.park_m(0xc2080017a0)",
- " /goroot/src/runtime/proc.c:1654 +0x113",
- "runtime.mcall(0x432684)",
- " /goroot/src/runtime/asm_amd64.s:186 +0x5a",
- "",
- }
- c, err := ParseDump(bytes.NewBufferString(strings.Join(data, "\n")), ioutil.Discard, false)
- if err != nil {
- t.Fatal(err)
- }
- expectedGR := []*Goroutine{
- {
- Signature: Signature{
- State: "idle",
- Stack: Stack{
- Calls: []Call{
- {
- SrcPath: "/goroot/src/runtime/sys_linux_amd64.s",
- Line: 400,
- Func: Func{Raw: "runtime.epollwait"},
- Args: Args{
- Values: []Arg{
- {Value: 0x4},
- {Value: 0x7fff671c7118},
- {Value: 0xffffffff00000080},
- {},
- {Value: 0xffffffff0028c1be},
- {},
- {},
- {},
- {},
- {},
- },
- Elided: true,
- },
- },
- {
- SrcPath: "/goroot/src/runtime/netpoll_epoll.go",
- Line: 68,
- Func: Func{Raw: "runtime.netpoll"},
- Args: Args{Values: []Arg{{Value: 0x901b01}, {}}},
- },
- {
- SrcPath: "/goroot/src/runtime/proc.c",
- Line: 1472,
- Func: Func{Raw: "findrunnable"},
- Args: Args{Values: []Arg{{Value: 0xc208012000}}},
- },
- {
- SrcPath: "/goroot/src/runtime/proc.c",
- Line: 1575,
- Func: Func{Raw: "schedule"},
- },
- {
- SrcPath: "/goroot/src/runtime/proc.c",
- Line: 1654,
- Func: Func{Raw: "runtime.park_m"},
- Args: Args{Values: []Arg{{Value: 0xc2080017a0}}},
- },
- {
- SrcPath: "/goroot/src/runtime/asm_amd64.s",
- Line: 186,
- Func: Func{Raw: "runtime.mcall"},
- Args: Args{Values: []Arg{{Value: 0x432684}}},
- },
- },
- },
- },
- ID: 0,
- First: true,
- },
- }
- compareGoroutines(t, expectedGR, c.Goroutines)
- }
- func TestParseDumpWithCarriageReturn(t *testing.T) {
- data := []string{
- "goroutine 1 [running]:",
- "github.com/cockroachdb/cockroach/storage/engine._Cfunc_DBIterSeek()",
- " ??:0 +0x6d",
- "gopkg.in/yaml%2ev2.handleErr(0xc208033b20)",
- " /gopath/src/gopkg.in/yaml.v2/yaml.go:153 +0xc6",
- "reflect.Value.assignTo(0x570860, 0xc20803f3e0, 0x15)",
- " /goroot/src/reflect/value.go:2125 +0x368",
- "main.main()",
- " /gopath/src/notabug.org/themusicgod1/panicparse/stack/stack.go:428 +0x27",
- "",
- }
- c, err := ParseDump(bytes.NewBufferString(strings.Join(data, "\r\n")), ioutil.Discard, false)
- if err != nil {
- t.Fatal(err)
- }
- expected := []*Goroutine{
- {
- Signature: Signature{
- State: "running",
- Stack: Stack{
- Calls: []Call{
- {
- SrcPath: "??",
- Func: Func{Raw: "github.com/cockroachdb/cockroach/storage/engine._Cfunc_DBIterSeek"},
- },
- {
- SrcPath: "/gopath/src/gopkg.in/yaml.v2/yaml.go",
- Line: 153,
- Func: Func{Raw: "gopkg.in/yaml%2ev2.handleErr"},
- Args: Args{Values: []Arg{{Value: 0xc208033b20}}},
- },
- {
- SrcPath: "/goroot/src/reflect/value.go",
- Line: 2125,
- Func: Func{Raw: "reflect.Value.assignTo"},
- Args: Args{Values: []Arg{{Value: 0x570860}, {Value: 0xc20803f3e0}, {Value: 0x15}}},
- },
- {
- SrcPath: "/gopath/src/notabug.org/themusicgod1/panicparse/stack/stack.go",
- Line: 428,
- Func: Func{Raw: "main.main"},
- },
- },
- },
- },
- ID: 1,
- First: true,
- },
- }
- compareGoroutines(t, expected, c.Goroutines)
- }
- func compareErr(t *testing.T, expected, actual error) {
- if expected.Error() != actual.Error() {
- t.Fatalf("%v != %v", expected, actual)
- }
- }
- func compareGoroutines(t *testing.T, expected, actual []*Goroutine) {
- if len(expected) != len(actual) {
- t.Fatalf("Different []*Goroutine length:\n- %v\n- %v", expected, actual)
- }
- for i := range expected {
- if !reflect.DeepEqual(expected[i], actual[i]) {
- t.Fatalf("Different Goroutine:\n- %v\n- %v", expected[i], actual[i])
- }
- }
- }
- func compareString(t *testing.T, expected, actual string) {
- if expected != actual {
- t.Fatalf("%q != %q", expected, actual)
- }
- }
|