github.com/cozy/cozy-stack@v0.0.0-20240603063001-31110fa4cae1/model/move/export_test.go (about) 1 package move 2 3 import ( 4 "math/rand" 5 "path" 6 "testing" 7 "time" 8 9 "github.com/cozy/cozy-stack/model/vfs" 10 "github.com/cozy/cozy-stack/pkg/config/config" 11 "github.com/cozy/cozy-stack/pkg/consts" 12 "github.com/cozy/cozy-stack/pkg/couchdb" 13 "github.com/cozy/cozy-stack/pkg/crypto" 14 "github.com/cozy/cozy-stack/tests/testutils" 15 "github.com/stretchr/testify/assert" 16 ) 17 18 type Stats struct { 19 TotalSize int64 20 Dirs map[string]struct{} 21 Files map[string][]byte 22 } 23 24 func TestExport(t *testing.T) { 25 if testing.Short() { 26 t.Skip("an instance is required for this test: test skipped due to the use of --short flag") 27 } 28 29 seed := time.Now().UTC().Unix() 30 t.Logf("seed = %d\n", seed) 31 rand.Seed(seed) 32 config.UseTestFile(t) 33 setup := testutils.NewSetup(t, t.Name()) 34 inst := setup.GetTestInstance() 35 36 t.Run("ExportFiles", func(t *testing.T) { 37 fs := inst.VFS() 38 39 // The partsSize is voluntary really small to have a lot of parts, 40 // which can help to test the edge cases 41 exportDoc := &ExportDoc{ 42 PartsSize: 10, 43 } 44 45 nbFiles := rand.Intn(100) 46 root, err := fs.DirByID(consts.RootDirID) 47 assert.NoError(t, err) 48 populateTree(t, fs, root, nbFiles) 49 50 nbVersions, err := couchdb.CountNormalDocs(inst, consts.FilesVersions) 51 assert.NoError(t, err) 52 53 // /* Uncomment this section for debug */ 54 // vfs.Walk(fs, root.Fullpath, func(fpath string, dir *vfs.DirDoc, file *vfs.FileDoc, err error) error { 55 // if err != nil { 56 // return err 57 // } 58 // if fpath == root.Fullpath { 59 // return nil 60 // } 61 // level := strings.Count(fpath, "/") 62 // for i := 0; i < level; i++ { 63 // if i == level-1 { 64 // _, err = t.Logf("└── ") 65 // } else { 66 // _, err = t.Logf("| ") 67 // } 68 // if err != nil { 69 // return err 70 // } 71 // } 72 // if dir != nil { 73 // _, err = t.Log(dir.DocName) 74 // } else { 75 // _, err = t.Loff("%s (%d)\n", file.DocName, file.ByteSize) 76 // } 77 // return err 78 // }) 79 // t.Logf("nb files = %d\n", nbFiles) 80 81 // Build the cursors 82 _, err = exportFiles(inst, exportDoc, nil) 83 assert.NoError(t, err) 84 85 // Check files 86 cursors := append(exportDoc.PartsCursors, "") 87 fileIDs := map[string]bool{} 88 for _, c := range cursors { 89 cursor, err := ParseCursor(exportDoc, c) 90 assert.NoError(t, err) 91 list, err := listFilesFromCursor(inst, exportDoc, cursor) 92 assert.NoError(t, err) 93 for _, f := range list { 94 assert.False(t, fileIDs[f.DocID]) 95 fileIDs[f.DocID] = true 96 } 97 } 98 assert.Len(t, fileIDs, nbFiles) 99 100 // Check file versions 101 versionsIDs := map[string]bool{} 102 for _, c := range cursors { 103 cursor, err := ParseCursor(exportDoc, c) 104 assert.NoError(t, err) 105 list, err := listVersionsFromCursor(inst, exportDoc, cursor) 106 assert.NoError(t, err) 107 for _, v := range list { 108 assert.False(t, versionsIDs[v.DocID]) 109 versionsIDs[v.DocID] = true 110 } 111 } 112 assert.Len(t, versionsIDs, nbVersions) 113 }) 114 } 115 116 func createFile(t *testing.T, fs vfs.VFS, parent *vfs.DirDoc) { 117 size := 1 + rand.Intn(25) 118 name := crypto.GenerateRandomString(8) 119 doc, err := vfs.NewFileDoc(name, parent.DocID, -1, nil, "application/octet-stream", "application", time.Now(), false, false, false, nil) 120 assert.NoError(t, err) 121 doc.CozyMetadata = vfs.NewCozyMetadata("") 122 file, err := fs.CreateFile(doc, nil) 123 assert.NoError(t, err) 124 buf := make([]byte, size) 125 _, err = file.Write(buf) 126 assert.NoError(t, err) 127 assert.NoError(t, file.Close()) 128 129 // Create some file versions 130 nb := rand.Intn(3) 131 for i := 0; i < nb; i++ { 132 size = 1 + rand.Intn(25) 133 olddoc := doc.Clone().(*vfs.FileDoc) 134 doc.CozyMetadata = olddoc.CozyMetadata.Clone() 135 doc.CozyMetadata.UpdatedAt = doc.CozyMetadata.UpdatedAt.Add(1 * time.Hour) 136 doc.MD5Sum = nil 137 doc.ByteSize = int64(size) 138 file, err = fs.CreateFile(doc, olddoc) 139 assert.NoError(t, err) 140 buf := make([]byte, size) 141 _, err = file.Write(buf) 142 assert.NoError(t, err) 143 assert.NoError(t, file.Close()) 144 } 145 } 146 147 func populateTree(t *testing.T, fs vfs.VFS, parent *vfs.DirDoc, nb int) { 148 nbDirs := rand.Intn(5) 149 if nbDirs > nb { 150 nbDirs %= (nb + 1) 151 } 152 153 // Create the sub-directories 154 for i := 0; i < nbDirs; i++ { 155 name := crypto.GenerateRandomString(6) 156 fullpath := path.Join(parent.Fullpath, name) 157 dir, err := vfs.Mkdir(fs, fullpath, nil) 158 assert.NoError(t, err) 159 nbFiles := rand.Intn(nb) 160 populateTree(t, fs, dir, nbFiles) 161 nb -= nbFiles 162 } 163 164 // Create some files 165 for j := 0; j < nb; j++ { 166 createFile(t, fs, parent) 167 } 168 }