github.com/voedger/voedger@v0.0.0-20240520144910-273e84102129/pkg/state/impl_bundled_host_state_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  	"github.com/voedger/voedger/pkg/appdef"
    14  	"github.com/voedger/voedger/pkg/istructs"
    15  )
    16  
    17  func TestBundledHostState_BasicUsage(t *testing.T) {
    18  	require := require.New(t)
    19  	factory := ProvideAsyncActualizerStateFactory()
    20  	n10nFn := func(view appdef.QName, wsid istructs.WSID, offset istructs.Offset) {}
    21  
    22  	// Create instance of async actualizer state
    23  	aaState := factory(context.Background(), mockedAppStructs, nil, SimpleWSIDFunc(istructs.WSID(1)), n10nFn, nil, nil, nil, nil, 2, 1)
    24  
    25  	// Declare simple extension
    26  	extension := func(state istructs.IState, intents istructs.IIntents) {
    27  		//Create key
    28  		kb, err := state.KeyBuilder(View, testViewRecordQName1)
    29  		require.NoError(err)
    30  		kb.PutInt64("pkFld", int64(64))
    31  
    32  		// Create new value
    33  		eb, err := intents.NewValue(kb)
    34  		require.NoError(err)
    35  		eb.PutInt64("vFld", 10)
    36  		eb.PutInt64(ColOffset, 45)
    37  	}
    38  
    39  	// Run extension
    40  	extension(aaState, aaState)
    41  
    42  	// Apply intents
    43  	readyToFlush, err := aaState.ApplyIntents()
    44  	require.NoError(err)
    45  	require.True(readyToFlush)
    46  
    47  	_ = aaState.FlushBundles()
    48  }
    49  
    50  func mockedAppStructs() istructs.IAppStructs {
    51  	mv := &mockValue{}
    52  	mv.
    53  		On("AsInt64", "vFld").Return(int64(10)).
    54  		On("AsInt64", ColOffset).Return(int64(45))
    55  	mvb1 := &mockValueBuilder{}
    56  	mvb1.
    57  		On("PutInt64", "vFld", int64(10)).
    58  		On("PutInt64", ColOffset, int64(45)).
    59  		On("Build").Return(mv)
    60  	mvb2 := &mockValueBuilder{}
    61  	mvb2.
    62  		On("PutInt64", "vFld", int64(10)).Once().
    63  		On("PutInt64", ColOffset, int64(45)).Once().
    64  		On("PutInt64", "vFld", int64(17)).Once().
    65  		On("PutInt64", ColOffset, int64(46)).Once()
    66  	mkb := &mockKeyBuilder{}
    67  	mkb.
    68  		On("PutInt64", "pkFld", int64(64))
    69  
    70  	viewRecords := &mockViewRecords{}
    71  	viewRecords.
    72  		On("KeyBuilder", testViewRecordQName1).Return(mkb).
    73  		On("NewValueBuilder", testViewRecordQName1).Return(mvb1).Once().
    74  		On("NewValueBuilder", testViewRecordQName1).Return(mvb2).Once().
    75  		On("PutBatch", istructs.WSID(1), mock.AnythingOfType("[]istructs.ViewKV")).Return(nil)
    76  
    77  	mockWorkspaceRecord := &mockRecord{}
    78  	mockWorkspaceRecord.On("AsQName", "WSKind").Return(testWSDescriptorQName)
    79  	mockWorkspaceRecord.On("QName").Return(qNameCDocWorkspaceDescriptor)
    80  	mockedRecords := &mockRecords{}
    81  	mockedRecords.On("GetSingleton", istructs.WSID(1), mock.Anything).Return(mockWorkspaceRecord, nil)
    82  
    83  	appDefBuilder := appdef.New()
    84  	wsDesc := appDefBuilder.AddCDoc(testWSDescriptorQName)
    85  	wsDesc.AddField(field_WSKind, appdef.DataKind_bytes, false)
    86  	view := appDefBuilder.AddView(testViewRecordQName1)
    87  	view.Key().PartKey().AddField("pkFld", appdef.DataKind_int64)
    88  	view.Key().ClustCols().AddField("ccFld", appdef.DataKind_string)
    89  	view.Value().
    90  		AddField("vFld", appdef.DataKind_int64, true).
    91  		AddField(ColOffset, appdef.DataKind_int64, true)
    92  	ws := appDefBuilder.AddWorkspace(testWSQName)
    93  	ws.AddType(testViewRecordQName1)
    94  	ws.SetDescriptor(testWSDescriptorQName)
    95  	appDef, err := appDefBuilder.Build()
    96  	if err != nil {
    97  		panic(err)
    98  	}
    99  
   100  	appStructs := &mockAppStructs{}
   101  	appStructs.
   102  		On("AppDef").Return(appDef).
   103  		On("AppQName").Return(testAppQName).
   104  		On("ViewRecords").Return(viewRecords).
   105  		On("Events").Return(&nilEvents{}).
   106  		On("Records").Return(mockedRecords)
   107  	return appStructs
   108  }
   109  
   110  func TestAsyncActualizerState_CanExist(t *testing.T) {
   111  	t.Run("Should be ok", func(t *testing.T) {
   112  		require := require.New(t)
   113  		stateStorage := &mockStorage{}
   114  		stateStorage.
   115  			On("NewKeyBuilder", testViewRecordQName1, nil).Return(newKeyBuilder(testStorage, testViewRecordQName1)).
   116  			On("GetBatch", mock.AnythingOfType("[]state.GetBatchItem")).
   117  			Return(nil).
   118  			Run(func(args mock.Arguments) {
   119  				args.Get(0).([]GetBatchItem)[0].value = &mockStateValue{}
   120  			})
   121  		s := asyncActualizerStateWithTestStateStorage(stateStorage)
   122  		kb, err := s.KeyBuilder(testStorage, testViewRecordQName1)
   123  		require.NoError(err)
   124  
   125  		_, ok, err := s.CanExist(kb)
   126  		require.NoError(err)
   127  
   128  		require.True(ok)
   129  	})
   130  	t.Run("Should return error when error occurred on get batch", func(t *testing.T) {
   131  		require := require.New(t)
   132  		stateStorage := &mockStorage{}
   133  		stateStorage.
   134  			On("NewKeyBuilder", testViewRecordQName1, nil).Return(newKeyBuilder(testStorage, testViewRecordQName1)).
   135  			On("GetBatch", mock.AnythingOfType("[]state.GetBatchItem")).Return(errTest)
   136  		s := asyncActualizerStateWithTestStateStorage(stateStorage)
   137  		kb, err := s.KeyBuilder(testStorage, testViewRecordQName1)
   138  		require.NoError(err)
   139  
   140  		_, _, err = s.CanExist(kb)
   141  
   142  		require.ErrorIs(err, errTest)
   143  	})
   144  }
   145  func TestAsyncActualizerState_CanExistAll(t *testing.T) {
   146  	t.Run("Should be ok", func(t *testing.T) {
   147  		require := require.New(t)
   148  		times := 0
   149  		stateStorage := &mockStorage{}
   150  		stateStorage.
   151  			On("NewKeyBuilder", testViewRecordQName1, nil).Return(newKeyBuilder(testStorage, testViewRecordQName1)).
   152  			On("GetBatch", mock.AnythingOfType("[]state.GetBatchItem")).Return(nil)
   153  		s := asyncActualizerStateWithTestStateStorage(stateStorage)
   154  		kb1, err := s.KeyBuilder(testStorage, testViewRecordQName1)
   155  		require.NoError(err)
   156  		kb2, err := s.KeyBuilder(testStorage, testViewRecordQName1)
   157  		require.NoError(err)
   158  
   159  		_ = s.CanExistAll([]istructs.IStateKeyBuilder{kb1, kb2}, func(istructs.IKeyBuilder, istructs.IStateValue, bool) error {
   160  			times++
   161  			return nil
   162  		})
   163  
   164  		require.Equal(2, times)
   165  	})
   166  	t.Run("Should return error when error occurred on can exist", func(t *testing.T) {
   167  		require := require.New(t)
   168  		stateStorage := &mockStorage{}
   169  		stateStorage.
   170  			On("NewKeyBuilder", testViewRecordQName1, nil).Return(newKeyBuilder(testStorage, testViewRecordQName1)).
   171  			On("GetBatch", mock.AnythingOfType("[]state.GetBatchItem")).Return(errTest)
   172  		s := asyncActualizerStateWithTestStateStorage(stateStorage)
   173  		kb1, err := s.KeyBuilder(testStorage, testViewRecordQName1)
   174  		require.NoError(err)
   175  		kb2, err := s.KeyBuilder(testStorage, testViewRecordQName1)
   176  		require.NoError(err)
   177  
   178  		err = s.CanExistAll([]istructs.IStateKeyBuilder{kb1, kb2}, nil)
   179  
   180  		require.ErrorIs(err, errTest)
   181  	})
   182  }
   183  func TestAsyncActualizerState_MustExist(t *testing.T) {
   184  	t.Run("Should be ok", func(t *testing.T) {
   185  		require := require.New(t)
   186  		stateStorage := &mockStorage{}
   187  		stateStorage.
   188  			On("NewKeyBuilder", testViewRecordQName1, nil).Return(newKeyBuilder(testStorage, testViewRecordQName1)).
   189  			On("GetBatch", mock.AnythingOfType("[]state.GetBatchItem")).
   190  			Return(nil).
   191  			Run(func(args mock.Arguments) {
   192  				args.Get(0).([]GetBatchItem)[0].value = &mockStateValue{}
   193  			})
   194  		s := asyncActualizerStateWithTestStateStorage(stateStorage)
   195  		kb, err := s.KeyBuilder(testStorage, testViewRecordQName1)
   196  		require.NoError(err)
   197  
   198  		_, err = s.MustExist(kb)
   199  
   200  		require.NoError(err)
   201  	})
   202  	t.Run("Should return error when entity not exists", func(t *testing.T) {
   203  		require := require.New(t)
   204  		stateStorage := &mockStorage{}
   205  		stateStorage.
   206  			On("NewKeyBuilder", testViewRecordQName1, nil).Return(newKeyBuilder(testStorage, testViewRecordQName1)).
   207  			On("GetBatch", mock.AnythingOfType("[]state.GetBatchItem")).
   208  			Return(nil).
   209  			Run(func(args mock.Arguments) {
   210  				args.Get(0).([]GetBatchItem)[0].value = nil
   211  			})
   212  		s := asyncActualizerStateWithTestStateStorage(stateStorage)
   213  		kb, err := s.KeyBuilder(testStorage, testViewRecordQName1)
   214  		require.NoError(err)
   215  
   216  		_, err = s.MustExist(kb)
   217  
   218  		require.ErrorIs(err, ErrNotExists)
   219  	})
   220  	t.Run("Should return error when error occurred on can exist", func(t *testing.T) {
   221  		require := require.New(t)
   222  		stateStorage := &mockStorage{}
   223  		stateStorage.
   224  			On("NewKeyBuilder", testViewRecordQName1, nil).Return(newKeyBuilder(testStorage, testViewRecordQName1)).
   225  			On("GetBatch", mock.AnythingOfType("[]state.GetBatchItem")).Return(errTest)
   226  		s := asyncActualizerStateWithTestStateStorage(stateStorage)
   227  		kb, err := s.KeyBuilder(testStorage, testViewRecordQName1)
   228  		require.NoError(err)
   229  
   230  		_, err = s.MustExist(kb)
   231  
   232  		require.ErrorIs(err, errTest)
   233  	})
   234  }
   235  func TestAsyncActualizerState_MustExistAll(t *testing.T) {
   236  	t.Run("Should be ok", func(t *testing.T) {
   237  		require := require.New(t)
   238  		stateStorage := &mockStorage{}
   239  		stateStorage.
   240  			On("NewKeyBuilder", testViewRecordQName1, nil).Return(newKeyBuilder(testStorage, testViewRecordQName1)).
   241  			On("GetBatch", mock.AnythingOfType("[]state.GetBatchItem")).
   242  			Return(nil).
   243  			Run(func(args mock.Arguments) {
   244  				args.Get(0).([]GetBatchItem)[0].value = &mockStateValue{}
   245  			})
   246  		s := asyncActualizerStateWithTestStateStorage(stateStorage)
   247  		k1, err := s.KeyBuilder(testStorage, testViewRecordQName1)
   248  		require.NoError(err)
   249  		k2, err := s.KeyBuilder(testStorage, testViewRecordQName1)
   250  		require.NoError(err)
   251  		kk := make([]istructs.IKeyBuilder, 0, 2)
   252  
   253  		_ = s.MustExistAll([]istructs.IStateKeyBuilder{k1, k2}, func(key istructs.IKeyBuilder, value istructs.IStateValue, ok bool) (err error) {
   254  			kk = append(kk, key)
   255  			require.True(ok)
   256  			return
   257  		})
   258  
   259  		require.Equal(k1, kk[0])
   260  		require.Equal(k1, kk[1])
   261  	})
   262  	t.Run("Should return error when entity not exists", func(t *testing.T) {
   263  		require := require.New(t)
   264  		stateStorage := &mockStorage{}
   265  		stateStorage.
   266  			On("NewKeyBuilder", testViewRecordQName1, nil).Return(newKeyBuilder(testStorage, testViewRecordQName1)).
   267  			On("GetBatch", mock.AnythingOfType("[]state.GetBatchItem")).
   268  			Return(nil).
   269  			Run(func(args mock.Arguments) {
   270  				args.Get(0).([]GetBatchItem)[0].value = nil
   271  			})
   272  		s := asyncActualizerStateWithTestStateStorage(stateStorage)
   273  		k1, err := s.KeyBuilder(testStorage, testViewRecordQName1)
   274  		require.NoError(err)
   275  		k2, err := s.KeyBuilder(testStorage, testViewRecordQName1)
   276  		require.NoError(err)
   277  
   278  		err = s.MustExistAll([]istructs.IStateKeyBuilder{k1, k2}, nil)
   279  
   280  		require.ErrorIs(err, ErrNotExists)
   281  	})
   282  }
   283  func TestAsyncActualizerState_MustNotExist(t *testing.T) {
   284  	t.Run("Should be ok", func(t *testing.T) {
   285  		require := require.New(t)
   286  		stateStorage := &mockStorage{}
   287  		stateStorage.
   288  			On("NewKeyBuilder", testViewRecordQName1, nil).Return(newKeyBuilder(testStorage, testViewRecordQName1)).
   289  			On("GetBatch", mock.AnythingOfType("[]state.GetBatchItem")).
   290  			Return(nil).
   291  			Run(func(args mock.Arguments) {
   292  				args.Get(0).([]GetBatchItem)[0].value = nil
   293  			})
   294  		s := asyncActualizerStateWithTestStateStorage(stateStorage)
   295  		k, err := s.KeyBuilder(testStorage, testViewRecordQName1)
   296  		require.NoError(err)
   297  
   298  		err = s.MustNotExist(k)
   299  
   300  		require.NoError(err)
   301  	})
   302  	t.Run("Should return error when entity exists", func(t *testing.T) {
   303  		require := require.New(t)
   304  		stateStorage := &mockStorage{}
   305  		stateStorage.
   306  			On("NewKeyBuilder", testViewRecordQName1, nil).Return(newKeyBuilder(testStorage, testViewRecordQName1)).
   307  			On("GetBatch", mock.AnythingOfType("[]state.GetBatchItem")).
   308  			Return(nil).
   309  			Run(func(args mock.Arguments) {
   310  				args.Get(0).([]GetBatchItem)[0].value = &mockStateValue{}
   311  			})
   312  		s := asyncActualizerStateWithTestStateStorage(stateStorage)
   313  		k, err := s.KeyBuilder(testStorage, testViewRecordQName1)
   314  		require.NoError(err)
   315  
   316  		err = s.MustNotExist(k)
   317  
   318  		require.ErrorIs(err, ErrExists)
   319  	})
   320  	t.Run("Should return error when error occurred on must exist", func(t *testing.T) {
   321  		require := require.New(t)
   322  		stateStorage := &mockStorage{}
   323  		stateStorage.
   324  			On("NewKeyBuilder", testViewRecordQName1, nil).Return(newKeyBuilder(testStorage, testViewRecordQName1)).
   325  			On("GetBatch", mock.AnythingOfType("[]state.GetBatchItem")).Return(errTest)
   326  		s := asyncActualizerStateWithTestStateStorage(stateStorage)
   327  		kb, err := s.KeyBuilder(testStorage, testViewRecordQName1)
   328  		require.NoError(err)
   329  
   330  		err = s.MustNotExist(kb)
   331  
   332  		require.ErrorIs(err, errTest)
   333  	})
   334  }
   335  func TestAsyncActualizerState_MustNotExistAll(t *testing.T) {
   336  	t.Run("Should be ok", func(t *testing.T) {
   337  		require := require.New(t)
   338  		stateStorage := &mockStorage{}
   339  		stateStorage.
   340  			On("NewKeyBuilder", testViewRecordQName1, nil).Return(newKeyBuilder(testStorage, testViewRecordQName1)).
   341  			On("GetBatch", mock.AnythingOfType("[]state.GetBatchItem")).
   342  			Return(nil).
   343  			Run(func(args mock.Arguments) {
   344  				args.Get(0).([]GetBatchItem)[0].value = nil
   345  			})
   346  		s := asyncActualizerStateWithTestStateStorage(stateStorage)
   347  		k1, err := s.KeyBuilder(testStorage, testViewRecordQName1)
   348  		require.NoError(err)
   349  		k2, err := s.KeyBuilder(testStorage, testViewRecordQName1)
   350  		require.NoError(err)
   351  
   352  		err = s.MustNotExistAll([]istructs.IStateKeyBuilder{k1, k2})
   353  
   354  		require.NoError(err)
   355  	})
   356  	t.Run("Should return error when entity exists", func(t *testing.T) {
   357  		require := require.New(t)
   358  		stateStorage := &mockStorage{}
   359  		stateStorage.
   360  			On("NewKeyBuilder", testViewRecordQName1, nil).Return(newKeyBuilder(testStorage, testViewRecordQName1)).
   361  			On("GetBatch", mock.AnythingOfType("[]state.GetBatchItem")).
   362  			Return(nil).
   363  			Run(func(args mock.Arguments) {
   364  				args.Get(0).([]GetBatchItem)[0].value = &mockStateValue{}
   365  			})
   366  		s := asyncActualizerStateWithTestStateStorage(stateStorage)
   367  		k1, err := s.KeyBuilder(testStorage, testViewRecordQName1)
   368  		require.NoError(err)
   369  		k2, err := s.KeyBuilder(testStorage, testViewRecordQName1)
   370  		require.NoError(err)
   371  
   372  		err = s.MustNotExistAll([]istructs.IStateKeyBuilder{k1, k2})
   373  
   374  		require.ErrorIs(err, ErrExists)
   375  	})
   376  }
   377  func TestAsyncActualizerState_Read(t *testing.T) {
   378  	t.Run("Should flush bundle before read", func(t *testing.T) {
   379  		require := require.New(t)
   380  		touched := false
   381  		mockedStructs, mockedViews := mockedStructs(t)
   382  		mockedViews.
   383  			On("KeyBuilder", testViewRecordQName1).Return(&nilKeyBuilder{}).
   384  			On("KeyBuilder", testViewRecordQName2).Return(&nilKeyBuilder{}).
   385  			On("NewValueBuilder", testViewRecordQName1).Return(&nilValueBuilder{}).
   386  			On("NewValueBuilder", testViewRecordQName2).Return(&nilValueBuilder{}).
   387  			On("PutBatch", istructs.WSID(1), mock.AnythingOfType("[]istructs.ViewKV")).
   388  			Return(nil).
   389  			Run(func(args mock.Arguments) {
   390  				require.Len(args.Get(1).([]istructs.ViewKV), 2)
   391  			}).
   392  			On("Read", context.Background(), istructs.WSID(1), mock.Anything, mock.AnythingOfType("istructs.ValuesCallback")).
   393  			Return(nil).
   394  			Run(func(args mock.Arguments) {
   395  				_ = args.Get(3).(istructs.ValuesCallback)(&nilKey{}, &nilValue{})
   396  			})
   397  
   398  		s := ProvideAsyncActualizerStateFactory()(context.Background(), func() istructs.IAppStructs { return mockedStructs }, nil, SimpleWSIDFunc(istructs.WSID(1)), nil, nil, nil, nil, nil, 10, 10)
   399  		kb1, err := s.KeyBuilder(View, testViewRecordQName1)
   400  		require.NoError(err)
   401  		kb2, err := s.KeyBuilder(View, testViewRecordQName2)
   402  		require.NoError(err)
   403  
   404  		_, _ = s.NewValue(kb1)
   405  		_, _ = s.NewValue(kb2)
   406  
   407  		readyToFlush, err := s.ApplyIntents()
   408  		require.False(readyToFlush)
   409  		require.NoError(err)
   410  
   411  		_ = s.Read(kb1, func(key istructs.IKey, value istructs.IStateValue) (err error) {
   412  			touched = true
   413  			return
   414  		})
   415  
   416  		require.True(touched)
   417  	})
   418  	t.Run("Should return error when error occurred on apply batch", func(t *testing.T) {
   419  		require := require.New(t)
   420  		touched := false
   421  		mockedStructs, mockedViews := mockedStructs(t)
   422  		mockedViews.
   423  			On("KeyBuilder", testViewRecordQName1).Return(&nilKeyBuilder{}).
   424  			On("KeyBuilder", testViewRecordQName2).Return(&nilKeyBuilder{}).
   425  			On("NewValueBuilder", testViewRecordQName1).Return(&nilValueBuilder{}).
   426  			On("NewValueBuilder", testViewRecordQName2).Return(&nilValueBuilder{}).
   427  			On("PutBatch", istructs.WSID(1), mock.AnythingOfType("[]istructs.ViewKV")).Return(errTest)
   428  		s := ProvideAsyncActualizerStateFactory()(context.Background(), func() istructs.IAppStructs { return mockedStructs }, nil, SimpleWSIDFunc(istructs.WSID(1)), nil, nil, nil, nil, nil, 10, 10)
   429  		kb1, err := s.KeyBuilder(View, testViewRecordQName1)
   430  		require.NoError(err)
   431  		kb2, err := s.KeyBuilder(View, testViewRecordQName2)
   432  		require.NoError(err)
   433  
   434  		_, _ = s.NewValue(kb1)
   435  		_, _ = s.NewValue(kb2)
   436  
   437  		readyToFlush, err := s.ApplyIntents()
   438  		require.False(readyToFlush)
   439  		require.NoError(err)
   440  
   441  		err = s.Read(kb1, func(key istructs.IKey, value istructs.IStateValue) (err error) {
   442  			touched = true
   443  			return err
   444  		})
   445  
   446  		require.ErrorIs(err, errTest)
   447  		require.False(touched)
   448  	})
   449  }
   450  func asyncActualizerStateWithTestStateStorage(s *mockStorage) istructs.IState {
   451  	as := ProvideAsyncActualizerStateFactory()(context.Background(), nilAppStructsFunc, nil, nil, nil, nil, nil, nil, nil, 10, 10)
   452  	as.(*asyncActualizerState).addStorage(testStorage, s, S_GET_BATCH|S_READ)
   453  	return as
   454  }