Spaces:
Running
Running
// _ _ | |
// __ _____ __ ___ ___ __ _| |_ ___ | |
// \ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \ | |
// \ V V / __/ (_| |\ V /| | (_| | || __/ | |
// \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___| | |
// | |
// Copyright © 2016 - 2024 Weaviate B.V. All rights reserved. | |
// | |
// CONTACT: [email protected] | |
// | |
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] | |
} | |