traefik/integration/log_rotation_test.go
Michael e522446909
Improve integration tests
Co-authored-by: Julien Salleyron <julien.salleyron@gmail.com>
2024-01-09 17:00:07 +01:00

189 lines
5 KiB
Go

//go:build !windows
// +build !windows
package integration
import (
"bufio"
"net/http"
"os"
"strings"
"syscall"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"github.com/traefik/traefik/v2/integration/try"
"github.com/traefik/traefik/v2/pkg/log"
)
const (
traefikTestLogFileRotated = traefikTestLogFile + ".rotated"
traefikTestAccessLogFileRotated = traefikTestAccessLogFile + ".rotated"
)
// Log rotation integration test suite.
type LogRotationSuite struct{ BaseSuite }
func TestLogRorationSuite(t *testing.T) {
suite.Run(t, new(LogRotationSuite))
}
func (s *LogRotationSuite) SetupSuite() {
s.BaseSuite.SetupSuite()
os.Remove(traefikTestAccessLogFile)
os.Remove(traefikTestLogFile)
os.Remove(traefikTestAccessLogFileRotated)
s.createComposeProject("access_log")
s.composeUp()
}
func (s *LogRotationSuite) TearDownSuite() {
s.BaseSuite.TearDownSuite()
generatedFiles := []string{
traefikTestLogFile,
traefikTestLogFileRotated,
traefikTestAccessLogFile,
traefikTestAccessLogFileRotated,
}
for _, filename := range generatedFiles {
if err := os.Remove(filename); err != nil {
log.WithoutContext().Warning(err)
}
}
}
func (s *LogRotationSuite) TestAccessLogRotation() {
// Start Traefik
cmd, _ := s.cmdTraefik(withConfigFile("fixtures/access_log_config.toml"))
defer s.displayTraefikLogFile(traefikTestLogFile)
// Verify Traefik started ok
s.verifyEmptyErrorLog("traefik.log")
s.waitForTraefik("server1")
// Make some requests
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil)
require.NoError(s.T(), err)
req.Host = "frontend1.docker.local"
err = try.Request(req, 500*time.Millisecond, try.StatusCodeIs(http.StatusOK), try.HasBody())
require.NoError(s.T(), err)
// Rename access log
err = os.Rename(traefikTestAccessLogFile, traefikTestAccessLogFileRotated)
require.NoError(s.T(), err)
// in the midst of the requests, issue SIGUSR1 signal to server process
err = cmd.Process.Signal(syscall.SIGUSR1)
require.NoError(s.T(), err)
// continue issuing requests
err = try.Request(req, 500*time.Millisecond, try.StatusCodeIs(http.StatusOK), try.HasBody())
require.NoError(s.T(), err)
err = try.Request(req, 500*time.Millisecond, try.StatusCodeIs(http.StatusOK), try.HasBody())
require.NoError(s.T(), err)
// Verify access.log.rotated output as expected
s.logAccessLogFile(traefikTestAccessLogFileRotated)
lineCount := s.verifyLogLines(traefikTestAccessLogFileRotated, 0, true)
assert.GreaterOrEqual(s.T(), lineCount, 1)
// make sure that the access log file is at least created before we do assertions on it
err = try.Do(1*time.Second, func() error {
_, err := os.Stat(traefikTestAccessLogFile)
return err
})
assert.NoError(s.T(), err, "access log file was not created in time")
// Verify access.log output as expected
s.logAccessLogFile(traefikTestAccessLogFile)
lineCount = s.verifyLogLines(traefikTestAccessLogFile, lineCount, true)
assert.Equal(s.T(), 3, lineCount)
s.verifyEmptyErrorLog(traefikTestLogFile)
}
func (s *LogRotationSuite) TestTraefikLogRotation() {
// Start Traefik
cmd := s.traefikCmd(withConfigFile("fixtures/traefik_log_config.toml"))
s.waitForTraefik("server1")
// Rename traefik log
err := os.Rename(traefikTestLogFile, traefikTestLogFileRotated)
require.NoError(s.T(), err)
// issue SIGUSR1 signal to server process
err = cmd.Process.Signal(syscall.SIGUSR1)
require.NoError(s.T(), err)
err = cmd.Process.Signal(syscall.SIGTERM)
require.NoError(s.T(), err)
// Allow time for switch to be processed
err = try.Do(3*time.Second, func() error {
_, err = os.Stat(traefikTestLogFile)
return err
})
require.NoError(s.T(), err)
// we have at least 6 lines in traefik.log.rotated
lineCount := s.verifyLogLines(traefikTestLogFileRotated, 0, false)
// GreaterOrEqualThan used to ensure test doesn't break
// If more log entries are output on startup
assert.GreaterOrEqual(s.T(), lineCount, 5)
// Verify traefik.log output as expected
lineCount = s.verifyLogLines(traefikTestLogFile, lineCount, false)
assert.GreaterOrEqual(s.T(), lineCount, 7)
}
func (s *LogRotationSuite) logAccessLogFile(fileName string) {
output, err := os.ReadFile(fileName)
require.NoError(s.T(), err)
log.WithoutContext().Infof("Contents of file %s\n%s", fileName, string(output))
}
func (s *LogRotationSuite) verifyEmptyErrorLog(name string) {
err := try.Do(5*time.Second, func() error {
traefikLog, e2 := os.ReadFile(name)
if e2 != nil {
return e2
}
assert.Empty(s.T(), string(traefikLog))
return nil
})
require.NoError(s.T(), err)
}
func (s *LogRotationSuite) verifyLogLines(fileName string, countInit int, accessLog bool) int {
rotated, err := os.Open(fileName)
require.NoError(s.T(), err)
rotatedLog := bufio.NewScanner(rotated)
count := countInit
for rotatedLog.Scan() {
line := rotatedLog.Text()
if accessLog {
if len(line) > 0 {
if !strings.Contains(line, "/api/rawdata") {
s.CheckAccessLogFormat(line, count)
count++
}
}
} else {
count++
}
}
return count
}