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  }