package loglevel import ( "io" "os" "path/filepath" "strings" "sync" "testing" ) func createFileRotater(t *testing.T) (*FileRotater, func()) { d, err := os.MkdirTemp("", "logtest") if err != nil { t.Fatalf("failed creating tmp dir: %v", err) } fn := filepath.Join(d, "test.log") fr, err := NewFileRotater(fn) if err != nil { t.Fatalf("NewFileRotater error: %v", err) } if fr == nil { t.Fatal("NewFileRotater returned nil") } return fr, func() { err := os.RemoveAll(d) if err != nil { t.Errorf("failed removing file: %v", err) } } } func TestNewFileRotater(t *testing.T) { _, cleanup := createFileRotater(t) cleanup() d, err := os.MkdirTemp("", "anotherlogtest") if err != nil { t.Fatalf("failed creating another tmp dir: %v", err) } nef := filepath.Join(d, "notexist", "test.log") _, err = NewFileRotater(nef) if err == nil { t.Error("NewFileRotater returned no error with nonexistent dir") } } func TestWriteConcurrent(t *testing.T) { fr, cleanup := createFileRotater(t) defer cleanup() MaxSize = 5 var wg sync.WaitGroup for range 5 { wg.Add(1) go func() { _, err := fr.Write([]byte("test")) defer wg.Done() if err != nil { t.Errorf("concurrent write returned an error: %v", err) } }() } wg.Wait() } func TestWriteTrim(t *testing.T) { fr, cleanup := createFileRotater(t) defer cleanup() writeNCheckSize := func(n int, size int64) { buf := make([]byte, n) for i := range n { buf[i] = 'x' } _, err := fr.Write(buf) if err != nil { t.Fatalf("failed writing: %v", err) } fs, err := fr.file.Stat() if err != nil { t.Fatalf("failed getting size: %v", err) } gsize := fs.Size() if gsize != size { t.Fatalf("got: %v, want: %v, max size: %v", gsize, size, MaxSize) } } // we test by writing a start message and checking if it disappears after trimmign // the max size we set to the length of the start message + 20 bytes begS := "this is the start" begB := []byte(begS) startN := int64(len(begB)) MaxSize = startN + 20 TrimSize = MaxSize / 2 // no trim yet _, err := fr.Write(begB) if err != nil { t.Fatalf("failed writing start message: %v", err) } // write until the trimming size writeNCheckSize(5, startN+5) writeNCheckSize(15, MaxSize) // set the length we want to write var n int64 = 11 // now the size should be the length of the trimmed message plus the remaining (non-trimmed part of the file) plus the length we want to write size := int64(len(TrimMsg)) + (MaxSize - TrimSize) + n writeNCheckSize(11, size) // disable trimming by setting it to a high value MaxSize = 9000 TrimSize = 9000 // now the size should be the old size plus the write size newN := 12 writeNCheckSize(newN, size+int64(newN)) _, err = fr.file.Seek(0, io.SeekStart) if err != nil { t.Fatalf("failed going to beginning of file: %v", err) } b, err := io.ReadAll(fr.file) if err != nil { t.Fatalf("failed reading file: %v", err) } corpus := string(b) if strings.Contains(corpus, begS) { t.Fatalf("file still contains beginning message: %v", corpus) } if !strings.Contains(corpus, TrimMsg) { t.Fatalf("file does not contain trim message: %v", corpus) } }