mirror of
https://github.com/lukaszraczylo/kubemirror.git
synced 2026-07-06 21:34:33 +00:00
improvements jan2025 (#6)
* feat(controller): add lazy watcher, improve resource usage and add pattern validation - [x] Add cache sync health check for readiness probe verification - [x] Create namespace lister with API reader support for fresh label queries - [x] Add pattern validation with warning logs for invalid glob patterns - [x] Implement lazy watcher initialization mode to scan for active resources - [x] Add requeue delay to namespace reconciler for cache settlement - [x] Replace custom containsString with slices.Contains from stdlib - [x] Add structured logging context to reconcilers (kind, group, version) - [x] Improve error variable naming for clarity in nested conditions - [x] Add nil-safe label access in namespace reconciler setup - [x] Add APIReader to namespace and source reconcilers for fresh data - [x] Improve type assertions with proper error handling in mirror operations - [x] Reorder struct fields for consistency and readability - [x] Add comprehensive pattern validation tests and validation API * feat(controller): add lazy watcher, improve resource usage and add pattern validation - [x] Add circuit breaker for reconciliation failure tracking and prevention - [x] Implement granular registration state tracking (not-registered, source-only, fully-registered) - [x] Add lazy controller initialization for active resource types only - [x] Consolidate namespace listing into single API call for efficiency - [x] Add mirror creation verification to catch webhook rejections - [x] Implement high-cardinality resource detection and warnings - [x] Add source deletion check in mirror reconciler to prevent races - [x] Preserve transformation annotations on errors in mirror reconciliation - [x] Expand constants documentation with labels vs annotations design rationale - [x] Add comprehensive test coverage for circuit breaker and registration states - [x] Add mutation-safety tests for hash computation * fixup! feat(controller): add lazy watcher, improve resource usage and add pattern validation
This commit is contained in:
+115
-2
@@ -168,12 +168,12 @@ func TestComputeContentHash_ConfigMap(t *testing.T) {
|
||||
name: "binaryData included in hash",
|
||||
cm1: &corev1.ConfigMap{
|
||||
BinaryData: map[string][]byte{
|
||||
"file": []byte{0x00, 0x01, 0x02},
|
||||
"file": {0x00, 0x01, 0x02},
|
||||
},
|
||||
},
|
||||
cm2: &corev1.ConfigMap{
|
||||
BinaryData: map[string][]byte{
|
||||
"file": []byte{0x00, 0x01, 0xFF},
|
||||
"file": {0x00, 0x01, 0xFF},
|
||||
},
|
||||
},
|
||||
wantSame: false,
|
||||
@@ -484,6 +484,119 @@ func mustComputeHash(t *testing.T, obj runtime.Object) string {
|
||||
return hash
|
||||
}
|
||||
|
||||
// TestComputeContentHash_NoMutation verifies that hash computation doesn't mutate the input object.
|
||||
// This is critical because NestedMap can modify the underlying map.
|
||||
func TestComputeContentHash_NoMutation(t *testing.T) {
|
||||
t.Run("unstructured object is not mutated", func(t *testing.T) {
|
||||
// Create an unstructured object with nested spec
|
||||
original := &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "Custom",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "test-resource",
|
||||
"namespace": "default",
|
||||
"annotations": map[string]interface{}{
|
||||
constants.AnnotationTransform: `{"rules":[{"field":"spec.value","action":"base64encode"}]}`,
|
||||
},
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"field1": "value1",
|
||||
"nested": map[string]interface{}{
|
||||
"deep": "data",
|
||||
},
|
||||
},
|
||||
"status": map[string]interface{}{
|
||||
"condition": "Ready",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// Deep copy the original to compare after hash computation
|
||||
expectedCopy := original.DeepCopy()
|
||||
|
||||
// Compute hash multiple times
|
||||
hash1, err := ComputeContentHash(original)
|
||||
require.NoError(t, err)
|
||||
|
||||
hash2, err := ComputeContentHash(original)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Hashes should be consistent (object wasn't modified)
|
||||
assert.Equal(t, hash1, hash2, "hash should be consistent across calls")
|
||||
|
||||
// Original object should be unchanged
|
||||
assert.Equal(t, expectedCopy.Object, original.Object, "original object should not be mutated")
|
||||
})
|
||||
|
||||
t.Run("secret is not mutated", func(t *testing.T) {
|
||||
secret := &corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-secret",
|
||||
Namespace: "default",
|
||||
Annotations: map[string]string{
|
||||
constants.AnnotationTransform: `{"rules":[]}`,
|
||||
},
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"password": []byte("secret123"),
|
||||
},
|
||||
Type: corev1.SecretTypeOpaque,
|
||||
}
|
||||
|
||||
// Copy for comparison
|
||||
originalData := make(map[string][]byte)
|
||||
for k, v := range secret.Data {
|
||||
originalData[k] = append([]byte(nil), v...)
|
||||
}
|
||||
originalAnnotations := make(map[string]string)
|
||||
for k, v := range secret.Annotations {
|
||||
originalAnnotations[k] = v
|
||||
}
|
||||
|
||||
// Compute hash
|
||||
_, err := ComputeContentHash(secret)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify no mutation
|
||||
assert.Equal(t, originalData, secret.Data, "secret data should not be mutated")
|
||||
assert.Equal(t, originalAnnotations, secret.Annotations, "secret annotations should not be mutated")
|
||||
})
|
||||
|
||||
t.Run("configmap is not mutated", func(t *testing.T) {
|
||||
cm := &corev1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-cm",
|
||||
Namespace: "default",
|
||||
},
|
||||
Data: map[string]string{
|
||||
"config.yaml": "key: value",
|
||||
},
|
||||
BinaryData: map[string][]byte{
|
||||
"binary": {0x00, 0x01, 0x02},
|
||||
},
|
||||
}
|
||||
|
||||
// Copy for comparison
|
||||
originalData := make(map[string]string)
|
||||
for k, v := range cm.Data {
|
||||
originalData[k] = v
|
||||
}
|
||||
originalBinaryData := make(map[string][]byte)
|
||||
for k, v := range cm.BinaryData {
|
||||
originalBinaryData[k] = append([]byte(nil), v...)
|
||||
}
|
||||
|
||||
// Compute hash
|
||||
_, err := ComputeContentHash(cm)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify no mutation
|
||||
assert.Equal(t, originalData, cm.Data, "configmap data should not be mutated")
|
||||
assert.Equal(t, originalBinaryData, cm.BinaryData, "configmap binary data should not be mutated")
|
||||
})
|
||||
}
|
||||
|
||||
// Benchmark tests
|
||||
func BenchmarkComputeContentHash_Secret(b *testing.B) {
|
||||
secret := &corev1.Secret{
|
||||
|
||||
Reference in New Issue
Block a user