github.com/kubeshop/testkube@v1.17.23/pkg/executor/scraper/filesystem_extractor_test.go (about) 1 package scraper_test 2 3 import ( 4 "bufio" 5 "context" 6 "encoding/json" 7 "io" 8 "os" 9 "path/filepath" 10 "strings" 11 "testing" 12 "time" 13 14 "github.com/kubeshop/testkube/pkg/filesystem" 15 16 "github.com/golang/mock/gomock" 17 "github.com/stretchr/testify/assert" 18 19 "github.com/kubeshop/testkube/pkg/executor/scraper" 20 ) 21 22 func TestRecursiveFilesystemExtractor_Extract(t *testing.T) { 23 t.Parallel() 24 25 ctrl := gomock.NewController(t) 26 defer ctrl.Finish() 27 28 fs := filesystem.NewMockFileSystem(ctrl) 29 fs.EXPECT().Stat("/my/directory").Return(nil, nil) 30 fs.EXPECT().OpenFileBuffered("/my/directory/file1").Return(bufio.NewReader(strings.NewReader("test")), nil) 31 extractor := scraper.NewRecursiveFilesystemExtractor(fs) 32 33 // Set up the expected calls to the mocked fs object 34 fs.EXPECT().Walk("/my/directory", gomock.Any()).Return(nil).DoAndReturn(func(_ string, walkFn filepath.WalkFunc) error { 35 fileInfo := filesystem.MockFileInfo{ 36 FName: "file1", 37 FIsDir: false, 38 } 39 return walkFn("/my/directory/file1", &fileInfo, nil) 40 }) 41 42 processFn := func(ctx context.Context, object *scraper.Object) error { 43 assert.Equal(t, "file1", object.Name) 44 return nil 45 } 46 47 notifyFn := func(ctx context.Context, path string) error { 48 assert.Equal(t, "/my/directory/file1", path) 49 return nil 50 } 51 52 // Call the Extract function 53 err := extractor.Extract(context.Background(), []string{"/my/directory"}, []string{".*"}, processFn, notifyFn) 54 assert.NoErrorf(t, err, "Extract failed: %v", err) 55 } 56 57 func TestArchiveFilesystemExtractor_Extract_NoMeta(t *testing.T) { 58 t.Parallel() 59 60 ctrl := gomock.NewController(t) 61 defer ctrl.Finish() 62 63 fs := filesystem.NewMockFileSystem(ctrl) 64 fs.EXPECT().Stat("/my/directory").Return(nil, nil) 65 testContent := "test" 66 fs.EXPECT().OpenFileBuffered("/my/directory/file1").Return(bufio.NewReader(strings.NewReader(testContent)), nil) 67 testFileInfo := filesystem.MockFileInfo{ 68 FName: "/my/directory/file1", 69 FSize: int64(len(testContent)), 70 FMode: 0755, 71 FModTime: time.Time{}, 72 FIsDir: false, 73 } 74 fs.EXPECT().Stat("/my/directory/file1").Return(&testFileInfo, nil) 75 extractor := scraper.NewArchiveFilesystemExtractor(fs) 76 77 // Set up the expected calls to the mocked fs object 78 fs.EXPECT().Walk("/my/directory", gomock.Any()).Return(nil).DoAndReturn(func(_ string, walkFn filepath.WalkFunc) error { 79 fileInfo := filesystem.MockFileInfo{ 80 FName: "file1", 81 FIsDir: false, 82 } 83 return walkFn("/my/directory/file1", &fileInfo, nil) 84 }) 85 86 processFnCallCount := 0 87 processFn := func(ctx context.Context, object *scraper.Object) error { 88 processFnCallCount++ 89 switch object.Name { 90 case "artifacts.tar.gz": 91 assert.Equal(t, scraper.DataTypeTarball, object.DataType) 92 default: 93 t.Fatalf("Unexpected object name: %s", object.Name) 94 } 95 96 return nil 97 } 98 99 notifyFn := func(ctx context.Context, path string) error { 100 assert.Equal(t, "/my/directory/file1", path) 101 return nil 102 } 103 104 // Call the Extract function 105 err := extractor.Extract(context.Background(), []string{"/my/directory"}, []string{".*"}, processFn, notifyFn) 106 assert.NoErrorf(t, err, "Extract failed: %v", err) 107 assert.Equal(t, 1, processFnCallCount) 108 } 109 110 func TestArchiveFilesystemExtractor_Extract_Meta(t *testing.T) { 111 t.Parallel() 112 113 ctrl := gomock.NewController(t) 114 defer ctrl.Finish() 115 116 fs := filesystem.NewMockFileSystem(ctrl) 117 fs.EXPECT().Stat("/my/directory").Return(nil, nil) 118 testContent := "test" 119 fs.EXPECT().OpenFileBuffered("/my/directory/file1").Return(bufio.NewReader(strings.NewReader(testContent)), nil) 120 testFileInfo := filesystem.MockFileInfo{ 121 FName: "/my/directory/file1", 122 FSize: int64(len(testContent)), 123 FMode: 0755, 124 FModTime: time.Time{}, 125 FIsDir: false, 126 } 127 fs.EXPECT().Stat("/my/directory/file1").Return(&testFileInfo, nil) 128 extractor := scraper.NewArchiveFilesystemExtractor(fs, scraper.GenerateTarballMetaFile()) 129 130 // Set up the expected calls to the mocked fs object 131 fs.EXPECT().Walk("/my/directory", gomock.Any()).Return(nil).DoAndReturn(func(_ string, walkFn filepath.WalkFunc) error { 132 fileInfo := filesystem.MockFileInfo{ 133 FName: "file1", 134 FIsDir: false, 135 } 136 return walkFn("/my/directory/file1", &fileInfo, nil) 137 }) 138 139 processFnCallCount := 0 140 processFn := func(ctx context.Context, object *scraper.Object) error { 141 processFnCallCount++ 142 switch object.Name { 143 case ".testkube-meta-files.json": 144 var meta scraper.FilesMeta 145 jsonData, err := io.ReadAll(object.Data) 146 if err != nil { 147 t.Fatalf("Failed to read meta files: %v", err) 148 } 149 if err := json.Unmarshal(jsonData, &meta); err != nil { 150 t.Fatalf("Failed to unmarshal meta files: %v", err) 151 } 152 assert.Len(t, meta.Files, 1) 153 assert.Equal(t, "artifacts.tar.gz", meta.Archive) 154 assert.Equal(t, scraper.DataTypeTarball, meta.DataType) 155 assert.Equal(t, "file1", meta.Files[0].Name) 156 assert.Equal(t, int64(len(testContent)), meta.Files[0].Size) 157 assert.Equal(t, scraper.DataTypeRaw, object.DataType) 158 case "artifacts.tar.gz": 159 assert.Equal(t, scraper.DataTypeTarball, object.DataType) 160 default: 161 t.Fatalf("Unexpected object name: %s", object.Name) 162 } 163 164 return nil 165 } 166 167 notifyFn := func(ctx context.Context, path string) error { 168 assert.Equal(t, "/my/directory/file1", path) 169 return nil 170 } 171 172 // Call the Extract function 173 err := extractor.Extract(context.Background(), []string{"/my/directory"}, []string{".*"}, processFn, notifyFn) 174 assert.NoErrorf(t, err, "Extract failed: %v", err) 175 assert.Equal(t, 2, processFnCallCount) 176 } 177 178 func TestRecursiveFilesystemExtractor_ExtractEmpty(t *testing.T) { 179 t.Parallel() 180 181 ctrl := gomock.NewController(t) 182 defer ctrl.Finish() 183 184 fs := filesystem.NewMockFileSystem(ctrl) 185 fs.EXPECT().Stat("/my/directory").Return(nil, os.ErrNotExist) 186 extractor := scraper.NewRecursiveFilesystemExtractor(fs) 187 188 processFn := func(ctx context.Context, object *scraper.Object) error { 189 t.Fatalf("processFn should not be called when no files were scraped") 190 return nil 191 } 192 193 notifyFn := func(ctx context.Context, path string) error { 194 t.Fatalf("notifyFn should not be called when no files were scraped") 195 return nil 196 } 197 198 // Call the Extract function 199 err := extractor.Extract(context.Background(), []string{"/my/directory"}, []string{".*"}, processFn, notifyFn) 200 assert.NoErrorf(t, err, "Extract failed: %v", err) 201 } 202 203 func TestArchiveFilesystemExtractor_ExtractEmpty(t *testing.T) { 204 t.Parallel() 205 206 ctrl := gomock.NewController(t) 207 defer ctrl.Finish() 208 209 fs := filesystem.NewMockFileSystem(ctrl) 210 fs.EXPECT().Stat("/my/directory").Return(nil, os.ErrNotExist) 211 extractor := scraper.NewArchiveFilesystemExtractor(fs) 212 213 processFn := func(ctx context.Context, object *scraper.Object) error { 214 t.Fatalf("processFn should not be called when no files were scraped") 215 return nil 216 } 217 218 notifyFn := func(ctx context.Context, path string) error { 219 t.Fatalf("notifyFn should not be called when no files were scraped") 220 return nil 221 } 222 223 // Call the Extract function 224 err := extractor.Extract(context.Background(), []string{"/my/directory"}, []string{".*"}, processFn, notifyFn) 225 assert.NoErrorf(t, err, "Extract failed: %v", err) 226 }