github.com/weaviate/weaviate@v1.24.6/adapters/handlers/rest/clusterapi/schema_component_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 clusterapi_test
    13  
    14  import (
    15  	"context"
    16  	"net/http"
    17  	"net/http/httptest"
    18  	"net/url"
    19  	"testing"
    20  
    21  	"github.com/sirupsen/logrus/hooks/test"
    22  	"github.com/stretchr/testify/assert"
    23  	"github.com/stretchr/testify/require"
    24  	"github.com/weaviate/weaviate/adapters/clients"
    25  	"github.com/weaviate/weaviate/adapters/handlers/rest/clusterapi"
    26  	"github.com/weaviate/weaviate/entities/models"
    27  	"github.com/weaviate/weaviate/usecases/cluster"
    28  	"github.com/weaviate/weaviate/usecases/config"
    29  	"github.com/weaviate/weaviate/usecases/scaler"
    30  	schemauc "github.com/weaviate/weaviate/usecases/schema"
    31  	"github.com/weaviate/weaviate/usecases/sharding"
    32  )
    33  
    34  // This is a cross-package test that tests the schema manager in a distributed
    35  // settings including some of its dependencies, such as the REST API and
    36  // clients. This setup pretends that replication was one-way for simplicity
    37  // sake, but uses the same components on either side to make sure that it
    38  // would work in both directions.
    39  func TestComponentCluster(t *testing.T) {
    40  	t.Run("add class", func(t *testing.T) {
    41  		localManager, remoteManager := setupManagers(t)
    42  
    43  		ctx := context.Background()
    44  
    45  		err := localManager.AddClass(ctx, nil, testClass())
    46  		require.Nil(t, err)
    47  
    48  		localClass, err := localManager.GetClass(ctx, nil, testClass().Class)
    49  		require.Nil(t, err)
    50  		remoteClass, err := remoteManager.GetClass(ctx, nil, testClass().Class)
    51  		require.Nil(t, err)
    52  
    53  		assert.Equal(t, localClass, remoteClass)
    54  	})
    55  
    56  	t.Run("add class and extend property", func(t *testing.T) {
    57  		localManager, remoteManager := setupManagers(t)
    58  
    59  		ctx := context.Background()
    60  
    61  		err := localManager.AddClass(ctx, nil, testClass())
    62  		require.Nil(t, err)
    63  
    64  		err = localManager.AddClassProperty(ctx, nil, testClass().Class, testProperty())
    65  		require.Nil(t, err)
    66  
    67  		localClass, err := localManager.GetClass(ctx, nil, testClass().Class)
    68  		require.Nil(t, err)
    69  		remoteClass, err := remoteManager.GetClass(ctx, nil, testClass().Class)
    70  		require.Nil(t, err)
    71  
    72  		assert.Equal(t, localClass, remoteClass)
    73  	})
    74  
    75  	t.Run("delete class", func(t *testing.T) {
    76  		localManager, remoteManager := setupManagers(t)
    77  
    78  		ctx := context.Background()
    79  
    80  		err := localManager.AddClass(ctx, nil, testClass())
    81  		require.Nil(t, err)
    82  
    83  		err = localManager.DeleteClass(ctx, nil, testClass().Class)
    84  		require.Nil(t, err)
    85  
    86  		localSchema, err := localManager.GetSchema(nil)
    87  		require.Nil(t, err)
    88  		remoteSchema, err := remoteManager.GetSchema(nil)
    89  		require.Nil(t, err)
    90  
    91  		assert.Equal(t, localSchema, remoteSchema)
    92  	})
    93  
    94  	t.Run("add class update config", func(t *testing.T) {
    95  		localManager, remoteManager := setupManagers(t)
    96  
    97  		ctx := context.Background()
    98  
    99  		err := localManager.AddClass(ctx, nil, testClass())
   100  		require.Nil(t, err)
   101  
   102  		updated := testClass()
   103  		updated.VectorIndexConfig.(map[string]interface{})["secondKey"] = "added"
   104  
   105  		err = localManager.UpdateClass(ctx, nil, testClass().Class, updated)
   106  		require.Nil(t, err)
   107  
   108  		localClass, err := localManager.GetClass(ctx, nil, testClass().Class)
   109  		require.Nil(t, err)
   110  		remoteClass, err := remoteManager.GetClass(ctx, nil, testClass().Class)
   111  		require.Nil(t, err)
   112  
   113  		assert.Equal(t, localClass, remoteClass)
   114  	})
   115  }
   116  
   117  func setupManagers(t *testing.T) (*schemauc.Manager, *schemauc.Manager) {
   118  	remoteManager := newSchemaManagerWithClusterStateAndClient(
   119  		&fakeClusterState{hosts: []string{"node1"}}, nil)
   120  
   121  	schemaHandlers := clusterapi.NewSchema(remoteManager.TxManager(), clusterapi.NewNoopAuthHandler())
   122  	mux := http.NewServeMux()
   123  	mux.Handle("/schema/transactions/", http.StripPrefix("/schema/transactions/",
   124  		schemaHandlers.Transactions()))
   125  	server := httptest.NewServer(mux)
   126  
   127  	client := clients.NewClusterSchema(&http.Client{})
   128  	parsedURL, err := url.Parse(server.URL)
   129  	require.Nil(t, err)
   130  	state := &fakeClusterState{hosts: []string{parsedURL.Host}}
   131  	localManager := newSchemaManagerWithClusterStateAndClient(state, client)
   132  
   133  	// this will also mark the tx managers as ready
   134  	localManager.StartServing(context.Background())
   135  	remoteManager.StartServing(context.Background())
   136  
   137  	return localManager, remoteManager
   138  }
   139  
   140  func testClass() *models.Class {
   141  	return &models.Class{
   142  		Class: "MyClass",
   143  		Properties: []*models.Property{
   144  			{
   145  				Name: "propOne", DataType: []string{"text"},
   146  			},
   147  		},
   148  		VectorIndexConfig: map[string]interface{}{
   149  			"foo": "bar",
   150  		},
   151  	}
   152  }
   153  
   154  func testProperty() *models.Property {
   155  	return &models.Property{
   156  		Name: "propTwo", DataType: []string{"int"},
   157  	}
   158  }
   159  
   160  // New Local Schema *Manager
   161  func newSchemaManagerWithClusterStateAndClient(clusterState *fakeClusterState,
   162  	client cluster.Client,
   163  ) *schemauc.Manager {
   164  	logger, _ := test.NewNullLogger()
   165  	vectorizerValidator := &fakeVectorizerValidator{
   166  		valid: []string{"text2vec-contextionary", "model1", "model2"},
   167  	}
   168  	sm, err := schemauc.NewManager(&NilMigrator{}, newFakeRepo(), logger, &fakeAuthorizer{},
   169  		config.Config{DefaultVectorizerModule: config.VectorizerModuleNone},
   170  		dummyParseVectorConfig, // only option for now
   171  		vectorizerValidator, dummyValidateInvertedConfig,
   172  		&fakeModuleConfig{}, clusterState, client, &fakeTxPersistence{},
   173  		&fakeScaleOutManager{},
   174  	)
   175  	if err != nil {
   176  		panic(err.Error())
   177  	}
   178  
   179  	return sm
   180  }
   181  
   182  type fakeScaleOutManager struct{}
   183  
   184  func (f *fakeScaleOutManager) Scale(ctx context.Context,
   185  	className string, updated sharding.Config, _, _ int64,
   186  ) (*sharding.State, error) {
   187  	return nil, nil
   188  }
   189  
   190  func (f *fakeScaleOutManager) SetSchemaManager(sm scaler.SchemaManager) {
   191  }
   192  
   193  // does nothing as this component test does not involve crashes
   194  type fakeTxPersistence struct{}
   195  
   196  func (f *fakeTxPersistence) StoreTx(ctx context.Context,
   197  	tx *cluster.Transaction,
   198  ) error {
   199  	return nil
   200  }
   201  
   202  func (f *fakeTxPersistence) DeleteTx(ctx context.Context,
   203  	txID string,
   204  ) error {
   205  	return nil
   206  }
   207  
   208  func (f *fakeTxPersistence) IterateAll(ctx context.Context,
   209  	cb func(tx *cluster.Transaction),
   210  ) error {
   211  	return nil
   212  }