* Copyright (c) 2025 Huawei Technologies Co., Ltd.
* openFuyao is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
package log
import (
"errors"
"fmt"
"os"
"path/filepath"
"syscall"
"testing"
"time"
)
func TestNewFileLogger(t *testing.T) {
dir := makeTempDir("TmpFileForTest", t)
defer os.RemoveAll(dir)
testFileName := filepath.Join(dir, "test.log")
l := &FileLogger{
fileName: testFileName,
}
defer l.Close()
b := []byte("test data")
n, err := l.Write(b)
assertIsNil(err, t)
assertEquals(len(b), n, t)
checkExistsFileWithSize(testFileName, n, t)
checkFileCount(dir, 1, t)
}
func TestOpenExistingLog(t *testing.T) {
dir := makeTempDir("TmpFileForTest", t)
defer os.RemoveAll(dir)
testFileName := filepath.Join(dir, "test.log")
data := []byte("test pre data")
err := os.WriteFile(testFileName, data, fileModeUserRwForWritingLog)
assertIsNil(err, t)
checkExistsFileWithSize(testFileName, len(data), t)
l := &FileLogger{
fileName: testFileName,
}
defer l.Close()
b := []byte("test post data")
n, err := l.Write(b)
assertIsNil(err, t)
assertEquals(len(b), n, t)
checkExistsFileWithSize(testFileName, len(b)+len(data), t)
checkFileCount(dir, 1, t)
}
func TestWriteInvalidLenLog(t *testing.T) {
dir := makeTempDir("TmpFileForTest", t)
defer os.RemoveAll(dir)
var maxContentLen = 5
megabyte = 1
testFileName := filepath.Join(dir, "test.log")
l := &FileLogger{
fileName: testFileName,
maxSize: maxContentLen,
}
data := []byte("efghijklmn")
_, err2 := l.Write(data)
assertNotNil(err2, t)
}
var testFileTimeCount = 0
func fakeTimeCurrent() time.Time {
testFileTimeCount += 1
return time.Now().Add(time.Minute * time.Duration(testFileTimeCount))
}
func TestAutoRotateCleanAndMaxBackups(t *testing.T) {
dir := makeTempDir("AutoCompressRotate", t)
defer os.RemoveAll(dir)
var maxContentLen = 5
var maxBackupNum = 2
const maxBackupFileMultiplier = 2
megabyte = 1
testFileName := filepath.Join(dir, "test.log")
l := &FileLogger{
fileName: testFileName,
maxSize: maxContentLen,
maxBackups: maxBackupNum,
}
defer l.Close()
data1 := []byte("abcd")
data1Len, err1 := l.Write(data1)
assertIsNil(err1, t)
assertEquals(len(data1), data1Len, t)
checkExistsFileWithSize(testFileName, data1Len, t)
checkFileCount(dir, 1, t)
const delayCount = 100
currentTime = fakeTimeCurrent
data2 := []byte("efgh")
data2Len, err2 := l.Write(data2)
assertIsNil(err2, t)
assertEquals(len(data2), data2Len, t)
checkExistsFileWithSize(testFileName, data2Len, t)
<-time.After(time.Millisecond * delayCount)
checkFileCountRange(dir, maxBackupNum, maxBackupNum+1, t)
currentTime = fakeTimeCurrent
data2 = []byte("ijk")
data2Len, err2 = l.Write(data2)
assertIsNil(err2, t)
assertEquals(len(data2), data2Len, t)
checkExistsFileWithSize(testFileName, data2Len, t)
<-time.After(time.Millisecond * delayCount)
checkFileCountRange(dir, maxBackupNum+1, maxBackupNum*maxBackupFileMultiplier+1, t)
currentTime = fakeTimeCurrent
data2 = []byte("ijk")
data2Len, err2 = l.Write(data2)
assertIsNil(err2, t)
assertEquals(len(data2), data2Len, t)
checkExistsFileWithSize(testFileName, data2Len, t)
<-time.After(time.Millisecond * delayCount)
checkFileCountRange(dir, maxBackupNum+1, maxBackupNum*maxBackupFileMultiplier+1, t)
}
func makeTempDir(name string, t testing.TB) string {
dir := time.Now().Format(name)
dir = filepath.Join(os.TempDir(), dir)
assertIsNil(os.Mkdir(dir, dirModeUserRwxForLogDir), t)
return dir
}
func checkExistsFileWithSize(path string, len int, t testing.TB) {
info, err := os.Stat(path)
assertIsNil(err, t)
assertEquals(int64(len), info.Size(), t)
}
func checkFileCount(dir string, expect int, t testing.TB) {
dirs, err := os.ReadDir(dir)
t.Logf("--> Check dir[%s] files:", dir)
for _, f := range dirs {
t.Logf(" %s\n", f.Name())
}
assertIsNil(err, t)
assertEquals(expect, len(dirs), t)
}
func checkFileCountRange(dir string, min, max int, t testing.TB) {
dirs, err := os.ReadDir(dir)
t.Logf("--> Check dir[%s] files:", dir)
for _, f := range dirs {
t.Logf(" %s\n", f.Name())
}
assertIsNil(err, t)
if len(dirs) < min || len(dirs) > max {
t.Errorf("file count out of range, expect [%d, %d], got: %d", min, max, len(dirs))
}
}
func getFileMode(name string) (os.FileMode, error) {
var actualMode os.FileMode
info, err := os.Stat(name)
if err != nil {
fmt.Println("Error getting file info:", err)
return actualMode, err
}
actualMode = info.Mode() & os.ModePerm
return actualMode, nil
}
func getRotateLogFile(dir string) (string, error) {
files, err := os.ReadDir(dir)
if err != nil {
fmt.Println("Error reading directory:", err)
return "", err
}
for _, file := range files {
if !file.IsDir() && filepath.Ext(file.Name()) == ".gz" {
return filepath.Join(dir, file.Name()), nil
}
}
return "", errors.New("not found rotate logfile")
}
func TestLogFilePermissions(t *testing.T) {
syscall.Umask(0)
dir := "/tmp/TmpFileForPermission"
fileName := "test.log"
defer os.RemoveAll(dir)
var maxContentLen = 5
megabyte = 1
testFileName := filepath.Join(dir, fileName)
l := &FileLogger{
fileName: testFileName,
maxSize: maxContentLen,
maxBackups: 1,
}
data := []byte("efgh")
_, err2 := l.Write(data)
assertIsNil(err2, t)
modeFile, err := getFileMode(testFileName)
assertIsNil(err, t)
assertEquals(os.FileMode(fileModeUserRwForWritingLog), modeFile, t)
modeDir, err := getFileMode(dir)
assertIsNil(err, t)
assertEquals(os.FileMode(dirModeUserRwxForLogDir), modeDir, t)
data = []byte("efg")
_, err2 = l.Write(data)
assertIsNil(err2, t)
const delayCount = 100
<-time.After(time.Millisecond * delayCount)
rotateFile, err := getRotateLogFile(dir)
assertIsNil(err, t)
modeRotateFile, err := getFileMode(rotateFile)
assertIsNil(err, t)
assertEquals(os.FileMode(fileModeUserRoForArchiveLog), modeRotateFile, t)
}