hako/internal/archival/rules/extractors_test.go
2026-01-12 19:35:18 +01:00

180 lines
4.6 KiB
Go

package rules
import (
"encoding/json"
"testing"
)
func TestArchiversCanBeNull(t *testing.T) {
tests := []struct {
name string
json string
wantNil bool
check func(t *testing.T, rule Rule)
}{
{
name: "mimetype rule with null extractors",
json: `{"mimetype": "text/html", "extractors": null}`,
wantNil: true,
check: func(t *testing.T, rule Rule) {
mr, ok := rule.(*MimetypeRule)
if !ok {
t.Fatalf("expected MimetypeRule, got %T", rule)
}
if mr.Archivers != nil {
t.Errorf("Archivers = %v, want nil", mr.Archivers)
}
},
},
{
name: "mimetype rule without extractors field",
json: `{"mimetype": "text/html"}`,
wantNil: true,
check: func(t *testing.T, rule Rule) {
mr, ok := rule.(*MimetypeRule)
if !ok {
t.Fatalf("expected MimetypeRule, got %T", rule)
}
if mr.Archivers != nil {
t.Errorf("Archivers = %v, want nil", mr.Archivers)
}
},
},
{
name: "hostname rule with null extractors",
json: `{"hostname": "example.com", "extractors": null}`,
wantNil: true,
check: func(t *testing.T, rule Rule) {
hr, ok := rule.(*HostnameRule)
if !ok {
t.Fatalf("expected HostnameRule, got %T", rule)
}
if hr.Archivers != nil {
t.Errorf("Archivers = %v, want nil", hr.Archivers)
}
},
},
{
name: "mimetype rule with extractors",
json: `{"mimetype": "text/html", "extractors": [{"key": "obelisk"}]}`,
wantNil: false,
check: func(t *testing.T, rule Rule) {
mr, ok := rule.(*MimetypeRule)
if !ok {
t.Fatalf("expected MimetypeRule, got %T", rule)
}
if mr.Archivers == nil {
t.Error("Archivers is nil, want non-nil")
}
if len(mr.Archivers) != 1 || mr.Archivers[0].Key != "obelisk" {
t.Errorf("Archivers = %v, want [{key: obelisk}]", mr.Archivers)
}
},
},
{
name: "and rule with null extractors in child",
json: `{"and": [{"mimetype": "text/html"}], "extractors": [{"key": "obelisk"}]}`,
wantNil: false,
check: func(t *testing.T, rule Rule) {
ar, ok := rule.(*AndRule)
if !ok {
t.Fatalf("expected AndRule, got %T", rule)
}
if len(ar.Rules) != 1 {
t.Errorf("Rules length = %d, want 1", len(ar.Rules))
}
// Child rule should have nil extractors
mr, ok := ar.Rules[0].(*MimetypeRule)
if !ok {
t.Fatalf("expected MimetypeRule child, got %T", ar.Rules[0])
}
if mr.Archivers != nil {
t.Errorf("Child rule Archivers = %v, want nil", mr.Archivers)
}
// Root rule should have extractors
if ar.Archivers == nil {
t.Error("Root rule Archivers is nil, want non-nil")
}
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
rule, err := UnmarshalRule([]byte(tt.json))
if err != nil {
t.Fatalf("UnmarshalRule() error = %v", err)
}
if rule == nil {
t.Fatal("UnmarshalRule() returned nil rule")
}
if tt.check != nil {
tt.check(t, rule)
}
})
}
}
func TestArchiversOmitEmpty(t *testing.T) {
// Test that rules without extractors don't include the field in JSON
tests := []struct {
name string
rule Rule
check func(t *testing.T, jsonStr string)
}{
{
name: "mimetype rule without extractors",
rule: &MimetypeRule{
Mimetype: "text/html",
Archivers: nil,
},
check: func(t *testing.T, jsonStr string) {
// Should not contain "extractors" field when nil
if jsonStr == "" {
t.Error("JSON is empty")
}
// When extractors is nil and omitempty is set, it should be omitted
// But Go's json package will include null if the field is explicitly set
// Let's check that it's either omitted or null
hasExtractors := contains(jsonStr, "extractors")
if hasExtractors && !contains(jsonStr, `"extractors":null`) {
t.Errorf("JSON contains extractors but not as null: %s", jsonStr)
}
},
},
{
name: "hostname rule without extractors",
rule: &HostnameRule{
Hostname: "example.com",
Archivers: nil,
},
check: func(t *testing.T, jsonStr string) {
hasExtractors := contains(jsonStr, "extractors")
if hasExtractors && !contains(jsonStr, `"extractors":null`) {
t.Errorf("JSON contains extractors but not as null: %s", jsonStr)
}
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
jsonBytes, err := json.Marshal(tt.rule)
if err != nil {
t.Fatalf("Marshal() error = %v", err)
}
if tt.check != nil {
tt.check(t, string(jsonBytes))
}
})
}
}
func contains(s, substr string) bool {
for i := 0; i <= len(s)-len(substr); i++ {
if s[i:i+len(substr)] == substr {
return true
}
}
return false
}