forked from Silverfish/proton-bridge
feat(GODT-2668): implemented new log retention policy.
This commit is contained in:
236
internal/logging/pruning_test.go
Normal file
236
internal/logging/pruning_test.go
Normal file
@ -0,0 +1,236 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
// Proton Mail Bridge is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Proton Mail Bridge is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package logging
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/ProtonMail/proton-bridge/v3/internal/constants"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
type fileInfo struct {
|
||||
filename string
|
||||
size int64
|
||||
}
|
||||
|
||||
var logFileSuffix = "_v" + constants.Version + "_" + constants.Tag + ".log"
|
||||
|
||||
func TestLogging_Pruning(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
const maxLogSize = 100
|
||||
sessionID1 := createDummySession(t, dir, maxLogSize, 50, 50, 250)
|
||||
sessionID2 := createDummySession(t, dir, maxLogSize, 100, 100, 350)
|
||||
sessionID3 := createDummySession(t, dir, maxLogSize, 150, 100, 350)
|
||||
|
||||
// Expected files per session
|
||||
session1Files := []fileInfo{
|
||||
{filename: string(sessionID1) + "_lau_000" + logFileSuffix, size: 50},
|
||||
{filename: string(sessionID1) + "_gui_000" + logFileSuffix, size: 50},
|
||||
{filename: string(sessionID1) + "_bri_000" + logFileSuffix, size: 100},
|
||||
{filename: string(sessionID1) + "_bri_001" + logFileSuffix, size: 100},
|
||||
{filename: string(sessionID1) + "_bri_002" + logFileSuffix, size: 50},
|
||||
}
|
||||
|
||||
session2Files := []fileInfo{
|
||||
{filename: string(sessionID2) + "_lau_000" + logFileSuffix, size: 100},
|
||||
{filename: string(sessionID2) + "_gui_000" + logFileSuffix, size: 100},
|
||||
{filename: string(sessionID2) + "_bri_000" + logFileSuffix, size: 100},
|
||||
{filename: string(sessionID2) + "_bri_001" + logFileSuffix, size: 100},
|
||||
{filename: string(sessionID2) + "_bri_002" + logFileSuffix, size: 100},
|
||||
{filename: string(sessionID2) + "_bri_003" + logFileSuffix, size: 50},
|
||||
}
|
||||
|
||||
session3Files := []fileInfo{
|
||||
{filename: string(sessionID3) + "_lau_000" + logFileSuffix, size: 100},
|
||||
{filename: string(sessionID3) + "_lau_001" + logFileSuffix, size: 50},
|
||||
{filename: string(sessionID3) + "_gui_000" + logFileSuffix, size: 100},
|
||||
{filename: string(sessionID3) + "_bri_000" + logFileSuffix, size: 100},
|
||||
{filename: string(sessionID3) + "_bri_001" + logFileSuffix, size: 100},
|
||||
{filename: string(sessionID3) + "_bri_002" + logFileSuffix, size: 100},
|
||||
{filename: string(sessionID3) + "_bri_003" + logFileSuffix, size: 50},
|
||||
}
|
||||
|
||||
allSessions := session1Files
|
||||
allSessions = append(allSessions, append(session2Files, session3Files...)...)
|
||||
checkFolderContent(t, dir, allSessions...)
|
||||
|
||||
failureCount, err := pruneLogs(dir, sessionID3, 2000) // nothing to prune
|
||||
require.Equal(t, failureCount, 0)
|
||||
require.NoError(t, err)
|
||||
checkFolderContent(t, dir, allSessions...)
|
||||
|
||||
failureCount, err = pruneLogs(dir, sessionID3, 1200) // session 1 is pruned
|
||||
require.Equal(t, failureCount, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
checkFolderContent(t, dir, append(session2Files, session3Files...)...)
|
||||
failureCount, err = pruneLogs(dir, sessionID3, 1000) // session 2 is pruned
|
||||
require.Equal(t, failureCount, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
checkFolderContent(t, dir, session3Files...)
|
||||
}
|
||||
|
||||
func TestLogging_PruningBigCurrentSession(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
const maxLogFileSize = 1000
|
||||
sessionID1 := createDummySession(t, dir, maxLogFileSize, 500, 500, 2500)
|
||||
sessionID2 := createDummySession(t, dir, maxLogFileSize, 1000, 1000, 3500)
|
||||
sessionID3 := createDummySession(t, dir, maxLogFileSize, 500, 500, 10500)
|
||||
|
||||
// Expected files per session
|
||||
session1Files := []fileInfo{
|
||||
{filename: string(sessionID1) + "_lau_000" + logFileSuffix, size: 500},
|
||||
{filename: string(sessionID1) + "_gui_000" + logFileSuffix, size: 500},
|
||||
{filename: string(sessionID1) + "_bri_000" + logFileSuffix, size: 1000},
|
||||
{filename: string(sessionID1) + "_bri_001" + logFileSuffix, size: 1000},
|
||||
{filename: string(sessionID1) + "_bri_002" + logFileSuffix, size: 500},
|
||||
}
|
||||
|
||||
session2Files := []fileInfo{
|
||||
{filename: string(sessionID2) + "_lau_000" + logFileSuffix, size: 1000},
|
||||
{filename: string(sessionID2) + "_gui_000" + logFileSuffix, size: 1000},
|
||||
{filename: string(sessionID2) + "_bri_000" + logFileSuffix, size: 1000},
|
||||
{filename: string(sessionID2) + "_bri_001" + logFileSuffix, size: 1000},
|
||||
{filename: string(sessionID2) + "_bri_002" + logFileSuffix, size: 1000},
|
||||
{filename: string(sessionID2) + "_bri_003" + logFileSuffix, size: 500},
|
||||
}
|
||||
|
||||
session3Files := []fileInfo{
|
||||
{filename: string(sessionID3) + "_lau_000" + logFileSuffix, size: 500},
|
||||
{filename: string(sessionID3) + "_gui_000" + logFileSuffix, size: 500},
|
||||
{filename: string(sessionID3) + "_bri_000" + logFileSuffix, size: 1000},
|
||||
{filename: string(sessionID3) + "_bri_001" + logFileSuffix, size: 1000},
|
||||
{filename: string(sessionID3) + "_bri_002" + logFileSuffix, size: 1000},
|
||||
{filename: string(sessionID3) + "_bri_003" + logFileSuffix, size: 1000},
|
||||
{filename: string(sessionID3) + "_bri_004" + logFileSuffix, size: 1000},
|
||||
{filename: string(sessionID3) + "_bri_005" + logFileSuffix, size: 1000},
|
||||
{filename: string(sessionID3) + "_bri_006" + logFileSuffix, size: 1000},
|
||||
{filename: string(sessionID3) + "_bri_007" + logFileSuffix, size: 1000},
|
||||
{filename: string(sessionID3) + "_bri_008" + logFileSuffix, size: 1000},
|
||||
{filename: string(sessionID3) + "_bri_009" + logFileSuffix, size: 1000},
|
||||
{filename: string(sessionID3) + "_bri_010" + logFileSuffix, size: 500},
|
||||
}
|
||||
|
||||
allSessions := session1Files
|
||||
allSessions = append(allSessions, append(session2Files, session3Files...)...)
|
||||
checkFolderContent(t, dir, allSessions...)
|
||||
|
||||
// current session is bigger than maxFileSize. We keep launcher and gui logs, the first and last bridge log
|
||||
// and only the last bridge log that keep the total file size under the limit.
|
||||
failureCount, err := pruneLogs(dir, sessionID3, 8000)
|
||||
require.Equal(t, failureCount, 0)
|
||||
require.NoError(t, err)
|
||||
checkFolderContent(t, dir, []fileInfo{
|
||||
{filename: string(sessionID3) + "_lau_000" + logFileSuffix, size: 500},
|
||||
{filename: string(sessionID3) + "_gui_000" + logFileSuffix, size: 500},
|
||||
{filename: string(sessionID3) + "_bri_000" + logFileSuffix, size: 1000},
|
||||
{filename: string(sessionID3) + "_bri_005" + logFileSuffix, size: 1000},
|
||||
{filename: string(sessionID3) + "_bri_006" + logFileSuffix, size: 1000},
|
||||
{filename: string(sessionID3) + "_bri_007" + logFileSuffix, size: 1000},
|
||||
{filename: string(sessionID3) + "_bri_008" + logFileSuffix, size: 1000},
|
||||
{filename: string(sessionID3) + "_bri_009" + logFileSuffix, size: 1000},
|
||||
{filename: string(sessionID3) + "_bri_010" + logFileSuffix, size: 500},
|
||||
}...)
|
||||
|
||||
failureCount, err = pruneLogs(dir, sessionID3, 5000)
|
||||
require.Equal(t, failureCount, 0)
|
||||
require.NoError(t, err)
|
||||
checkFolderContent(t, dir, []fileInfo{
|
||||
{filename: string(sessionID3) + "_lau_000" + logFileSuffix, size: 500},
|
||||
{filename: string(sessionID3) + "_gui_000" + logFileSuffix, size: 500},
|
||||
{filename: string(sessionID3) + "_bri_000" + logFileSuffix, size: 1000},
|
||||
{filename: string(sessionID3) + "_bri_008" + logFileSuffix, size: 1000},
|
||||
{filename: string(sessionID3) + "_bri_009" + logFileSuffix, size: 1000},
|
||||
{filename: string(sessionID3) + "_bri_010" + logFileSuffix, size: 500},
|
||||
}...)
|
||||
|
||||
// whatever maxFileSize is, we will always keep the following files
|
||||
minimalFiles := []fileInfo{
|
||||
{filename: string(sessionID3) + "_lau_000" + logFileSuffix, size: 500},
|
||||
{filename: string(sessionID3) + "_gui_000" + logFileSuffix, size: 500},
|
||||
{filename: string(sessionID3) + "_bri_000" + logFileSuffix, size: 1000},
|
||||
{filename: string(sessionID3) + "_bri_010" + logFileSuffix, size: 500},
|
||||
}
|
||||
failureCount, err = pruneLogs(dir, sessionID3, 2000)
|
||||
require.Equal(t, failureCount, 0)
|
||||
require.NoError(t, err)
|
||||
checkFolderContent(t, dir, minimalFiles...)
|
||||
|
||||
failureCount, err = pruneLogs(dir, sessionID3, 0)
|
||||
require.Equal(t, failureCount, 0)
|
||||
require.NoError(t, err)
|
||||
checkFolderContent(t, dir, minimalFiles...)
|
||||
}
|
||||
|
||||
func createDummySession(t *testing.T, dir string, maxLogFileSize int64, launcherLogSize, guiLogSize, bridgeLogSize int64) SessionID {
|
||||
time.Sleep(2 * time.Millisecond) // ensure our sessionID is unused.
|
||||
sessionID := NewSessionID()
|
||||
if launcherLogSize > 0 {
|
||||
createDummyRotatedLogFile(t, dir, sessionID, LauncherShortAppName, launcherLogSize, maxLogFileSize)
|
||||
}
|
||||
|
||||
if guiLogSize > 0 {
|
||||
createDummyRotatedLogFile(t, dir, sessionID, GUIShortAppName, guiLogSize, maxLogFileSize)
|
||||
}
|
||||
|
||||
if bridgeLogSize > 0 {
|
||||
createDummyRotatedLogFile(t, dir, sessionID, BridgeShortAppName, bridgeLogSize, maxLogFileSize)
|
||||
}
|
||||
|
||||
return sessionID
|
||||
}
|
||||
|
||||
func createDummyRotatedLogFile(t *testing.T, dir string, sessionID SessionID, appName AppName, totalSize, maxLogFileSize int64) {
|
||||
rotator, err := NewDefaultRotator(dir, sessionID, appName, maxLogFileSize, NoPruning)
|
||||
require.NoError(t, err)
|
||||
for i := int64(0); i < totalSize/maxLogFileSize; i++ {
|
||||
count, err := rotator.Write(make([]byte, maxLogFileSize))
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, int64(count), maxLogFileSize)
|
||||
}
|
||||
|
||||
remainder := totalSize % maxLogFileSize
|
||||
if remainder > 0 {
|
||||
count, err := rotator.Write(make([]byte, remainder))
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, int64(count), remainder)
|
||||
}
|
||||
|
||||
require.NoError(t, rotator.wc.Close())
|
||||
}
|
||||
|
||||
func checkFolderContent(t *testing.T, dir string, fileInfos ...fileInfo) {
|
||||
for _, fi := range fileInfos {
|
||||
checkFileExistsWithSize(t, dir, fi)
|
||||
}
|
||||
|
||||
entries, err := os.ReadDir(dir)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, len(fileInfos), len(entries))
|
||||
}
|
||||
|
||||
func checkFileExistsWithSize(t *testing.T, dir string, info fileInfo) {
|
||||
stat, err := os.Stat(filepath.Join(dir, info.filename))
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, stat.Size(), info.size)
|
||||
}
|
||||
Reference in New Issue
Block a user