github.com/NVIDIA/aistore@v1.3.23-0.20240517131212-7df6609be51d/fs/walk_test.go (about) 1 // Package fs provides mountpath and FQN abstractions and methods to resolve/map stored content 2 /* 3 * Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved. 4 */ 5 package fs_test 6 7 import ( 8 "math/rand" 9 "os" 10 "path/filepath" 11 "reflect" 12 "sort" 13 "testing" 14 15 "github.com/NVIDIA/aistore/api/apc" 16 "github.com/NVIDIA/aistore/cmn" 17 "github.com/NVIDIA/aistore/cmn/cos" 18 "github.com/NVIDIA/aistore/core/mock" 19 "github.com/NVIDIA/aistore/fs" 20 "github.com/NVIDIA/aistore/tools" 21 "github.com/NVIDIA/aistore/tools/tassert" 22 ) 23 24 func TestWalkBck(t *testing.T) { 25 var ( 26 bck = cmn.Bck{Name: "name", Provider: apc.AIS} 27 tests = []struct { 28 name string 29 mpathCnt int 30 sorted bool 31 }{ 32 {name: "simple_sorted", mpathCnt: 1, sorted: true}, 33 {name: "10mpaths_sorted", mpathCnt: 10, sorted: true}, 34 } 35 ) 36 37 for _, test := range tests { 38 t.Run(test.name, func(t *testing.T) { 39 fs.TestNew(mock.NewIOS()) 40 fs.CSM.Reg(fs.ObjectType, &fs.ObjectContentResolver{}, true) 41 42 mpaths := make([]string, 0, test.mpathCnt) 43 defer func() { 44 for _, mpath := range mpaths { 45 os.RemoveAll(mpath) 46 } 47 }() 48 49 for range test.mpathCnt { 50 mpath, err := os.MkdirTemp("", "testwalk") 51 tassert.CheckFatal(t, err) 52 53 err = cos.CreateDir(mpath) 54 tassert.CheckFatal(t, err) 55 56 _, err = fs.Add(mpath, "daeID") 57 tassert.CheckFatal(t, err) 58 59 mpaths = append(mpaths, mpath) 60 } 61 62 avail, _ := fs.Get() 63 var fileNames []string 64 for _, mpath := range avail { 65 dir := mpath.MakePathCT(&bck, fs.ObjectType) 66 err := cos.CreateDir(dir) 67 tassert.CheckFatal(t, err) 68 69 _, names := tools.PrepareDirTree(t, tools.DirTreeDesc{ 70 InitDir: dir, 71 Dirs: rand.Int()%100 + 1, 72 Files: rand.Int()%100 + 1, 73 Depth: rand.Int()%4 + 1, 74 Empty: false, 75 }) 76 fileNames = append(fileNames, names...) 77 } 78 79 var ( 80 objs = make([]string, 0, 100) 81 fqns = make([]string, 0, 100) 82 ) 83 err := fs.WalkBck(&fs.WalkBckOpts{ 84 WalkOpts: fs.WalkOpts{ 85 Bck: bck, 86 CTs: []string{fs.ObjectType}, 87 Callback: func(fqn string, _ fs.DirEntry) error { 88 var parsed fs.ParsedFQN 89 err := parsed.Init(fqn) 90 tassert.CheckError(t, err) 91 objs = append(objs, parsed.ObjName) 92 fqns = append(fqns, fqn) 93 return nil 94 }, 95 Sorted: test.sorted, 96 }, 97 }) 98 tassert.CheckFatal(t, err) 99 100 sorted := sort.IsSorted(sort.StringSlice(objs)) 101 tassert.Fatalf(t, sorted == test.sorted, "expected the output to be sorted=%t", test.sorted) 102 103 sort.Strings(fqns) 104 sort.Strings(fileNames) 105 tassert.Fatalf(t, reflect.DeepEqual(fqns, fileNames), "found objects don't match expected objects") 106 }) 107 } 108 } 109 110 func TestWalkBckSkipDir(t *testing.T) { 111 rnd := cos.NowRand() 112 type ( 113 mpathMeta struct { 114 total int 115 done bool 116 } 117 ) 118 119 var ( 120 bck = cmn.Bck{Name: "name", Provider: apc.AIS} 121 mpathCnt = 5 + rnd.Int()%5 122 minObjectsCnt = 10 123 mpaths = make(map[string]*mpathMeta) 124 ) 125 126 fs.TestNew(mock.NewIOS()) 127 fs.CSM.Reg(fs.ObjectType, &fs.ObjectContentResolver{}, true) 128 129 defer func() { 130 for mpath := range mpaths { 131 os.RemoveAll(mpath) 132 } 133 }() 134 135 for range mpathCnt { 136 mpath, err := os.MkdirTemp("", "testwalk") 137 tassert.CheckFatal(t, err) 138 139 err = cos.CreateDir(mpath) 140 tassert.CheckFatal(t, err) 141 142 _, err = fs.Add(mpath, "daeID") 143 tassert.CheckFatal(t, err) 144 mpaths[mpath] = &mpathMeta{total: 0, done: false} 145 } 146 147 avail, _ := fs.Get() 148 for _, mpath := range avail { 149 dir := mpath.MakePathCT(&bck, fs.ObjectType) 150 err := cos.CreateDir(dir) 151 tassert.CheckFatal(t, err) 152 153 totalFilesCnt := rand.Int()%100 + minObjectsCnt 154 for range totalFilesCnt { 155 f, err := os.CreateTemp(dir, "") 156 tassert.CheckFatal(t, err) 157 f.Close() 158 } 159 } 160 161 fqns := make([]string, 0, 100) 162 err := fs.WalkBck(&fs.WalkBckOpts{ 163 WalkOpts: fs.WalkOpts{ 164 Bck: bck, 165 CTs: []string{fs.ObjectType}, 166 Callback: func(fqn string, _ fs.DirEntry) error { 167 fqns = append(fqns, fqn) 168 return nil 169 }, 170 Sorted: true, 171 }, 172 ValidateCb: func(fqn string, de fs.DirEntry) error { 173 var parsed fs.ParsedFQN 174 if de.IsDir() { 175 return nil 176 } 177 err := parsed.Init(fqn) 178 tassert.CheckError(t, err) 179 cos.Assert(!mpaths[parsed.Mountpath.Path].done) 180 if rand.Int()%10 == 0 { 181 mpaths[parsed.Mountpath.Path].done = true 182 return filepath.SkipDir 183 } 184 mpaths[parsed.Mountpath.Path].total++ 185 return nil 186 }, 187 }) 188 tassert.CheckFatal(t, err) 189 190 expectedTotal := 0 191 for _, meta := range mpaths { 192 expectedTotal += meta.total 193 } 194 tassert.Fatalf(t, expectedTotal == len(fqns), "expected %d objects, got %d", expectedTotal, len(fqns)) 195 }