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  }