From e43914cf4493af559e9210c72ccd2ae913d6247e Mon Sep 17 00:00:00 2001 From: Humair Khan Date: Wed, 27 Mar 2024 12:08:36 -0400 Subject: [PATCH] test: add unittests for ns scoped obj store config Signed-off-by: Humair Khan --- backend/src/v2/component/launcher_v2_test.go | 2 +- backend/src/v2/config/env_test.go | 377 ++++++++++++++++++ backend/src/v2/metadata/client_fake.go | 2 +- backend/src/v2/metadata/client_test.go | 14 +- .../src/v2/objectstore/object_store_test.go | 176 +++++++- 5 files changed, 545 insertions(+), 26 deletions(-) create mode 100644 backend/src/v2/config/env_test.go diff --git a/backend/src/v2/component/launcher_v2_test.go b/backend/src/v2/component/launcher_v2_test.go index e3e8835ff8b..5f9438b9fb0 100644 --- a/backend/src/v2/component/launcher_v2_test.go +++ b/backend/src/v2/component/launcher_v2_test.go @@ -77,7 +77,7 @@ func Test_executeV2_Parameters(t *testing.T) { fakeMetadataClient := metadata.NewFakeClient() bucket, err := blob.OpenBucket(context.Background(), "gs://test-bucket") assert.Nil(t, err) - bucketConfig, err := objectstore.ParseBucketConfig("gs://test-bucket/pipeline-root/") + bucketConfig, err := objectstore.ParseBucketConfig("gs://test-bucket/pipeline-root/", nil) assert.Nil(t, err) _, _, err = executeV2(context.Background(), test.executorInput, addNumbersComponent, "sh", test.executorArgs, bucket, bucketConfig, fakeMetadataClient, "namespace", fakeKubernetesClientset) diff --git a/backend/src/v2/config/env_test.go b/backend/src/v2/config/env_test.go new file mode 100644 index 00000000000..89b63f45554 --- /dev/null +++ b/backend/src/v2/config/env_test.go @@ -0,0 +1,377 @@ +// Copyright 2024 The Kubeflow Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package config + +import ( + "github.com/kubeflow/pipelines/backend/src/v2/objectstore" + "github.com/stretchr/testify/assert" + "testing" +) + +func Test_getDefaultMinioSessionInfo(t *testing.T) { + actualDefaultSession := getDefaultMinioSessionInfo() + expectedDefaultSession := objectstore.SessionInfo{ + Region: "minio", + Endpoint: "minio-service.kubeflow:9000", + DisableSSL: true, + SecretName: "mlpipeline-minio-artifact", + AccessKeyKey: "accesskey", + SecretKeyKey: "secretkey", + } + assert.Equal(t, actualDefaultSession, expectedDefaultSession) +} + +func TestGetBucketSessionInfo(t *testing.T) { + tt := []struct { + msg string + config Config + expectedSessionInfo objectstore.SessionInfo + pipelineroot string + // optional + shouldError bool + // optional + errorMsg string + }{ + { + msg: "invalid_unsupported_object_store_protocol", + pipelineroot: "unsupported://my-bucket/v2/artifacts", + config: Config{}, + expectedSessionInfo: objectstore.SessionInfo{}, + shouldError: true, + errorMsg: "unsupported Cloud bucket", + }, + { + msg: "invalid_unsupported_pipeline_root_format", + pipelineroot: "minio.unsupported.format", + config: Config{}, + expectedSessionInfo: objectstore.SessionInfo{}, + shouldError: true, + errorMsg: "unrecognized pipeline root format", + }, + { + msg: "valid_no_providers", + pipelineroot: "minio://my-bucket/v2/artifacts", + config: Config{}, + expectedSessionInfo: objectstore.SessionInfo{ + Region: "minio", + Endpoint: "minio-service.kubeflow:9000", + DisableSSL: true, + SecretName: "mlpipeline-minio-artifact", + AccessKeyKey: "accesskey", + SecretKeyKey: "secretkey", + }, + }, + { + msg: "invalid_one_empty_minio_provider", + pipelineroot: "minio://my-bucket/v2/artifacts", + config: Config{ + data: map[string]string{ + "providers": ` +minio: {} +`, + }, + }, + expectedSessionInfo: objectstore.SessionInfo{}, + shouldError: true, + errorMsg: "Invalid provider config", + }, + { + msg: "invalid_one_empty_minio_provider_no_authconfigs", + pipelineroot: "minio://my-bucket/v2/artifacts", + config: Config{ + data: map[string]string{ + "providers": ` +minio: + authConfigs: [] +`, + }, + }, + expectedSessionInfo: objectstore.SessionInfo{}, + shouldError: true, + errorMsg: "Invalid provider config", + }, + { + msg: "invalid_one_minio_provider_endpoint_only", + pipelineroot: "minio://my-bucket/v2/artifacts", + config: Config{ + data: map[string]string{ + "providers": ` +minio: + endpoint: some-endpoint.com +`, + }, + }, + expectedSessionInfo: objectstore.SessionInfo{}, + shouldError: true, + errorMsg: "Invalid provider config", + }, + { + msg: "valid_one_minio_provider", + pipelineroot: "minio://my-bucket/v2/artifacts", + config: Config{ + data: map[string]string{ + "providers": ` +minio: + endpoint: some-endpoint.com + region: minio + authConfigs: [] +`, + }, + }, + expectedSessionInfo: objectstore.SessionInfo{ + Region: "minio", + Endpoint: "some-endpoint.com", + DisableSSL: false, + SecretName: "mlpipeline-minio-artifact", + AccessKeyKey: "accesskey", + SecretKeyKey: "secretkey", + }, + }, + { + msg: "valid_pick_matching_provider", + pipelineroot: "minio://my-bucket/v2/artifacts", + config: Config{ + data: map[string]string{ + "providers": ` +gcs: + endpoint: storage.cloud.google.com + region: gcs + authConfigs: [] +minio: + endpoint: some-endpoint.com + region: minio + authConfigs: [] +aws: + endpoint: s3.amazonaws.com + region: s3 + authConfigs: [] +`, + }, + }, + expectedSessionInfo: objectstore.SessionInfo{ + Region: "minio", + Endpoint: "some-endpoint.com", + DisableSSL: false, + SecretName: "mlpipeline-minio-artifact", + AccessKeyKey: "accesskey", + SecretKeyKey: "secretkey", + }, + }, + { + msg: "invalid_non_minio_should_require_secret", + pipelineroot: "s3://my-bucket/v2/artifacts", + config: Config{ + data: map[string]string{ + "providers": ` +s3: + endpoint: s3.amazonaws.com + region: us-east-1 + authConfigs: [] +`, + }, + }, + expectedSessionInfo: objectstore.SessionInfo{}, + shouldError: true, + errorMsg: "Invalid provider config", + }, + { + msg: "invalid_matching_prefix_should_require_secretref", + pipelineroot: "minio://my-bucket/v2/artifacts/pick/this", + config: Config{ + data: map[string]string{ + "providers": ` +minio: + endpoint: minio.endpoint.com + region: minio + authConfigs: + - bucketName: my-bucket + keyPrefix: v2/artifacts/skip/this + secretRef: + secretName: minio-skip-this-secret + accessKeyKey: minio_skip_this_access_key + secretKeyKey: minio_skip_this_secret_key + - bucketName: my-bucket + keyPrefix: v2/artifacts/pick/this +`, + }, + }, + expectedSessionInfo: objectstore.SessionInfo{}, + shouldError: true, + errorMsg: "Invalid provider config", + }, + { + msg: "valid_s3_with_secret", + pipelineroot: "s3://my-bucket/v2/artifacts", + config: Config{ + data: map[string]string{ + "providers": ` +s3: + endpoint: s3.amazonaws.com + region: us-east-1 + defaultProviderSecretRef: + secretName: "s3-provider-secret" + accessKeyKey: "different_access_key" + secretKeyKey: "different_secret_key" +`, + }, + }, + expectedSessionInfo: objectstore.SessionInfo{ + Region: "us-east-1", + Endpoint: "s3.amazonaws.com", + DisableSSL: false, + SecretName: "s3-provider-secret", + SecretKeyKey: "different_secret_key", + AccessKeyKey: "different_access_key", + }, + }, + { + msg: "valid_minio_first_matching_auth_config", + pipelineroot: "minio://my-bucket/v2/artifacts/pick/this", + config: Config{ + data: map[string]string{ + "providers": ` +minio: + endpoint: minio.endpoint.com + region: minio + defaultProviderSecretRef: + secretName: minio-default-provider-secret + accessKeyKey: minio_default_different_access_key + secretKeyKey: minio_default_different_secret_key + authConfigs: + - bucketName: my-bucket + keyPrefix: v2/artifacts/skip/this + secretRef: + secretName: minio-skip-this-secret + accessKeyKey: minio_skip_this_access_key + secretKeyKey: minio_skip_this_secret_key + - bucketName: my-bucket + keyPrefix: v2/artifacts/pick/this + secretRef: + secretName: minio-pick-this-secret + accessKeyKey: minio_pick_this_access_key + secretKeyKey: minio_pick_this_secret_key + - bucketName: my-bucket + keyPrefix: v2/artifacts + secretRef: + secretName: minio-not-reached-secret + accessKeyKey: minio_not_reached_access_key + secretKeyKey: minio_not_reached_secret_key +`, + }, + }, + expectedSessionInfo: objectstore.SessionInfo{ + Region: "minio", + Endpoint: "minio.endpoint.com", + DisableSSL: false, + SecretName: "minio-pick-this-secret", + SecretKeyKey: "minio_pick_this_secret_key", + AccessKeyKey: "minio_pick_this_access_key", + }, + }, + { + msg: "valid_gs_first_matching_auth_config", + pipelineroot: "gs://my-bucket/v2/artifacts/pick/this", + config: Config{ + data: map[string]string{ + "providers": ` +minio: + endpoint: minio.endpoint.com + region: minio + defaultProviderSecretRef: + secretName: minio-default-provider-secret + accessKeyKey: minio_default_different_access_key + secretKeyKey: minio_default_different_secret_key + authConfigs: + - bucketName: my-bucket + keyPrefix: v2/artifacts/skip/this + secretRef: + secretName: minio-skip-this-secret + accessKeyKey: minio_skip_this_access_key + secretKeyKey: minio_skip_this_secret_key +gcs: + endpoint: storage.googleapis.com + region: gcs + defaultProviderSecretRef: + secretName: gcs-default-provider-secret + accessKeyKey: gcs_default_different_access_key + secretKeyKey: gcs_default_different_secret_key + authConfigs: + - bucketName: my-bucket + keyPrefix: v2/artifacts/pick/this + secretRef: + secretName: gcs-pick-this-secret + accessKeyKey: gcs_pick_this_access_key + secretKeyKey: gcs_pick_this_secret_key +`, + }, + }, + expectedSessionInfo: objectstore.SessionInfo{ + Region: "gcs", + Endpoint: "storage.googleapis.com", + DisableSSL: false, + SecretName: "gcs-pick-this-secret", + SecretKeyKey: "gcs_pick_this_secret_key", + AccessKeyKey: "gcs_pick_this_access_key", + }, + }, + { + msg: "valid_pick_default_when_no_matching_prefix", + pipelineroot: "gs://my-bucket/v2/artifacts/pick/default", + config: Config{ + data: map[string]string{ + "providers": ` +gcs: + endpoint: storage.googleapis.com + region: gcs + defaultProviderSecretRef: + secretName: gcs-default-provider-secret + accessKeyKey: gcs_default_different_access_key + secretKeyKey: gcs_default_different_secret_key + authConfigs: + - bucketName: my-bucket + keyPrefix: v2/artifacts/skip/this + secretRef: + secretName: gcs-skip-this-secret + accessKeyKey: gcs_skip_this_access_key + secretKeyKey: gcs_skip_this_secret_key +`, + }, + }, + expectedSessionInfo: objectstore.SessionInfo{ + Region: "gcs", + Endpoint: "storage.googleapis.com", + DisableSSL: false, + SecretName: "gcs-default-provider-secret", + SecretKeyKey: "gcs_default_different_secret_key", + AccessKeyKey: "gcs_default_different_access_key", + }, + }, + } + + for _, test := range tt { + t.Run(test.msg, func(t *testing.T) { + actualSession, err := test.config.GetBucketSessionInfo(test.pipelineroot) + if test.shouldError { + assert.Error(t, err) + if err != nil && test.errorMsg != "" { + assert.Contains(t, err.Error(), test.errorMsg) + } + } else { + assert.Nil(t, err) + } + assert.Equal(t, test.expectedSessionInfo, actualSession) + }) + } +} diff --git a/backend/src/v2/metadata/client_fake.go b/backend/src/v2/metadata/client_fake.go index c2887832d83..fe2773ebd52 100644 --- a/backend/src/v2/metadata/client_fake.go +++ b/backend/src/v2/metadata/client_fake.go @@ -32,7 +32,7 @@ func NewFakeClient() *FakeClient { return &FakeClient{} } -func (c *FakeClient) GetPipeline(ctx context.Context, pipelineName, runID, namespace, runResource, pipelineRoot string) (*Pipeline, error) { +func (c *FakeClient) GetPipeline(ctx context.Context, pipelineName, runID, namespace, runResource, pipelineRoot string, bucketSessionInfo string) (*Pipeline, error) { return nil, nil } diff --git a/backend/src/v2/metadata/client_test.go b/backend/src/v2/metadata/client_test.go index 86a16fe7724..94f081b32b0 100644 --- a/backend/src/v2/metadata/client_test.go +++ b/backend/src/v2/metadata/client_test.go @@ -89,7 +89,7 @@ func Test_GetPipeline(t *testing.T) { mlmdClient, err := NewTestMlmdClient() fatalIf(err) - pipeline, err := client.GetPipeline(ctx, "get-pipeline-test", runId, namespace, runResource, pipelineRoot) + pipeline, err := client.GetPipeline(ctx, "get-pipeline-test", runId, namespace, runResource, pipelineRoot, "") fatalIf(err) expectPipelineRoot := fmt.Sprintf("%s/get-pipeline-test/%s", pipelineRoot, runId) if pipeline.GetPipelineRoot() != expectPipelineRoot { @@ -138,10 +138,10 @@ func Test_GetPipeline_Twice(t *testing.T) { client, err := metadata.NewClient(testMlmdServerAddress, testMlmdServerPort) fatalIf(err) - pipeline, err := client.GetPipeline(ctx, "get-pipeline-test", runId, namespace, runResource, pipelineRoot) + pipeline, err := client.GetPipeline(ctx, "get-pipeline-test", runId, namespace, runResource, pipelineRoot, "") fatalIf(err) // The second call to GetPipeline won't fail because it avoid inserting to MLMD again. - samePipeline, err := client.GetPipeline(ctx, "get-pipeline-test", runId, namespace, runResource, pipelineRoot) + samePipeline, err := client.GetPipeline(ctx, "get-pipeline-test", runId, namespace, runResource, pipelineRoot, "") fatalIf(err) if pipeline.GetCtxID() != samePipeline.GetCtxID() { t.Errorf("Expect pipeline context ID %d, actual is %d", pipeline.GetCtxID(), samePipeline.GetCtxID()) @@ -159,7 +159,7 @@ func Test_GetPipelineFromExecution(t *testing.T) { } client := newLocalClientOrFatal(t) ctx := context.Background() - pipeline, err := client.GetPipeline(ctx, "get-pipeline-from-execution", newUUIDOrFatal(t), "kubeflow", "workflow/abc", "gs://my-bucket/root") + pipeline, err := client.GetPipeline(ctx, "get-pipeline-from-execution", newUUIDOrFatal(t), "kubeflow", "workflow/abc", "gs://my-bucket/root", "") fatalIf(err) execution, err := client.CreateExecution(ctx, pipeline, &metadata.ExecutionConfig{ TaskName: "task1", @@ -193,7 +193,7 @@ func Test_GetPipelineConcurrently(t *testing.T) { wg.Add(1) go func() { defer wg.Done() - _, err := client.GetPipeline(ctx, fmt.Sprintf("get-pipeline-concurrently-test-%s", runIdText), runIdText, namespace, "workflows.argoproj.io/hello-world-"+runIdText, pipelineRoot) + _, err := client.GetPipeline(ctx, fmt.Sprintf("get-pipeline-concurrently-test-%s", runIdText), runIdText, namespace, "workflows.argoproj.io/hello-world-"+runIdText, pipelineRoot, "") if err != nil { t.Error(err) } @@ -205,7 +205,7 @@ func Test_GetPipelineConcurrently(t *testing.T) { wg.Add(1) go func() { defer wg.Done() - _, err := client.GetPipeline(ctx, fmt.Sprintf("get-pipeline-concurrently-test-%s", runIdText), runIdText, namespace, "workflows.argoproj.io/hello-world-"+runIdText, pipelineRoot) + _, err := client.GetPipeline(ctx, fmt.Sprintf("get-pipeline-concurrently-test-%s", runIdText), runIdText, namespace, "workflows.argoproj.io/hello-world-"+runIdText, pipelineRoot, "") if err != nil { t.Error(err) } @@ -274,7 +274,7 @@ func Test_DAG(t *testing.T) { client := newLocalClientOrFatal(t) ctx := context.Background() // These parameters do not matter. - pipeline, err := client.GetPipeline(ctx, "pipeline-name", newUUIDOrFatal(t), "ns1", "workflow/pipeline-1234", pipelineRoot) + pipeline, err := client.GetPipeline(ctx, "pipeline-name", newUUIDOrFatal(t), "ns1", "workflow/pipeline-1234", pipelineRoot, "") if err != nil { t.Fatal(err) } diff --git a/backend/src/v2/objectstore/object_store_test.go b/backend/src/v2/objectstore/object_store_test.go index 86cd48da521..c09595f5513 100644 --- a/backend/src/v2/objectstore/object_store_test.go +++ b/backend/src/v2/objectstore/object_store_test.go @@ -12,14 +12,22 @@ // See the License for the specific language governing permissions and // limitations under the License. -package objectstore_test +package objectstore import ( + "context" + "fmt" + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/credentials" + "github.com/aws/aws-sdk-go/aws/session" + "github.com/stretchr/testify/assert" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes/fake" "os" "reflect" "testing" - "github.com/kubeflow/pipelines/backend/src/v2/objectstore" _ "gocloud.dev/blob/gcsblob" ) @@ -27,13 +35,13 @@ func Test_parseCloudBucket(t *testing.T) { tests := []struct { name string path string - want *objectstore.Config + want *Config wantErr bool }{ { name: "Parses GCS - Just the bucket", path: "gs://my-bucket", - want: &objectstore.Config{ + want: &Config{ Scheme: "gs://", BucketName: "my-bucket", Prefix: "", @@ -43,7 +51,7 @@ func Test_parseCloudBucket(t *testing.T) { { name: "Parses GCS - Just the bucket with trailing slash", path: "gs://my-bucket/", - want: &objectstore.Config{ + want: &Config{ Scheme: "gs://", BucketName: "my-bucket", Prefix: "", @@ -53,7 +61,7 @@ func Test_parseCloudBucket(t *testing.T) { { name: "Parses GCS - Bucket with prefix", path: "gs://my-bucket/my-path", - want: &objectstore.Config{ + want: &Config{ Scheme: "gs://", BucketName: "my-bucket", Prefix: "my-path/", @@ -63,7 +71,7 @@ func Test_parseCloudBucket(t *testing.T) { { name: "Parses GCS - Bucket with prefix and trailing slash", path: "gs://my-bucket/my-path/", - want: &objectstore.Config{ + want: &Config{ Scheme: "gs://", BucketName: "my-bucket", Prefix: "my-path/", @@ -73,7 +81,7 @@ func Test_parseCloudBucket(t *testing.T) { { name: "Parses GCS - Bucket with multiple path components in prefix", path: "gs://my-bucket/my-path/123", - want: &objectstore.Config{ + want: &Config{ Scheme: "gs://", BucketName: "my-bucket", Prefix: "my-path/123/", @@ -83,7 +91,7 @@ func Test_parseCloudBucket(t *testing.T) { { name: "Parses GCS - Bucket with multiple path components in prefix and trailing slash", path: "gs://my-bucket/my-path/123/", - want: &objectstore.Config{ + want: &Config{ Scheme: "gs://", BucketName: "my-bucket", Prefix: "my-path/123/", @@ -93,7 +101,7 @@ func Test_parseCloudBucket(t *testing.T) { { name: "Parses Minio - Bucket with query string", path: "minio://my-bucket", - want: &objectstore.Config{ + want: &Config{ Scheme: "minio://", BucketName: "my-bucket", Prefix: "", @@ -103,7 +111,7 @@ func Test_parseCloudBucket(t *testing.T) { }, { name: "Parses Minio - Bucket with prefix", path: "minio://my-bucket/my-path", - want: &objectstore.Config{ + want: &Config{ Scheme: "minio://", BucketName: "my-bucket", Prefix: "my-path/", @@ -113,18 +121,36 @@ func Test_parseCloudBucket(t *testing.T) { }, { name: "Parses Minio - Bucket with multiple path components in prefix", path: "minio://my-bucket/my-path/123", - want: &objectstore.Config{ + want: &Config{ Scheme: "minio://", BucketName: "my-bucket", Prefix: "my-path/123/", QueryString: "", }, wantErr: false, + }, { + name: "Parses S3 - Bucket with session", + path: "s3://my-bucket/my-path/123", + want: &Config{ + Scheme: "s3://", + BucketName: "my-bucket", + Prefix: "my-path/123/", + QueryString: "", + Session: &SessionInfo{ + Region: "us-east-1", + Endpoint: "s3.amazonaws.com", + DisableSSL: true, + SecretName: "s3-provider-secret", + SecretKeyKey: "different_secret_key", + AccessKeyKey: "different_access_key", + }, + }, + wantErr: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := objectstore.ParseBucketConfig(tt.path) + got, err := ParseBucketConfig(tt.path, tt.want.Session) if (err != nil) != tt.wantErr { t.Errorf("%q: parseCloudBucket() error = %v, wantErr %v", tt.name, err, tt.wantErr) return @@ -132,6 +158,7 @@ func Test_parseCloudBucket(t *testing.T) { if !reflect.DeepEqual(got, tt.want) { t.Errorf("%q: parseCloudBucket() = %v, want %v", tt.name, got, tt.want) } + assert.Equal(t, got.Session, tt.want.Session) }) } } @@ -145,21 +172,21 @@ func Test_bucketConfig_KeyFromURI(t *testing.T) { tests := []struct { name string - bucketConfig *objectstore.Config + bucketConfig *Config uri string want string wantErr bool }{ { name: "Bucket with empty prefix", - bucketConfig: &objectstore.Config{Scheme: "gs://", BucketName: "my-bucket", Prefix: ""}, + bucketConfig: &Config{Scheme: "gs://", BucketName: "my-bucket", Prefix: ""}, uri: "gs://my-bucket/path1/path2", want: "path1/path2", wantErr: false, }, { name: "Bucket with non-empty Prefix ", - bucketConfig: &objectstore.Config{Scheme: "gs://", BucketName: "my-bucket", Prefix: "path0/"}, + bucketConfig: &Config{Scheme: "gs://", BucketName: "my-bucket", Prefix: "path0/"}, uri: "gs://my-bucket/path0/path1/path2", want: "path1/path2", wantErr: false, @@ -215,7 +242,7 @@ func Test_GetMinioDefaultEndpoint(t *testing.T) { } else { os.Unsetenv("MINIO_SERVICE_SERVICE_PORT") } - got := objectstore.MinioDefaultEndpoint() + got := MinioDefaultEndpoint() if got != tt.want { t.Errorf( "MinioDefaultEndpoint() = %q, want %q\nwhen MINIO_SERVICE_SERVICE_HOST=%q MINIO_SERVICE_SERVICE_PORT=%q", @@ -225,3 +252,118 @@ func Test_GetMinioDefaultEndpoint(t *testing.T) { }) } } + +func Test_createBucketSession(t *testing.T) { + tt := []struct { + msg string + ns string + sessionInfo *SessionInfo + sessionSecret *corev1.Secret + expectedConfig *aws.Config + wantErr bool + errorMsg string + }{ + { + msg: "Bucket with session", + ns: "testnamespace", + sessionInfo: &SessionInfo{ + Region: "us-east-1", + Endpoint: "s3.amazonaws.com", + DisableSSL: false, + SecretName: "s3-provider-secret", + SecretKeyKey: "test_secret_key", + AccessKeyKey: "test_access_key", + }, + sessionSecret: &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{Name: "s3-provider-secret", Namespace: "testnamespace"}, + Data: map[string][]byte{"test_secret_key": []byte("secretKey"), "test_access_key": []byte("accessKey")}, + }, + expectedConfig: &aws.Config{ + Credentials: credentials.NewStaticCredentials("accessKey", "secretKey", ""), + Region: aws.String("us-east-1"), + Endpoint: aws.String("s3.amazonaws.com"), + DisableSSL: aws.Bool(false), + S3ForcePathStyle: aws.Bool(true), + }, + }, + { + msg: "Bucket with no session", + ns: "testnamespace", + sessionInfo: nil, + sessionSecret: nil, + expectedConfig: nil, + }, + { + msg: "Bucket with session but secret doesn't exist", + ns: "testnamespace", + sessionInfo: &SessionInfo{ + Region: "us-east-1", + Endpoint: "s3.amazonaws.com", + DisableSSL: false, + SecretName: "does-not-exist", + SecretKeyKey: "test_secret_key", + AccessKeyKey: "test_access_key", + }, + sessionSecret: nil, + expectedConfig: nil, + wantErr: true, + errorMsg: "secrets \"does-not-exist\" not found", + }, + { + msg: "Bucket with session secret exists but key mismatch", + ns: "testnamespace", + sessionInfo: &SessionInfo{ + Region: "us-east-1", + Endpoint: "s3.amazonaws.com", + DisableSSL: false, + SecretName: "s3-provider-secret", + SecretKeyKey: "does_not_exist_secret_key", + AccessKeyKey: "does_not_exist_access_key", + }, + sessionSecret: &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{Name: "s3-provider-secret", Namespace: "testnamespace"}, + Data: map[string][]byte{"test_secret_key": []byte("secretKey"), "test_access_key": []byte("accessKey")}, + }, + expectedConfig: nil, + wantErr: true, + errorMsg: "could not find specified keys", + }, + } + for _, test := range tt { + t.Run(test.msg, func(t *testing.T) { + fakeKubernetesClientset := fake.NewSimpleClientset() + ctx := context.Background() + + if test.sessionSecret != nil { + testersecret, err := fakeKubernetesClientset.CoreV1().Secrets(test.ns).Create( + ctx, + test.sessionSecret, + metav1.CreateOptions{}) + assert.Nil(t, err) + fmt.Printf(testersecret.Namespace) + } + + actualSession, err := createBucketSession(ctx, test.ns, test.sessionInfo, fakeKubernetesClientset) + if test.wantErr { + assert.Error(t, err) + if test.errorMsg != "" { + assert.Contains(t, err.Error(), test.errorMsg) + } + } else { + assert.Nil(t, err) + } + + if test.expectedConfig != nil { + // confirm config is populated with values from the session + expectedSess, err := session.NewSession(test.expectedConfig) + assert.Nil(t, err) + assert.Equal(t, expectedSess.Config.Region, actualSession.Config.Region) + assert.Equal(t, expectedSess.Config.Credentials, actualSession.Config.Credentials) + assert.Equal(t, expectedSess.Config.DisableSSL, actualSession.Config.DisableSSL) + assert.Equal(t, expectedSess.Config.S3ForcePathStyle, actualSession.Config.S3ForcePathStyle) + } else { + assert.Nil(t, actualSession) + } + }) + } +}