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 }