test panic log text

k3s-v1.15.3
Haowei Cai 2019-04-01 15:43:34 -07:00
parent 0e61b77826
commit 999a02ceb6
1 changed files with 68 additions and 0 deletions

View File

@ -17,7 +17,12 @@ limitations under the License.
package runtime
import (
"bytes"
"fmt"
"io"
"os"
"regexp"
"strings"
"testing"
)
@ -69,3 +74,66 @@ func TestCustomHandleError(t *testing.T) {
t.Errorf("did not receive custom handler")
}
}
func TestHandleCrashLog(t *testing.T) {
log, err := captureStderr(func() {
defer func() {
if r := recover(); r == nil {
t.Fatalf("expected a panic to recover from")
}
}()
defer HandleCrash()
panic("test panic")
})
if err != nil {
t.Fatalf("%v", err)
}
// Example log:
//
// ...] Observed a panic: test panic
// goroutine 6 [running]:
// command-line-arguments.logPanic(0x..., 0x...)
// .../src/k8s.io/kubernetes/staging/src/k8s.io/apimachinery/pkg/util/runtime/runtime.go:69 +0x...
lines := strings.Split(log, "\n")
if len(lines) < 4 {
t.Fatalf("panic log should have 1 line of message, 1 line per goroutine and 2 lines per function call")
}
if match, _ := regexp.MatchString("Observed a panic: test panic", lines[0]); !match {
t.Errorf("mismatch panic message: %s", lines[0])
}
// The following regexp's verify that Kubernetes panic log matches Golang stdlib
// stacktrace pattern. We need to update these regexp's if stdlib changes its pattern.
if match, _ := regexp.MatchString(`goroutine [0-9]+ \[.+\]:`, lines[1]); !match {
t.Errorf("mismatch goroutine: %s", lines[1])
}
if match, _ := regexp.MatchString(`logPanic(.*)`, lines[2]); !match {
t.Errorf("mismatch symbolized function name: %s", lines[2])
}
if match, _ := regexp.MatchString(`runtime\.go:[0-9]+ \+0x`, lines[3]); !match {
t.Errorf("mismatch file/line/offset information: %s", lines[3])
}
}
// captureStderr redirects stderr to result string, and then restore stderr from backup
func captureStderr(f func()) (string, error) {
r, w, err := os.Pipe()
if err != nil {
return "", err
}
bak := os.Stderr
os.Stderr = w
defer func() { os.Stderr = bak }()
resultCh := make(chan string)
// copy the output in a separate goroutine so printing can't block indefinitely
go func() {
var buf bytes.Buffer
io.Copy(&buf, r)
resultCh <- buf.String()
}()
f()
w.Close()
return <-resultCh, nil
}