Initial commit: logcorrelator with unified packaging (DEB + RPM using fpm)
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
224
internal/config/config_test.go
Normal file
224
internal/config/config_test.go
Normal file
@ -0,0 +1,224 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestLoad_ValidConfig(t *testing.T) {
|
||||
content := `
|
||||
# Test configuration
|
||||
service.name logcorrelator
|
||||
service.language go
|
||||
|
||||
input.unix_socket apache_source /var/run/logcorrelator/apache.sock json
|
||||
input.unix_socket network_source /var/run/logcorrelator/network.sock json
|
||||
|
||||
output.file.enabled true
|
||||
output.file.path /var/log/logcorrelator/correlated.log
|
||||
|
||||
output.clickhouse.enabled false
|
||||
output.clickhouse.dsn clickhouse://user:pass@localhost:9000/db
|
||||
output.clickhouse.table correlated_logs
|
||||
|
||||
correlation.key src_ip,src_port
|
||||
correlation.time_window.value 1
|
||||
correlation.time_window.unit s
|
||||
|
||||
correlation.orphan_policy.apache_always_emit true
|
||||
correlation.orphan_policy.network_emit false
|
||||
`
|
||||
|
||||
tmpDir := t.TempDir()
|
||||
configPath := filepath.Join(tmpDir, "config.conf")
|
||||
if err := os.WriteFile(configPath, []byte(content), 0644); err != nil {
|
||||
t.Fatalf("failed to write config: %v", err)
|
||||
}
|
||||
|
||||
cfg, err := Load(configPath)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if cfg.Service.Name != "logcorrelator" {
|
||||
t.Errorf("expected service name logcorrelator, got %s", cfg.Service.Name)
|
||||
}
|
||||
if len(cfg.Inputs.UnixSockets) != 2 {
|
||||
t.Errorf("expected 2 unix sockets, got %d", len(cfg.Inputs.UnixSockets))
|
||||
}
|
||||
if !cfg.Outputs.File.Enabled {
|
||||
t.Error("expected file output enabled")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoad_InvalidPath(t *testing.T) {
|
||||
_, err := Load("/nonexistent/path/config.conf")
|
||||
if err == nil {
|
||||
t.Error("expected error for nonexistent path")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoad_InvalidDirective(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
configPath := filepath.Join(tmpDir, "config.conf")
|
||||
content := `invalid.directive value`
|
||||
if err := os.WriteFile(configPath, []byte(content), 0644); err != nil {
|
||||
t.Fatalf("failed to write config: %v", err)
|
||||
}
|
||||
|
||||
_, err := Load(configPath)
|
||||
if err == nil {
|
||||
t.Error("expected error for invalid directive")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoad_Comments(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
configPath := filepath.Join(tmpDir, "config.conf")
|
||||
content := `
|
||||
# This is a comment
|
||||
service.name logcorrelator
|
||||
# Another comment
|
||||
input.unix_socket test /tmp/test.sock json
|
||||
input.unix_socket test2 /tmp/test2.sock json
|
||||
output.file.enabled true
|
||||
`
|
||||
if err := os.WriteFile(configPath, []byte(content), 0644); err != nil {
|
||||
t.Fatalf("failed to write config: %v", err)
|
||||
}
|
||||
|
||||
cfg, err := Load(configPath)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if cfg.Service.Name != "logcorrelator" {
|
||||
t.Errorf("expected service name logcorrelator, got %s", cfg.Service.Name)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidate_MinimumInputs(t *testing.T) {
|
||||
cfg := &Config{
|
||||
Inputs: InputsConfig{
|
||||
UnixSockets: []UnixSocketConfig{
|
||||
{Name: "only_one", Path: "/tmp/test.sock"},
|
||||
},
|
||||
},
|
||||
Outputs: OutputsConfig{
|
||||
File: FileOutputConfig{Enabled: true},
|
||||
},
|
||||
}
|
||||
|
||||
err := cfg.Validate()
|
||||
if err == nil {
|
||||
t.Error("expected error for less than 2 inputs")
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidate_AtLeastOneOutput(t *testing.T) {
|
||||
cfg := &Config{
|
||||
Inputs: InputsConfig{
|
||||
UnixSockets: []UnixSocketConfig{
|
||||
{Name: "a", Path: "/tmp/a.sock"},
|
||||
{Name: "b", Path: "/tmp/b.sock"},
|
||||
},
|
||||
},
|
||||
Outputs: OutputsConfig{
|
||||
File: FileOutputConfig{Enabled: false},
|
||||
ClickHouse: ClickHouseOutputConfig{Enabled: false},
|
||||
Stdout: StdoutOutputConfig{Enabled: false},
|
||||
},
|
||||
}
|
||||
|
||||
err := cfg.Validate()
|
||||
if err == nil {
|
||||
t.Error("expected error for no outputs enabled")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetTimeWindow(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
config CorrelationConfig
|
||||
expected time.Duration
|
||||
}{
|
||||
{
|
||||
name: "seconds",
|
||||
config: CorrelationConfig{
|
||||
TimeWindow: TimeWindowConfig{Value: 1, Unit: "s"},
|
||||
},
|
||||
expected: time.Second,
|
||||
},
|
||||
{
|
||||
name: "milliseconds",
|
||||
config: CorrelationConfig{
|
||||
TimeWindow: TimeWindowConfig{Value: 500, Unit: "ms"},
|
||||
},
|
||||
expected: 500 * time.Millisecond,
|
||||
},
|
||||
{
|
||||
name: "minutes",
|
||||
config: CorrelationConfig{
|
||||
TimeWindow: TimeWindowConfig{Value: 2, Unit: "m"},
|
||||
},
|
||||
expected: 2 * time.Minute,
|
||||
},
|
||||
{
|
||||
name: "default",
|
||||
config: CorrelationConfig{
|
||||
TimeWindow: TimeWindowConfig{},
|
||||
},
|
||||
expected: time.Second,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := tt.config.GetTimeWindow()
|
||||
if result != tt.expected {
|
||||
t.Errorf("expected %v, got %v", tt.expected, result)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseBool(t *testing.T) {
|
||||
tests := []struct {
|
||||
input string
|
||||
expected bool
|
||||
hasError bool
|
||||
}{
|
||||
{"true", true, false},
|
||||
{"True", true, false},
|
||||
{"TRUE", true, false},
|
||||
{"yes", true, false},
|
||||
{"1", true, false},
|
||||
{"on", true, false},
|
||||
{"false", false, false},
|
||||
{"False", false, false},
|
||||
{"no", false, false},
|
||||
{"0", false, false},
|
||||
{"off", false, false},
|
||||
{"invalid", false, true},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.input, func(t *testing.T) {
|
||||
result, err := parseBool(tt.input)
|
||||
if tt.hasError {
|
||||
if err == nil {
|
||||
t.Error("expected error, got nil")
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
if result != tt.expected {
|
||||
t.Errorf("expected %v, got %v", tt.expected, result)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user