github.com/weaviate/weaviate@v1.24.6/test/modules/backup-azure/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-azure"
    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_AzureBackend_Backup(t *testing.T) {
    38  	ctx := context.Background()
    39  	compose, err := docker.New().WithAzurite().Start(ctx)
    40  	if err != nil {
    41  		t.Fatal(errors.Wrapf(err, "cannot start"))
    42  	}
    43  
    44  	t.Setenv(envAzureEndpoint, compose.GetAzurite().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(), 30*time.Second)
    57  	defer cancel()
    58  
    59  	dataDir := t.TempDir()
    60  	className := "BackupClass"
    61  	backupID := "backup_id"
    62  	containerName := "container"
    63  	endpoint := os.Getenv(envAzureEndpoint)
    64  	metadataFilename := "backup.json"
    65  
    66  	t.Log("setup env")
    67  	t.Setenv(envAzureEndpoint, endpoint)
    68  	t.Setenv(envAzureStorageConnectionString, fmt.Sprintf(connectionString, endpoint))
    69  	t.Setenv(envAzureContainer, containerName)
    70  	moduleshelper.CreateAzureContainer(testCtx, t, endpoint, containerName)
    71  	defer moduleshelper.DeleteAzureContainer(testCtx, t, endpoint, containerName)
    72  
    73  	t.Run("store backup meta in Azure", func(t *testing.T) {
    74  		t.Setenv(envAzureContainer, containerName)
    75  		azure := mod.New()
    76  		err := azure.Init(testCtx, newFakeModuleParams(dataDir))
    77  		require.Nil(t, err)
    78  
    79  		t.Run("access permissions", func(t *testing.T) {
    80  			err := azure.Initialize(testCtx, backupID)
    81  			assert.Nil(t, err)
    82  		})
    83  
    84  		t.Run("backup meta does not exist yet", func(t *testing.T) {
    85  			meta, err := azure.GetObject(testCtx, backupID, metadataFilename)
    86  			assert.Nil(t, meta)
    87  			assert.NotNil(t, err)
    88  			assert.IsType(t, backup.ErrNotFound{}, err)
    89  		})
    90  
    91  		t.Run("put backup meta on backend", func(t *testing.T) {
    92  			desc := &backup.BackupDescriptor{
    93  				StartedAt:   time.Now(),
    94  				CompletedAt: time.Time{},
    95  				ID:          backupID,
    96  				Classes: []backup.ClassDescriptor{
    97  					{
    98  						Name: className,
    99  					},
   100  				},
   101  				Status:  string(backup.Started),
   102  				Version: ubak.Version,
   103  			}
   104  
   105  			b, err := json.Marshal(desc)
   106  			require.Nil(t, err)
   107  
   108  			err = azure.PutObject(testCtx, backupID, metadataFilename, b)
   109  			require.Nil(t, err)
   110  
   111  			dest := azure.HomeDir(backupID)
   112  
   113  			expected := fmt.Sprintf("http://%s/devstoreaccount1/%s/%s", os.Getenv(envAzureEndpoint), containerName, backupID)
   114  			assert.Equal(t, expected, dest)
   115  		})
   116  
   117  		t.Run("assert backup meta contents", func(t *testing.T) {
   118  			obj, err := azure.GetObject(testCtx, backupID, metadataFilename)
   119  			require.Nil(t, err)
   120  
   121  			var meta backup.BackupDescriptor
   122  			err = json.Unmarshal(obj, &meta)
   123  			require.Nil(t, err)
   124  			assert.NotEmpty(t, meta.StartedAt)
   125  			assert.Empty(t, meta.CompletedAt)
   126  			assert.Equal(t, meta.Status, string(backup.Started))
   127  			assert.Empty(t, meta.Error)
   128  			assert.Len(t, meta.Classes, 1)
   129  			assert.Equal(t, meta.Classes[0].Name, className)
   130  			assert.Equal(t, meta.Version, ubak.Version)
   131  			assert.Nil(t, meta.Classes[0].Error)
   132  		})
   133  	})
   134  }
   135  
   136  func moduleLevelCopyObjects(t *testing.T) {
   137  	testCtx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
   138  	defer cancel()
   139  
   140  	dataDir := t.TempDir()
   141  	key := "moduleLevelCopyObjects"
   142  	backupID := "backup_id"
   143  	containerName := "container"
   144  	endpoint := os.Getenv(envAzureEndpoint)
   145  
   146  	t.Log("setup env")
   147  	t.Setenv(envAzureEndpoint, endpoint)
   148  	t.Setenv(envAzureStorageConnectionString, fmt.Sprintf(connectionString, endpoint))
   149  	t.Setenv(envAzureContainer, containerName)
   150  	moduleshelper.CreateAzureContainer(testCtx, t, endpoint, containerName)
   151  	defer moduleshelper.DeleteAzureContainer(testCtx, t, endpoint, containerName)
   152  
   153  	t.Run("copy objects", func(t *testing.T) {
   154  		t.Setenv(envAzureContainer, containerName)
   155  		azure := mod.New()
   156  		err := azure.Init(testCtx, newFakeModuleParams(dataDir))
   157  		require.Nil(t, err)
   158  
   159  		t.Run("put object to bucket", func(t *testing.T) {
   160  			err := azure.PutObject(testCtx, backupID, key, []byte("hello"))
   161  			assert.Nil(t, err)
   162  		})
   163  
   164  		t.Run("get object from bucket", func(t *testing.T) {
   165  			meta, err := azure.GetObject(testCtx, backupID, key)
   166  			assert.Nil(t, err)
   167  			assert.Equal(t, []byte("hello"), meta)
   168  		})
   169  	})
   170  }
   171  
   172  func moduleLevelCopyFiles(t *testing.T) {
   173  	testCtx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
   174  	defer cancel()
   175  
   176  	dataDir := t.TempDir()
   177  	key := "moduleLevelCopyFiles"
   178  	backupID := "backup_id"
   179  	containerName := "container"
   180  	endpoint := os.Getenv(envAzureEndpoint)
   181  
   182  	t.Log("setup env")
   183  	t.Setenv(envAzureEndpoint, endpoint)
   184  	t.Setenv(envAzureStorageConnectionString, fmt.Sprintf(connectionString, endpoint))
   185  	t.Setenv(envAzureContainer, containerName)
   186  	moduleshelper.CreateAzureContainer(testCtx, t, endpoint, containerName)
   187  	defer moduleshelper.DeleteAzureContainer(testCtx, t, endpoint, containerName)
   188  
   189  	t.Run("copy files", func(t *testing.T) {
   190  		fpaths := moduleshelper.CreateTestFiles(t, dataDir)
   191  		fpath := fpaths[0]
   192  		expectedContents, err := os.ReadFile(fpath)
   193  		require.Nil(t, err)
   194  		require.NotNil(t, expectedContents)
   195  
   196  		t.Setenv(envAzureContainer, containerName)
   197  		azure := mod.New()
   198  		err = azure.Init(testCtx, newFakeModuleParams(dataDir))
   199  		require.Nil(t, err)
   200  
   201  		t.Run("verify source data path", func(t *testing.T) {
   202  			assert.Equal(t, dataDir, azure.SourceDataPath())
   203  		})
   204  
   205  		t.Run("copy file to backend", func(t *testing.T) {
   206  			srcPath, _ := filepath.Rel(dataDir, fpath)
   207  			err := azure.PutFile(testCtx, backupID, key, srcPath)
   208  			require.Nil(t, err)
   209  
   210  			contents, err := azure.GetObject(testCtx, backupID, key)
   211  			require.Nil(t, err)
   212  			assert.Equal(t, expectedContents, contents)
   213  		})
   214  
   215  		t.Run("fetch file from backend", func(t *testing.T) {
   216  			destPath := dataDir + "/file_0.copy.db"
   217  
   218  			err := azure.WriteToFile(testCtx, backupID, key, destPath)
   219  			require.Nil(t, err)
   220  
   221  			contents, err := os.ReadFile(destPath)
   222  			require.Nil(t, err)
   223  			assert.Equal(t, expectedContents, contents)
   224  		})
   225  	})
   226  }
   227  
   228  type fakeModuleParams struct {
   229  	logger   logrus.FieldLogger
   230  	provider fakeStorageProvider
   231  	config   config.Config
   232  }
   233  
   234  func newFakeModuleParams(dataPath string) *fakeModuleParams {
   235  	logger, _ := logrustest.NewNullLogger()
   236  	return &fakeModuleParams{
   237  		logger:   logger,
   238  		provider: fakeStorageProvider{dataPath: dataPath},
   239  	}
   240  }
   241  
   242  func (f *fakeModuleParams) GetStorageProvider() moduletools.StorageProvider {
   243  	return &f.provider
   244  }
   245  
   246  func (f *fakeModuleParams) GetAppState() interface{} {
   247  	return nil
   248  }
   249  
   250  func (f *fakeModuleParams) GetLogger() logrus.FieldLogger {
   251  	return f.logger
   252  }
   253  
   254  func (f *fakeModuleParams) GetConfig() config.Config {
   255  	return f.config
   256  }
   257  
   258  type fakeStorageProvider struct {
   259  	dataPath string
   260  }
   261  
   262  func (f *fakeStorageProvider) Storage(name string) (moduletools.Storage, error) {
   263  	return nil, nil
   264  }
   265  
   266  func (f *fakeStorageProvider) DataPath() string {
   267  	return f.dataPath
   268  }