github.com/weaviate/weaviate@v1.24.6/test/modules/backup-s3/backup_backend_test.go (about)

     1  //                           _       _
     2  // __      _____  __ ___   ___  __ _| |_ ___
     3  // \ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \
     4  //  \ V  V /  __/ (_| |\ V /| | (_| | ||  __/
     5  //   \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___|
     6  //
     7  //  Copyright © 2016 - 2024 Weaviate B.V. All rights reserved.
     8  //
     9  //  CONTACT: hello@weaviate.io
    10  //
    11  
    12  package test
    13  
    14  import (
    15  	"context"
    16  	"encoding/json"
    17  	"fmt"
    18  	"os"
    19  	"path/filepath"
    20  	"testing"
    21  	"time"
    22  
    23  	"github.com/pkg/errors"
    24  	"github.com/sirupsen/logrus"
    25  	logrustest "github.com/sirupsen/logrus/hooks/test"
    26  	"github.com/stretchr/testify/assert"
    27  	"github.com/stretchr/testify/require"
    28  	"github.com/weaviate/weaviate/entities/backup"
    29  	"github.com/weaviate/weaviate/entities/moduletools"
    30  	mod "github.com/weaviate/weaviate/modules/backup-s3"
    31  	"github.com/weaviate/weaviate/test/docker"
    32  	moduleshelper "github.com/weaviate/weaviate/test/helper/modules"
    33  	ubak "github.com/weaviate/weaviate/usecases/backup"
    34  	"github.com/weaviate/weaviate/usecases/config"
    35  )
    36  
    37  func Test_S3Backend_Backup(t *testing.T) {
    38  	ctx := context.Background()
    39  	compose, err := docker.New().WithMinIO().Start(ctx)
    40  	if err != nil {
    41  		t.Fatal(errors.Wrapf(err, "cannot start"))
    42  	}
    43  
    44  	t.Setenv(envMinioEndpoint, compose.GetMinIO().URI())
    45  
    46  	t.Run("store backup meta", moduleLevelStoreBackupMeta)
    47  	t.Run("copy objects", moduleLevelCopyObjects)
    48  	t.Run("copy files", moduleLevelCopyFiles)
    49  
    50  	if err := compose.Terminate(ctx); err != nil {
    51  		t.Fatal(errors.Wrapf(err, "failed to terminate test containers"))
    52  	}
    53  }
    54  
    55  func moduleLevelStoreBackupMeta(t *testing.T) {
    56  	testCtx, cancel := context.WithTimeout(context.Background(), time.Minute)
    57  	defer cancel()
    58  
    59  	dataDir := t.TempDir()
    60  	className := "BackupClass"
    61  	backupID := "backup_id"
    62  	bucketName := "bucket"
    63  	region := "eu-west-1"
    64  	endpoint := os.Getenv(envMinioEndpoint)
    65  	metadataFilename := "backup.json"
    66  
    67  	t.Log("setup env")
    68  	t.Setenv(envAwsRegion, region)
    69  	t.Setenv(envS3AccessKey, "aws_access_key")
    70  	t.Setenv(envS3SecretKey, "aws_secret_key")
    71  	t.Setenv(envS3Bucket, bucketName)
    72  	createBucket(testCtx, t, endpoint, region, bucketName)
    73  
    74  	t.Run("store backup meta in s3", func(t *testing.T) {
    75  		t.Setenv(envS3UseSSL, "false")
    76  		t.Setenv(envS3Endpoint, endpoint)
    77  		s3 := mod.New()
    78  		err := s3.Init(testCtx, newFakeModuleParams(dataDir))
    79  		require.Nil(t, err)
    80  
    81  		t.Run("access permissions", func(t *testing.T) {
    82  			err := s3.Initialize(testCtx, backupID)
    83  			assert.Nil(t, err)
    84  		})
    85  
    86  		t.Run("backup meta does not exist yet", func(t *testing.T) {
    87  			meta, err := s3.GetObject(testCtx, backupID, metadataFilename)
    88  			assert.Nil(t, meta)
    89  			assert.NotNil(t, err)
    90  			assert.IsType(t, backup.ErrNotFound{}, err)
    91  		})
    92  
    93  		t.Run("put backup meta in backend", func(t *testing.T) {
    94  			desc := &backup.BackupDescriptor{
    95  				StartedAt:   time.Now(),
    96  				CompletedAt: time.Time{},
    97  				ID:          backupID,
    98  				Classes: []backup.ClassDescriptor{
    99  					{
   100  						Name: className,
   101  					},
   102  				},
   103  				Status:  string(backup.Started),
   104  				Version: ubak.Version,
   105  			}
   106  
   107  			b, err := json.Marshal(desc)
   108  			require.Nil(t, err)
   109  
   110  			err = s3.PutObject(testCtx, backupID, metadataFilename, b)
   111  			require.Nil(t, err)
   112  
   113  			dest := s3.HomeDir(backupID)
   114  			expected := fmt.Sprintf("s3://%s/%s", bucketName, backupID)
   115  			assert.Equal(t, expected, dest)
   116  		})
   117  
   118  		t.Run("assert backup meta contents", func(t *testing.T) {
   119  			obj, err := s3.GetObject(testCtx, backupID, metadataFilename)
   120  			require.Nil(t, err)
   121  
   122  			var meta backup.BackupDescriptor
   123  			err = json.Unmarshal(obj, &meta)
   124  			require.Nil(t, err)
   125  			assert.NotEmpty(t, meta.StartedAt)
   126  			assert.Empty(t, meta.CompletedAt)
   127  			assert.Equal(t, meta.Status, string(backup.Started))
   128  			assert.Empty(t, meta.Error)
   129  			assert.Len(t, meta.Classes, 1)
   130  			assert.Equal(t, meta.Classes[0].Name, className)
   131  			assert.Equal(t, meta.Version, ubak.Version)
   132  			assert.Nil(t, meta.Classes[0].Error)
   133  		})
   134  	})
   135  }
   136  
   137  func moduleLevelCopyObjects(t *testing.T) {
   138  	testCtx, cancel := context.WithTimeout(context.Background(), time.Minute)
   139  	defer cancel()
   140  
   141  	dataDir := t.TempDir()
   142  	key := "moduleLevelCopyObjects"
   143  	backupID := "backup_id"
   144  	bucketName := "bucket"
   145  	region := "eu-west-1"
   146  	endpoint := os.Getenv(envMinioEndpoint)
   147  
   148  	t.Log("setup env")
   149  	t.Setenv(envAwsRegion, region)
   150  	t.Setenv(envS3AccessKey, "aws_access_key")
   151  	t.Setenv(envS3SecretKey, "aws_secret_key")
   152  	t.Setenv(envS3Bucket, bucketName)
   153  	createBucket(testCtx, t, endpoint, region, bucketName)
   154  
   155  	t.Run("copy objects", func(t *testing.T) {
   156  		t.Setenv(envS3UseSSL, "false")
   157  		t.Setenv(envS3Endpoint, endpoint)
   158  		s3 := mod.New()
   159  		err := s3.Init(testCtx, newFakeModuleParams(dataDir))
   160  		require.Nil(t, err)
   161  
   162  		t.Run("put object to bucket", func(t *testing.T) {
   163  			err := s3.PutObject(testCtx, backupID, key, []byte("hello"))
   164  			assert.Nil(t, err, "expected nil, got: %v", err)
   165  		})
   166  
   167  		t.Run("get object from bucket", func(t *testing.T) {
   168  			meta, err := s3.GetObject(testCtx, backupID, key)
   169  			assert.Nil(t, err, "expected nil, got: %v", err)
   170  			assert.Equal(t, []byte("hello"), meta)
   171  		})
   172  	})
   173  }
   174  
   175  func moduleLevelCopyFiles(t *testing.T) {
   176  	testCtx, cancel := context.WithTimeout(context.Background(), time.Minute)
   177  	defer cancel()
   178  
   179  	dataDir := t.TempDir()
   180  	key := "moduleLevelCopyFiles"
   181  	backupID := "backup_id"
   182  	bucketName := "bucket"
   183  	region := "eu-west-1"
   184  	endpoint := os.Getenv(envMinioEndpoint)
   185  
   186  	t.Log("setup env")
   187  	t.Setenv(envAwsRegion, region)
   188  	t.Setenv(envS3AccessKey, "aws_access_key")
   189  	t.Setenv(envS3SecretKey, "aws_secret_key")
   190  	t.Setenv(envS3Bucket, bucketName)
   191  	createBucket(testCtx, t, endpoint, region, bucketName)
   192  
   193  	t.Run("copy files", func(t *testing.T) {
   194  		fpaths := moduleshelper.CreateTestFiles(t, dataDir)
   195  		fpath := fpaths[0]
   196  		expectedContents, err := os.ReadFile(fpath)
   197  		require.Nil(t, err)
   198  		require.NotNil(t, expectedContents)
   199  
   200  		t.Setenv(envS3UseSSL, "false")
   201  		t.Setenv(envS3Endpoint, endpoint)
   202  		s3 := mod.New()
   203  		err = s3.Init(testCtx, newFakeModuleParams(dataDir))
   204  		require.Nil(t, err)
   205  
   206  		t.Run("verify source data path", func(t *testing.T) {
   207  			assert.Equal(t, dataDir, s3.SourceDataPath())
   208  		})
   209  
   210  		t.Run("copy file to backend", func(t *testing.T) {
   211  			srcPath, _ := filepath.Rel(dataDir, fpath)
   212  			err := s3.PutFile(testCtx, backupID, key, srcPath)
   213  			require.Nil(t, err)
   214  
   215  			contents, err := s3.GetObject(testCtx, backupID, key)
   216  			require.Nil(t, err)
   217  			assert.Equal(t, expectedContents, contents)
   218  		})
   219  
   220  		t.Run("fetch file from backend", func(t *testing.T) {
   221  			destPath := dataDir + "/file_0.copy.db"
   222  
   223  			err := s3.WriteToFile(testCtx, backupID, key, destPath)
   224  			require.Nil(t, err)
   225  
   226  			contents, err := os.ReadFile(destPath)
   227  			require.Nil(t, err)
   228  			assert.Equal(t, expectedContents, contents)
   229  		})
   230  	})
   231  }
   232  
   233  type fakeModuleParams struct {
   234  	logger   logrus.FieldLogger
   235  	provider fakeStorageProvider
   236  	config   config.Config
   237  }
   238  
   239  func newFakeModuleParams(dataPath string) *fakeModuleParams {
   240  	logger, _ := logrustest.NewNullLogger()
   241  	return &fakeModuleParams{
   242  		logger:   logger,
   243  		provider: fakeStorageProvider{dataPath: dataPath},
   244  	}
   245  }
   246  
   247  func (f *fakeModuleParams) GetStorageProvider() moduletools.StorageProvider {
   248  	return &f.provider
   249  }
   250  
   251  func (f *fakeModuleParams) GetAppState() interface{} {
   252  	return nil
   253  }
   254  
   255  func (f *fakeModuleParams) GetLogger() logrus.FieldLogger {
   256  	return f.logger
   257  }
   258  
   259  func (f *fakeModuleParams) GetConfig() config.Config {
   260  	return f.config
   261  }
   262  
   263  type fakeStorageProvider struct {
   264  	dataPath string
   265  }
   266  
   267  func (f *fakeStorageProvider) Storage(name string) (moduletools.Storage, error) {
   268  	return nil, nil
   269  }
   270  
   271  func (f *fakeStorageProvider) DataPath() string {
   272  	return f.dataPath
   273  }