github.com/weaviate/weaviate@v1.24.6/usecases/schema/tenant_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 schema 13 14 import ( 15 "context" 16 "testing" 17 18 "github.com/stretchr/testify/assert" 19 "github.com/weaviate/weaviate/entities/models" 20 "github.com/weaviate/weaviate/entities/schema" 21 ) 22 23 func TestAddTenants(t *testing.T) { 24 var ( 25 ctx = context.Background() 26 mt = &models.MultiTenancyConfig{Enabled: true} 27 tenants = []*models.Tenant{{Name: "USER1"}, {Name: "USER2"}} 28 cls = "C1" 29 properties = []*models.Property{ 30 { 31 Name: "uUID", 32 DataType: schema.DataTypeText.PropString(), 33 }, 34 } 35 repConfig = &models.ReplicationConfig{Factor: 1} 36 ) 37 38 type test struct { 39 name string 40 Class string 41 tenants []*models.Tenant 42 initial *models.Class 43 errMsgs []string 44 } 45 tests := []test{ 46 { 47 name: "UnknownClass", 48 Class: "UnknownClass", 49 tenants: tenants, 50 initial: &models.Class{ 51 Class: cls, 52 MultiTenancyConfig: mt, 53 Properties: properties, 54 ReplicationConfig: repConfig, 55 }, 56 errMsgs: []string{ErrNotFound.Error()}, 57 }, 58 { 59 name: "MTIsNil", 60 Class: cls, 61 tenants: tenants, 62 initial: &models.Class{ 63 Class: cls, 64 MultiTenancyConfig: nil, 65 Properties: properties, 66 ReplicationConfig: repConfig, 67 }, 68 errMsgs: []string{"not enabled"}, 69 }, 70 { 71 name: "MTDisabled", 72 Class: cls, 73 tenants: tenants, 74 initial: &models.Class{ 75 Class: cls, 76 MultiTenancyConfig: &models.MultiTenancyConfig{Enabled: false}, 77 Properties: properties, 78 ReplicationConfig: repConfig, 79 }, 80 errMsgs: []string{"not enabled"}, 81 }, 82 { 83 name: "EmptyTenantValue", 84 Class: cls, 85 tenants: []*models.Tenant{{Name: "Aaaa"}, {Name: ""}, {Name: "Bbbb"}}, 86 initial: &models.Class{ 87 Class: cls, 88 MultiTenancyConfig: &models.MultiTenancyConfig{Enabled: true}, 89 Properties: properties, 90 ReplicationConfig: repConfig, 91 }, 92 errMsgs: []string{"tenant"}, 93 }, 94 { 95 name: "InvalidActivityStatus", 96 Class: cls, 97 tenants: []*models.Tenant{ 98 {Name: "Aaaa", ActivityStatus: "DOES_NOT_EXIST_1"}, 99 {Name: "Bbbb", ActivityStatus: "DOES_NOT_EXIST_2"}, 100 }, 101 initial: &models.Class{ 102 Class: cls, 103 MultiTenancyConfig: &models.MultiTenancyConfig{Enabled: true}, 104 Properties: properties, 105 ReplicationConfig: repConfig, 106 }, 107 errMsgs: []string{ 108 "invalid activity status", 109 "DOES_NOT_EXIST_1", 110 "DOES_NOT_EXIST_2", 111 }, 112 }, 113 { 114 name: "UnsupportedActivityStatus", 115 Class: cls, 116 tenants: []*models.Tenant{ 117 {Name: "Aaaa", ActivityStatus: models.TenantActivityStatusWARM}, 118 {Name: "Bbbb", ActivityStatus: models.TenantActivityStatusFROZEN}, 119 }, 120 initial: &models.Class{ 121 Class: cls, 122 MultiTenancyConfig: &models.MultiTenancyConfig{Enabled: true}, 123 Properties: properties, 124 ReplicationConfig: repConfig, 125 }, 126 errMsgs: []string{ 127 "not yet supported activity status", 128 models.TenantActivityStatusWARM, 129 models.TenantActivityStatusFROZEN, 130 }, 131 }, 132 { 133 name: "Success", 134 Class: cls, 135 tenants: []*models.Tenant{ 136 {Name: "Aaaa"}, 137 {Name: "Bbbb", ActivityStatus: models.TenantActivityStatusHOT}, 138 {Name: "Cccc", ActivityStatus: models.TenantActivityStatusCOLD}, 139 }, 140 initial: &models.Class{ 141 Class: cls, 142 MultiTenancyConfig: &models.MultiTenancyConfig{Enabled: true}, 143 Properties: properties, 144 ReplicationConfig: repConfig, 145 }, 146 errMsgs: []string{}, 147 }, 148 // TODO test with replication factor >= 2 149 } 150 151 // AddTenants 152 for _, test := range tests { 153 sm := newSchemaManager() 154 err := sm.AddClass(ctx, nil, test.initial) 155 if err == nil { 156 _, err = sm.AddTenants(ctx, nil, test.Class, test.tenants) 157 } 158 if len(test.errMsgs) == 0 { 159 assert.Nil(t, err) 160 ss := sm.schemaCache.ShardingState[test.Class] 161 assert.NotNil(t, ss, test.name) 162 assert.Equal(t, len(ss.Physical), len(test.tenants), test.name) 163 } else { 164 for _, msg := range test.errMsgs { 165 assert.ErrorContains(t, err, msg, test.name) 166 } 167 } 168 } 169 } 170 171 func TestUpdateTenants(t *testing.T) { 172 var ( 173 ctx = context.Background() 174 mt = &models.MultiTenancyConfig{Enabled: true} 175 tenants = []*models.Tenant{ 176 {Name: "USER1", ActivityStatus: models.TenantActivityStatusHOT}, 177 {Name: "USER2", ActivityStatus: models.TenantActivityStatusHOT}, 178 } 179 cls = "C1" 180 properties = []*models.Property{ 181 { 182 Name: "uUID", 183 DataType: schema.DataTypeText.PropString(), 184 }, 185 } 186 repConfig = &models.ReplicationConfig{Factor: 1} 187 ) 188 189 type test struct { 190 name string 191 Class string 192 updateTenants []*models.Tenant 193 initial *models.Class 194 errMsgs []string 195 skipAdd bool 196 } 197 tests := []test{ 198 { 199 name: "UnknownClass", 200 Class: "UnknownClass", 201 updateTenants: tenants, 202 initial: &models.Class{ 203 Class: cls, 204 MultiTenancyConfig: mt, 205 Properties: properties, 206 ReplicationConfig: repConfig, 207 }, 208 errMsgs: []string{ErrNotFound.Error()}, 209 }, 210 { 211 name: "MTIsNil", 212 Class: cls, 213 updateTenants: tenants, 214 initial: &models.Class{ 215 Class: cls, 216 MultiTenancyConfig: nil, 217 Properties: properties, 218 ReplicationConfig: repConfig, 219 }, 220 errMsgs: []string{"not enabled"}, 221 skipAdd: true, 222 }, 223 { 224 name: "MTDisabled", 225 Class: cls, 226 updateTenants: tenants, 227 initial: &models.Class{ 228 Class: cls, 229 MultiTenancyConfig: &models.MultiTenancyConfig{Enabled: false}, 230 Properties: properties, 231 ReplicationConfig: repConfig, 232 }, 233 errMsgs: []string{"not enabled"}, 234 skipAdd: true, 235 }, 236 { 237 name: "EmptyTenantValue", 238 Class: cls, 239 updateTenants: []*models.Tenant{{Name: ""}}, 240 initial: &models.Class{ 241 Class: cls, 242 MultiTenancyConfig: &models.MultiTenancyConfig{Enabled: true}, 243 Properties: properties, 244 ReplicationConfig: repConfig, 245 }, 246 errMsgs: []string{"tenant"}, 247 }, 248 { 249 name: "InvalidActivityStatus", 250 Class: cls, 251 updateTenants: []*models.Tenant{ 252 {Name: tenants[0].Name, ActivityStatus: "DOES_NOT_EXIST_1"}, 253 {Name: tenants[1].Name, ActivityStatus: "DOES_NOT_EXIST_2"}, 254 }, 255 initial: &models.Class{ 256 Class: cls, 257 MultiTenancyConfig: &models.MultiTenancyConfig{Enabled: true}, 258 Properties: properties, 259 ReplicationConfig: repConfig, 260 }, 261 errMsgs: []string{ 262 "invalid activity status", 263 "DOES_NOT_EXIST_1", 264 "DOES_NOT_EXIST_2", 265 }, 266 }, 267 { 268 name: "UnsupportedActivityStatus", 269 Class: cls, 270 updateTenants: []*models.Tenant{ 271 {Name: tenants[0].Name, ActivityStatus: models.TenantActivityStatusWARM}, 272 {Name: tenants[1].Name, ActivityStatus: models.TenantActivityStatusFROZEN}, 273 }, 274 initial: &models.Class{ 275 Class: cls, 276 MultiTenancyConfig: &models.MultiTenancyConfig{Enabled: true}, 277 Properties: properties, 278 ReplicationConfig: repConfig, 279 }, 280 errMsgs: []string{ 281 "not yet supported activity status", 282 models.TenantActivityStatusWARM, 283 models.TenantActivityStatusFROZEN, 284 }, 285 }, 286 { 287 name: "EmptyActivityStatus", 288 Class: cls, 289 updateTenants: []*models.Tenant{ 290 {Name: tenants[0].Name}, 291 {Name: tenants[1].Name, ActivityStatus: ""}, 292 }, 293 initial: &models.Class{ 294 Class: cls, 295 MultiTenancyConfig: &models.MultiTenancyConfig{Enabled: true}, 296 Properties: properties, 297 ReplicationConfig: repConfig, 298 }, 299 errMsgs: []string{"invalid activity status"}, 300 }, 301 { 302 name: "Success", 303 Class: cls, 304 updateTenants: []*models.Tenant{ 305 {Name: tenants[0].Name, ActivityStatus: models.TenantActivityStatusCOLD}, 306 {Name: tenants[1].Name, ActivityStatus: models.TenantActivityStatusCOLD}, 307 }, 308 initial: &models.Class{ 309 Class: cls, 310 MultiTenancyConfig: &models.MultiTenancyConfig{Enabled: true}, 311 Properties: properties, 312 ReplicationConfig: repConfig, 313 }, 314 errMsgs: []string{}, 315 }, 316 } 317 318 for _, test := range tests { 319 sm := newSchemaManager() 320 if err := sm.AddClass(ctx, nil, test.initial); err != nil { 321 t.Fatalf("%s: add class: %v", test.name, err) 322 } 323 if !test.skipAdd { 324 if _, err := sm.AddTenants(ctx, nil, cls, tenants); err != nil { 325 t.Fatalf("%s: add tenants: %v", test.name, err) 326 } 327 } 328 329 err := sm.UpdateTenants(ctx, nil, test.Class, test.updateTenants) 330 if len(test.errMsgs) == 0 { 331 if err != nil { 332 t.Fatalf("%s: update tenants: %v", test.name, err) 333 } 334 ss := sm.schemaCache.ShardingState[test.Class] 335 if ss == nil { 336 t.Fatalf("%s: sharding state equal nil", test.name) 337 } 338 339 assert.Len(t, ss.Physical, len(tenants)) 340 for _, tenant := range test.updateTenants { 341 assert.Equal(t, tenant.ActivityStatus, ss.Physical[tenant.Name].Status, test.name) 342 } 343 } else { 344 for _, msg := range test.errMsgs { 345 assert.ErrorContains(t, err, msg, test.name) 346 } 347 } 348 } 349 } 350 351 func TestDeleteTenants(t *testing.T) { 352 var ( 353 ctx = context.Background() 354 tenants = []*models.Tenant{ 355 {Name: "USER1"}, 356 {Name: "USER2"}, 357 {Name: "USER3"}, 358 {Name: "USER4"}, 359 } 360 cls = "C1" 361 properties = []*models.Property{ 362 { 363 Name: "uUID", 364 DataType: schema.DataTypeText.PropString(), 365 }, 366 } 367 repConfig = &models.ReplicationConfig{Factor: 1} 368 ) 369 370 type test struct { 371 name string 372 Class string 373 tenants []*models.Tenant 374 initial *models.Class 375 errMsg string 376 addTenants bool 377 } 378 tests := []test{ 379 { 380 name: "UnknownClass", 381 Class: "UnknownClass", 382 tenants: tenants, 383 initial: &models.Class{ 384 Class: cls, MultiTenancyConfig: &models.MultiTenancyConfig{Enabled: true}, 385 Properties: properties, 386 ReplicationConfig: repConfig, 387 }, 388 errMsg: ErrNotFound.Error(), 389 }, 390 { 391 name: "MTIsNil", 392 Class: "C1", 393 tenants: tenants, 394 initial: &models.Class{ 395 Class: cls, 396 MultiTenancyConfig: nil, 397 Properties: properties, 398 ReplicationConfig: repConfig, 399 }, 400 errMsg: "not enabled", 401 }, 402 { 403 name: "MTDisabled", 404 Class: "C1", 405 tenants: tenants, 406 initial: &models.Class{ 407 Class: cls, 408 MultiTenancyConfig: &models.MultiTenancyConfig{Enabled: false}, 409 Properties: properties, 410 ReplicationConfig: repConfig, 411 }, 412 errMsg: "not enabled", 413 }, 414 { 415 name: "EmptyTenantValue", 416 Class: "C1", 417 tenants: []*models.Tenant{{Name: "Aaaa"}, {Name: ""}, {Name: "Bbbb"}}, 418 initial: &models.Class{ 419 Class: cls, 420 MultiTenancyConfig: &models.MultiTenancyConfig{Enabled: true}, 421 Properties: properties, 422 ReplicationConfig: repConfig, 423 }, 424 errMsg: "empty tenant name at index 1", 425 }, 426 { 427 name: "Success", 428 Class: "C1", 429 tenants: tenants[:2], 430 initial: &models.Class{ 431 Class: cls, 432 MultiTenancyConfig: &models.MultiTenancyConfig{Enabled: true}, 433 Properties: properties, 434 ReplicationConfig: repConfig, 435 }, 436 errMsg: "", 437 addTenants: true, 438 }, 439 } 440 441 for _, test := range tests { 442 sm := newSchemaManager() 443 err := sm.AddClass(ctx, nil, test.initial) 444 if err != nil { 445 t.Fatalf("%s: add class: %v", test.name, err) 446 } 447 if test.addTenants { 448 _, err = sm.AddTenants(ctx, nil, test.Class, tenants) 449 if err != nil { 450 t.Fatalf("%s: add tenants: %v", test.name, err) 451 } 452 } 453 var tenantNames []string 454 for i := range test.tenants { 455 tenantNames = append(tenantNames, test.tenants[i].Name) 456 } 457 458 err = sm.DeleteTenants(ctx, nil, test.Class, tenantNames) 459 if test.errMsg == "" { 460 if err != nil { 461 t.Fatalf("%s: remove tenants: %v", test.name, err) 462 } 463 ss := sm.schemaCache.ShardingState[test.Class] 464 if ss == nil { 465 t.Fatalf("%s: sharding state equal nil", test.name) 466 } 467 assert.Equal(t, len(test.tenants)+len(ss.Physical), len(tenants)) 468 } else { 469 assert.ErrorContains(t, err, test.errMsg, test.name) 470 } 471 472 } 473 }