mirror of
https://github.com/stakater/Reloader.git
synced 2026-08-20 04:26:28 +00:00
Per review: instead of logging the skipped pattern inside ShouldReload (which lacks workload identity), collect the compile errors on ReloadCheckResult.Errors and log them at the upgrade call site, where the resource name, type, and namespace are known. Add a test for the multi-value case where one comma-separated pattern is malformed and a valid one still matches.
278 lines
9.2 KiB
Go
278 lines
9.2 KiB
Go
package common
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/stakater/Reloader/internal/pkg/options"
|
|
)
|
|
|
|
func TestShouldReload_IgnoredWorkloadTypes(t *testing.T) {
|
|
// Save original state
|
|
originalWorkloadTypes := options.WorkloadTypesToIgnore
|
|
defer func() {
|
|
options.WorkloadTypesToIgnore = originalWorkloadTypes
|
|
}()
|
|
|
|
tests := []struct {
|
|
name string
|
|
ignoredWorkloadTypes []string
|
|
resourceType string
|
|
shouldReload bool
|
|
description string
|
|
}{
|
|
{
|
|
name: "Jobs ignored - Job should not reload",
|
|
ignoredWorkloadTypes: []string{"jobs"},
|
|
resourceType: "Job",
|
|
shouldReload: false,
|
|
description: "When jobs are ignored, Job resources should not be reloaded",
|
|
},
|
|
{
|
|
name: "Jobs ignored - CronJob should reload",
|
|
ignoredWorkloadTypes: []string{"jobs"},
|
|
resourceType: "CronJob",
|
|
shouldReload: true,
|
|
description: "When jobs are ignored, CronJob resources should still be processed",
|
|
},
|
|
{
|
|
name: "CronJobs ignored - CronJob should not reload",
|
|
ignoredWorkloadTypes: []string{"cronjobs"},
|
|
resourceType: "CronJob",
|
|
shouldReload: false,
|
|
description: "When cronjobs are ignored, CronJob resources should not be reloaded",
|
|
},
|
|
{
|
|
name: "CronJobs ignored - Job should reload",
|
|
ignoredWorkloadTypes: []string{"cronjobs"},
|
|
resourceType: "Job",
|
|
shouldReload: true,
|
|
description: "When cronjobs are ignored, Job resources should still be processed",
|
|
},
|
|
{
|
|
name: "Both ignored - Job should not reload",
|
|
ignoredWorkloadTypes: []string{"jobs", "cronjobs"},
|
|
resourceType: "Job",
|
|
shouldReload: false,
|
|
description: "When both are ignored, Job resources should not be reloaded",
|
|
},
|
|
{
|
|
name: "Both ignored - CronJob should not reload",
|
|
ignoredWorkloadTypes: []string{"jobs", "cronjobs"},
|
|
resourceType: "CronJob",
|
|
shouldReload: false,
|
|
description: "When both are ignored, CronJob resources should not be reloaded",
|
|
},
|
|
{
|
|
name: "Both ignored - Deployment should reload",
|
|
ignoredWorkloadTypes: []string{"jobs", "cronjobs"},
|
|
resourceType: "Deployment",
|
|
shouldReload: true,
|
|
description: "When both are ignored, other workload types should still be processed",
|
|
},
|
|
{
|
|
name: "None ignored - Job should reload",
|
|
ignoredWorkloadTypes: []string{},
|
|
resourceType: "Job",
|
|
shouldReload: true,
|
|
description: "When nothing is ignored, all workload types should be processed",
|
|
},
|
|
{
|
|
name: "None ignored - CronJob should reload",
|
|
ignoredWorkloadTypes: []string{},
|
|
resourceType: "CronJob",
|
|
shouldReload: true,
|
|
description: "When nothing is ignored, all workload types should be processed",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
// Set the ignored workload types
|
|
options.WorkloadTypesToIgnore = tt.ignoredWorkloadTypes
|
|
|
|
// Create minimal test config and options
|
|
config := Config{
|
|
ResourceName: "test-resource",
|
|
Annotation: "configmap.reloader.stakater.com/reload",
|
|
}
|
|
|
|
annotations := Map{
|
|
"configmap.reloader.stakater.com/reload": "test-config",
|
|
}
|
|
|
|
// Create ReloaderOptions with the ignored workload types
|
|
opts := &ReloaderOptions{
|
|
WorkloadTypesToIgnore: tt.ignoredWorkloadTypes,
|
|
AutoReloadAll: true, // Enable auto-reload to simplify test
|
|
ReloaderAutoAnnotation: "reloader.stakater.com/auto",
|
|
}
|
|
|
|
// Call ShouldReload
|
|
result := ShouldReload(config, tt.resourceType, annotations, Map{}, opts)
|
|
|
|
// Check the result
|
|
if result.ShouldReload != tt.shouldReload {
|
|
t.Errorf("For resource type %s with ignored types %v, expected ShouldReload=%v, got=%v",
|
|
tt.resourceType, tt.ignoredWorkloadTypes, tt.shouldReload, result.ShouldReload)
|
|
}
|
|
|
|
t.Logf("✓ %s", tt.description)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestShouldReload_IgnoredWorkloadTypes_ValidationError(t *testing.T) {
|
|
// Save original state
|
|
originalWorkloadTypes := options.WorkloadTypesToIgnore
|
|
defer func() {
|
|
options.WorkloadTypesToIgnore = originalWorkloadTypes
|
|
}()
|
|
|
|
// Test with invalid workload type - should still continue processing
|
|
options.WorkloadTypesToIgnore = []string{"invalid"}
|
|
|
|
config := Config{
|
|
ResourceName: "test-resource",
|
|
Annotation: "configmap.reloader.stakater.com/reload",
|
|
}
|
|
|
|
annotations := Map{
|
|
"configmap.reloader.stakater.com/reload": "test-config",
|
|
}
|
|
|
|
opts := &ReloaderOptions{
|
|
WorkloadTypesToIgnore: []string{"invalid"},
|
|
AutoReloadAll: true, // Enable auto-reload to simplify test
|
|
ReloaderAutoAnnotation: "reloader.stakater.com/auto",
|
|
}
|
|
|
|
// Should not panic and should continue with normal processing
|
|
result := ShouldReload(config, "Job", annotations, Map{}, opts)
|
|
|
|
// Since validation failed, it should continue with normal processing (should reload)
|
|
if !result.ShouldReload {
|
|
t.Errorf("Expected ShouldReload=true when validation fails, got=%v", result.ShouldReload)
|
|
}
|
|
}
|
|
|
|
// Test that validates the fix for issue #996
|
|
func TestShouldReload_IssueRBACPermissionFixed(t *testing.T) {
|
|
// Save original state
|
|
originalWorkloadTypes := options.WorkloadTypesToIgnore
|
|
defer func() {
|
|
options.WorkloadTypesToIgnore = originalWorkloadTypes
|
|
}()
|
|
|
|
tests := []struct {
|
|
name string
|
|
ignoredWorkloadTypes []string
|
|
resourceType string
|
|
description string
|
|
}{
|
|
{
|
|
name: "Issue #996 - ignoreJobs prevents Job processing",
|
|
ignoredWorkloadTypes: []string{"jobs"},
|
|
resourceType: "Job",
|
|
description: "Job resources are skipped entirely, preventing RBAC permission errors",
|
|
},
|
|
{
|
|
name: "Issue #996 - ignoreCronJobs prevents CronJob processing",
|
|
ignoredWorkloadTypes: []string{"cronjobs"},
|
|
resourceType: "CronJob",
|
|
description: "CronJob resources are skipped entirely, preventing RBAC permission errors",
|
|
},
|
|
{
|
|
name: "Issue #996 - both ignored prevent both types",
|
|
ignoredWorkloadTypes: []string{"jobs", "cronjobs"},
|
|
resourceType: "Job",
|
|
description: "Job resources are skipped entirely when both types are ignored",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
// Set the ignored workload types
|
|
options.WorkloadTypesToIgnore = tt.ignoredWorkloadTypes
|
|
|
|
config := Config{
|
|
ResourceName: "test-resource",
|
|
Annotation: "configmap.reloader.stakater.com/reload",
|
|
}
|
|
|
|
annotations := Map{
|
|
"configmap.reloader.stakater.com/reload": "test-config",
|
|
}
|
|
|
|
opts := &ReloaderOptions{
|
|
WorkloadTypesToIgnore: tt.ignoredWorkloadTypes,
|
|
AutoReloadAll: true, // Enable auto-reload to simplify test
|
|
ReloaderAutoAnnotation: "reloader.stakater.com/auto",
|
|
}
|
|
|
|
// Call ShouldReload
|
|
result := ShouldReload(config, tt.resourceType, annotations, Map{}, opts)
|
|
|
|
// Should not reload when workload type is ignored
|
|
if result.ShouldReload {
|
|
t.Errorf("Expected ShouldReload=false for ignored workload type %s, got=%v",
|
|
tt.resourceType, result.ShouldReload)
|
|
}
|
|
|
|
t.Logf("✓ %s", tt.description)
|
|
})
|
|
}
|
|
}
|
|
|
|
// A malformed regex in a named reload annotation must not panic the operator.
|
|
// Regression test: previously regexp.MustCompile("^"+value+"$") panicked on an
|
|
// invalid pattern, crashing Reloader cluster-wide (no recover on the worker).
|
|
func TestShouldReload_InvalidRegexAnnotation_DoesNotPanic(t *testing.T) {
|
|
config := Config{
|
|
ResourceName: "app-config",
|
|
Annotation: "secret.reloader.stakater.com/reload",
|
|
}
|
|
annotations := Map{
|
|
// unbalanced bracket => invalid regex
|
|
"secret.reloader.stakater.com/reload": "app-config[",
|
|
}
|
|
opts := &ReloaderOptions{
|
|
ReloaderAutoAnnotation: "reloader.stakater.com/auto",
|
|
}
|
|
|
|
// Before the fix this panicked inside ShouldReload.
|
|
result := ShouldReload(config, "Deployment", annotations, Map{}, opts)
|
|
|
|
if result.ShouldReload {
|
|
t.Errorf("Expected ShouldReload=false for an invalid regex pattern, got=%v", result.ShouldReload)
|
|
}
|
|
if len(result.Errors) != 1 {
|
|
t.Errorf("Expected 1 surfaced regex error, got=%d: %v", len(result.Errors), result.Errors)
|
|
}
|
|
}
|
|
|
|
// When a named reload annotation holds several comma-separated patterns, a
|
|
// single malformed one is skipped while a valid one still matches, and the
|
|
// skipped pattern's error is surfaced on the result.
|
|
func TestShouldReload_InvalidRegexAnnotation_SkipsMalformedPattern(t *testing.T) {
|
|
config := Config{
|
|
ResourceName: "app-config",
|
|
Annotation: "secret.reloader.stakater.com/reload",
|
|
}
|
|
annotations := Map{
|
|
// first pattern is invalid (unbalanced bracket), second matches
|
|
"secret.reloader.stakater.com/reload": "bad[,app-config",
|
|
}
|
|
opts := &ReloaderOptions{
|
|
ReloaderAutoAnnotation: "reloader.stakater.com/auto",
|
|
}
|
|
|
|
result := ShouldReload(config, "Deployment", annotations, Map{}, opts)
|
|
|
|
if !result.ShouldReload {
|
|
t.Errorf("Expected ShouldReload=true from the valid pattern, got=%v", result.ShouldReload)
|
|
}
|
|
if len(result.Errors) != 1 {
|
|
t.Errorf("Expected the malformed pattern to surface 1 error, got=%d: %v", len(result.Errors), result.Errors)
|
|
}
|
|
}
|