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  }