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 }