github.com/weaviate/weaviate@v1.24.6/entities/backup/descriptor_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 backup 13 14 import ( 15 "sort" 16 "testing" 17 "time" 18 19 "github.com/stretchr/testify/assert" 20 ) 21 22 func TestExcludeClasses(t *testing.T) { 23 tests := []struct { 24 in BackupDescriptor 25 xs []string 26 out []string 27 }{ 28 {in: BackupDescriptor{}, xs: []string{}, out: []string{}}, 29 {in: BackupDescriptor{Classes: []ClassDescriptor{{Name: "a"}}}, xs: []string{}, out: []string{"a"}}, 30 {in: BackupDescriptor{Classes: []ClassDescriptor{{Name: "a"}}}, xs: []string{"a"}, out: []string{}}, 31 {in: BackupDescriptor{Classes: []ClassDescriptor{{Name: "1"}, {Name: "2"}, {Name: "3"}, {Name: "4"}}}, xs: []string{"2", "3"}, out: []string{"1", "4"}}, 32 {in: BackupDescriptor{Classes: []ClassDescriptor{{Name: "1"}, {Name: "2"}, {Name: "3"}}}, xs: []string{"1", "3"}, out: []string{"2"}}, 33 34 // {in: []BackupDescriptor{"1", "2", "3", "4"}, xs: []string{"2", "3"}, out: []string{"1", "4"}}, 35 // {in: []BackupDescriptor{"1", "2", "3"}, xs: []string{"1", "3"}, out: []string{"2"}}, 36 } 37 for _, tc := range tests { 38 tc.in.Exclude(tc.xs) 39 lst := tc.in.List() 40 assert.Equal(t, tc.out, lst) 41 } 42 } 43 44 func TestIncludeClasses(t *testing.T) { 45 tests := []struct { 46 in BackupDescriptor 47 xs []string 48 out []string 49 }{ 50 {in: BackupDescriptor{}, xs: []string{}, out: []string{}}, 51 {in: BackupDescriptor{Classes: []ClassDescriptor{{Name: "a"}}}, xs: []string{}, out: []string{"a"}}, 52 {in: BackupDescriptor{Classes: []ClassDescriptor{{Name: "a"}}}, xs: []string{"a"}, out: []string{"a"}}, 53 {in: BackupDescriptor{Classes: []ClassDescriptor{{Name: "1"}, {Name: "2"}, {Name: "3"}, {Name: "4"}}}, xs: []string{"2", "3"}, out: []string{"2", "3"}}, 54 {in: BackupDescriptor{Classes: []ClassDescriptor{{Name: "1"}, {Name: "2"}, {Name: "3"}}}, xs: []string{"1", "3"}, out: []string{"1", "3"}}, 55 } 56 for _, tc := range tests { 57 tc.in.Include(tc.xs) 58 lst := tc.in.List() 59 assert.Equal(t, tc.out, lst) 60 } 61 } 62 63 func TestAllExist(t *testing.T) { 64 x := BackupDescriptor{Classes: []ClassDescriptor{{Name: "a"}}} 65 if y := x.AllExist(nil); y != "" { 66 t.Errorf("x.AllExists(nil) got=%v want=%v", y, "") 67 } 68 if y := x.AllExist([]string{"a"}); y != "" { 69 t.Errorf("x.AllExists(['a']) got=%v want=%v", y, "") 70 } 71 if y := x.AllExist([]string{"b"}); y != "b" { 72 t.Errorf("x.AllExists(['a']) got=%v want=%v", y, "b") 73 } 74 } 75 76 func TestValidateBackup(t *testing.T) { 77 timept := time.Now().UTC() 78 bytes := []byte("hello") 79 tests := []struct { 80 desc BackupDescriptor 81 successV1 bool 82 successV2 bool 83 }{ 84 // first level check 85 {desc: BackupDescriptor{}}, 86 {desc: BackupDescriptor{ID: "1"}}, 87 {desc: BackupDescriptor{ID: "1", Version: "1"}}, 88 {desc: BackupDescriptor{ID: "1", Version: "1", ServerVersion: "1"}}, 89 { 90 desc: BackupDescriptor{ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept}, 91 successV1: true, successV2: true, 92 }, 93 {desc: BackupDescriptor{ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept, Error: "err"}}, 94 {desc: BackupDescriptor{ 95 ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept, 96 Classes: []ClassDescriptor{{}}, 97 }}, 98 {desc: BackupDescriptor{ 99 ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept, 100 Classes: []ClassDescriptor{{Name: "n"}}, 101 }}, 102 {desc: BackupDescriptor{ 103 ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept, 104 Classes: []ClassDescriptor{{Name: "n", Schema: bytes}}, 105 }}, 106 {desc: BackupDescriptor{ 107 ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept, 108 Classes: []ClassDescriptor{{Name: "n", Schema: bytes, ShardingState: bytes}}, 109 }, successV1: true, successV2: true}, 110 {desc: BackupDescriptor{ 111 ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept, 112 Classes: []ClassDescriptor{{ 113 Name: "n", Schema: bytes, ShardingState: bytes, 114 Shards: []*ShardDescriptor{{Name: ""}}, 115 }}, 116 }}, 117 {desc: BackupDescriptor{ 118 ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept, 119 Classes: []ClassDescriptor{{ 120 Name: "n", Schema: bytes, ShardingState: bytes, 121 Shards: []*ShardDescriptor{{Name: "n", Node: ""}}, 122 }}, 123 }}, 124 {desc: BackupDescriptor{ 125 ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept, 126 Classes: []ClassDescriptor{{ 127 Name: "n", Schema: bytes, ShardingState: bytes, 128 Shards: []*ShardDescriptor{{Name: "n", Node: "n"}}, 129 }}, 130 }, successV2: true}, 131 {desc: BackupDescriptor{ 132 ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept, 133 Classes: []ClassDescriptor{{ 134 Name: "n", Schema: bytes, ShardingState: bytes, 135 Shards: []*ShardDescriptor{{ 136 Name: "n", Node: "n", 137 PropLengthTrackerPath: "n", DocIDCounterPath: "n", ShardVersionPath: "n", 138 }}, 139 }}, 140 }, successV1: true, successV2: true}, 141 {desc: BackupDescriptor{ 142 ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept, 143 Classes: []ClassDescriptor{{ 144 Name: "n", Schema: bytes, ShardingState: bytes, 145 Shards: []*ShardDescriptor{{ 146 Name: "n", Node: "n", 147 PropLengthTrackerPath: "n", DocIDCounterPath: "n", ShardVersionPath: "n", 148 Files: []string{"file"}, 149 }}, 150 }}, 151 }, successV2: true}, 152 {desc: BackupDescriptor{ 153 ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept, 154 Classes: []ClassDescriptor{{ 155 Name: "n", Schema: bytes, ShardingState: bytes, 156 Shards: []*ShardDescriptor{{ 157 Name: "n", Node: "n", 158 PropLengthTrackerPath: "n", DocIDCounterPath: "n", ShardVersionPath: "n", 159 DocIDCounter: bytes, Files: []string{"file"}, 160 }}, 161 }}, 162 }, successV2: true}, 163 {desc: BackupDescriptor{ 164 ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept, 165 Classes: []ClassDescriptor{{ 166 Name: "n", Schema: bytes, ShardingState: bytes, 167 Shards: []*ShardDescriptor{{ 168 Name: "n", Node: "n", 169 PropLengthTrackerPath: "n", DocIDCounterPath: "n", ShardVersionPath: "n", 170 DocIDCounter: bytes, Version: bytes, PropLengthTracker: bytes, Files: []string{""}, 171 }}, 172 }}, 173 }, successV2: true}, 174 {desc: BackupDescriptor{ 175 ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept, 176 Classes: []ClassDescriptor{{ 177 Name: "n", Schema: bytes, ShardingState: bytes, 178 Shards: []*ShardDescriptor{{ 179 Name: "n", Node: "n", 180 PropLengthTrackerPath: "n", DocIDCounterPath: "n", ShardVersionPath: "n", 181 DocIDCounter: bytes, Version: bytes, PropLengthTracker: bytes, Files: []string{"file"}, 182 }}, 183 }}, 184 }, successV1: true, successV2: true}, 185 } 186 for i, tc := range tests { 187 err := tc.desc.Validate(false) 188 if got := err == nil; got != tc.successV1 { 189 t.Errorf("%d. validate(%+v): want=%v got=%v err=%v", i, tc.desc, tc.successV1, got, err) 190 } 191 err = tc.desc.Validate(true) 192 if got := err == nil; got != tc.successV2 { 193 t.Errorf("%d. validate(%+v): want=%v got=%v err=%v", i, tc.desc, tc.successV1, got, err) 194 } 195 } 196 } 197 198 func TestBackwardCompatibility(t *testing.T) { 199 timept := time.Now().UTC() 200 tests := []struct { 201 desc BackupDescriptor 202 success bool 203 }{ 204 // first level check 205 {desc: BackupDescriptor{}}, 206 {desc: BackupDescriptor{ID: "1"}}, 207 {desc: BackupDescriptor{ID: "1", Version: "1"}}, 208 {desc: BackupDescriptor{ID: "1", Version: "1", ServerVersion: "1"}}, 209 {desc: BackupDescriptor{ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept}}, 210 {desc: BackupDescriptor{ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept, Error: "err"}}, 211 {desc: BackupDescriptor{ 212 ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept, 213 Classes: []ClassDescriptor{{ 214 Name: "n", 215 Shards: []*ShardDescriptor{{Name: "n", Node: ""}}, 216 }}, 217 }}, 218 {desc: BackupDescriptor{ 219 ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept, 220 Classes: []ClassDescriptor{{ 221 Name: "n", 222 Shards: []*ShardDescriptor{{ 223 Name: "n", Node: "n", 224 }}, 225 }}, 226 }, success: true}, 227 } 228 for i, tc := range tests { 229 desc := tc.desc.ToDistributed() 230 err := desc.Validate() 231 if got := err == nil; got != tc.success { 232 t.Errorf("%d. validate(%+v): want=%v got=%v err=%v", i, tc.desc, tc.success, got, err) 233 } 234 } 235 } 236 237 func TestDistributedBackup(t *testing.T) { 238 d := DistributedBackupDescriptor{ 239 Nodes: map[string]*NodeDescriptor{ 240 "N1": {Classes: []string{"1", "2"}}, 241 "N2": {Classes: []string{"3", "4"}}, 242 }, 243 } 244 if n := d.Len(); n != 2 { 245 t.Errorf("#nodes got:%v want:%v", n, 2) 246 } 247 if n := d.Count(); n != 4 { 248 t.Errorf("#classes got:%v want:%v", n, 4) 249 } 250 d.Exclude([]string{"3", "4"}) 251 d.RemoveEmpty() 252 if n := d.Len(); n != 1 { 253 t.Errorf("#nodes got:%v want:%v", n, 2) 254 } 255 if n := d.Count(); n != 2 { 256 t.Errorf("#classes got:%v want:%v", n, 4) 257 } 258 } 259 260 func TestDistributedBackupExcludeClasses(t *testing.T) { 261 tests := []struct { 262 in DistributedBackupDescriptor 263 xs []string 264 out []string 265 }{ 266 { 267 in: DistributedBackupDescriptor{}, 268 xs: []string{}, 269 out: []string{}, 270 }, 271 { 272 in: DistributedBackupDescriptor{ 273 Nodes: map[string]*NodeDescriptor{ 274 "N1": {Classes: []string{"a"}}, 275 }, 276 }, 277 xs: []string{}, 278 out: []string{"a"}, 279 }, 280 { 281 in: DistributedBackupDescriptor{ 282 Nodes: map[string]*NodeDescriptor{ 283 "N1": {Classes: []string{"a"}}, 284 }, 285 }, 286 xs: []string{"a"}, 287 out: []string{}, 288 }, 289 { 290 in: DistributedBackupDescriptor{ 291 Nodes: map[string]*NodeDescriptor{ 292 "N1": {Classes: []string{"1", "2"}}, 293 "N2": {Classes: []string{"3", "4"}}, 294 }, 295 }, 296 xs: []string{"2", "3"}, 297 out: []string{"1", "4"}, 298 }, 299 300 { 301 in: DistributedBackupDescriptor{ 302 Nodes: map[string]*NodeDescriptor{ 303 "N1": {Classes: []string{"1", "2"}}, 304 "N2": {Classes: []string{"3"}}, 305 }, 306 }, 307 xs: []string{"1", "3"}, 308 out: []string{"2"}, 309 }, 310 } 311 312 for _, tc := range tests { 313 tc.in.Exclude(tc.xs) 314 lst := tc.in.Classes() 315 sort.Strings(lst) 316 assert.Equal(t, tc.out, lst) 317 } 318 } 319 320 func TestDistributedBackupIncludeClasses(t *testing.T) { 321 tests := []struct { 322 in DistributedBackupDescriptor 323 xs []string 324 out []string 325 }{ 326 { 327 in: DistributedBackupDescriptor{}, 328 xs: []string{}, 329 out: []string{}, 330 }, 331 { 332 in: DistributedBackupDescriptor{ 333 Nodes: map[string]*NodeDescriptor{ 334 "N1": {Classes: []string{"a"}}, 335 }, 336 }, 337 xs: []string{}, 338 out: []string{"a"}, 339 }, 340 { 341 in: DistributedBackupDescriptor{ 342 Nodes: map[string]*NodeDescriptor{ 343 "N1": {Classes: []string{"a"}}, 344 }, 345 }, 346 xs: []string{"a"}, 347 out: []string{"a"}, 348 }, 349 { 350 in: DistributedBackupDescriptor{ 351 Nodes: map[string]*NodeDescriptor{ 352 "N1": {Classes: []string{"1", "2"}}, 353 "N2": {Classes: []string{"3", "4"}}, 354 }, 355 }, 356 xs: []string{"2", "3"}, 357 out: []string{"2", "3"}, 358 }, 359 360 { 361 in: DistributedBackupDescriptor{ 362 Nodes: map[string]*NodeDescriptor{ 363 "N1": {Classes: []string{"1", "2"}}, 364 "N2": {Classes: []string{"3"}}, 365 }, 366 }, 367 xs: []string{"1", "3"}, 368 out: []string{"1", "3"}, 369 }, 370 } 371 for _, tc := range tests { 372 tc.in.Include(tc.xs) 373 lst := tc.in.Classes() 374 sort.Strings(lst) 375 assert.Equal(t, tc.out, lst) 376 } 377 } 378 379 func TestDistributedBackupAllExist(t *testing.T) { 380 x := DistributedBackupDescriptor{Nodes: map[string]*NodeDescriptor{"N1": {Classes: []string{"a"}}}} 381 if y := x.AllExist(nil); y != "" { 382 t.Errorf("x.AllExists(nil) got=%v want=%v", y, "") 383 } 384 if y := x.AllExist([]string{"a"}); y != "" { 385 t.Errorf("x.AllExists(['a']) got=%v want=%v", y, "") 386 } 387 if y := x.AllExist([]string{"b"}); y != "b" { 388 t.Errorf("x.AllExists(['a']) got=%v want=%v", y, "b") 389 } 390 } 391 392 func TestDistributedBackupValidate(t *testing.T) { 393 timept := time.Now().UTC() 394 tests := []struct { 395 desc DistributedBackupDescriptor 396 success bool 397 }{ 398 // first level check 399 {desc: DistributedBackupDescriptor{}}, 400 {desc: DistributedBackupDescriptor{ID: "1"}}, 401 {desc: DistributedBackupDescriptor{ID: "1", Version: "1"}}, 402 {desc: DistributedBackupDescriptor{ID: "1", Version: "1", ServerVersion: "1"}}, 403 {desc: DistributedBackupDescriptor{ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept, Error: "err"}}, 404 {desc: DistributedBackupDescriptor{ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept}}, 405 {desc: DistributedBackupDescriptor{ 406 ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept, 407 Nodes: map[string]*NodeDescriptor{"N": {}}, 408 }, success: true}, 409 } 410 for i, tc := range tests { 411 err := tc.desc.Validate() 412 if got := err == nil; got != tc.success { 413 t.Errorf("%d. validate(%+v): want=%v got=%v err=%v", i, tc.desc, tc.success, got, err) 414 } 415 } 416 } 417 418 func TestTestDistributedBackupResetStatus(t *testing.T) { 419 begin := time.Now().UTC().Add(-2) 420 desc := DistributedBackupDescriptor{ 421 StartedAt: begin, 422 CompletedAt: begin.Add(2), 423 ID: "1", 424 Version: "1", 425 ServerVersion: "1", 426 Nodes: map[string]*NodeDescriptor{ 427 "1": {}, 428 "2": {Status: Success}, 429 "3": {Error: "error"}, 430 }, 431 Error: "error", 432 } 433 434 desc.ResetStatus() 435 if !desc.StartedAt.After(begin) { 436 t.Fatalf("!desc.StartedAt.After(begin)") 437 } 438 want := DistributedBackupDescriptor{ 439 StartedAt: desc.StartedAt, 440 ID: "1", 441 Version: "1", 442 ServerVersion: "1", 443 Nodes: map[string]*NodeDescriptor{ 444 "1": {Status: Started}, 445 "2": {Status: Started}, 446 "3": {Status: Started, Error: ""}, 447 }, 448 Status: Started, 449 } 450 assert.Equal(t, want, desc) 451 } 452 453 func TestShardDescriptorClear(t *testing.T) { 454 s := ShardDescriptor{ 455 Name: "name", 456 Node: "node", 457 PropLengthTrackerPath: "a/b", 458 PropLengthTracker: []byte{1}, 459 DocIDCounterPath: "a/c", 460 DocIDCounter: []byte{2}, 461 ShardVersionPath: "a/d", 462 Version: []byte{3}, 463 Files: []string{"file"}, 464 Chunk: 1, 465 } 466 467 want := ShardDescriptor{ 468 Name: "name", 469 Node: "node", 470 Files: []string{"file"}, 471 Chunk: 1, 472 } 473 s.ClearTemporary() 474 assert.Equal(t, want, s) 475 }