diff --git a/internal/controllers/reconciliation/edgecase_test.go b/internal/controllers/reconciliation/edgecase_test.go index c86ad6d3..1fa806f6 100644 --- a/internal/controllers/reconciliation/edgecase_test.go +++ b/internal/controllers/reconciliation/edgecase_test.go @@ -2,8 +2,10 @@ package reconciliation import ( "context" + "fmt" "sync/atomic" "testing" + "time" "github.com/stretchr/testify/require" "k8s.io/apimachinery/pkg/api/errors" @@ -139,3 +141,81 @@ func TestEmptySynthesis(t *testing.T) { return errors.IsNotFound(upstream.Get(ctx, client.ObjectKeyFromObject(comp), comp)) }) } + +func TestLargeNamespaceDeletion(t *testing.T) { + ctx := testutil.NewContext(t) + mgr := testutil.NewManager(t) + upstream := mgr.GetClient() + + registerControllers(t, mgr) + ns := &unstructured.Unstructured{ + Object: map[string]any{ + "apiVersion": "v1", + "kind": "Namespace", + "metadata": map[string]any{ + "name": "test", + }, + }, + } + testutil.WithFakeExecutor(t, mgr, func(ctx context.Context, s *apiv1.Synthesizer, input *krmv1.ResourceList) (*krmv1.ResourceList, error) { + output := &krmv1.ResourceList{} + output.Items = []*unstructured.Unstructured{ns} + + for i := 0; i < 500; i++ { + cm := &unstructured.Unstructured{ + Object: map[string]any{ + "apiVersion": "v1", + "kind": "ConfigMap", + "metadata": map[string]any{ + "name": fmt.Sprintf("test-%d", i), + "namespace": ns.GetName(), + }, + }, + } + output.Items = append(output.Items, cm) + } + + return output, nil + }) + + setupTestSubject(t, mgr) + mgr.Start(t) + _, comp := writeGenericComposition(t, upstream) + + testutil.Eventually(t, func() bool { + err := upstream.Get(ctx, client.ObjectKeyFromObject(comp), comp) + return err == nil && comp.Status.CurrentSynthesis != nil && comp.Status.CurrentSynthesis.Ready != nil + }) + + go func() { + for i := 0; i < 500; i++ { + cm := &unstructured.Unstructured{ + Object: map[string]any{ + "apiVersion": "v1", + "kind": "ConfigMap", + "metadata": map[string]any{ + "name": fmt.Sprintf("test-%d", i), + "namespace": ns.GetName(), + }, + }, + } + t.Logf("deleting configmap %s", cm.GetName()) + err := mgr.DownstreamClient.Delete(ctx, cm) + require.NoError(t, client.IgnoreNotFound(err)) + time.Sleep(time.Millisecond * 3) + } + }() + + require.NoError(t, upstream.Delete(ctx, comp)) + + testutil.Eventually(t, func() bool { + err := upstream.Get(ctx, client.ObjectKeyFromObject(comp), comp) + if errors.IsNotFound(err) { + t.Logf("deleted!") + return true + } + t.Logf("composition deleting=%t", comp.DeletionTimestamp != nil) + return false + }) + t.Logf("done!") +}