diff options
Diffstat (limited to 'modules/storage/minio_test.go')
-rw-r--r-- | modules/storage/minio_test.go | 216 |
1 files changed, 216 insertions, 0 deletions
diff --git a/modules/storage/minio_test.go b/modules/storage/minio_test.go new file mode 100644 index 00000000..9ce1dbc7 --- /dev/null +++ b/modules/storage/minio_test.go @@ -0,0 +1,216 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package storage + +import ( + "context" + "net/http" + "net/http/httptest" + "os" + "testing" + + "code.gitea.io/gitea/modules/setting" + + "github.com/minio/minio-go/v7" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestMinioStorageIterator(t *testing.T) { + if os.Getenv("CI") == "" { + t.Skip("minioStorage not present outside of CI") + return + } + testStorageIterator(t, setting.MinioStorageType, &setting.Storage{ + MinioConfig: setting.MinioStorageConfig{ + Endpoint: "minio:9000", + AccessKeyID: "123456", + SecretAccessKey: "12345678", + Bucket: "gitea", + Location: "us-east-1", + }, + }) +} + +func TestVirtualHostMinioStorage(t *testing.T) { + if os.Getenv("CI") == "" { + t.Skip("minioStorage not present outside of CI") + return + } + testStorageIterator(t, setting.MinioStorageType, &setting.Storage{ + MinioConfig: setting.MinioStorageConfig{ + Endpoint: "minio:9000", + AccessKeyID: "123456", + SecretAccessKey: "12345678", + Bucket: "gitea", + Location: "us-east-1", + BucketLookup: "dns", + }, + }) +} + +func TestMinioStoragePath(t *testing.T) { + m := &MinioStorage{basePath: ""} + assert.Equal(t, "", m.buildMinioPath("/")) + assert.Equal(t, "", m.buildMinioPath(".")) + assert.Equal(t, "a", m.buildMinioPath("/a")) + assert.Equal(t, "a/b", m.buildMinioPath("/a/b/")) + assert.Equal(t, "", m.buildMinioDirPrefix("")) + assert.Equal(t, "a/", m.buildMinioDirPrefix("/a/")) + + m = &MinioStorage{basePath: "/"} + assert.Equal(t, "", m.buildMinioPath("/")) + assert.Equal(t, "", m.buildMinioPath(".")) + assert.Equal(t, "a", m.buildMinioPath("/a")) + assert.Equal(t, "a/b", m.buildMinioPath("/a/b/")) + assert.Equal(t, "", m.buildMinioDirPrefix("")) + assert.Equal(t, "a/", m.buildMinioDirPrefix("/a/")) + + m = &MinioStorage{basePath: "/base"} + assert.Equal(t, "base", m.buildMinioPath("/")) + assert.Equal(t, "base", m.buildMinioPath(".")) + assert.Equal(t, "base/a", m.buildMinioPath("/a")) + assert.Equal(t, "base/a/b", m.buildMinioPath("/a/b/")) + assert.Equal(t, "base/", m.buildMinioDirPrefix("")) + assert.Equal(t, "base/a/", m.buildMinioDirPrefix("/a/")) + + m = &MinioStorage{basePath: "/base/"} + assert.Equal(t, "base", m.buildMinioPath("/")) + assert.Equal(t, "base", m.buildMinioPath(".")) + assert.Equal(t, "base/a", m.buildMinioPath("/a")) + assert.Equal(t, "base/a/b", m.buildMinioPath("/a/b/")) + assert.Equal(t, "base/", m.buildMinioDirPrefix("")) + assert.Equal(t, "base/a/", m.buildMinioDirPrefix("/a/")) +} + +func TestS3StorageBadRequest(t *testing.T) { + if os.Getenv("CI") == "" { + t.Skip("S3Storage not present outside of CI") + return + } + cfg := &setting.Storage{ + MinioConfig: setting.MinioStorageConfig{ + Endpoint: "minio:9000", + AccessKeyID: "123456", + SecretAccessKey: "12345678", + Bucket: "bucket", + Location: "us-east-1", + }, + } + message := "ERROR" + old := getBucketVersioning + defer func() { getBucketVersioning = old }() + getBucketVersioning = func(ctx context.Context, minioClient *minio.Client, bucket string) error { + return minio.ErrorResponse{ + StatusCode: http.StatusBadRequest, + Code: "FixtureError", + Message: message, + } + } + _, err := NewStorage(setting.MinioStorageType, cfg) + require.ErrorContains(t, err, message) +} + +func TestMinioCredentials(t *testing.T) { + const ( + ExpectedAccessKey = "ExampleAccessKeyID" + ExpectedSecretAccessKey = "ExampleSecretAccessKeyID" + // Use a FakeEndpoint for IAM credentials to avoid logging any + // potential real IAM credentials when running in EC2. + FakeEndpoint = "http://localhost" + ) + + t.Run("Static Credentials", func(t *testing.T) { + cfg := setting.MinioStorageConfig{ + AccessKeyID: ExpectedAccessKey, + SecretAccessKey: ExpectedSecretAccessKey, + } + creds := buildMinioCredentials(cfg, FakeEndpoint) + v, err := creds.Get() + + require.NoError(t, err) + assert.Equal(t, ExpectedAccessKey, v.AccessKeyID) + assert.Equal(t, ExpectedSecretAccessKey, v.SecretAccessKey) + }) + + t.Run("Chain", func(t *testing.T) { + cfg := setting.MinioStorageConfig{} + + t.Run("EnvMinio", func(t *testing.T) { + t.Setenv("MINIO_ACCESS_KEY", ExpectedAccessKey+"Minio") + t.Setenv("MINIO_SECRET_KEY", ExpectedSecretAccessKey+"Minio") + + creds := buildMinioCredentials(cfg, FakeEndpoint) + v, err := creds.Get() + + require.NoError(t, err) + assert.Equal(t, ExpectedAccessKey+"Minio", v.AccessKeyID) + assert.Equal(t, ExpectedSecretAccessKey+"Minio", v.SecretAccessKey) + }) + + t.Run("EnvAWS", func(t *testing.T) { + t.Setenv("AWS_ACCESS_KEY", ExpectedAccessKey+"AWS") + t.Setenv("AWS_SECRET_KEY", ExpectedSecretAccessKey+"AWS") + + creds := buildMinioCredentials(cfg, FakeEndpoint) + v, err := creds.Get() + + require.NoError(t, err) + assert.Equal(t, ExpectedAccessKey+"AWS", v.AccessKeyID) + assert.Equal(t, ExpectedSecretAccessKey+"AWS", v.SecretAccessKey) + }) + + t.Run("FileMinio", func(t *testing.T) { + t.Setenv("MINIO_SHARED_CREDENTIALS_FILE", "testdata/minio.json") + // prevent loading any actual credentials files from the user + t.Setenv("AWS_SHARED_CREDENTIALS_FILE", "testdata/fake") + + creds := buildMinioCredentials(cfg, FakeEndpoint) + v, err := creds.Get() + + require.NoError(t, err) + assert.Equal(t, ExpectedAccessKey+"MinioFile", v.AccessKeyID) + assert.Equal(t, ExpectedSecretAccessKey+"MinioFile", v.SecretAccessKey) + }) + + t.Run("FileAWS", func(t *testing.T) { + // prevent loading any actual credentials files from the user + t.Setenv("MINIO_SHARED_CREDENTIALS_FILE", "testdata/fake.json") + t.Setenv("AWS_SHARED_CREDENTIALS_FILE", "testdata/aws_credentials") + + creds := buildMinioCredentials(cfg, FakeEndpoint) + v, err := creds.Get() + + require.NoError(t, err) + assert.Equal(t, ExpectedAccessKey+"AWSFile", v.AccessKeyID) + assert.Equal(t, ExpectedSecretAccessKey+"AWSFile", v.SecretAccessKey) + }) + + t.Run("IAM", func(t *testing.T) { + // prevent loading any actual credentials files from the user + t.Setenv("MINIO_SHARED_CREDENTIALS_FILE", "testdata/fake.json") + t.Setenv("AWS_SHARED_CREDENTIALS_FILE", "testdata/fake") + + // Spawn a server to emulate the EC2 Instance Metadata + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // The client will actually make 3 requests here, + // first will be to get the IMDSv2 token, second to + // get the role, and third for the actual + // credentials. However, we can return credentials + // every request since we're not emulating a full + // IMDSv2 flow. + w.Write([]byte(`{"Code":"Success","AccessKeyId":"ExampleAccessKeyIDIAM","SecretAccessKey":"ExampleSecretAccessKeyIDIAM"}`)) + })) + defer server.Close() + + // Use the provided EC2 Instance Metadata server + creds := buildMinioCredentials(cfg, server.URL) + v, err := creds.Get() + + require.NoError(t, err) + assert.Equal(t, ExpectedAccessKey+"IAM", v.AccessKeyID) + assert.Equal(t, ExpectedSecretAccessKey+"IAM", v.SecretAccessKey) + }) + }) +} |