@@ -3,6 +3,7 @@ package utils
33import (
44 "context"
55 "encoding/json"
6+ "fmt"
67 "log"
78 "os"
89 "path/filepath"
@@ -186,6 +187,102 @@ func TestLoadGroupedManifestsFromPath(t *testing.T) {
186187
187188}
188189
190+ func TestLoadGroupedManifestsFromPathWithNumericSorting (t * testing.T ) {
191+ // Create temporary directory
192+ tmpDir , err := os .MkdirTemp ("" , "restore-numeric-test" )
193+ if err != nil {
194+ t .Fatalf ("Failed to create temporary directory: %v" , err )
195+ }
196+ defer os .RemoveAll (tmpDir )
197+
198+ // Create restores directory
199+ restoreDir := filepath .Join (tmpDir , "manifests" )
200+ if err := os .MkdirAll (restoreDir , 0755 ); err != nil {
201+ t .Fatalf ("Failed to create restore directory: %v" , err )
202+ }
203+
204+ // Create 12 subdirectories to test numeric sorting (restore1 through restore12)
205+ // This tests the bug where restore10, restore11, restore12 would come before restore2 with alphabetical sorting
206+ for i := 1 ; i <= 12 ; i ++ {
207+ restoreSubDir := filepath .Join (restoreDir , fmt .Sprintf ("restore%d" , i ))
208+ if err := os .Mkdir (restoreSubDir , 0755 ); err != nil {
209+ t .Fatalf ("Failed to create restore subdirectory %d: %v" , i , err )
210+ }
211+
212+ // Create a restore file in each subdirectory
213+ restoreFile := filepath .Join (restoreSubDir , fmt .Sprintf ("1_default-restore%d.yaml" , i ))
214+ content := fmt .Sprintf ("apiVersion: velero.io/v1\n kind: Restore\n metadata:\n name: restore%d\n spec:\n backupName: backup%d\n " , i , i )
215+ if err := os .WriteFile (restoreFile , []byte (content ), 0644 ); err != nil {
216+ t .Fatalf ("Failed to create restore file %d: %v" , i , err )
217+ }
218+ }
219+
220+ manifests , err := LoadGroupedManifestsFromPath (restoreDir , & logr.Logger {})
221+ if err != nil {
222+ t .Fatalf ("Failed to load restores: %v" , err )
223+ }
224+
225+ // Verify we have 12 groups
226+ assert .Equal (t , 12 , len (manifests ), "Expected 12 restore groups" )
227+
228+ // Verify each group has 1 manifest and they are in the correct numeric order
229+ for i := 0 ; i < 12 ; i ++ {
230+ assert .Equal (t , 1 , len (manifests [i ]), "Expected 1 manifest in group %d" , i )
231+
232+ // Verify the restore name matches the expected numeric order
233+ expectedName := fmt .Sprintf ("restore%d" , i + 1 )
234+ actualName := manifests [i ][0 ].GetName ()
235+ assert .Equal (t , expectedName , actualName ,
236+ "Expected restore at index %d to be %s but got %s" , i , expectedName , actualName )
237+ }
238+ }
239+
240+ func TestExtractTrailingNumber (t * testing.T ) {
241+ testcases := []struct {
242+ name string
243+ input string
244+ expected int
245+ }{
246+ {
247+ name : "single digit" ,
248+ input : "restore1" ,
249+ expected : 1 ,
250+ },
251+ {
252+ name : "double digit" ,
253+ input : "restore10" ,
254+ expected : 10 ,
255+ },
256+ {
257+ name : "triple digit" ,
258+ input : "restore123" ,
259+ expected : 123 ,
260+ },
261+ {
262+ name : "no number" ,
263+ input : "restore" ,
264+ expected : 0 ,
265+ },
266+ {
267+ name : "number in middle" ,
268+ input : "restore1test" ,
269+ expected : 0 ,
270+ },
271+ {
272+ name : "group prefix" ,
273+ input : "group2" ,
274+ expected : 2 ,
275+ },
276+ }
277+
278+ for _ , tc := range testcases {
279+ t .Run (tc .name , func (t * testing.T ) {
280+ result := extractTrailingNumber (tc .input )
281+ assert .Equal (t , tc .expected , result )
282+ })
283+ }
284+ }
285+
189286func TestReadSeedReconfigurationFromFile (t * testing.T ) {
190287 type dummySeedReconfiguration struct {
191288 seedreconfig.SeedReconfiguration
0 commit comments