Spaces:
Sleeping
Sleeping
| // _ _ | |
| // __ _____ __ ___ ___ __ _| |_ ___ | |
| // \ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \ | |
| // \ V V / __/ (_| |\ V /| | (_| | || __/ | |
| // \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___| | |
| // | |
| // Copyright © 2016 - 2024 Weaviate B.V. All rights reserved. | |
| // | |
| // CONTACT: hello@weaviate.io | |
| // | |
| package schema | |
| import ( | |
| "context" | |
| "encoding/json" | |
| "testing" | |
| "github.com/stretchr/testify/assert" | |
| "github.com/stretchr/testify/require" | |
| "github.com/weaviate/weaviate/entities/backup" | |
| "github.com/weaviate/weaviate/entities/models" | |
| "github.com/weaviate/weaviate/usecases/sharding" | |
| ) | |
| func TestRestoreClass_WithCircularRefs(t *testing.T) { | |
| // When restoring a class, there could be circular refs between the classes, | |
| // thus any validation that checks if linked classes exist would fail on the | |
| // first class to import. Since we have no control over the order of imports | |
| // when restoring, we need to relax this validation. | |
| classes := []*models.Class{ | |
| { | |
| Class: "Class_A", | |
| Properties: []*models.Property{{ | |
| Name: "to_Class_B", | |
| DataType: []string{"Class_B"}, | |
| }, { | |
| Name: "to_Class_C", | |
| DataType: []string{"Class_C"}, | |
| }}, | |
| }, | |
| { | |
| Class: "Class_B", | |
| Properties: []*models.Property{{ | |
| Name: "to_Class_A", | |
| DataType: []string{"Class_A"}, | |
| }, { | |
| Name: "to_Class_C", | |
| DataType: []string{"Class_C"}, | |
| }}, | |
| }, | |
| { | |
| Class: "Class_C", | |
| Properties: []*models.Property{{ | |
| Name: "to_Class_A", | |
| DataType: []string{"Class_A"}, | |
| }, { | |
| Name: "to_Class_B", | |
| DataType: []string{"Class_B"}, | |
| }}, | |
| }, | |
| } | |
| mgr := newSchemaManager() | |
| for _, classRaw := range classes { | |
| schemaBytes, err := json.Marshal(classRaw) | |
| require.Nil(t, err) | |
| // for this particular test the sharding state does not matter, so we can | |
| // initiate any new sharding state | |
| shardingConfig, err := sharding.ParseConfig(nil, 1) | |
| require.Nil(t, err) | |
| nodes := fakeNodes{[]string{"node1", "node2"}} | |
| shardingState, err := sharding.InitState(classRaw.Class, shardingConfig, nodes, 1, false) | |
| require.Nil(t, err) | |
| shardingBytes, err := shardingState.JSON() | |
| require.Nil(t, err) | |
| descriptor := backup.ClassDescriptor{Name: classRaw.Class, Schema: schemaBytes, ShardingState: shardingBytes} | |
| err = mgr.RestoreClass(context.Background(), &descriptor, map[string]string{}) | |
| assert.Nil(t, err, "class passes validation") | |
| } | |
| } | |
| func TestRestoreClass_WithNodeMapping(t *testing.T) { | |
| classes := []*models.Class{{Class: "Class_A"}} | |
| mgr := newSchemaManager() | |
| for _, classRaw := range classes { | |
| schemaBytes, err := json.Marshal(classRaw) | |
| require.Nil(t, err) | |
| shardingConfig, err := sharding.ParseConfig(nil, 2) | |
| require.Nil(t, err) | |
| nodes := fakeNodes{[]string{"node1", "node2"}} | |
| shardingState, err := sharding.InitState(classRaw.Class, shardingConfig, nodes, 2, false) | |
| require.Nil(t, err) | |
| shardingBytes, err := shardingState.JSON() | |
| require.Nil(t, err) | |
| descriptor := backup.ClassDescriptor{Name: classRaw.Class, Schema: schemaBytes, ShardingState: shardingBytes} | |
| err = mgr.RestoreClass(context.Background(), &descriptor, map[string]string{"node1": "new-node1"}) | |
| assert.NoError(t, err) | |
| // Ensure that sharding state has been updated with the new node names | |
| for _, shard := range mgr.ShardingState { | |
| for _, v := range shard.Physical { | |
| for _, node := range v.BelongsToNodes { | |
| assert.Contains(t, []string{"new-node1", "node2"}, node) | |
| } | |
| } | |
| } | |
| } | |
| } | |
| type fakeNodes struct { | |
| nodes []string | |
| } | |
| func (f fakeNodes) Candidates() []string { | |
| return f.nodes | |
| } | |
| func (f fakeNodes) LocalName() string { | |
| return f.nodes[0] | |
| } | |