Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 116 additions & 0 deletions timberjack_linux_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package timberjack

import (
"os"
"path/filepath"
"syscall"
"testing"
)

func TestRotate_OpenNewFails(t *testing.T) {
if os.Getuid() == 0 {
t.Skip("Skipping test when running as root")
}
badPath := "/bad/path/logfile.log"
if _, err := os.Stat(badPath); err == nil {
t.Skip("Skipping test that relies on non-existent path")
}
l := &Logger{
Filename: badPath,
}
// force an invalid path to trigger openNew failure
err := l.rotate("manual")
if err == nil {
t.Fatal("expected error from rotate due to invalid openNew")
}
}

func TestCompressLogFile_CopyFails(t *testing.T) {
if os.Getuid() == 0 {
t.Skip("Skipping test when running as root")
}
dir := t.TempDir()
src := filepath.Join(dir, "bad.log")
dst := src + ".gz"

if err := os.WriteFile(src, []byte("data"), 0o200); err != nil { // write-only
t.Fatalf("failed to create test file: %v", err)
}
defer os.Chmod(src, 0o644)

originalStat := osStat
osStat = func(name string) (os.FileInfo, error) {
return os.Stat(src)
}
defer func() { osStat = originalStat }()

l := &Logger{}
// snapshot patched osStat
l.resolveConfigLocked()

err := l.compressLogFile(src, dst)
if err == nil {
t.Errorf("expected failure during compression, got: %v", err)
}
}

func TestOpenNewDefaultPerm(t *testing.T) {
// Ensure no bits get masked out.
syscall.Umask(0o000)

Comment thread
DeRuina marked this conversation as resolved.
dir := makeTempDir("TestOpenNewDefaultPerm", t)
defer os.RemoveAll(dir)

l := &Logger{
Filename: logFile(dir),
}
defer l.Close()

_, err := l.Write([]byte("foo"))
isNil(err, t)
hasPerm(logFile(dir), 0o640, t)
}

func TestOpenNewCustomPerm(t *testing.T) {
// Ensure no bits get masked out.
syscall.Umask(0o000)

Comment thread
DeRuina marked this conversation as resolved.
Comment thread
DeRuina marked this conversation as resolved.
dir := makeTempDir("TestOpenNewCustomPerm", t)
defer os.RemoveAll(dir)

filename := logFile(dir)
l1 := &Logger{
Filename: filename,
FileMode: 0o747,
}
t.Cleanup(func() {
l1.Close()
})
_, err := l1.Write([]byte("foo"))
isNil(err, t)
hasPerm(filename, 0o747, t)

filename += ".1"
l2 := &Logger{
Filename: filename,
FileMode: 0o200,
}
t.Cleanup(func() {
l2.Close()
})
_, err = l2.Write([]byte("foo"))
isNil(err, t)
hasPerm(filename, 0o200, t)

filename += ".2"
l3 := &Logger{
Filename: filename,
FileMode: 0o666,
}
t.Cleanup(func() {
l3.Close()
})
_, err = l3.Write([]byte("foo"))
isNil(err, t)
hasPerm(filename, 0o666, t)
}
112 changes: 8 additions & 104 deletions timberjack_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import (
"sort"
"strings"
"sync"
"syscall"
"testing"
"time"

Expand Down Expand Up @@ -77,6 +76,9 @@ func TestNewFile(t *testing.T) {
}

func TestOpenExisting(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("Skipping default perm test on Windows")
}
Comment thread
DeRuina marked this conversation as resolved.
currentTime = fakeTime
dir := makeTempDir("TestOpenExisting", t)
defer os.RemoveAll(dir)
Expand Down Expand Up @@ -1098,6 +1100,7 @@ func TestOpenExistingOrNew_Fallback(t *testing.T) {
t.Fatalf("expected fallback to openNew, got error: %v", err)
}

logger.Close()
// Clean up the recreated file
if rmErr := os.Remove(path); rmErr != nil && !os.IsNotExist(rmErr) {
t.Errorf("cleanup failed: %v", rmErr)
Expand Down Expand Up @@ -1158,14 +1161,15 @@ func TestBackupName(t *testing.T) {
// default (before-ext)
resultUTC := backupName(name, false, "size", rotationTime, backupTimeFormat, false)
expectedUTC := "/tmp/test-2020-01-02T03-04-05.006-size.log"
if resultUTC != expectedUTC {

if filepath.Base(resultUTC) != filepath.Base(expectedUTC) {
t.Errorf("expected %q, got %q", expectedUTC, resultUTC)
}
Comment thread
DeRuina marked this conversation as resolved.

// after-ext
after := backupName(name, false, "size", rotationTime, backupTimeFormat, true)
expectedAfter := "/tmp/test.log-2020-01-02T03-04-05.006-size"
if after != expectedAfter {
if filepath.Base(after) != filepath.Base(expectedAfter) {
t.Errorf("expected %q, got %q", expectedAfter, after)
Comment thread
DeRuina marked this conversation as resolved.
Comment thread
DeRuina marked this conversation as resolved.
}
}
Expand Down Expand Up @@ -1219,18 +1223,6 @@ func TestRunScheduledRotations_NoMarks(t *testing.T) {
}
}

func TestRotate_OpenNewFails(t *testing.T) {
badPath := "/bad/path/logfile.log"
l := &Logger{
Filename: badPath,
}
// force an invalid path to trigger openNew failure
err := l.rotate("manual")
if err == nil {
t.Fatal("expected error from rotate due to invalid openNew")
}
}

func TestRotate_TriggersTimeReason(t *testing.T) {
currentTime = func() time.Time {
return time.Date(2024, 5, 1, 12, 0, 0, 0, time.UTC)
Expand Down Expand Up @@ -1402,32 +1394,6 @@ func TestOpenNew_StatUnexpectedError(t *testing.T) {
}
}

func TestCompressLogFile_CopyFails(t *testing.T) {
dir := t.TempDir()
src := filepath.Join(dir, "bad.log")
dst := src + ".gz"

if err := os.WriteFile(src, []byte("data"), 0o200); err != nil { // write-only
t.Fatalf("failed to create test file: %v", err)
}
defer os.Chmod(src, 0o644)

originalStat := osStat
osStat = func(name string) (os.FileInfo, error) {
return os.Stat(src)
}
defer func() { osStat = originalStat }()

l := &Logger{}
// snapshot patched osStat
l.resolveConfigLocked()

err := l.compressLogFile(src, dst)
if err == nil {
t.Errorf("expected failure during compression, got: %v", err)
}
}

func TestOpenExistingOrNew_StatFailure(t *testing.T) {
originalStat := osStat
defer func() { osStat = originalStat }()
Expand Down Expand Up @@ -1955,6 +1921,7 @@ func TestRotate_StartMillOnlyOnce_Observable(t *testing.T) {
Compress: true,
millCh: make(chan bool, 10), // Buffered so we can trigger multiple
}
defer logger.Close()

// Create two valid backup files to be compressed
for i := 0; i < 2; i++ {
Expand Down Expand Up @@ -2637,69 +2604,6 @@ func TestWriteToClosedLogger(t *testing.T) {
}
}

func TestOpenNewDefaultPerm(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("Skipping default perm test on Windows")
}

// Ensure no bits get masked out.
syscall.Umask(0o000)

dir := makeTempDir("TestOpenNewDefaultPerm", t)
defer os.RemoveAll(dir)

l := &Logger{
Filename: logFile(dir),
}
defer l.Close()

_, err := l.Write([]byte("foo"))
isNil(err, t)
hasPerm(logFile(dir), 0o640, t)
}

func TestOpenNewCustomPerm(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("Skipping custom perm test on Windows")
}

// Ensure no bits get masked out.
syscall.Umask(0o000)

dir := makeTempDir("TestOpenNewCustomPerm", t)
defer os.RemoveAll(dir)

filename := logFile(dir)
l := &Logger{
Filename: filename,
FileMode: 0o747,
}
_, err := l.Write([]byte("foo"))
isNil(err, t)
hasPerm(filename, 0o747, t)
l.Close()

filename += ".1"
l = &Logger{
Filename: filename,
FileMode: 0o200,
}
_, err = l.Write([]byte("foo"))
isNil(err, t)
hasPerm(filename, 0o200, t)
l.Close()

filename += ".2"
l = &Logger{
Filename: filename,
FileMode: 0o666,
}
_, err = l.Write([]byte("foo"))
isNil(err, t)
hasPerm(filename, 0o666, t)
l.Close()
}

// waitForFileWithSuffix polls dir for a file ending in suffix, up to timeout.
func waitForFileWithSuffix(t *testing.T, dir, suffix string, timeout time.Duration) (string, error) {
t.Helper()
Expand Down