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 }