From ce360b40338146102c684549b9cb26b805a7c973 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Fri, 8 May 2026 23:20:03 +0800 Subject: [PATCH] Use string.Builder to concatenate string in loop. * Fix TestFindVolumeRestoresForPodLegacy error. * Stablize the TestExecute case in pvc_action_test.go * Use toolchain to set the specific version for go. Signed-off-by: Xun Jiang --- go.mod | 4 +- pkg/backup/actions/csi/pvc_action_test.go | 37 +++++++++++++------ ...d_volume_restore_controller_legacy_test.go | 5 +-- pkg/util/csi/volume_snapshot.go | 7 ++-- pkg/util/kube/pod.go | 17 +++++---- pkg/util/kube/pvc_pv.go | 7 ++-- 6 files changed, 48 insertions(+), 29 deletions(-) diff --git a/go.mod b/go.mod index fed96a3c6..ceaa1f5f9 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,8 @@ module github.com/vmware-tanzu/velero -go 1.25.9 +go 1.25.0 + +toolchain go1.25.10 require ( cloud.google.com/go/storage v1.57.2 diff --git a/pkg/backup/actions/csi/pvc_action_test.go b/pkg/backup/actions/csi/pvc_action_test.go index 9ffe20be5..4cada562f 100644 --- a/pkg/backup/actions/csi/pvc_action_test.go +++ b/pkg/backup/actions/csi/pvc_action_test.go @@ -227,33 +227,42 @@ func TestExecute(t *testing.T) { pvcMap, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&tc.pvc) require.NoError(t, err) + var reconcileErrCh chan error if tc.pvc != nil && !tc.failVSCreate && !tc.skipVSReadyUpdate { + reconcileErrCh = make(chan error, 1) go func() { var vsList snapshotv1api.VolumeSnapshotList - err := wait.PollUntilContextTimeout(t.Context(), 1*time.Second, 10*time.Second, true, func(ctx context.Context) (bool, error) { - err = pvcBIA.crClient.List(ctx, &vsList, &crclient.ListOptions{Namespace: tc.pvc.Namespace}) - - require.NoError(t, err) - if err != nil || len(vsList.Items) == 0 { + err := wait.PollUntilContextTimeout(t.Context(), 100*time.Millisecond, 10*time.Second, true, func(ctx context.Context) (bool, error) { + if err := pvcBIA.crClient.List(ctx, &vsList, &crclient.ListOptions{Namespace: tc.pvc.Namespace}); err != nil { return false, err } + if len(vsList.Items) == 0 { + return false, nil + } return true, nil }) + if err != nil { + reconcileErrCh <- err + return + } - require.NoError(t, err) vscName := "testVSC" + handleName := "testHandle" + vsc := builder.ForVolumeSnapshotContent(vscName).Status(&snapshotv1api.VolumeSnapshotContentStatus{SnapshotHandle: &handleName}).Result() + err = pvcBIA.crClient.Create(t.Context(), vsc) + if err != nil { + reconcileErrCh <- err + return + } + + // Update VS status only after VSC exists to avoid racing with Execute's VSC lookup. readyToUse := true vsList.Items[0].Status = &snapshotv1api.VolumeSnapshotStatus{ BoundVolumeSnapshotContentName: &vscName, ReadyToUse: &readyToUse, } err = pvcBIA.crClient.Update(t.Context(), &vsList.Items[0]) - require.NoError(t, err) - - handleName := "testHandle" - vsc := builder.ForVolumeSnapshotContent("testVSC").Status(&snapshotv1api.VolumeSnapshotContentStatus{SnapshotHandle: &handleName}).Result() - err = pvcBIA.crClient.Create(t.Context(), vsc) - require.NoError(t, err) + reconcileErrCh <- err }() } @@ -274,6 +283,10 @@ func TestExecute(t *testing.T) { require.NoError(t, err) } + if reconcileErrCh != nil { + require.NoError(t, <-reconcileErrCh) + } + if tc.expectedDataUpload != nil { dataUploadList := new(velerov2alpha1.DataUploadList) err := crClient.List(t.Context(), dataUploadList, &crclient.ListOptions{LabelSelector: labels.SelectorFromSet(map[string]string{velerov1api.BackupNameLabel: tc.backup.Name})}) diff --git a/pkg/controller/pod_volume_restore_controller_legacy_test.go b/pkg/controller/pod_volume_restore_controller_legacy_test.go index a107603e0..4e52a1707 100644 --- a/pkg/controller/pod_volume_restore_controller_legacy_test.go +++ b/pkg/controller/pod_volume_restore_controller_legacy_test.go @@ -35,18 +35,17 @@ func TestFindVolumeRestoresForPodLegacy(t *testing.T) { scheme := runtime.NewScheme() scheme.AddKnownTypes(velerov1api.SchemeGroupVersion, &velerov1api.PodVolumeRestore{}, &velerov1api.PodVolumeRestoreList{}) - clientBuilder := fake.NewClientBuilder().WithScheme(scheme) // no matching PVR reconciler := &PodVolumeRestoreReconcilerLegacy{ - Client: clientBuilder.Build(), + Client: fake.NewClientBuilder().WithScheme(scheme).Build(), logger: logrus.New(), } requests := reconciler.findVolumeRestoresForPod(t.Context(), pod) assert.Empty(t, requests) // contain one matching PVR - reconciler.Client = clientBuilder.WithLists(&velerov1api.PodVolumeRestoreList{ + reconciler.Client = fake.NewClientBuilder().WithScheme(scheme).WithLists(&velerov1api.PodVolumeRestoreList{ Items: []velerov1api.PodVolumeRestore{ { ObjectMeta: metav1.ObjectMeta{ diff --git a/pkg/util/csi/volume_snapshot.go b/pkg/util/csi/volume_snapshot.go index d8e44e522..a58f9b223 100644 --- a/pkg/util/csi/volume_snapshot.go +++ b/pkg/util/csi/volume_snapshot.go @@ -740,17 +740,18 @@ func DiagnoseVS(vs *snapshotv1api.VolumeSnapshot, events *corev1api.EventList) s } } - diag := fmt.Sprintf("VS %s/%s, bind to %s, readyToUse %v, errMessage %s\n", vs.Namespace, vs.Name, vscName, readyToUse, errMessage) + var diag strings.Builder + _, _ = fmt.Fprintf(&diag, "VS %s/%s, bind to %s, readyToUse %v, errMessage %s\n", vs.Namespace, vs.Name, vscName, readyToUse, errMessage) if events != nil { for _, e := range events.Items { if e.InvolvedObject.UID == vs.UID && e.Type == corev1api.EventTypeWarning { - diag += fmt.Sprintf("VS event reason %s, message %s\n", e.Reason, e.Message) + _, _ = fmt.Fprintf(&diag, "VS event reason %s, message %s\n", e.Reason, e.Message) } } } - return diag + return diag.String() } func DiagnoseVSC(vsc *snapshotv1api.VolumeSnapshotContent) string { diff --git a/pkg/util/kube/pod.go b/pkg/util/kube/pod.go index 4ff05b43e..9a59f926f 100644 --- a/pkg/util/kube/pod.go +++ b/pkg/util/kube/pod.go @@ -20,6 +20,7 @@ import ( "fmt" "io" "os" + "strings" "time" "github.com/pkg/errors" @@ -183,16 +184,17 @@ func GetPodContainerTerminateMessage(pod *corev1api.Pod, container string) strin // GetPodTerminateMessage returns the terminate message for all containers of a pod func GetPodTerminateMessage(pod *corev1api.Pod) string { - message := "" + //message := "" + var message strings.Builder for _, containerStatus := range pod.Status.ContainerStatuses { if containerStatus.State.Terminated != nil { if containerStatus.State.Terminated.Message != "" { - message += containerStatus.State.Terminated.Message + "/" + _, _ = fmt.Fprintf(&message, "%s/", containerStatus.State.Terminated.Message) } } } - return message + return message.String() } func getPodLogReader(ctx context.Context, podGetter corev1client.CoreV1Interface, pod string, namespace string, logOptions *corev1api.PodLogOptions) (io.ReadCloser, error) { @@ -272,21 +274,22 @@ func ToSystemAffinity(loadAffinity *LoadAffinity, volumeTopology *corev1api.Node } func DiagnosePod(pod *corev1api.Pod, events *corev1api.EventList) string { - diag := fmt.Sprintf("Pod %s/%s, phase %s, node name %s, message %s\n", pod.Namespace, pod.Name, pod.Status.Phase, pod.Spec.NodeName, pod.Status.Message) + var diag strings.Builder + _, _ = fmt.Fprintf(&diag, "Pod %s/%s, phase %s, node name %s, message %s\n", pod.Namespace, pod.Name, pod.Status.Phase, pod.Spec.NodeName, pod.Status.Message) for _, condition := range pod.Status.Conditions { - diag += fmt.Sprintf("Pod condition %s, status %s, reason %s, message %s\n", condition.Type, condition.Status, condition.Reason, condition.Message) + _, _ = fmt.Fprintf(&diag, "Pod condition %s, status %s, reason %s, message %s\n", condition.Type, condition.Status, condition.Reason, condition.Message) } if events != nil { for _, e := range events.Items { if e.InvolvedObject.UID == pod.UID && e.Type == corev1api.EventTypeWarning { - diag += fmt.Sprintf("Pod event reason %s, message %s\n", e.Reason, e.Message) + _, _ = fmt.Fprintf(&diag, "Pod event reason %s, message %s\n", e.Reason, e.Message) } } } - return diag + return diag.String() } var funcExit = os.Exit diff --git a/pkg/util/kube/pvc_pv.go b/pkg/util/kube/pvc_pv.go index d5d2e2041..fa886bf60 100644 --- a/pkg/util/kube/pvc_pv.go +++ b/pkg/util/kube/pvc_pv.go @@ -464,17 +464,18 @@ func GetPVCForPodVolume(vol *corev1api.Volume, pod *corev1api.Pod, crClient crcl } func DiagnosePVC(pvc *corev1api.PersistentVolumeClaim, events *corev1api.EventList) string { - diag := fmt.Sprintf("PVC %s/%s, phase %s, binding to %s\n", pvc.Namespace, pvc.Name, pvc.Status.Phase, pvc.Spec.VolumeName) + var diag strings.Builder + _, _ = fmt.Fprintf(&diag, "PVC %s/%s, phase %s, binding to %s\n", pvc.Namespace, pvc.Name, pvc.Status.Phase, pvc.Spec.VolumeName) if events != nil { for _, e := range events.Items { if e.InvolvedObject.UID == pvc.UID && e.Type == corev1api.EventTypeWarning { - diag += fmt.Sprintf("PVC event reason %s, message %s\n", e.Reason, e.Message) + _, _ = fmt.Fprintf(&diag, "PVC event reason %s, message %s\n", e.Reason, e.Message) } } } - return diag + return diag.String() } func DiagnosePV(pv *corev1api.PersistentVolume) string {