github.com/yankunsam/loki/v2@v2.6.3-0.20220817130409-389df5235c27/pkg/storage/chunk/client/local/fs_object_client_test.go (about) 1 package local 2 3 import ( 4 "bytes" 5 "context" 6 "io/ioutil" 7 "os" 8 "path" 9 "path/filepath" 10 "strings" 11 "testing" 12 "time" 13 14 "github.com/stretchr/testify/require" 15 16 "github.com/grafana/loki/pkg/storage/chunk/client/util" 17 ) 18 19 func TestFSObjectClient_DeleteChunksBefore(t *testing.T) { 20 deleteFilesOlderThan := 10 * time.Minute 21 22 fsChunksDir := t.TempDir() 23 24 bucketClient, err := NewFSObjectClient(FSConfig{ 25 Directory: fsChunksDir, 26 }) 27 require.NoError(t, err) 28 29 file1 := "file1" 30 file2 := "file2" 31 32 // Creating dummy files 33 require.NoError(t, os.Chdir(fsChunksDir)) 34 35 f, err := os.Create(file1) 36 require.NoError(t, err) 37 require.NoError(t, f.Close()) 38 39 f, err = os.Create(file2) 40 require.NoError(t, err) 41 require.NoError(t, f.Close()) 42 43 // Verify whether all files are created 44 files, _ := ioutil.ReadDir(".") 45 require.Equal(t, 2, len(files), "Number of files should be 2") 46 47 // No files should be deleted, since all of them are not much older 48 require.NoError(t, bucketClient.DeleteChunksBefore(context.Background(), time.Now().Add(-deleteFilesOlderThan))) 49 files, _ = ioutil.ReadDir(".") 50 require.Equal(t, 2, len(files), "Number of files should be 2") 51 52 // Changing mtime of file1 to make it look older 53 require.NoError(t, os.Chtimes(file1, time.Now().Add(-deleteFilesOlderThan), time.Now().Add(-deleteFilesOlderThan))) 54 require.NoError(t, bucketClient.DeleteChunksBefore(context.Background(), time.Now().Add(-deleteFilesOlderThan))) 55 56 // Verifying whether older file got deleted 57 files, _ = ioutil.ReadDir(".") 58 require.Equal(t, 1, len(files), "Number of files should be 1 after enforcing retention") 59 } 60 61 func TestFSObjectClient_List(t *testing.T) { 62 fsObjectsDir := t.TempDir() 63 64 bucketClient, err := NewFSObjectClient(FSConfig{ 65 Directory: fsObjectsDir, 66 }) 67 require.NoError(t, err) 68 69 allFiles := []string{ 70 "outer-file1", 71 "outer-file2", 72 "folder1/file1", 73 "folder1/file2", 74 "folder2/file3", 75 "folder2/file4", 76 "folder2/file5", 77 "deeply/nested/folder/a", 78 "deeply/nested/folder/b", 79 "deeply/nested/folder/c", 80 } 81 82 topLevelFolders := map[string]bool{} 83 topLevelFiles := map[string]bool{} 84 filesInTopLevelFolders := map[string]map[string]bool{} 85 86 for _, f := range allFiles { 87 require.NoError(t, bucketClient.PutObject(context.Background(), f, bytes.NewReader([]byte(f)))) 88 89 s := strings.Split(f, "/") 90 if len(s) > 1 { 91 topLevelFolders[s[0]] = true 92 } else { 93 topLevelFiles[s[0]] = true 94 } 95 96 if len(s) == 2 { 97 if filesInTopLevelFolders[s[0]] == nil { 98 filesInTopLevelFolders[s[0]] = map[string]bool{} 99 } 100 filesInTopLevelFolders[s[0]][s[1]] = true 101 } 102 } 103 104 // create an empty directory which should get excluded from the list 105 require.NoError(t, util.EnsureDirectory(filepath.Join(fsObjectsDir, "empty-folder"))) 106 107 storageObjects, commonPrefixes, err := bucketClient.List(context.Background(), "", "/") 108 require.NoError(t, err) 109 110 require.Len(t, storageObjects, len(topLevelFiles)) 111 for _, so := range storageObjects { 112 require.True(t, topLevelFiles[so.Key]) 113 } 114 115 require.Len(t, commonPrefixes, len(topLevelFolders)) 116 for _, commonPrefix := range commonPrefixes { 117 require.True(t, topLevelFolders[string(commonPrefix)[:len(commonPrefix)-1]]) // 1 to remove "/" separator. 118 } 119 120 for folder, files := range filesInTopLevelFolders { 121 storageObjects, commonPrefixes, err := bucketClient.List(context.Background(), folder, "/") 122 require.NoError(t, err) 123 124 require.Len(t, storageObjects, len(files)) 125 for _, so := range storageObjects { 126 require.True(t, strings.HasPrefix(so.Key, folder+"/")) 127 require.True(t, files[path.Base(so.Key)]) 128 } 129 130 require.Len(t, commonPrefixes, 0) 131 } 132 133 // List everything from the top, recursively. 134 storageObjects, commonPrefixes, err = bucketClient.List(context.Background(), "", "") 135 require.NoError(t, err) 136 137 // Since delimiter is empty, there are no commonPrefixes. 138 require.Empty(t, commonPrefixes) 139 140 var storageObjectPaths []string 141 for _, so := range storageObjects { 142 storageObjectPaths = append(storageObjectPaths, so.Key) 143 } 144 require.ElementsMatch(t, allFiles, storageObjectPaths) 145 146 storageObjects, commonPrefixes, err = bucketClient.List(context.Background(), "doesnt_exist", "") 147 require.NoError(t, err) 148 require.Empty(t, storageObjects) 149 require.Empty(t, commonPrefixes) 150 151 storageObjects, commonPrefixes, err = bucketClient.List(context.Background(), "outer-file1", "") 152 require.NoError(t, err) 153 require.Len(t, storageObjects, 1) 154 require.Equal(t, "outer-file1", storageObjects[0].Key) 155 require.Empty(t, commonPrefixes) 156 } 157 158 func TestFSObjectClient_DeleteObject(t *testing.T) { 159 fsObjectsDir := t.TempDir() 160 161 bucketClient, err := NewFSObjectClient(FSConfig{ 162 Directory: fsObjectsDir, 163 }) 164 require.NoError(t, err) 165 166 foldersWithFiles := make(map[string][]string) 167 foldersWithFiles["folder1"] = []string{"file1", "file2"} 168 169 for folder, files := range foldersWithFiles { 170 for _, filename := range files { 171 err := bucketClient.PutObject(context.Background(), path.Join(folder, filename), bytes.NewReader([]byte(filename))) 172 require.NoError(t, err) 173 } 174 } 175 176 // let us check if we have right folders created 177 _, commonPrefixes, err := bucketClient.List(context.Background(), "", "/") 178 require.NoError(t, err) 179 require.Len(t, commonPrefixes, len(foldersWithFiles)) 180 181 // let us delete file1 from folder1 and check that file1 is gone but folder1 with file2 is still there 182 require.NoError(t, bucketClient.DeleteObject(context.Background(), path.Join("folder1", "file1"))) 183 _, err = os.Stat(filepath.Join(fsObjectsDir, filepath.Join("folder1", "file1"))) 184 require.True(t, os.IsNotExist(err)) 185 186 _, err = os.Stat(filepath.Join(fsObjectsDir, filepath.Join("folder1", "file2"))) 187 require.NoError(t, err) 188 189 // let us delete second file as well and check that folder1 also got removed 190 require.NoError(t, bucketClient.DeleteObject(context.Background(), path.Join("folder1", "file2"))) 191 _, err = os.Stat(filepath.Join(fsObjectsDir, "folder1")) 192 require.True(t, os.IsNotExist(err)) 193 194 _, err = os.Stat(fsObjectsDir) 195 require.NoError(t, err) 196 197 // let us see ensure folder2 is still there will all the files: 198 /*files, commonPrefixes, err := bucketClient.List(context.Background(), "folder2/") 199 require.NoError(t, err) 200 require.Len(t, commonPrefixes, 0) 201 require.Len(t, files, len(foldersWithFiles["folder2/"]))*/ 202 }