blob: 3aeea1f21729e4db24b1a5d3acfc8f9c18a09365 [file] [log] [blame] [edit]
// Copyright 2016 Marc-Antoine Ruel. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
package internal
import (
"path"
"path/filepath"
"strings"
"testing"
"github.com/maruel/panicparse/v2/stack"
)
var testPalette = &Palette{
EOLReset: "A",
RoutineFirst: "B",
Routine: "C",
CreatedBy: "D",
Package: "E",
SrcFile: "F",
FuncMain: "G",
FuncLocationUnknown: "H",
FuncLocationUnknownExported: "I",
FuncGoMod: "J",
FuncGoModExported: "K",
FuncGOPATH: "L",
FuncGOPATHExported: "M",
FuncGoPkg: "N",
FuncGoPkgExported: "O",
FuncStdLib: "P",
FuncStdLibExported: "Q",
Arguments: "R",
}
func TestCalcBucketsLengths(t *testing.T) {
t.Parallel()
a := stack.Aggregated{
Buckets: []*stack.Bucket{
{
Signature: stack.Signature{
Stack: stack.Stack{
Calls: []stack.Call{
newCallLocal("main.funcĀ·001", stack.Args{}, "/home/user/go/src/foo/baz.go", 123),
},
},
},
IDs: []int{},
First: true,
},
},
}
srcLen, pkgLen := calcBucketsLengths(&a, fullPath)
// When printing, it prints the remote path, not the transposed local path.
compareString(t, "/home/user/go/src/foo/baz.go:123", fullPath.formatCall(&a.Buckets[0].Signature.Stack.Calls[0]))
compareInt(t, len("/home/user/go/src/foo/baz.go:123"), srcLen)
compareString(t, "main", a.Buckets[0].Signature.Stack.Calls[0].Func.ImportPath)
compareInt(t, len("main"), pkgLen)
srcLen, pkgLen = calcBucketsLengths(&a, basePath)
compareString(t, "baz.go:123", basePath.formatCall(&a.Buckets[0].Signature.Stack.Calls[0]))
compareInt(t, len("baz.go:123"), srcLen)
compareString(t, "main", a.Buckets[0].Signature.Stack.Calls[0].Func.ImportPath)
compareInt(t, len("main"), pkgLen)
}
func TestBucketHeader(t *testing.T) {
t.Parallel()
b := stack.Bucket{
Signature: stack.Signature{
State: "chan receive",
CreatedBy: stack.Stack{
Calls: []stack.Call{
newCallLocal("main.mainImpl", stack.Args{}, "/home/user/go/src/github.com/foo/bar/baz.go", 74),
},
},
SleepMax: 6,
SleepMin: 2,
},
IDs: []int{1, 2},
First: true,
}
// When printing, it prints the remote path, not the transposed local path.
compareString(t, "B2: chan receive [2~6 minutes]D [Created by main.mainImpl @ /home/user/go/src/github.com/foo/bar/baz.go:74]A\n", testPalette.BucketHeader(&b, fullPath, true))
compareString(t, "C2: chan receive [2~6 minutes]D [Created by main.mainImpl @ /home/user/go/src/github.com/foo/bar/baz.go:74]A\n", testPalette.BucketHeader(&b, fullPath, false))
compareString(t, "B2: chan receive [2~6 minutes]D [Created by main.mainImpl @ github.com/foo/bar/baz.go:74]A\n", testPalette.BucketHeader(&b, relPath, true))
compareString(t, "C2: chan receive [2~6 minutes]D [Created by main.mainImpl @ github.com/foo/bar/baz.go:74]A\n", testPalette.BucketHeader(&b, relPath, false))
compareString(t, "B2: chan receive [2~6 minutes]D [Created by main.mainImpl @ baz.go:74]A\n", testPalette.BucketHeader(&b, basePath, true))
compareString(t, "C2: chan receive [2~6 minutes]D [Created by main.mainImpl @ baz.go:74]A\n", testPalette.BucketHeader(&b, basePath, false))
b = stack.Bucket{
Signature: stack.Signature{
State: "b0rked",
SleepMax: 6,
SleepMin: 6,
Locked: true,
},
IDs: []int{},
First: true,
}
compareString(t, "C0: b0rked [6 minutes] [locked]A\n", testPalette.BucketHeader(&b, basePath, false))
}
func TestStackLines(t *testing.T) {
t.Parallel()
s := &stack.Signature{
State: "idle",
Stack: stack.Stack{
Calls: []stack.Call{
newCallLocal(
"runtime.Epollwait",
stack.Args{
Values: []stack.Arg{
{Value: 4},
{Value: 0x7fff671c7118},
{Value: 0xffffffff00000080},
{},
{Value: 0xffffffff0028c1be},
{},
{},
{},
{},
{},
},
Elided: true,
},
"/goroot/src/runtime/sys_linux_amd64.s",
400),
newCallLocal(
"runtime.netpoll",
stack.Args{Values: []stack.Arg{{Value: 0x901b01}, {}}},
"/goroot/src/runtime/netpoll_epoll.go",
68),
newCallLocal(
"main.Main",
stack.Args{Values: []stack.Arg{{Value: 0xc208012000}}},
"/home/user/go/src/main.go",
1472),
newCallLocal(
"foo.OtherExported",
stack.Args{},
"/home/user/go/src/foo/bar.go",
1575),
newCallLocal(
"foo.otherPrivate",
stack.Args{},
"/home/user/go/src/foo/bar.go",
10),
},
Elided: true,
},
}
// When printing, it prints the remote path, not the transposed local path.
want := "" +
" Eruntime F/goroot/src/runtime/sys_linux_amd64.s:400 QEpollwaitR(4, 0x7fff671c7118, 0xffffffff00000080, 0, 0xffffffff0028c1be, 0, 0, 0, 0, 0, ...)A\n" +
" Eruntime F/goroot/src/runtime/netpoll_epoll.go:68 PnetpollR(0x901b01, 0)A\n" +
" Emain F/home/user/go/src/main.go:1472 GMainR(0xc208012000)A\n" +
" Efoo F/home/user/go/src/foo/bar.go:1575 MOtherExportedR()A\n" +
" Efoo F/home/user/go/src/foo/bar.go:10 LotherPrivateR()A\n" +
" (...)\n"
compareString(t, want, testPalette.StackLines(s, 10, 10, fullPath))
want = "" +
" Eruntime Fsys_linux_amd64.s:400 QEpollwaitR(4, 0x7fff671c7118, 0xffffffff00000080, 0, 0xffffffff0028c1be, 0, 0, 0, 0, 0, ...)A\n" +
" Eruntime Fnetpoll_epoll.go:68 PnetpollR(0x901b01, 0)A\n" +
" Emain Fmain.go:1472 GMainR(0xc208012000)A\n" +
" Efoo Fbar.go:1575 MOtherExportedR()A\n" +
" Efoo Fbar.go:10 LotherPrivateR()A\n" +
" (...)\n"
compareString(t, want, testPalette.StackLines(s, 10, 10, basePath))
}
//
func newFunc(s string) stack.Func {
f := stack.Func{}
if err := f.Init(s); err != nil {
panic(err)
}
return f
}
func newCallLocal(f string, a stack.Args, s string, l int) stack.Call {
c := stack.Call{Func: newFunc(f), Args: a, RemoteSrcPath: s, Line: l}
// Do the equivalent of Call.init().
c.SrcName = filepath.Base(c.RemoteSrcPath)
c.DirSrc = path.Join(filepath.Base(c.RemoteSrcPath[:len(c.RemoteSrcPath)-len(c.SrcName)-1]), c.SrcName)
const goroot = "/goroot/src/"
const gopath = "/home/user/go/src/"
const gopathmod = "/home/user/go/pkg/mod/"
// Do the equivalent of Call.updateLocations().
if strings.HasPrefix(s, goroot) {
c.LocalSrcPath = s
c.RelSrcPath = s[len(goroot):]
c.Location = stack.Stdlib
} else if strings.HasPrefix(s, gopath) {
c.LocalSrcPath = s
c.RelSrcPath = s[len(gopath):]
c.Location = stack.GOPATH
} else if strings.HasPrefix(s, gopathmod) {
c.LocalSrcPath = s
c.RelSrcPath = s[len(gopathmod):]
c.Location = stack.GoPkg
}
return c
}
func compareInt(t *testing.T, want, got int) {
if want != got {
t.Helper()
t.Fatalf("%d != %d", want, got)
}
}