Files
windows_exporter/internal/log/logger_test.go
T

193 lines
5.2 KiB
Go

// SPDX-License-Identifier: Apache-2.0
//
// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//go:build windows
package log
import (
"log/slog"
"os"
"path/filepath"
"strings"
"testing"
"github.com/prometheus/common/promslog"
"github.com/stretchr/testify/require"
)
func newConfig(t *testing.T, file string, rotation Rotation) *Config {
t.Helper()
allowedFile := &AllowedFile{}
require.NoError(t, allowedFile.Set(file))
return &Config{Config: &promslog.Config{}, File: allowedFile, Rotation: rotation}
}
func TestNewFileWithoutRotation(t *testing.T) {
t.Parallel()
path := filepath.Join(t.TempDir(), "windows_exporter.log")
logger, closer, err := New(newConfig(t, path, Rotation{}))
require.NoError(t, err)
require.NotNil(t, closer)
logger.Info("hello")
require.NoError(t, closer.Close())
data, err := os.ReadFile(path)
require.NoError(t, err)
require.Contains(t, string(data), "hello")
}
func writeMegabytes(logger *slog.Logger, megabytes int) {
message := strings.Repeat("x", 1024)
for range megabytes * 1100 {
logger.Info(message)
}
}
func TestNewFileWithSizeRotation(t *testing.T) {
t.Parallel()
dir := t.TempDir()
path := filepath.Join(dir, "windows_exporter.log")
logger, closer, err := New(newConfig(t, path, Rotation{MaxSize: 1}))
require.NoError(t, err)
require.NotNil(t, closer)
writeMegabytes(logger, 2)
require.NoError(t, closer.Close())
entries, err := os.ReadDir(dir)
require.NoError(t, err)
require.GreaterOrEqual(t, len(entries), 2, "expected the active log file and at least one backup")
info, err := os.Stat(path)
require.NoError(t, err)
require.LessOrEqual(t, info.Size(), int64(1024*1024))
}
func TestNewFileMaxBackups(t *testing.T) {
t.Parallel()
dir := t.TempDir()
path := filepath.Join(dir, "windows_exporter.log")
logger, closer, err := New(newConfig(t, path, Rotation{MaxSize: 1, MaxBackups: 2}))
require.NoError(t, err)
// Rotates at least four times; only the two newest backups are kept.
writeMegabytes(logger, 5)
require.NoError(t, closer.Close())
entries, err := os.ReadDir(dir)
require.NoError(t, err)
require.Len(t, entries, 3, "expected the active log file and two backups")
}
func TestNewFileUnwritable(t *testing.T) {
t.Parallel()
// The parent of the log file is a file, so the log file can't be created.
parent := filepath.Join(t.TempDir(), "not-a-directory")
require.NoError(t, os.WriteFile(parent, nil, 0o600))
path := filepath.Join(parent, "windows_exporter.log")
for name, rotation := range map[string]Rotation{
"without rotation": {},
"with rotation": {MaxSize: 1},
} {
t.Run(name, func(t *testing.T) {
t.Parallel()
_, _, err := New(newConfig(t, path, rotation))
require.ErrorContains(t, err, "failed to open log file")
})
}
}
func TestNewRotationValidation(t *testing.T) {
t.Parallel()
path := filepath.Join(t.TempDir(), "windows_exporter.log")
for name, tc := range map[string]struct {
file string
rotation Rotation
err string
}{
"stream": {"stdout", Rotation{MaxSize: 10}, "requires log.file to be a file path"},
"no max size": {path, Rotation{MaxBackups: 3}, "requires log.rotation.max-size"},
"negative size": {path, Rotation{MaxSize: -1}, "max-size must not be negative"},
"negative backups": {path, Rotation{MaxSize: 1, MaxBackups: -1}, "max-backups must not be negative"},
} {
t.Run(name, func(t *testing.T) {
t.Parallel()
_, _, err := New(newConfig(t, tc.file, tc.rotation))
require.ErrorContains(t, err, tc.err)
})
}
}
func TestAllowedFileSetEventLogIsLazy(t *testing.T) {
t.Parallel()
path := filepath.Join(t.TempDir(), "windows_exporter.log")
// The service default is replaced by --log.file: Set must not open the
// event log, or the handle would never be closed.
file := &AllowedFile{}
require.NoError(t, file.Set(eventLogFile))
require.Nil(t, file.w)
require.False(t, file.isPath())
require.NoError(t, file.Set(path))
require.True(t, file.isPath())
logger, closer, err := New(&Config{Config: &promslog.Config{}, File: file})
require.NoError(t, err)
logger.Info("hello")
require.NoError(t, closer.Close())
require.Contains(t, readFile(t, path), "hello")
}
func TestNewEventLog(t *testing.T) {
t.Parallel()
logger, closer, err := New(newConfig(t, eventLogFile, Rotation{}))
require.NoError(t, err)
require.NotNil(t, logger)
require.NotNil(t, closer, "the event log handle must be released")
require.NoError(t, closer.Close())
_, _, err = New(newConfig(t, eventLogFile, Rotation{MaxSize: 1}))
require.ErrorContains(t, err, "requires log.file to be a file path")
}
func TestNewStreamHasNoCloser(t *testing.T) {
t.Parallel()
_, closer, err := New(newConfig(t, "stderr", Rotation{}))
require.NoError(t, err)
require.Nil(t, closer)
}