Skip to content
Snippets Groups Projects
Unverified Commit 91fa16e1 authored by Tomasz Maczukin's avatar Tomasz Maczukin
Browse files

Add tests for unix goroutines dumper

parent a79f3f53
No related branches found
No related tags found
No related merge requests found
......@@ -15,7 +15,7 @@ const (
)
var (
configuration = NewConfig()
configuration = NewConfig(logrus.StandardLogger())
logFlags = []cli.Flag{
cli.BoolFlag{
......@@ -52,6 +52,7 @@ func formatNames() []string {
}
type Config struct {
logger *logrus.Logger
level logrus.Level
format logrus.Formatter
......@@ -120,8 +121,8 @@ func (l *Config) SetFormat(format string) error {
}
func (l *Config) ReloadConfiguration() {
logrus.SetFormatter(l.format)
logrus.SetLevel(l.level)
l.logger.SetFormatter(l.format)
l.logger.SetLevel(l.level)
if l.level == logrus.DebugLevel {
l.enableGoroutinesDump()
......@@ -137,7 +138,7 @@ func (l *Config) enableGoroutinesDump() {
l.goroutinesDumpStopCh = make(chan bool)
watchForGoroutinesDump(l.goroutinesDumpStopCh)
watchForGoroutinesDump(l.logger, l.goroutinesDumpStopCh)
}
func (l *Config) disableGoroutinesDump() {
......@@ -149,8 +150,9 @@ func (l *Config) disableGoroutinesDump() {
l.goroutinesDumpStopCh = nil
}
func NewConfig() *Config {
func NewConfig(logger *logrus.Logger) *Config {
return &Config{
logger: logger,
level: logrus.InfoLevel,
format: new(RunnerTextFormatter),
}
......@@ -165,7 +167,7 @@ func ConfigureLogging(app *cli.App) {
appBefore := app.Before
app.Before = func(cliCtx *cli.Context) error {
logrus.SetOutput(os.Stderr)
Configuration().logger.SetOutput(os.Stderr)
err := Configuration().handleCliCtx(cliCtx)
if err != nil {
......
......@@ -4,6 +4,7 @@ import (
"testing"
"github.com/sirupsen/logrus"
"github.com/sirupsen/logrus/hooks/test"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/urfave/cli"
......@@ -11,9 +12,9 @@ import (
"gitlab.com/gitlab-org/gitlab-runner/helpers"
)
func prepareFakeConfiguration() func() {
func prepareFakeConfiguration(logger *logrus.Logger) func() {
oldConfiguration := configuration
configuration = NewConfig()
configuration = NewConfig(logger)
return func() {
configuration = oldConfiguration
......@@ -90,20 +91,22 @@ func TestHandleCliCtx(t *testing.T) {
},
}
for name, test := range tests {
for name, testCase := range tests {
t.Run(name, func(t *testing.T) {
defer prepareFakeConfiguration()()
logger, _ := test.NewNullLogger()
defer prepareFakeConfiguration(logger)()
defer helpers.MakeFatalToPanic()()
testFunc := func() {
testCommandRun(test.args...)
if test.expectedError == "" {
assert.Equal(t, test.expectedLevel, Configuration().level)
assert.Equal(t, test.expectedFormatter, Configuration().format)
assert.Equal(t, test.expectedLevelSetWithCli, Configuration().IsLevelSetWithCli())
assert.Equal(t, test.expectedFormatSetWithCli, Configuration().IsFormatSetWithCli())
if test.goroutinesDumpStopChExists {
testCommandRun(testCase.args...)
if testCase.expectedError == "" {
assert.Equal(t, testCase.expectedLevel, Configuration().level)
assert.Equal(t, testCase.expectedFormatter, Configuration().format)
assert.Equal(t, testCase.expectedLevelSetWithCli, Configuration().IsLevelSetWithCli())
assert.Equal(t, testCase.expectedFormatSetWithCli, Configuration().IsFormatSetWithCli())
if testCase.goroutinesDumpStopChExists {
assert.NotNil(t, Configuration().goroutinesDumpStopCh)
} else {
assert.Nil(t, Configuration().goroutinesDumpStopCh)
......@@ -111,7 +114,7 @@ func TestHandleCliCtx(t *testing.T) {
}
}
if test.expectedError != "" {
if testCase.expectedError != "" {
var message *logrus.Entry
var ok bool
......@@ -129,7 +132,7 @@ func TestHandleCliCtx(t *testing.T) {
require.NoError(t, err)
assert.Contains(t, panicMessage, "Error while setting up logging configuration")
assert.Contains(t, panicMessage, test.expectedError)
assert.Contains(t, panicMessage, testCase.expectedError)
} else {
assert.NotPanics(t, testFunc)
......@@ -139,7 +142,9 @@ func TestHandleCliCtx(t *testing.T) {
}
func TestGoroutinesDumpDisabling(t *testing.T) {
config := new(Config)
logger, _ := test.NewNullLogger()
config := NewConfig(logger)
config.level = logrus.DebugLevel
config.ReloadConfiguration()
config.ReloadConfiguration()
......
......@@ -11,20 +11,36 @@ import (
"github.com/sirupsen/logrus"
)
func watchForGoroutinesDump(stopCh chan bool) {
dumpStacks := make(chan os.Signal, 1)
func watchForGoroutinesDump(logger *logrus.Logger, stopCh chan bool) (chan bool, chan bool) {
dumpedCh := make(chan bool)
finishedCh := make(chan bool)
dumpStacksCh := make(chan os.Signal, 1)
// On USR1 dump stacks of all go routines
signal.Notify(dumpStacks, syscall.SIGUSR1)
for {
select {
case <-dumpStacks:
buf := make([]byte, 1<<20)
len := runtime.Stack(buf, true)
logrus.Printf("=== received SIGUSR1 ===\n*** goroutine dump...\n%s\n*** end\n", buf[0:len])
case <-stopCh:
return
signal.Notify(dumpStacksCh, syscall.SIGUSR1)
go func() {
for {
select {
case <-dumpStacksCh:
buf := make([]byte, 1<<20)
len := runtime.Stack(buf, true)
logger.Printf("=== received SIGUSR1 ===\n*** goroutine dump...\n%s\n*** end\n", buf[0:len])
nonBlockingSend(dumpedCh, true)
case <-stopCh:
close(finishedCh)
return
}
}
}()
return dumpedCh, finishedCh
}
func nonBlockingSend(ch chan bool, value bool) {
select {
case ch <- value:
default:
}
}
// +build darwin dragonfly freebsd linux netbsd openbsd
package log
import (
"os"
"syscall"
"testing"
"github.com/sirupsen/logrus"
"github.com/sirupsen/logrus/hooks/test"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestStackDumping(t *testing.T) {
logger, hook := test.NewNullLogger()
logger.SetFormatter(new(logrus.TextFormatter))
stopCh := make(chan bool)
dumpedCh, finishedCh := watchForGoroutinesDump(logger, stopCh)
require.NotNil(t, dumpedCh)
require.NotNil(t, finishedCh)
proc, err := os.FindProcess(os.Getpid())
require.NoError(t, err)
proc.Signal(syscall.SIGUSR1)
<-dumpedCh
logrusOutput, err := hook.LastEntry().String()
require.NoError(t, err)
assert.Contains(t, logrusOutput, "=== received SIGUSR1 ===")
assert.Contains(t, logrusOutput, "*** goroutine dump...")
close(stopCh)
<-finishedCh
}
package log
func watchForGoroutinesDump(stopCh chan bool) {
import (
"github.com/sirupsen/logrus"
)
func watchForGoroutinesDump(logger *logrus.Logger, stopCh chan bool) (chan bool, chan bool) {
return nil, nil
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment