Repository: apecloud/kubeblocks

Issue:
[BUG] A flaky test
Two recent cases:
https://github.com/apecloud/kubeblocks/actions/runs/15605479252/job/43953866983?pr=9400
https://github.com/apecloud/kubeblocks/actions/runs/15605506016/job/43953952545?pr=9404

The error message is:
```
• [PANICKED] [0.076 seconds]
Component Controller [BeforeEach] system account disable
  [BeforeEach] /home/runner/work/kubeblocks/kubeblocks/controllers/apps/component/component_controller_test.go:119
  [It] /home/runner/work/kubeblocks/kubeblocks/controllers/apps/component/component_controller_test.go:1693

  Timeline >>
  STEP: clean resources @ 09/03/25 07:25:09.024
  STEP: clear resources Component @ 09/03/25 07:25:09.024
  STEP: clear resources ComponentDefinition @ 09/03/25 07:25:09.027
  STEP: clear resources ComponentVersion @ 09/03/25 07:25:09.034
  STEP: clear resources ServiceAccount @ 09/03/25 07:25:09.037
  STEP: clear resources Role @ 09/03/25 07:25:09.043
  STEP: clear resources RoleBinding @ 09/03/25 07:25:09.048
  [PANICKED] in [BeforeEach] - /home/runner/go/pkg/mod/github.com/onsi/gomega@v1.36.3/internal/async_assertion.go:321 @ 09/03/25 07:25:09.056
  STEP: clean resources @ 09/03/25 07:25:09.056
  STEP: clear resources Component @ 09/03/25 07:25:09.056
  STEP: clear resources ComponentDefinition @ 09/03/25 07:25:09.059
  STEP: clear resources ComponentVersion @ 09/03/25 07:25:09.064
  STEP: clear resources ServiceAccount @ 09/03/25 07:25:09.07
  STEP: clear resources Role @ 09/03/25 07:25:09.078
  STEP: clear resources RoleBinding @ 09/03/25 07:25:09.081
  STEP: clear resources Pod @ 09/03/25 07:25:09.087
  STEP: clear resources PersistentVolumeClaim @ 09/03/25 07:25:09.091
  STEP: clear resources ConfigMap @ 09/03/25 07:25:09.093
  STEP: clear resources StorageClass @ 09/03/25 07:25:09.098
  << Timeline

  [PANICKED] Test Panicked
  In [BeforeEach] at: /home/runner/go/pkg/mod/github.com/onsi/gomega@v1.36.3/internal/async_assertion.go:321 @ 09/03/25 07:25:09.056

  expected DeletionTimestamp is not nil, obj: {"metadata":{"name":"kb-test-compdef-pod","namespace":"default","uid":"a52d5dc8-45c4-4678-b251-e071a9fe63aa","resourceVersion":"1389","creationTimestamp":"2025-09-03T07:25:09Z","labels":{"app.kubernetes.io/instance":"test-clusterwuhreq","app.kubernetes.io/managed-by":"kubeblocks","apps.kubeblocks.io/component-name":"default"},"ownerReferences":[{"apiVersion":"apps.kubeblocks.io/v1","kind":"Component","name":"test-clusterwuhreq-default","uid":"b019eabb-963f-4340-9ae7-e573e52deb14","controller":true,"blockOwnerDeletion":true}],"managedFields":[{"manager":"component.test","operation":"Update","apiVersion":"rbac.authorization.k8s.io/v1","time":"2025-09-03T07:25:09Z","fieldsType":"FieldsV1","fieldsV1":{"f:metadata":{"f:labels":{".":{},"f:app.kubernetes.io/instance":{},"f:app.kubernetes.io/managed-by":{},"f:apps.kubeblocks.io/component-name":{}},"f:ownerReferences":{".":{},"k:{\"uid\":\"b019eabb-963f-4340-9ae7-e573e52deb14\"}":{}}},"f:roleRef":{},"f:subjects":{}}}]},"subjects":[{"kind":"ServiceAccount","name":"kb-test-compdef","namespace":"default"}],"roleRef":{"apiGroup":"rbac.authorization.k8s.io","kind":"ClusterRole","name":"kubeblocks-cluster-pod-role"}}
```

The likely reason is a component's reconciliation in process when the component is deleted with finalizer removed. When a rolebinding is deleted, the old reconciliation re-creates a new rolebinding, thus causing the panic.

Hints from issue comments:
@cjc7373: Another different flaky test: https://github.com/apecloud/kubeblocks/actions/runs/16015636339/job/45181645049@github-actions: This issue has been marked as stale because it has been open for 30 days with no activity

Solution patch:
diff --git a/pkg/unstructured/xml_config.go b/pkg/unstructured/xml_config.go
index 6d4b0f2bc..053f9dc5d 100644
--- a/pkg/unstructured/xml_config.go
+++ b/pkg/unstructured/xml_config.go
@@ -41,6 +41,8 @@ func init() {
 	mxjv2.CastValuesToBool(true)
 	// enable cast to int
 	mxjv2.CastValuesToInt(true)
+	// enable XML escape chars decoder
+	mxjv2.XMLEscapeCharsDecoder()
 
 	CfgObjectRegistry().RegisterConfigCreator(parametersv1alpha1.XML, func(name string) ConfigObject {
 		return &xmlConfig{name: name}



Test patch:
diff --git a/controllers/apps/component/component_controller_test.go b/controllers/apps/component/component_controller_test.go
index b785caf3f..a487fadd4 100644
--- a/controllers/apps/component/component_controller_test.go
+++ b/controllers/apps/component/component_controller_test.go
@@ -98,7 +98,7 @@ var _ = Describe("Component Controller", func() {
 		By("clean resources")
 
 		// delete components (and all dependent sub-resources), and component definitions & versions
-		testapps.ClearComponentResourcesWithRemoveFinalizerOption(&testCtx)
+		testapps.ClearComponentResources(&testCtx)
 
 		// delete rest mocked objects
 		inNS := client.InNamespace(testCtx.DefaultNamespace)
diff --git a/pkg/testutil/apps/common_util.go b/pkg/testutil/apps/common_util.go
index 230f8ae0a..cc8c43d03 100644
--- a/pkg/testutil/apps/common_util.go
+++ b/pkg/testutil/apps/common_util.go
@@ -373,6 +373,14 @@ func ClearClusterResourcesWithRemoveFinalizerOption(testCtx *testutil.TestContex
 	ClearResourcesWithRemoveFinalizerOption(testCtx, intctrlutil.ComponentVersionSignature, true, hasLabels)
 }
 
+func ClearComponentResources(testCtx *testutil.TestContext) {
+	inNs := client.InNamespace(testCtx.DefaultNamespace)
+	hasLabels := client.HasLabels{testCtx.TestObjLabelKey}
+	ClearResources(testCtx, intctrlutil.ComponentSignature, inNs, hasLabels)
+	ClearResources(testCtx, intctrlutil.ComponentDefinitionSignature, hasLabels)
+	ClearResources(testCtx, intctrlutil.ComponentVersionSignature, hasLabels)
+}
+
 // ClearComponentResourcesWithRemoveFinalizerOption clears all dependent resources belonging to existing components.
 func ClearComponentResourcesWithRemoveFinalizerOption(testCtx *testutil.TestContext) {
 	inNs := client.InNamespace(testCtx.DefaultNamespace)