github.com/weaviate/weaviate@v1.24.6/adapters/repos/db/restart_journey_integration_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  //go:build integrationTest
    13  // +build integrationTest
    14  
    15  package db
    16  
    17  import (
    18  	"context"
    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/entities/additional"
    25  	"github.com/weaviate/weaviate/entities/dto"
    26  	"github.com/weaviate/weaviate/entities/filters"
    27  	"github.com/weaviate/weaviate/entities/models"
    28  	"github.com/weaviate/weaviate/entities/schema"
    29  	enthnsw "github.com/weaviate/weaviate/entities/vectorindex/hnsw"
    30  )
    31  
    32  func TestRestartJourney(t *testing.T) {
    33  	dirName := t.TempDir()
    34  
    35  	logger, _ := test.NewNullLogger()
    36  	thingclass := &models.Class{
    37  		VectorIndexConfig:   enthnsw.NewDefaultUserConfig(),
    38  		InvertedIndexConfig: invertedConfig(),
    39  		Class:               "Class",
    40  		Properties: []*models.Property{
    41  			{
    42  				Name:         "description",
    43  				DataType:     []string{string(schema.DataTypeText)},
    44  				Tokenization: "word",
    45  			},
    46  		},
    47  	}
    48  	shardState := singleShardState()
    49  	schemaGetter := &fakeSchemaGetter{
    50  		schema:     schema.Schema{Objects: &models.Schema{Classes: nil}},
    51  		shardState: shardState,
    52  	}
    53  	repo, err := New(logger, Config{
    54  		MemtablesFlushDirtyAfter:  60,
    55  		RootPath:                  dirName,
    56  		QueryMaximumResults:       10000,
    57  		MaxImportGoroutinesFactor: 1,
    58  	}, &fakeRemoteClient{}, &fakeNodeResolver{}, &fakeRemoteNodeClient{}, &fakeReplicationClient{}, nil)
    59  	require.Nil(t, err)
    60  	repo.SetSchemaGetter(schemaGetter)
    61  	require.Nil(t, repo.WaitForStartup(testCtx()))
    62  	migrator := NewMigrator(repo, logger)
    63  
    64  	t.Run("creating the thing class", func(t *testing.T) {
    65  		require.Nil(t,
    66  			migrator.AddClass(context.Background(), thingclass,
    67  				shardState))
    68  	})
    69  
    70  	// update schema getter so it's in sync with class
    71  	schemaGetter.schema = schema.Schema{
    72  		Objects: &models.Schema{
    73  			Classes: []*models.Class{thingclass},
    74  		},
    75  	}
    76  
    77  	t.Run("import some data", func(t *testing.T) {
    78  		err := repo.PutObject(context.Background(), &models.Object{
    79  			Class: "Class",
    80  			ID:    "9d64350e-5027-40ea-98db-e3b97e6f6f8f",
    81  			Properties: map[string]interface{}{
    82  				"description": "the band is just fantastic that is really what I think",
    83  			},
    84  		}, []float32{0.1, 0.2, 0.3}, nil, nil)
    85  		require.Nil(t, err)
    86  
    87  		err = repo.PutObject(context.Background(), &models.Object{
    88  			Class: "Class",
    89  			ID:    "46ebcce8-fb77-413b-ade6-26c427af3f33",
    90  			Properties: map[string]interface{}{
    91  				"description": "oh by the way, which one's pink?",
    92  			},
    93  		}, []float32{-0.1, 0.2, -0.3}, nil, nil)
    94  		require.Nil(t, err)
    95  	})
    96  
    97  	t.Run("control", func(t *testing.T) {
    98  		t.Run("verify object by id", func(t *testing.T) {
    99  			res, err := repo.ObjectByID(context.Background(), "46ebcce8-fb77-413b-ade6-26c427af3f33", nil, additional.Properties{}, "")
   100  			require.Nil(t, err)
   101  			require.NotNil(t, res)
   102  			assert.Equal(t, "oh by the way, which one's pink?",
   103  				res.Schema.(map[string]interface{})["description"])
   104  		})
   105  
   106  		t.Run("find object by id through filter", func(t *testing.T) {
   107  			res, err := repo.ObjectSearch(context.Background(), 0, 10,
   108  				&filters.LocalFilter{
   109  					Root: &filters.Clause{
   110  						Operator: filters.OperatorEqual,
   111  						Value: &filters.Value{
   112  							Value: "9d64350e-5027-40ea-98db-e3b97e6f6f8f",
   113  							Type:  schema.DataTypeText,
   114  						},
   115  						On: &filters.Path{
   116  							Class:    "Class",
   117  							Property: "id",
   118  						},
   119  					},
   120  				}, nil, additional.Properties{}, "")
   121  			require.Nil(t, err)
   122  			require.Len(t, res, 1)
   123  			assert.Equal(t, "the band is just fantastic that is really what I think",
   124  				res[0].Schema.(map[string]interface{})["description"])
   125  		})
   126  
   127  		t.Run("find object through regular inverted index", func(t *testing.T) {
   128  			res, err := repo.ObjectSearch(context.Background(), 0, 10,
   129  				&filters.LocalFilter{
   130  					Root: &filters.Clause{
   131  						Operator: filters.OperatorEqual,
   132  						Value: &filters.Value{
   133  							Value: "pink",
   134  							Type:  schema.DataTypeText,
   135  						},
   136  						On: &filters.Path{
   137  							Class:    "Class",
   138  							Property: "description",
   139  						},
   140  					},
   141  				}, nil, additional.Properties{}, "")
   142  			require.Nil(t, err)
   143  			require.Len(t, res, 1)
   144  			assert.Equal(t, "oh by the way, which one's pink?",
   145  				res[0].Schema.(map[string]interface{})["description"])
   146  		})
   147  
   148  		t.Run("find object through vector index", func(t *testing.T) {
   149  			res, err := repo.VectorSearch(context.Background(),
   150  				dto.GetParams{
   151  					ClassName:    "Class",
   152  					SearchVector: []float32{0.05, 0.1, 0.15},
   153  					Pagination: &filters.Pagination{
   154  						Limit: 1,
   155  					},
   156  				})
   157  			require.Nil(t, err)
   158  			require.Len(t, res, 1)
   159  			assert.Equal(t, "the band is just fantastic that is really what I think",
   160  				res[0].Schema.(map[string]interface{})["description"])
   161  		})
   162  	})
   163  
   164  	var newRepo *DB
   165  	t.Run("shutdown and recreate", func(t *testing.T) {
   166  		require.Nil(t, repo.Shutdown(context.Background()))
   167  		repo = nil
   168  
   169  		newRepo, err = New(logger, Config{
   170  			MemtablesFlushDirtyAfter:  60,
   171  			RootPath:                  dirName,
   172  			QueryMaximumResults:       10000,
   173  			MaxImportGoroutinesFactor: 1,
   174  		}, &fakeRemoteClient{}, &fakeNodeResolver{}, &fakeRemoteNodeClient{}, &fakeReplicationClient{}, nil)
   175  		require.Nil(t, err)
   176  		newRepo.SetSchemaGetter(schemaGetter)
   177  		require.Nil(t, newRepo.WaitForStartup(testCtx()))
   178  	})
   179  
   180  	t.Run("verify after restart", func(t *testing.T) {
   181  		t.Run("verify object by id", func(t *testing.T) {
   182  			res, err := newRepo.ObjectByID(context.Background(), "46ebcce8-fb77-413b-ade6-26c427af3f33", nil, additional.Properties{}, "")
   183  			require.Nil(t, err)
   184  			require.NotNil(t, res)
   185  			assert.Equal(t, "oh by the way, which one's pink?",
   186  				res.Schema.(map[string]interface{})["description"])
   187  		})
   188  
   189  		t.Run("find object by id through filter", func(t *testing.T) {
   190  			res, err := newRepo.ObjectSearch(context.Background(), 0, 10,
   191  				&filters.LocalFilter{
   192  					Root: &filters.Clause{
   193  						Operator: filters.OperatorEqual,
   194  						Value: &filters.Value{
   195  							Value: "9d64350e-5027-40ea-98db-e3b97e6f6f8f",
   196  							Type:  schema.DataTypeText,
   197  						},
   198  						On: &filters.Path{
   199  							Class:    "Class",
   200  							Property: "id",
   201  						},
   202  					},
   203  				}, nil, additional.Properties{}, "")
   204  			require.Nil(t, err)
   205  			require.Len(t, res, 1)
   206  			assert.Equal(t, "the band is just fantastic that is really what I think",
   207  				res[0].Schema.(map[string]interface{})["description"])
   208  		})
   209  
   210  		t.Run("find object through regular inverted index", func(t *testing.T) {
   211  			res, err := newRepo.ObjectSearch(context.Background(), 0, 10,
   212  				&filters.LocalFilter{
   213  					Root: &filters.Clause{
   214  						Operator: filters.OperatorEqual,
   215  						Value: &filters.Value{
   216  							Value: "pink",
   217  							Type:  schema.DataTypeText,
   218  						},
   219  						On: &filters.Path{
   220  							Class:    "Class",
   221  							Property: "description",
   222  						},
   223  					},
   224  				}, nil, additional.Properties{}, "")
   225  			require.Nil(t, err)
   226  			require.Len(t, res, 1)
   227  			assert.Equal(t, "oh by the way, which one's pink?",
   228  				res[0].Schema.(map[string]interface{})["description"])
   229  		})
   230  
   231  		t.Run("find object through vector index", func(t *testing.T) {
   232  			res, err := newRepo.VectorSearch(context.Background(),
   233  				dto.GetParams{
   234  					ClassName:    "Class",
   235  					SearchVector: []float32{0.05, 0.1, 0.15},
   236  					Pagination: &filters.Pagination{
   237  						Limit: 1,
   238  					},
   239  				})
   240  			require.Nil(t, err)
   241  			require.Len(t, res, 1)
   242  			assert.Equal(t, "the band is just fantastic that is really what I think",
   243  				res[0].Schema.(map[string]interface{})["description"])
   244  		})
   245  	})
   246  
   247  	t.Run("shutdown", func(t *testing.T) {
   248  		require.Nil(t, newRepo.Shutdown(context.Background()))
   249  	})
   250  }