github.com/voedger/voedger@v0.0.0-20240520144910-273e84102129/pkg/state/impl_records_storage_test.go (about) 1 /* 2 * Copyright (c) 2022-present unTill Pro, Ltd. 3 */ 4 5 package state 6 7 import ( 8 "context" 9 "testing" 10 11 "github.com/stretchr/testify/mock" 12 "github.com/stretchr/testify/require" 13 14 "github.com/voedger/voedger/pkg/appdef" 15 "github.com/voedger/voedger/pkg/istructs" 16 ) 17 18 func createAppDef() appdef.IAppDef { 19 appDef := appdef.New() 20 appDef.AddObject(testRecordQName1). 21 AddField("number", appdef.DataKind_int64, false) 22 appDef.AddObject(testRecordQName2). 23 AddField("age", appdef.DataKind_int64, false) 24 wsDesc := appDef.AddCDoc(testWSDescriptorQName) 25 wsDesc.AddField(field_WSKind, appdef.DataKind_bytes, false) 26 ws := appDef.AddWorkspace(testWSQName) 27 ws.AddType(testRecordQName1) 28 ws.AddType(testRecordQName2) 29 ws.SetDescriptor(testWSDescriptorQName) 30 31 app, err := appDef.Build() 32 if err != nil { 33 panic(err) 34 } 35 return app 36 } 37 38 func TestRecordsStorage_GetBatch(t *testing.T) { 39 type result struct { 40 key istructs.IKeyBuilder 41 value istructs.IStateValue 42 exists bool 43 } 44 t.Run("Should handle general records", func(t *testing.T) { 45 require := require.New(t) 46 records := &mockRecords{} 47 records. 48 On("GetBatch", istructs.WSID(1), true, mock.AnythingOfType("[]istructs.RecordGetBatchItem")). 49 Return(nil). 50 Run(func(args mock.Arguments) { 51 items := args.Get(2).([]istructs.RecordGetBatchItem) 52 record := &mockRecord{} 53 record.On("QName").Return(testRecordQName1) 54 record.On("AsInt64", "number").Return(int64(10)) 55 items[0].Record = record 56 }). 57 On("GetBatch", istructs.WSID(2), true, mock.AnythingOfType("[]istructs.RecordGetBatchItem")). 58 Return(nil). 59 Run(func(args mock.Arguments) { 60 items := args.Get(2).([]istructs.RecordGetBatchItem) 61 record1 := &mockRecord{} 62 record1. 63 On("QName").Return(testRecordQName2). 64 On("AsInt64", "age").Return(int64(20)) 65 items[0].Record = record1 66 record2 := &mockRecord{} 67 record2. 68 On("QName").Return(testRecordQName2). 69 On("AsInt64", "age").Return(int64(21)) 70 items[1].Record = record2 71 }) 72 73 appDef := appdef.New() 74 appDef.AddObject(testRecordQName1). 75 AddField("number", appdef.DataKind_int64, false) 76 appDef.AddObject(testRecordQName2). 77 AddField("age", appdef.DataKind_int64, false) 78 79 app, err := appDef.Build() 80 require.NoError(err) 81 82 appStructs := &mockAppStructs{} 83 appStructs. 84 On("AppDef").Return(app). 85 On("AppQName").Return(testAppQName). 86 On("Records").Return(records). 87 On("ViewRecords").Return(&nilViewRecords{}). 88 On("Events").Return(&nilEvents{}) 89 s := ProvideQueryProcessorStateFactory()(context.Background(), appStructsFunc(appStructs), nil, SimpleWSIDFunc(istructs.WSID(1)), nil, nil, nil, nil, nil, nil, nil, nil) 90 k1, err := s.KeyBuilder(Record, appdef.NullQName) 91 require.NoError(err) 92 k1.PutRecordID(Field_ID, 1) 93 k2, err := s.KeyBuilder(Record, appdef.NullQName) 94 require.NoError(err) 95 k2.PutRecordID(Field_ID, 2) 96 k2.PutInt64(Field_WSID, 2) 97 k3, err := s.KeyBuilder(Record, appdef.NullQName) 98 require.NoError(err) 99 k3.PutRecordID(Field_ID, 3) 100 k3.PutInt64(Field_WSID, 2) 101 102 rr := make([]result, 0) 103 err = s.CanExistAll([]istructs.IStateKeyBuilder{k1, k2, k3}, func(key istructs.IKeyBuilder, value istructs.IStateValue, ok bool) (err error) { 104 rr = append(rr, result{ 105 key: key.(*recordsKeyBuilder), 106 value: value, 107 exists: ok, 108 }) 109 return 110 }) 111 require.NoError(err) 112 113 require.Len(rr, 3) 114 require.Equal(istructs.RecordID(1), rr[0].key.(*recordsKeyBuilder).id) 115 require.Equal(istructs.WSID(1), rr[0].key.(*recordsKeyBuilder).wsid) 116 require.True(rr[0].exists) 117 require.Equal(int64(10), rr[0].value.AsInt64("number")) 118 require.Equal(istructs.RecordID(2), rr[1].key.(*recordsKeyBuilder).id) 119 require.Equal(istructs.WSID(2), rr[1].key.(*recordsKeyBuilder).wsid) 120 require.True(rr[1].exists) 121 require.Equal(int64(20), rr[1].value.AsInt64("age")) 122 require.Equal(istructs.RecordID(3), rr[2].key.(*recordsKeyBuilder).id) 123 require.Equal(istructs.WSID(2), rr[2].key.(*recordsKeyBuilder).wsid) 124 require.True(rr[2].exists) 125 require.Equal(int64(21), rr[2].value.AsInt64("age")) 126 }) 127 t.Run("Should handle singleton records", func(t *testing.T) { 128 require := require.New(t) 129 singleton1 := &mockRecord{} 130 singleton1. 131 On("QName").Return(testRecordQName1). 132 On("AsQName", mock.Anything).Return(testRecordQName1). 133 On("AsInt64", "number").Return(int64(10)). 134 On("FieldNames", mock.Anything).Run(func(a mock.Arguments) { 135 x := a.Get(0).(func(name string)) 136 x("number") 137 }) 138 singleton2 := &mockRecord{} 139 singleton2. 140 On("QName").Return(testRecordQName2). 141 On("AsQName", mock.Anything).Return(testRecordQName2). 142 On("AsInt64", "age").Return(int64(18)). 143 On("FieldNames", mock.Anything).Run(func(a mock.Arguments) { 144 x := a.Get(0).(func(name string)) 145 x("age") 146 }) 147 nullRecord := &mockRecord{} 148 nullRecord.On("QName").Return(appdef.NullQName) 149 150 mockWorkspaceRecord := &mockRecord{} 151 mockWorkspaceRecord.On("AsQName", "WSKind").Return(testWSDescriptorQName) 152 mockWorkspaceRecord.On("QName").Return(qNameCDocWorkspaceDescriptor) 153 154 records := &mockRecords{} 155 records. 156 On("GetSingleton", istructs.WSID(1), testRecordQName1).Return(singleton1, nil). 157 On("GetSingleton", istructs.WSID(2), testRecordQName2).Return(nullRecord, nil). 158 On("GetSingleton", istructs.WSID(3), testRecordQName2).Return(singleton2, nil). 159 On("GetSingleton", mock.Anything, qNameCDocWorkspaceDescriptor).Return(mockWorkspaceRecord, nil) 160 161 appStructs := &mockAppStructs{} 162 appStructs. 163 On("AppDef").Return(createAppDef()). 164 On("AppQName").Return(testAppQName). 165 On("Records").Return(records). 166 On("ViewRecords").Return(&nilViewRecords{}). 167 On("Events").Return(&nilEvents{}) 168 s := ProvideQueryProcessorStateFactory()(context.Background(), appStructsFunc(appStructs), nil, SimpleWSIDFunc(istructs.WSID(1)), nil, nil, nil, nil, nil, nil, nil, nil) 169 k1, err := s.KeyBuilder(Record, appdef.NullQName) 170 require.NoError(err) 171 k1.PutQName(Field_Singleton, testRecordQName1) 172 k2, err := s.KeyBuilder(Record, appdef.NullQName) 173 require.NoError(err) 174 k2.PutQName(Field_Singleton, testRecordQName2) 175 k2.PutInt64(Field_WSID, 2) 176 k3, err := s.KeyBuilder(Record, appdef.NullQName) 177 require.NoError(err) 178 k3.PutQName(Field_Singleton, testRecordQName2) 179 k3.PutInt64(Field_WSID, 3) 180 181 rr := make([]result, 0) 182 err = s.CanExistAll([]istructs.IStateKeyBuilder{k1, k2, k3}, func(key istructs.IKeyBuilder, value istructs.IStateValue, ok bool) (err error) { 183 rr = append(rr, result{ 184 key: key.(*recordsKeyBuilder), 185 value: value, 186 exists: ok, 187 }) 188 return 189 }) 190 require.NoError(err) 191 192 require.Len(rr, 3) 193 require.Equal(int64(10), rr[0].value.AsInt64("number")) 194 require.True(rr[0].exists) 195 require.Equal(istructs.WSID(2), rr[1].key.(*recordsKeyBuilder).wsid) 196 require.Nil(rr[1].value) 197 require.False(rr[1].exists) 198 require.Equal(istructs.WSID(3), rr[2].key.(*recordsKeyBuilder).wsid) 199 require.True(rr[2].exists) 200 require.Equal(int64(18), rr[2].value.AsInt64("age")) 201 }) 202 t.Run("Should return error when 'id' not found", func(t *testing.T) { 203 require := require.New(t) 204 s := ProvideQueryProcessorStateFactory()(context.Background(), nilAppStructsFunc, nil, SimpleWSIDFunc(istructs.WSID(1)), nil, nil, nil, nil, nil, nil, nil, nil) 205 k, err := s.KeyBuilder(Record, appdef.NullQName) 206 require.NoError(err) 207 208 _, ok, err := s.CanExist(k) 209 210 require.False(ok) 211 require.ErrorIs(err, ErrNotFound) 212 }) 213 t.Run("Should return error on get", func(t *testing.T) { 214 require := require.New(t) 215 records := &mockRecords{} 216 records.On("Get", istructs.WSID(1), true, mock.Anything).Return(nil, errTest) 217 appStructs := &mockAppStructs{} 218 appStructs. 219 On("AppDef").Return(createAppDef()). 220 On("AppQName").Return(testAppQName). 221 On("Records").Return(records). 222 On("ViewRecords").Return(&nilViewRecords{}). 223 On("Events").Return(&nilEvents{}) 224 s := ProvideQueryProcessorStateFactory()(context.Background(), appStructsFunc(appStructs), nil, SimpleWSIDFunc(istructs.WSID(1)), nil, nil, nil, nil, nil, nil, nil, nil) 225 k, err := s.KeyBuilder(Record, appdef.NullQName) 226 require.NoError(err) 227 k.PutRecordID(Field_ID, istructs.RecordID(1)) 228 229 _, ok, err := s.CanExist(k) 230 231 require.False(ok) 232 require.ErrorIs(err, errTest) 233 }) 234 t.Run("Should return error on get singleton", func(t *testing.T) { 235 require := require.New(t) 236 237 mockWorkspaceRecord := &mockRecord{} 238 mockWorkspaceRecord.On("AsQName", "WSKind").Return(testWSDescriptorQName) 239 mockWorkspaceRecord.On("QName").Return(qNameCDocWorkspaceDescriptor) 240 241 records := &mockRecords{} 242 records.On("GetSingleton", istructs.WSID(1), testRecordQName1).Return(&mockRecord{}, errTest) 243 records.On("GetSingleton", mock.Anything, qNameCDocWorkspaceDescriptor).Return(mockWorkspaceRecord, nil) 244 appStructs := &mockAppStructs{} 245 appStructs. 246 On("AppDef").Return(createAppDef()). 247 On("AppQName").Return(testAppQName). 248 On("Records").Return(records). 249 On("ViewRecords").Return(&nilViewRecords{}). 250 On("Events").Return(&nilEvents{}) 251 s := ProvideQueryProcessorStateFactory()(context.Background(), appStructsFunc(appStructs), nil, SimpleWSIDFunc(istructs.WSID(1)), nil, nil, nil, nil, nil, nil, nil, nil) 252 k, err := s.KeyBuilder(Record, appdef.NullQName) 253 require.NoError(err) 254 k.PutQName(Field_Singleton, testRecordQName1) 255 256 _, ok, err := s.CanExist(k) 257 258 require.False(ok) 259 require.ErrorIs(err, errTest) 260 }) 261 } 262 func TestRecordsStorage_Insert(t *testing.T) { 263 require := require.New(t) 264 fieldName := "name" 265 value := "Voedger" //??? 266 rw := &mockRowWriter{} 267 rw. 268 On("PutString", fieldName, value) 269 cud := &mockCUD{} 270 cud.On("Create").Return(rw) 271 s := ProvideCommandProcessorStateFactory()(context.Background(), nil, nil, SimpleWSIDFunc(istructs.NullWSID), nil, 272 func() istructs.ICUD { return cud }, nil, nil, 1, nil, nil, nil, nil) 273 kb, err := s.KeyBuilder(Record, testRecordQName1) 274 require.NoError(err) 275 276 vb, err := s.NewValue(kb) 277 require.NoError(err) 278 vb.PutString(fieldName, value) 279 280 require.NoError(s.ValidateIntents()) 281 require.NoError(s.ApplyIntents()) 282 rw.AssertExpectations(t) 283 } 284 func TestRecordsStorage_Update(t *testing.T) { 285 require := require.New(t) 286 fieldName := "name" 287 value := "Voedger" 288 rw := &mockRowWriter{} 289 rw.On("PutString", fieldName, value) 290 r := &mockRecord{} 291 sv := &recordsValue{record: r} 292 cud := &mockCUD{} 293 cud.On("Update", mock.Anything).Return(rw) 294 s := ProvideCommandProcessorStateFactory()(context.Background(), nil, nil, SimpleWSIDFunc(istructs.NullWSID), nil, 295 func() istructs.ICUD { return cud }, nil, nil, 1, nil, nil, nil, nil) 296 kb, err := s.KeyBuilder(Record, testRecordQName1) 297 require.NoError(err) 298 299 vb, err := s.UpdateValue(kb, sv) 300 require.NoError(err) 301 vb.PutString(fieldName, value) 302 303 require.NoError(s.ValidateIntents()) 304 require.NoError(s.ApplyIntents()) 305 rw.AssertExpectations(t) 306 } 307 308 func TestRecordsStorage_ValidateInWorkspaces_Reads(t *testing.T) { 309 require := require.New(t) 310 311 mockedStructs, mockedViews := mockedStructs(t) 312 mockedViews. 313 On("KeyBuilder", mock.Anything).Return(&nilKeyBuilder{}). 314 On("NewValueBuilder", mock.Anything).Return(&nilValueBuilder{}). 315 On("Get", istructs.WSID(1), mock.Anything).Return(&nilValue{}, nil). 316 On("PutBatch", mock.Anything, mock.Anything).Return(nil) 317 318 s := ProvideAsyncActualizerStateFactory()(context.Background(), appStructsFunc(mockedStructs), nil, SimpleWSIDFunc(istructs.WSID(1)), nil, nil, nil, nil, nil, 10, 10) 319 320 wrongSingleton := appdef.NewQName("test", "RecordX") 321 wrongKb, err := s.KeyBuilder(Record, appdef.NullQName) 322 wrongKb.PutQName(Field_Singleton, wrongSingleton) 323 require.NoError(err) 324 expectedError := typeIsNotDefinedInWorkspaceWithDescriptor(wrongSingleton, testWSDescriptorQName) 325 326 t.Run("CanExist should validate for unavailable records", func(t *testing.T) { 327 value, ok, err := s.CanExist(wrongKb) 328 require.EqualError(err, expectedError.Error()) 329 require.Nil(value) 330 require.False(ok) 331 }) 332 333 t.Run("CanExistAll should validate for unavailable records", func(t *testing.T) { 334 err = s.CanExistAll([]istructs.IStateKeyBuilder{wrongKb}, nil) 335 require.EqualError(err, expectedError.Error()) 336 }) 337 338 t.Run("MustExist should validate for unavailable records", func(t *testing.T) { 339 value, err := s.MustExist(wrongKb) 340 require.EqualError(err, expectedError.Error()) 341 require.Nil(value) 342 }) 343 344 t.Run("MustNotExist should validate for unavailable records", func(t *testing.T) { 345 err := s.MustNotExist(wrongKb) 346 require.EqualError(err, expectedError.Error()) 347 }) 348 349 t.Run("MustExistAll should validate for unavailable records", func(t *testing.T) { 350 err = s.MustExistAll([]istructs.IStateKeyBuilder{wrongKb}, nil) 351 require.EqualError(err, expectedError.Error()) 352 }) 353 354 t.Run("MustNotExistAll should validate for unavailable records", func(t *testing.T) { 355 err = s.MustNotExistAll([]istructs.IStateKeyBuilder{wrongKb}) 356 require.EqualError(err, expectedError.Error()) 357 }) 358 } 359 360 func TestRecordsStorage_ValidateInWorkspaces_Writes(t *testing.T) { 361 require := require.New(t) 362 363 mockedStructs, mockedViews := mockedStructs(t) 364 mockedViews. 365 On("KeyBuilder", mock.Anything).Return(&nilKeyBuilder{}). 366 On("NewValueBuilder", mock.Anything).Return(&nilValueBuilder{}). 367 On("Get", istructs.WSID(1), mock.Anything).Return(&nilValue{}, nil). 368 On("PutBatch", mock.Anything, mock.Anything).Return(nil) 369 370 s := ProvideCommandProcessorStateFactory()(context.Background(), appStructsFunc(mockedStructs), nil, 371 SimpleWSIDFunc(istructs.WSID(1)), nil, nil, nil, nil, 10, nil, nil, nil, nil) 372 373 wrongSingleton := appdef.NewQName("test", "RecordX") 374 wrongKb, err := s.KeyBuilder(Record, wrongSingleton) 375 require.NoError(err) 376 expectedError := typeIsNotDefinedInWorkspaceWithDescriptor(wrongSingleton, testWSDescriptorQName) 377 378 t.Run("NewValue should validate for unavailable records", func(t *testing.T) { 379 builder, err := s.NewValue(wrongKb) 380 require.EqualError(err, expectedError.Error()) 381 require.Nil(builder) 382 }) 383 384 }