github.com/weaviate/weaviate@v1.24.6/test/helper/journey/backup_and_restore_journey.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 journey
    13  
    14  import (
    15  	"strconv"
    16  	"testing"
    17  	"time"
    18  
    19  	"github.com/stretchr/testify/require"
    20  	"github.com/weaviate/weaviate/client/backups"
    21  	"github.com/weaviate/weaviate/entities/models"
    22  	"github.com/weaviate/weaviate/test/helper"
    23  	"github.com/weaviate/weaviate/test/helper/sample-schema/books"
    24  )
    25  
    26  func backupAndRestoreJourneyTest(t *testing.T, weaviateEndpoint, backend string, namedVectors bool) {
    27  	if weaviateEndpoint != "" {
    28  		helper.SetupClient(weaviateEndpoint)
    29  	}
    30  
    31  	var booksClass *models.Class
    32  	if namedVectors {
    33  		booksClass = books.ClassNamedContextionaryVectorizer()
    34  	} else {
    35  		booksClass = books.ClassContextionaryVectorizer()
    36  	}
    37  	helper.CreateClass(t, booksClass)
    38  	defer helper.DeleteClass(t, booksClass.Class)
    39  
    40  	verifyThatAllBooksExist := func(t *testing.T) {
    41  		book := helper.AssertGetObject(t, booksClass.Class, books.Dune)
    42  		require.Equal(t, books.Dune, book.ID)
    43  		book = helper.AssertGetObject(t, booksClass.Class, books.ProjectHailMary)
    44  		require.Equal(t, books.ProjectHailMary, book.ID)
    45  		book = helper.AssertGetObject(t, booksClass.Class, books.TheLordOfTheIceGarden)
    46  		require.Equal(t, books.TheLordOfTheIceGarden, book.ID)
    47  	}
    48  
    49  	vectorsForDune := func() map[string][]float32 {
    50  		vectors := map[string][]float32{}
    51  		duneBook := helper.AssertGetObject(t, booksClass.Class, books.Dune)
    52  
    53  		if namedVectors {
    54  			for name := range booksClass.VectorConfig {
    55  				vectors[name] = duneBook.Vectors[name]
    56  			}
    57  		} else {
    58  			vectors["vector"] = duneBook.Vector
    59  		}
    60  		return vectors
    61  	}
    62  
    63  	backupID := "backup-1_named_vectors" + strconv.FormatBool(namedVectors)
    64  	t.Run("add data to Books schema", func(t *testing.T) {
    65  		for _, book := range books.Objects() {
    66  			helper.CreateObject(t, book)
    67  			helper.AssertGetObjectEventually(t, book.Class, book.ID)
    68  		}
    69  	})
    70  
    71  	t.Run("verify that Books objects exist", func(t *testing.T) {
    72  		verifyThatAllBooksExist(t)
    73  	})
    74  	initialVectors := vectorsForDune()
    75  
    76  	t.Run("verify invalid compression config", func(t *testing.T) {
    77  		// unknown compression level
    78  		resp, err := helper.CreateBackup(t, &models.BackupConfig{
    79  			CompressionLevel: "some-weird-config",
    80  		}, booksClass.Class, backend, backupID)
    81  
    82  		helper.AssertRequestFail(t, resp, err, func() {
    83  			_, ok := err.(*backups.BackupsCreateUnprocessableEntity)
    84  			require.True(t, ok, "not backups.BackupsCreateUnprocessableEntity")
    85  		})
    86  
    87  		// out of band cpu %
    88  		resp, err = helper.CreateBackup(t, &models.BackupConfig{
    89  			CPUPercentage: 120,
    90  		}, booksClass.Class, backend, backupID)
    91  		helper.AssertRequestFail(t, resp, err, func() {
    92  			_, ok := err.(*backups.BackupsCreateUnprocessableEntity)
    93  			require.True(t, ok, "not backups.BackupsCreateUnprocessableEntity")
    94  		})
    95  
    96  		// out of band chunkSize
    97  		resp, err = helper.CreateBackup(t, &models.BackupConfig{
    98  			ChunkSize: 1024,
    99  		}, booksClass.Class, backend, backupID)
   100  		helper.AssertRequestFail(t, resp, err, func() {
   101  			_, ok := err.(*backups.BackupsCreateUnprocessableEntity)
   102  			require.True(t, ok, "not backups.BackupsCreateUnprocessableEntity")
   103  		})
   104  	})
   105  
   106  	t.Run("start backup process", func(t *testing.T) {
   107  		params := backups.NewBackupsCreateParams().
   108  			WithBackend(backend).
   109  			WithBody(&models.BackupCreateRequest{
   110  				ID:      backupID,
   111  				Include: []string{booksClass.Class},
   112  				Config: &models.BackupConfig{
   113  					CPUPercentage:    80,
   114  					ChunkSize:        512,
   115  					CompressionLevel: models.BackupConfigCompressionLevelDefaultCompression,
   116  				},
   117  			})
   118  		resp, err := helper.Client(t).Backups.BackupsCreate(params, nil)
   119  
   120  		helper.AssertRequestOk(t, resp, err, func() {
   121  			meta := resp.GetPayload()
   122  			require.NotNil(t, meta)
   123  			require.Equal(t, models.BackupCreateStatusResponseStatusSTARTED, *meta.Status)
   124  		})
   125  	})
   126  
   127  	t.Run("verify that backup process is completed", func(t *testing.T) {
   128  		params := backups.NewBackupsCreateStatusParams().
   129  			WithBackend(backend).
   130  			WithID(backupID)
   131  		for {
   132  			resp, err := helper.Client(t).Backups.BackupsCreateStatus(params, nil)
   133  			require.Nil(t, err)
   134  			require.NotNil(t, resp)
   135  			meta := resp.GetPayload()
   136  			require.NotNil(t, meta)
   137  			switch *meta.Status {
   138  			case models.BackupCreateStatusResponseStatusSUCCESS:
   139  				return
   140  			case models.BackupCreateStatusResponseStatusFAILED:
   141  				t.Errorf("failed to create backup, got response: %+v", meta)
   142  				return
   143  			default:
   144  				time.Sleep(1 * time.Second)
   145  			}
   146  		}
   147  	})
   148  
   149  	t.Run("verify that Books objects still exist", func(t *testing.T) {
   150  		verifyThatAllBooksExist(t)
   151  	})
   152  
   153  	t.Run("remove Books class", func(t *testing.T) {
   154  		helper.DeleteClass(t, booksClass.Class)
   155  	})
   156  
   157  	t.Run("verify that objects don't exist", func(t *testing.T) {
   158  		err := helper.AssertGetObjectFailsEventually(t, booksClass.Class, books.Dune)
   159  		require.NotNil(t, err)
   160  		err = helper.AssertGetObjectFailsEventually(t, booksClass.Class, books.ProjectHailMary)
   161  		require.NotNil(t, err)
   162  		err = helper.AssertGetObjectFailsEventually(t, booksClass.Class, books.TheLordOfTheIceGarden)
   163  		require.NotNil(t, err)
   164  	})
   165  
   166  	// out of band cpu %
   167  	t.Run("invalid restore request", func(t *testing.T) {
   168  		resp, err := helper.RestoreBackup(t, &models.RestoreConfig{
   169  			CPUPercentage: 180,
   170  		}, booksClass.Class, backend, backupID, map[string]string{})
   171  
   172  		helper.AssertRequestFail(t, resp, err, func() {
   173  			_, ok := err.(*backups.BackupsRestoreUnprocessableEntity)
   174  			require.True(t, ok, "not backups.BackupsRestoreUnprocessableEntity")
   175  		})
   176  	})
   177  
   178  	t.Run("start restore process", func(t *testing.T) {
   179  		params := backups.NewBackupsRestoreParams().
   180  			WithBackend(backend).
   181  			WithID(backupID).
   182  			WithBody(&models.BackupRestoreRequest{
   183  				Include: []string{booksClass.Class},
   184  			})
   185  		resp, err := helper.Client(t).Backups.BackupsRestore(params, nil)
   186  		helper.AssertRequestOk(t, resp, err, func() {
   187  			meta := resp.GetPayload()
   188  			require.NotNil(t, meta)
   189  			require.Equal(t, models.BackupCreateStatusResponseStatusSTARTED, *meta.Status)
   190  		})
   191  	})
   192  	t.Run("verify that restore process is completed", func(t *testing.T) {
   193  		params := backups.NewBackupsRestoreStatusParams().
   194  			WithBackend(backend).
   195  			WithID(backupID)
   196  		for {
   197  			resp, err := helper.Client(t).Backups.BackupsRestoreStatus(params, nil)
   198  			require.Nil(t, err)
   199  			require.NotNil(t, resp)
   200  			meta := resp.GetPayload()
   201  			require.NotNil(t, meta)
   202  			switch *meta.Status {
   203  			case models.BackupRestoreStatusResponseStatusSUCCESS:
   204  				return
   205  			case models.BackupRestoreStatusResponseStatusFAILED:
   206  				t.Errorf("failed to restore backup, got response: %+v", meta)
   207  				return
   208  			default:
   209  				time.Sleep(1 * time.Second)
   210  			}
   211  		}
   212  	})
   213  
   214  	t.Run("verify that Books objects exist after restore", func(t *testing.T) {
   215  		verifyThatAllBooksExist(t)
   216  	})
   217  
   218  	t.Run("verify that vectors are the same after restore", func(t *testing.T) {
   219  		restoredVectors := vectorsForDune()
   220  		require.Equal(t, initialVectors, restoredVectors)
   221  	})
   222  }