github.com/percona/percona-xtradb-cluster-operator@v1.14.0/pkg/pxc/backup/storage/options_test.go (about)

     1  package storage
     2  
     3  import (
     4  	"context"
     5  	"reflect"
     6  	"testing"
     7  
     8  	corev1 "k8s.io/api/core/v1"
     9  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    10  	"k8s.io/apimachinery/pkg/runtime"
    11  	"sigs.k8s.io/controller-runtime/pkg/client/fake"
    12  
    13  	api "github.com/percona/percona-xtradb-cluster-operator/pkg/apis/pxc/v1"
    14  )
    15  
    16  func TestGetS3Options(t *testing.T) {
    17  	ctx := context.Background()
    18  
    19  	const ns = "my-ns"
    20  
    21  	const storageName = "my-storage"
    22  	const secretName = "my-secret"
    23  	const accessKeyID = "some-access-key"
    24  	const secretAccessKey = "some-secret-key"
    25  
    26  	boolPtr := func(b bool) *bool { return &b }
    27  
    28  	tests := []struct {
    29  		name            string
    30  		destination     string
    31  		bucket          string
    32  		accessKeyID     string
    33  		secretAccessKey string
    34  		endpoint        string
    35  		region          string
    36  		verifyTLS       *bool
    37  		storage         *api.BackupStorageSpec
    38  
    39  		expected    *S3Options
    40  		expectedErr string
    41  	}{
    42  		{
    43  			name:     "no secret",
    44  			bucket:   "somebucket",
    45  			endpoint: "some-endpoint",
    46  			region:   "some-region",
    47  			expected: &S3Options{
    48  				Endpoint:   "some-endpoint",
    49  				BucketName: "somebucket",
    50  				Region:     "some-region",
    51  				VerifyTLS:  true,
    52  			},
    53  		},
    54  		{
    55  			name:            "with secret",
    56  			bucket:          "somebucket",
    57  			accessKeyID:     accessKeyID,
    58  			secretAccessKey: secretAccessKey,
    59  			expected: &S3Options{
    60  				BucketName:      "somebucket",
    61  				AccessKeyID:     accessKeyID,
    62  				SecretAccessKey: secretAccessKey,
    63  				VerifyTLS:       true,
    64  				Region:          "us-east-1",
    65  			},
    66  		},
    67  		{
    68  			name:   "bucket without prefix",
    69  			bucket: "my-bucket",
    70  			expected: &S3Options{
    71  				BucketName: "my-bucket",
    72  				VerifyTLS:  true,
    73  				Region:     "us-east-1",
    74  			},
    75  		},
    76  		{
    77  			name:   "bucket with prefix",
    78  			bucket: "my-bucket/prefix",
    79  			expected: &S3Options{
    80  				BucketName: "my-bucket",
    81  				Prefix:     "prefix/",
    82  				VerifyTLS:  true,
    83  				Region:     "us-east-1",
    84  			},
    85  		},
    86  		{
    87  			name:        "destination with bucket",
    88  			destination: "s3://invalid-bucket/prefix/backup-name",
    89  			bucket:      "my-bucket",
    90  			expected: &S3Options{
    91  				BucketName: "my-bucket",
    92  				VerifyTLS:  true,
    93  				Region:     "us-east-1",
    94  			},
    95  		},
    96  		{
    97  			name:        "destination without prefix",
    98  			destination: "s3://destination-bucket/backup-name",
    99  			expected: &S3Options{
   100  				BucketName: "destination-bucket",
   101  				VerifyTLS:  true,
   102  				Region:     "us-east-1",
   103  			},
   104  		},
   105  		{
   106  			name:        "destination with prefix",
   107  			destination: "s3://destination-bucket/prefix/backup-name",
   108  			expected: &S3Options{
   109  				BucketName: "destination-bucket",
   110  				Prefix:     "prefix/",
   111  				VerifyTLS:  true,
   112  				Region:     "us-east-1",
   113  			},
   114  		},
   115  		{
   116  			name:        "no destination",
   117  			expectedErr: "bucket name is not set",
   118  		},
   119  		{
   120  			name:      "verifyTLS in backup",
   121  			bucket:    "somebucket",
   122  			verifyTLS: boolPtr(false),
   123  			expected: &S3Options{
   124  				BucketName: "somebucket",
   125  				VerifyTLS:  false,
   126  				Region:     "us-east-1",
   127  			},
   128  		},
   129  		{
   130  			name:      "verifyTLS in backup and cluster",
   131  			bucket:    "somebucket",
   132  			verifyTLS: boolPtr(true),
   133  			storage: &api.BackupStorageSpec{
   134  				VerifyTLS: boolPtr(false),
   135  			},
   136  			expected: &S3Options{
   137  				BucketName: "somebucket",
   138  				VerifyTLS:  false,
   139  				Region:     "us-east-1",
   140  			},
   141  		},
   142  	}
   143  
   144  	for _, tt := range tests {
   145  		t.Run(tt.name, func(t *testing.T) {
   146  			backup := testBackup(ns, storageName, tt.destination, tt.verifyTLS, &api.BackupStorageS3Spec{
   147  				Bucket:            tt.bucket,
   148  				CredentialsSecret: secretName,
   149  				Region:            tt.region,
   150  				EndpointURL:       tt.endpoint,
   151  			}, nil)
   152  
   153  			var cluster *api.PerconaXtraDBCluster
   154  			if tt.storage != nil {
   155  				cluster = &api.PerconaXtraDBCluster{
   156  					Spec: api.PerconaXtraDBClusterSpec{
   157  						Backup: &api.PXCScheduledBackup{
   158  							Storages: map[string]*api.BackupStorageSpec{
   159  								storageName: tt.storage,
   160  							},
   161  						},
   162  					},
   163  				}
   164  			}
   165  
   166  			objs := []runtime.Object{}
   167  			if tt.accessKeyID != "" || tt.secretAccessKey != "" {
   168  				objs = append(objs, &corev1.Secret{
   169  					ObjectMeta: metav1.ObjectMeta{
   170  						Name:      secretName,
   171  						Namespace: ns,
   172  					},
   173  					Data: map[string][]byte{
   174  						"AWS_ACCESS_KEY_ID":     []byte(tt.accessKeyID),
   175  						"AWS_SECRET_ACCESS_KEY": []byte(tt.secretAccessKey),
   176  					},
   177  				})
   178  			}
   179  			cl := fake.NewClientBuilder().WithRuntimeObjects(objs...).Build()
   180  
   181  			opts, err := getS3Options(ctx, cl, cluster, backup)
   182  			if err != nil && tt.expectedErr != err.Error() {
   183  				t.Fatal(err)
   184  			}
   185  			if !reflect.DeepEqual(opts, tt.expected) {
   186  				t.Fatalf("expected: %+v, got: %+v", tt.expected, opts)
   187  			}
   188  		})
   189  	}
   190  }
   191  
   192  func TestGetAzureOptions(t *testing.T) {
   193  	ctx := context.Background()
   194  
   195  	const ns = "my-ns"
   196  
   197  	const storageName = "my-storage"
   198  	const secretName = "my-secret"
   199  	const accountName = "some-access-key"
   200  	const accountKey = "some-secret-key"
   201  
   202  	tests := []struct {
   203  		name        string
   204  		destination string
   205  		container   string
   206  		accountName string
   207  		accountKey  string
   208  		endpoint    string
   209  
   210  		expected    *AzureOptions
   211  		expectedErr string
   212  	}{
   213  		{
   214  			name:        "no secret",
   215  			container:   "some-container",
   216  			endpoint:    "some-endpoint",
   217  			expectedErr: `failed to get secret: secrets "my-secret" not found`,
   218  		},
   219  		{
   220  			name:        "container without prefix",
   221  			container:   "my-container",
   222  			accountName: accountName,
   223  			accountKey:  accountKey,
   224  			endpoint:    "some-endpoint",
   225  			expected: &AzureOptions{
   226  				StorageAccount: accountName,
   227  				AccessKey:      accountKey,
   228  				Container:      "my-container",
   229  				Endpoint:       "some-endpoint",
   230  			},
   231  		},
   232  		{
   233  			name:        "container with prefix",
   234  			container:   "my-container/prefix",
   235  			accountName: accountName,
   236  			accountKey:  accountKey,
   237  			expected: &AzureOptions{
   238  				StorageAccount: accountName,
   239  				AccessKey:      accountKey,
   240  				Container:      "my-container",
   241  				Prefix:         "prefix/",
   242  			},
   243  		},
   244  		{
   245  			name:        "destination with container",
   246  			destination: "azure://invalid-container/prefix/backup-name",
   247  			container:   "my-container",
   248  			accountName: accountName,
   249  			accountKey:  accountKey,
   250  			expected: &AzureOptions{
   251  				StorageAccount: accountName,
   252  				AccessKey:      accountKey,
   253  				Container:      "my-container",
   254  			},
   255  		},
   256  		{
   257  			name:        "destination without prefix",
   258  			destination: "azure://destination-container/backup-name",
   259  			accountName: accountName,
   260  			accountKey:  accountKey,
   261  			expected: &AzureOptions{
   262  				StorageAccount: accountName,
   263  				AccessKey:      accountKey,
   264  				Container:      "destination-container",
   265  			},
   266  		},
   267  		{
   268  			name:        "destination with prefix",
   269  			destination: "azure://destination-container/prefix/backup-name",
   270  			accountName: accountName,
   271  			accountKey:  accountKey,
   272  			expected: &AzureOptions{
   273  				StorageAccount: accountName,
   274  				AccessKey:      accountKey,
   275  				Container:      "destination-container",
   276  				Prefix:         "prefix/",
   277  			},
   278  		},
   279  		{
   280  			name:        "no destination",
   281  			accountName: accountName,
   282  			accountKey:  accountKey,
   283  			expectedErr: "container name is not set",
   284  		},
   285  	}
   286  
   287  	for _, tt := range tests {
   288  		t.Run(tt.name, func(t *testing.T) {
   289  			backup := testBackup(ns, storageName, tt.destination, nil, nil, &api.BackupStorageAzureSpec{
   290  				ContainerPath:     tt.container,
   291  				CredentialsSecret: secretName,
   292  				Endpoint:          tt.endpoint,
   293  			})
   294  
   295  			objs := []runtime.Object{}
   296  			if tt.accountName != "" || tt.accountKey != "" {
   297  				objs = append(objs, testSecret(ns, secretName, map[string][]byte{
   298  					"AZURE_STORAGE_ACCOUNT_NAME": []byte(tt.accountName),
   299  					"AZURE_STORAGE_ACCOUNT_KEY":  []byte(tt.accountKey),
   300  				}))
   301  			}
   302  			cl := fake.NewClientBuilder().WithRuntimeObjects(objs...).Build()
   303  
   304  			opts, err := getAzureOptions(ctx, cl, backup)
   305  			if err != nil && tt.expectedErr != err.Error() {
   306  				t.Fatal(err)
   307  			}
   308  			if !reflect.DeepEqual(opts, tt.expected) {
   309  				t.Fatalf("expected: %+v, got: %+v", tt.expected, opts)
   310  			}
   311  		})
   312  	}
   313  }
   314  
   315  func testSecret(ns string, name string, data map[string][]byte) *corev1.Secret {
   316  	return &corev1.Secret{
   317  		ObjectMeta: metav1.ObjectMeta{
   318  			Name:      name,
   319  			Namespace: ns,
   320  		},
   321  		Data: data,
   322  	}
   323  }
   324  
   325  func testBackup(ns string, storageName string, destination string, verifyTLS *bool, s3 *api.BackupStorageS3Spec, azure *api.BackupStorageAzureSpec) *api.PerconaXtraDBClusterBackup {
   326  	return &api.PerconaXtraDBClusterBackup{
   327  		ObjectMeta: metav1.ObjectMeta{
   328  			Name:      "my-backup",
   329  			Namespace: ns,
   330  		},
   331  		Spec: api.PXCBackupSpec{
   332  			StorageName: storageName,
   333  		},
   334  		Status: api.PXCBackupStatus{
   335  			Destination: api.PXCBackupDestination(destination),
   336  			S3:          s3,
   337  			Azure:       azure,
   338  			VerifyTLS:   verifyTLS,
   339  		},
   340  	}
   341  }