- Replace custom directive tests with YAML-based tests - Test valid YAML config loading - Test invalid YAML handling - Test default values with partial YAML config Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
210 lines
4.5 KiB
Go
210 lines
4.5 KiB
Go
package config
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestLoad_ValidConfig(t *testing.T) {
|
|
content := `
|
|
service:
|
|
name: logcorrelator
|
|
language: go
|
|
|
|
inputs:
|
|
unix_sockets:
|
|
- name: apache_source
|
|
path: /var/run/logcorrelator/apache.sock
|
|
format: json
|
|
- name: network_source
|
|
path: /var/run/logcorrelator/network.sock
|
|
format: json
|
|
|
|
outputs:
|
|
file:
|
|
enabled: true
|
|
path: /var/log/logcorrelator/correlated.log
|
|
clickhouse:
|
|
enabled: false
|
|
dsn: clickhouse://user:pass@localhost:9000/db
|
|
table: correlated_logs
|
|
|
|
correlation:
|
|
key:
|
|
- src_ip
|
|
- src_port
|
|
time_window:
|
|
value: 1
|
|
unit: s
|
|
orphan_policy:
|
|
apache_always_emit: true
|
|
network_emit: false
|
|
`
|
|
|
|
tmpDir := t.TempDir()
|
|
configPath := filepath.Join(tmpDir, "config.yml")
|
|
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.yml")
|
|
if err == nil {
|
|
t.Error("expected error for nonexistent path")
|
|
}
|
|
}
|
|
|
|
func TestLoad_InvalidYAML(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
configPath := filepath.Join(tmpDir, "config.yml")
|
|
content := `invalid: yaml: content: [`
|
|
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 YAML")
|
|
}
|
|
}
|
|
|
|
func TestLoad_DefaultValues(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
configPath := filepath.Join(tmpDir, "config.yml")
|
|
content := `
|
|
service:
|
|
name: test-service
|
|
inputs:
|
|
unix_sockets:
|
|
- name: a
|
|
path: /tmp/a.sock
|
|
- name: b
|
|
path: /tmp/b.sock
|
|
outputs:
|
|
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 != "test-service" {
|
|
t.Errorf("expected service name test-service, got %s", cfg.Service.Name)
|
|
}
|
|
// Check defaults
|
|
if cfg.Correlation.TimeWindow.Value != 1 {
|
|
t.Errorf("expected default time window value 1, got %d", cfg.Correlation.TimeWindow.Value)
|
|
}
|
|
if cfg.Correlation.OrphanPolicy.ApacheAlwaysEmit != true {
|
|
t.Error("expected default apache_always_emit to be true")
|
|
}
|
|
}
|
|
|
|
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)
|
|
}
|
|
})
|
|
}
|
|
}
|