diff --git a/testhelper/docker/resource/minio/minio.go b/testhelper/docker/resource/minio/minio.go index 1d5612be..ffcbb920 100644 --- a/testhelper/docker/resource/minio/minio.go +++ b/testhelper/docker/resource/minio/minio.go @@ -1,10 +1,15 @@ package minio import ( + "bufio" + "compress/gzip" "context" "fmt" + "io" "log" "net/http" + "slices" + "strings" "github.com/minio/minio-go/v7" "github.com/minio/minio-go/v7/pkg/credentials" @@ -23,20 +28,9 @@ type Resource struct { Client *minio.Client } -func (mr *Resource) ToFileManagerConfig(prefix string) map[string]any { - return map[string]any{ - "bucketName": mr.BucketName, - "accessKeyID": mr.AccessKeyID, - "secretAccessKey": mr.AccessKeySecret, - "accessKey": mr.AccessKeySecret, - "enableSSE": false, - "prefix": prefix, - "endPoint": mr.Endpoint, - "s3ForcePathStyle": true, - "disableSSL": true, - "useSSL": false, - "region": mr.Region, - } +type File struct { + Key string + Content string } func Setup(pool *dockertest.Pool, d resource.Cleaner, opts ...func(*Config)) (*Resource, error) { @@ -116,3 +110,67 @@ func Setup(pool *dockertest.Pool, d resource.Cleaner, opts ...func(*Config)) (*R Client: client, }, nil } + +func (r *Resource) Contents(ctx context.Context, prefix string) ([]File, error) { + contents := make([]File, 0) + + opts := minio.ListObjectsOptions{ + Recursive: true, + Prefix: prefix, + } + for objInfo := range r.Client.ListObjects(ctx, r.BucketName, opts) { + if objInfo.Err != nil { + return nil, objInfo.Err + } + + o, err := r.Client.GetObject(ctx, r.BucketName, objInfo.Key, minio.GetObjectOptions{}) + if err != nil { + return nil, err + } + + var r io.Reader + br := bufio.NewReader(o) + magic, err := br.Peek(2) + // check if the file is gzipped using the magic number + if err == nil && magic[0] == 31 && magic[1] == 139 { + r, err = gzip.NewReader(br) + if err != nil { + return nil, fmt.Errorf("gunzip: %w", err) + } + } else { + r = br + } + + b, err := io.ReadAll(r) + if err != nil { + return nil, err + } + + contents = append(contents, File{ + Key: objInfo.Key, + Content: string(b), + }) + } + + slices.SortStableFunc(contents, func(a, b File) int { + return strings.Compare(a.Key, b.Key) + }) + + return contents, nil +} + +func (r *Resource) ToFileManagerConfig(prefix string) map[string]any { + return map[string]any{ + "bucketName": r.BucketName, + "accessKeyID": r.AccessKeyID, + "secretAccessKey": r.AccessKeySecret, + "accessKey": r.AccessKeySecret, + "enableSSE": false, + "prefix": prefix, + "endPoint": r.Endpoint, + "s3ForcePathStyle": true, + "disableSSL": true, + "useSSL": false, + "region": r.Region, + } +} diff --git a/testhelper/docker/resource/minio/minio_test.go b/testhelper/docker/resource/minio/minio_test.go index 408cf3f1..5c06535e 100644 --- a/testhelper/docker/resource/minio/minio_test.go +++ b/testhelper/docker/resource/minio/minio_test.go @@ -1,6 +1,8 @@ package minio import ( + "bytes" + "compress/gzip" "context" "testing" @@ -53,3 +55,50 @@ func TestMinioResource(t *testing.T) { require.Len(t, items, 1) }) } + +func TestMinioContents(t *testing.T) { + pool, err := dockertest.NewPool("") + require.NoError(t, err) + + minioResource, err := Setup(pool, t) + require.NoError(t, err) + + _, err = minioResource.Client.PutObject(context.Background(), + minioResource.BucketName, "test-bucket/hello.txt", bytes.NewBufferString("hello"), -1, minio.PutObjectOptions{}, + ) + require.NoError(t, err) + + var b bytes.Buffer + gz := gzip.NewWriter(&b) + _, err = gz.Write([]byte("hello compressed")) + require.NoError(t, err) + err = gz.Close() + require.NoError(t, err) + + _, err = minioResource.Client.PutObject(context.Background(), + minioResource.BucketName, "test-bucket/hello.txt.gz", &b, -1, minio.PutObjectOptions{}, + ) + require.NoError(t, err) + + _, err = minioResource.Client.PutObject(context.Background(), + minioResource.BucketName, "test-bucket/empty", bytes.NewBuffer([]byte{}), -1, minio.PutObjectOptions{}, + ) + require.NoError(t, err) + + files, err := minioResource.Contents(context.Background(), "test-bucket/") + require.NoError(t, err) + + require.Equal(t, []File{ + {Key: "test-bucket/empty", Content: ""}, + {Key: "test-bucket/hello.txt", Content: "hello"}, + {Key: "test-bucket/hello.txt.gz", Content: "hello compressed"}, + }, files) + + t.Run("canceled context", func(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + cancel() + + _, err := minioResource.Contents(ctx, "test-bucket/") + require.ErrorIs(t, err, context.Canceled) + }) +}