diff --git a/pkg/systemlogmonitor/log_monitor_test.go b/pkg/systemlogmonitor/log_monitor_test.go index ec8d3634..2bd47c2b 100644 --- a/pkg/systemlogmonitor/log_monitor_test.go +++ b/pkg/systemlogmonitor/log_monitor_test.go @@ -17,10 +17,15 @@ limitations under the License. package systemlogmonitor import ( + "fmt" "reflect" + "runtime" "testing" "time" + "github.com/stretchr/testify/assert" + + watchertest "k8s.io/node-problem-detector/pkg/systemlogmonitor/logwatchers/testing" logtypes "k8s.io/node-problem-detector/pkg/systemlogmonitor/types" "k8s.io/node-problem-detector/pkg/types" ) @@ -131,3 +136,13 @@ func TestGenerateStatus(t *testing.T) { } } } + +func TestGoroutineLeak(t *testing.T) { + orignal := runtime.NumGoroutine() + f := watchertest.NewFakeLogWatcher(10) + f.InjectError(fmt.Errorf("unexpected error")) + l := &logMonitor{watcher: f} + _, err := l.Start() + assert.Error(t, err) + assert.Equal(t, orignal, runtime.NumGoroutine()) +} diff --git a/pkg/systemlogmonitor/logwatchers/filelog/log_watcher_test.go b/pkg/systemlogmonitor/logwatchers/filelog/log_watcher_test.go index 730de818..06a5b5b3 100644 --- a/pkg/systemlogmonitor/logwatchers/filelog/log_watcher_test.go +++ b/pkg/systemlogmonitor/logwatchers/filelog/log_watcher_test.go @@ -19,6 +19,7 @@ package filelog import ( "io/ioutil" "os" + "runtime" "testing" "time" @@ -170,3 +171,16 @@ Jan 2 03:04:05 kernel: [2.000000] 3 } } } + +func TestGoroutineLeak(t *testing.T) { + orignal := runtime.NumGoroutine() + w := NewSyslogWatcherOrDie(types.WatcherConfig{ + Plugin: "filelog", + PluginConfig: getTestPluginConfig(), + LogPath: "/not/exist/path", + Lookback: "10m", + }) + _, err := w.Watch() + assert.Error(t, err) + assert.Equal(t, orignal, runtime.NumGoroutine()) +} diff --git a/pkg/systemlogmonitor/logwatchers/journald/log_watcher_test.go b/pkg/systemlogmonitor/logwatchers/journald/log_watcher_test.go index 356a4262..dab60491 100644 --- a/pkg/systemlogmonitor/logwatchers/journald/log_watcher_test.go +++ b/pkg/systemlogmonitor/logwatchers/journald/log_watcher_test.go @@ -19,12 +19,14 @@ limitations under the License. package journald import ( + "runtime" "testing" "time" "github.com/coreos/go-systemd/sdjournal" "github.com/stretchr/testify/assert" + "k8s.io/node-problem-detector/pkg/systemlogmonitor/logwatchers/types" logtypes "k8s.io/node-problem-detector/pkg/systemlogmonitor/types" ) @@ -62,3 +64,16 @@ func TestTranslate(t *testing.T) { assert.Equal(t, test.log, translate(test.entry)) } } + +func TestGoroutineLeak(t *testing.T) { + orignal := runtime.NumGoroutine() + w := NewJournaldWatcher(types.WatcherConfig{ + Plugin: "journald", + PluginConfig: map[string]string{"source": "not-exist-service"}, + LogPath: "/not/exist/path", + Lookback: "10m", + }) + _, err := w.Watch() + assert.Error(t, err) + assert.Equal(t, orignal, runtime.NumGoroutine()) +} diff --git a/pkg/systemlogmonitor/logwatchers/testing/fake_log_watcher.go b/pkg/systemlogmonitor/logwatchers/testing/fake_log_watcher.go new file mode 100644 index 00000000..f9e717de --- /dev/null +++ b/pkg/systemlogmonitor/logwatchers/testing/fake_log_watcher.go @@ -0,0 +1,59 @@ +/* +Copyright 2017 The Kubernetes Authors All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package testing + +import ( + "sync" + + "k8s.io/node-problem-detector/pkg/systemlogmonitor/logwatchers/types" + logtypes "k8s.io/node-problem-detector/pkg/systemlogmonitor/types" +) + +// FakeLogWatcher is a fake mock of log watcher. +type FakeLogWatcher struct { + sync.Mutex + buf chan *logtypes.Log + err error +} + +var _ types.LogWatcher = &FakeLogWatcher{} + +func NewFakeLogWatcher(bufferSize int) *FakeLogWatcher { + return &FakeLogWatcher{buf: make(chan *logtypes.Log, bufferSize)} +} + +// InjectLog injects a fake log into the watch channel +func (f *FakeLogWatcher) InjectLog(log *logtypes.Log) { + f.buf <- log +} + +// InjectError injects an error of Watch function. +func (f *FakeLogWatcher) InjectError(err error) { + f.Lock() + defer f.Unlock() + f.err = err +} + +// Watch is the fake watch function. +func (f *FakeLogWatcher) Watch() (<-chan *logtypes.Log, error) { + return f.buf, f.err +} + +// Stop is the fake stop function. +func (f *FakeLogWatcher) Stop() { + close(f.buf) +}