open-nomad/client/logmon/logmon_test.go

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

307 lines
7.7 KiB
Go
Raw Normal View History

package logmon
import (
"crypto/rand"
2019-03-20 14:45:09 +00:00
"fmt"
"os"
"path/filepath"
2019-06-28 11:49:07 +00:00
"runtime"
"testing"
"github.com/hashicorp/nomad/ci"
"github.com/hashicorp/nomad/client/lib/fifo"
"github.com/hashicorp/nomad/helper/testlog"
"github.com/hashicorp/nomad/helper/uuid"
2019-03-20 14:45:09 +00:00
"github.com/hashicorp/nomad/testutil"
"github.com/stretchr/testify/require"
)
func TestLogmon_Start_rotate(t *testing.T) {
ci.Parallel(t)
require := require.New(t)
2019-06-28 11:49:07 +00:00
var stdoutFifoPath, stderrFifoPath string
dir := t.TempDir()
2019-06-28 11:49:07 +00:00
if runtime.GOOS == "windows" {
stdoutFifoPath = "//./pipe/test-rotate.stdout"
stderrFifoPath = "//./pipe/test-rotate.stderr"
} else {
stdoutFifoPath = filepath.Join(dir, "stdout.fifo")
stderrFifoPath = filepath.Join(dir, "stderr.fifo")
}
cfg := &LogConfig{
LogDir: dir,
StdoutLogFile: "stdout",
StdoutFifo: stdoutFifoPath,
StderrLogFile: "stderr",
StderrFifo: stderrFifoPath,
MaxFiles: 2,
MaxFileSizeMB: 1,
}
lm := NewLogMon(testlog.HCLogger(t))
require.NoError(lm.Start(cfg))
2019-04-01 19:56:43 +00:00
stdout, err := fifo.OpenWriter(stdoutFifoPath)
require.NoError(err)
// Write enough bytes such that the log is rotated
bytes1MB := make([]byte, 1024*1024)
_, err = rand.Read(bytes1MB)
require.NoError(err)
2019-03-20 14:45:09 +00:00
_, err = stdout.Write(bytes1MB)
require.NoError(err)
2019-03-20 14:45:09 +00:00
testutil.WaitForResult(func() (bool, error) {
_, err = os.Stat(filepath.Join(dir, "stdout.0"))
return err == nil, err
}, func(err error) {
require.NoError(err)
})
testutil.WaitForResult(func() (bool, error) {
_, err = os.Stat(filepath.Join(dir, "stdout.1"))
return err == nil, err
}, func(err error) {
require.NoError(err)
})
_, err = os.Stat(filepath.Join(dir, "stdout.2"))
require.Error(err)
require.NoError(lm.Stop())
require.NoError(lm.Stop())
}
2019-06-28 14:35:20 +00:00
// asserts that calling Start twice restarts the log rotator and that any logs
// published while the listener was unavailable are received.
2019-06-28 14:35:20 +00:00
func TestLogmon_Start_restart_flusheslogs(t *testing.T) {
ci.Parallel(t)
2019-06-28 14:35:20 +00:00
if runtime.GOOS == "windows" {
t.Skip("windows does not support pushing data to a pipe with no servers")
}
require := require.New(t)
2019-06-28 11:49:07 +00:00
var stdoutFifoPath, stderrFifoPath string
dir := t.TempDir()
2019-06-28 11:49:07 +00:00
if runtime.GOOS == "windows" {
stdoutFifoPath = "//./pipe/test-restart.stdout"
stderrFifoPath = "//./pipe/test-restart.stderr"
} else {
stdoutFifoPath = filepath.Join(dir, "stdout.fifo")
stderrFifoPath = filepath.Join(dir, "stderr.fifo")
}
cfg := &LogConfig{
LogDir: dir,
StdoutLogFile: "stdout",
StdoutFifo: stdoutFifoPath,
StderrLogFile: "stderr",
StderrFifo: stderrFifoPath,
MaxFiles: 2,
MaxFileSizeMB: 1,
}
lm := NewLogMon(testlog.HCLogger(t))
impl, ok := lm.(*logmonImpl)
require.True(ok)
require.NoError(lm.Start(cfg))
2019-04-01 19:56:43 +00:00
stdout, err := fifo.OpenWriter(stdoutFifoPath)
require.NoError(err)
2019-04-01 19:56:43 +00:00
stderr, err := fifo.OpenWriter(stderrFifoPath)
require.NoError(err)
// Write a string and assert it was written to the file
2019-03-20 14:45:09 +00:00
_, err = stdout.Write([]byte("test\n"))
require.NoError(err)
2019-03-20 14:45:09 +00:00
testutil.WaitForResult(func() (bool, error) {
raw, err := os.ReadFile(filepath.Join(dir, "stdout.0"))
2019-03-20 14:45:09 +00:00
if err != nil {
return false, err
}
return "test\n" == string(raw), fmt.Errorf("unexpected stdout %q", string(raw))
}, func(err error) {
require.NoError(err)
})
require.True(impl.tl.IsRunning())
// Close stdout and assert that logmon no longer writes to the file
require.NoError(stdout.Close())
require.NoError(stderr.Close())
2019-03-21 17:36:46 +00:00
testutil.WaitForResult(func() (bool, error) {
return !impl.tl.IsRunning(), fmt.Errorf("logmon is still running")
}, func(err error) {
require.NoError(err)
})
2019-04-01 19:56:43 +00:00
stdout, err = fifo.OpenWriter(stdoutFifoPath)
require.NoError(err)
2019-04-01 19:56:43 +00:00
stderr, err = fifo.OpenWriter(stderrFifoPath)
require.NoError(err)
2019-03-21 17:36:46 +00:00
2019-03-20 14:45:09 +00:00
_, err = stdout.Write([]byte("te"))
require.NoError(err)
2019-03-21 17:36:46 +00:00
2019-03-20 14:45:09 +00:00
testutil.WaitForResult(func() (bool, error) {
raw, err := os.ReadFile(filepath.Join(dir, "stdout.0"))
2019-03-20 14:45:09 +00:00
if err != nil {
return false, err
}
return "test\n" == string(raw), fmt.Errorf("unexpected stdout %q", string(raw))
}, func(err error) {
require.NoError(err)
})
// Start logmon again and assert that it appended to the file
require.NoError(lm.Start(cfg))
stdout, err = fifo.OpenWriter(stdoutFifoPath)
require.NoError(err)
stderr, err = fifo.OpenWriter(stderrFifoPath)
require.NoError(err)
2019-03-20 14:45:09 +00:00
_, err = stdout.Write([]byte("st\n"))
require.NoError(err)
2019-03-20 14:45:09 +00:00
testutil.WaitForResult(func() (bool, error) {
raw, err := os.ReadFile(filepath.Join(dir, "stdout.0"))
2019-03-20 14:45:09 +00:00
if err != nil {
return false, err
}
2019-03-21 17:36:46 +00:00
expected := "test\ntest\n" == string(raw)
return expected, fmt.Errorf("unexpected stdout %q", string(raw))
2019-03-20 14:45:09 +00:00
}, func(err error) {
require.NoError(err)
})
}
2019-06-28 14:35:20 +00:00
// asserts that calling Start twice restarts the log rotator
func TestLogmon_Start_restart(t *testing.T) {
ci.Parallel(t)
2019-06-28 14:35:20 +00:00
require := require.New(t)
var stdoutFifoPath, stderrFifoPath string
dir := t.TempDir()
2019-06-28 14:35:20 +00:00
if runtime.GOOS == "windows" {
stdoutFifoPath = "//./pipe/test-restart.stdout"
stderrFifoPath = "//./pipe/test-restart.stderr"
} else {
stdoutFifoPath = filepath.Join(dir, "stdout.fifo")
stderrFifoPath = filepath.Join(dir, "stderr.fifo")
}
cfg := &LogConfig{
LogDir: dir,
StdoutLogFile: "stdout",
2019-06-28 14:35:20 +00:00
StdoutFifo: stdoutFifoPath,
StderrLogFile: "stderr",
2019-06-28 14:35:20 +00:00
StderrFifo: stderrFifoPath,
MaxFiles: 2,
MaxFileSizeMB: 1,
}
lm := NewLogMon(testlog.HCLogger(t))
impl, ok := lm.(*logmonImpl)
require.True(ok)
require.NoError(lm.Start(cfg))
t.Cleanup(func() {
require.NoError(lm.Stop())
})
2019-06-28 14:35:20 +00:00
stdout, err := fifo.OpenWriter(stdoutFifoPath)
require.NoError(err)
stderr, err := fifo.OpenWriter(stderrFifoPath)
require.NoError(err)
// Write a string and assert it was written to the file
_, err = stdout.Write([]byte("test\n"))
require.NoError(err)
testutil.WaitForResult(func() (bool, error) {
raw, err := os.ReadFile(filepath.Join(dir, "stdout.0"))
2019-06-28 14:35:20 +00:00
if err != nil {
return false, err
}
return "test\n" == string(raw), fmt.Errorf("unexpected stdout %q", string(raw))
}, func(err error) {
require.NoError(err)
})
require.True(impl.tl.IsRunning())
// Close stderr and assert that logmon no longer writes to the file
// Keep stdout open to ensure that IsRunning requires both
2019-06-28 14:35:20 +00:00
require.NoError(stderr.Close())
testutil.WaitForResult(func() (bool, error) {
return !impl.tl.IsRunning(), fmt.Errorf("logmon is still running")
}, func(err error) {
require.NoError(err)
})
// Start logmon again and assert that it can receive logs again
2019-06-28 14:35:20 +00:00
require.NoError(lm.Start(cfg))
stdout, err = fifo.OpenWriter(stdoutFifoPath)
require.NoError(err)
t.Cleanup(func() {
require.NoError(stdout.Close())
})
2019-06-28 14:35:20 +00:00
stderr, err = fifo.OpenWriter(stderrFifoPath)
require.NoError(err)
t.Cleanup(func() {
require.NoError(stderr.Close())
})
2019-06-28 14:35:20 +00:00
_, err = stdout.Write([]byte("test\n"))
require.NoError(err)
testutil.WaitForResult(func() (bool, error) {
raw, err := os.ReadFile(filepath.Join(dir, "stdout.0"))
2019-06-28 14:35:20 +00:00
if err != nil {
return false, err
}
expected := "test\ntest\n" == string(raw)
return expected, fmt.Errorf("unexpected stdout %q", string(raw))
}, func(err error) {
require.NoError(err)
})
}
// panicWriter panics on use
type panicWriter struct{}
func (panicWriter) Write([]byte) (int, error) {
panic("should not be called")
}
func (panicWriter) Close() error {
panic("should not be called")
}
// TestLogmon_NewError asserts that newLogRotatorWrapper will return an error
// if its unable to create the necessray files.
func TestLogmon_NewError(t *testing.T) {
ci.Parallel(t)
// Pick a path that does not exist
path := filepath.Join(uuid.Generate(), uuid.Generate(), uuid.Generate())
logger := testlog.HCLogger(t)
// No code that uses the writer should get hit
rotator := panicWriter{}
w, err := newLogRotatorWrapper(path, logger, rotator)
require.Error(t, err)
require.Nil(t, w)
}