github.com/voedger/voedger@v0.0.0-20240520144910-273e84102129/pkg/state/impl_view_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 mockedStructs2(t *testing.T, addWsDescriptor bool) (*mockAppStructs, *mockViewRecords) {
    19  	appDef := appdef.New()
    20  
    21  	appDef.AddPackage("test", "test.com/test")
    22  
    23  	view := appDef.AddView(testViewRecordQName1)
    24  	view.Key().PartKey().AddField("pkk", appdef.DataKind_int64)
    25  	view.Key().ClustCols().AddField("cck", appdef.DataKind_string)
    26  	view.Value().AddField("vk", appdef.DataKind_string, false)
    27  
    28  	view = appDef.AddView(testViewRecordQName2)
    29  	view.Key().PartKey().AddField("pkk", appdef.DataKind_int64)
    30  	view.Key().ClustCols().AddField("cck", appdef.DataKind_string)
    31  	view.Value().AddField("vk", appdef.DataKind_string, false)
    32  
    33  	mockWorkspaceRecord := &mockRecord{}
    34  	mockWorkspaceRecord.On("AsQName", "WSKind").Return(testWSDescriptorQName)
    35  	mockWorkspaceRecord.On("QName").Return(qNameCDocWorkspaceDescriptor)
    36  	mockedRecords := &mockRecords{}
    37  	mockedRecords.On("GetSingleton", istructs.WSID(1), mock.Anything).Return(mockWorkspaceRecord, nil)
    38  
    39  	mockedViews := &mockViewRecords{}
    40  	mockedViews.On("KeyBuilder", testViewRecordQName1).Return(newKeyBuilder(View, testViewRecordQName1))
    41  
    42  	if addWsDescriptor {
    43  		wsDesc := appDef.AddCDoc(testWSDescriptorQName)
    44  		wsDesc.AddField(field_WSKind, appdef.DataKind_bytes, false)
    45  	}
    46  
    47  	ws := appDef.AddWorkspace(testWSQName)
    48  	ws.AddType(testViewRecordQName1)
    49  	ws.AddType(testViewRecordQName2)
    50  	ws.SetDescriptor(testWSDescriptorQName)
    51  
    52  	app, err := appDef.Build()
    53  	require.NoError(t, err)
    54  
    55  	appStructs := &mockAppStructs{}
    56  	appStructs.
    57  		On("AppDef").Return(app).
    58  		On("AppQName").Return(testAppQName).
    59  		On("Records").Return(mockedRecords).
    60  		On("Events").Return(&nilEvents{}).
    61  		On("ViewRecords").Return(mockedViews)
    62  
    63  	return appStructs, mockedViews
    64  }
    65  
    66  func mockedStructs(t *testing.T) (*mockAppStructs, *mockViewRecords) {
    67  	return mockedStructs2(t, true)
    68  }
    69  
    70  func TestViewRecordsStorage_GetBatch(t *testing.T) {
    71  	t.Run("Should be ok", func(t *testing.T) {
    72  		require := require.New(t)
    73  
    74  		mockedStructs, mockedViews := mockedStructs(t)
    75  		valueOnGet := &mockValue{}
    76  		valueOnGet.On("AsString", "vk").Return("value")
    77  		mockedViews.
    78  			On("Get", istructs.WSID(1), mock.Anything).Return(valueOnGet, nil)
    79  
    80  		s := ProvideQueryProcessorStateFactory()(context.Background(), appStructsFunc(mockedStructs), nil, SimpleWSIDFunc(istructs.WSID(1)), nil, nil, nil, nil, nil, nil, nil, nil)
    81  		k, e := s.KeyBuilder(View, testViewRecordQName1)
    82  		require.NoError(e)
    83  		k.PutInt64("pkk", 64)
    84  		k.PutString("cck", "ccv")
    85  
    86  		sv, ok, err := s.CanExist(k)
    87  		require.NoError(err)
    88  
    89  		require.True(ok)
    90  		require.Equal("value", sv.AsString("vk"))
    91  	})
    92  	t.Run("Should return error on get", func(t *testing.T) {
    93  		require := require.New(t)
    94  		mockedStructs, mockedViews := mockedStructs(t)
    95  		mockedViews.
    96  			On("Get", istructs.WSID(1), mock.Anything).Return(nil, errTest)
    97  
    98  		s := ProvideQueryProcessorStateFactory()(context.Background(), appStructsFunc(mockedStructs), nil, SimpleWSIDFunc(istructs.WSID(1)), nil, nil, nil, nil, nil, nil, nil, nil)
    99  		k, err := s.KeyBuilder(View, testViewRecordQName1)
   100  		require.NoError(err)
   101  		k.PutInt64("pkk", 64)
   102  
   103  		_, ok, err := s.CanExist(k)
   104  
   105  		require.False(ok)
   106  		require.ErrorIs(err, errTest)
   107  	})
   108  }
   109  func TestViewRecordsStorage_Read(t *testing.T) {
   110  	t.Run("Should be ok", func(t *testing.T) {
   111  		require := require.New(t)
   112  		mockedStructs, mockedViews := mockedStructs(t)
   113  		touched := false
   114  		mockedViews.
   115  			On("Read", context.Background(), istructs.WSID(1), mock.Anything, mock.AnythingOfType("istructs.ValuesCallback")).
   116  			Return(nil).
   117  			Run(func(args mock.Arguments) {
   118  				require.NotNil(args.Get(2))
   119  				require.NoError(args.Get(3).(istructs.ValuesCallback)(nil, nil))
   120  			})
   121  		s := ProvideQueryProcessorStateFactory()(context.Background(), appStructsFunc(mockedStructs), nil, SimpleWSIDFunc(istructs.WSID(1)), nil, nil, nil, nil, nil, nil, nil, nil)
   122  		k, err := s.KeyBuilder(View, testViewRecordQName1)
   123  		require.NoError(err)
   124  		err = s.Read(k, func(istructs.IKey, istructs.IStateValue) error {
   125  			touched = true
   126  			return nil
   127  		})
   128  		require.NoError(err)
   129  		require.True(touched)
   130  	})
   131  	t.Run("Should return error on read", func(t *testing.T) {
   132  		require := require.New(t)
   133  		mockedStructs, mockedViews := mockedStructs(t)
   134  		mockedViews.
   135  			On("KeyBuilder", testViewRecordQName1).Return(newKeyBuilder(View, testViewRecordQName1)).
   136  			On("Read", context.Background(), istructs.WSID(1), mock.Anything, mock.Anything).
   137  			Return(errTest)
   138  		s := ProvideQueryProcessorStateFactory()(context.Background(), appStructsFunc(mockedStructs), nil, SimpleWSIDFunc(istructs.WSID(1)), nil, nil, nil, nil, nil, nil, nil, nil)
   139  		k, err := s.KeyBuilder(View, testViewRecordQName1)
   140  		require.NoError(err)
   141  		err = s.Read(k, func(istructs.IKey, istructs.IStateValue) error { return nil })
   142  		require.ErrorIs(err, errTest)
   143  	})
   144  }
   145  func TestViewRecordsStorage_ApplyBatch_should_return_error_on_put_batch(t *testing.T) {
   146  	require := require.New(t)
   147  	mockedStructs, mockedViews := mockedStructs(t)
   148  	mockedViews.
   149  		On("KeyBuilder", testViewRecordQName1).Return(&nilKeyBuilder{}).
   150  		On("NewValueBuilder", testViewRecordQName1).Return(&nilValueBuilder{}).
   151  		On("PutBatch", istructs.WSID(1), mock.Anything).Return(errTest)
   152  	s := ProvideAsyncActualizerStateFactory()(context.Background(), appStructsFunc(mockedStructs), nil, SimpleWSIDFunc(istructs.WSID(1)), nil, nil, nil, nil, nil, 10, 10)
   153  	kb, err := s.KeyBuilder(View, testViewRecordQName1)
   154  	require.NoError(err)
   155  	_, err = s.NewValue(kb)
   156  	require.NoError(err)
   157  	readyToFlush, err := s.ApplyIntents()
   158  	require.False(readyToFlush)
   159  	require.NoError(err)
   160  	err = s.FlushBundles()
   161  	require.ErrorIs(err, errTest)
   162  }
   163  
   164  func TestViewRecordsStorage_ApplyBatch_NullWSIDGoesLast(t *testing.T) {
   165  	require := require.New(t)
   166  
   167  	mockedStructs, mockedViews := mockedStructs(t)
   168  
   169  	appliedWSIDs := make([]istructs.WSID, 0)
   170  	mockedViews.
   171  		On("KeyBuilder", testViewRecordQName1).Return(&nilKeyBuilder{}).
   172  		On("NewValueBuilder", testViewRecordQName1).Return(&nilValueBuilder{}).
   173  		On("PutBatch", mock.Anything, mock.Anything).Run(func(args mock.Arguments) {
   174  		appliedWSIDs = append(appliedWSIDs, args[0].(istructs.WSID))
   175  	}).
   176  		Return(nil)
   177  
   178  	putViewRec := func(s IBundledHostState) {
   179  		kb, err := s.KeyBuilder(View, testViewRecordQName1)
   180  		require.NoError(err)
   181  		_, err = s.NewValue(kb)
   182  		require.NoError(err)
   183  	}
   184  
   185  	putOffset := func(s IBundledHostState) {
   186  		kb, err := s.KeyBuilder(View, testViewRecordQName1)
   187  		kb.PutInt64(Field_WSID, int64(istructs.NullWSID))
   188  		require.NoError(err)
   189  		_, err = s.NewValue(kb)
   190  		require.NoError(err)
   191  	}
   192  
   193  	applyAndFlush := func(s IBundledHostState) {
   194  		readyToFlush, err := s.ApplyIntents()
   195  		require.False(readyToFlush)
   196  		require.NoError(err)
   197  		err = s.FlushBundles()
   198  		require.NoError(err)
   199  	}
   200  
   201  	s := ProvideAsyncActualizerStateFactory()(context.Background(), appStructsFunc(mockedStructs), nil, SimpleWSIDFunc(istructs.WSID(1)), nil, nil, nil, nil, nil, 10, 10)
   202  	putViewRec(s)
   203  	putViewRec(s)
   204  	putOffset(s)
   205  	applyAndFlush(s)
   206  	require.Len(appliedWSIDs, 2)
   207  	require.Equal(istructs.NullWSID, appliedWSIDs[1])
   208  
   209  	appliedWSIDs = appliedWSIDs[:0]
   210  	putOffset(s)
   211  	putViewRec(s)
   212  	putViewRec(s)
   213  	applyAndFlush(s)
   214  	require.Len(appliedWSIDs, 2)
   215  	require.Equal(istructs.NullWSID, appliedWSIDs[1])
   216  }
   217  
   218  func TestViewRecordsStorage_ValidateInWorkspaces(t *testing.T) {
   219  	require := require.New(t)
   220  
   221  	mockedStructs, mockedViews := mockedStructs(t)
   222  	mockedViews.
   223  		On("KeyBuilder", mock.Anything).Return(&nilKeyBuilder{}).
   224  		On("NewValueBuilder", mock.Anything).Return(&nilValueBuilder{}).
   225  		On("Get", istructs.WSID(1), mock.Anything).Return(&nilValue{}, nil).
   226  		On("PutBatch", mock.Anything, mock.Anything).Return(nil)
   227  	s := ProvideAsyncActualizerStateFactory()(context.Background(), appStructsFunc(mockedStructs), nil, SimpleWSIDFunc(istructs.WSID(1)), nil, nil, nil, nil, nil, 10, 10)
   228  
   229  	wrongQName := appdef.NewQName("test", "viewRecordX")
   230  	wrongKb, err := s.KeyBuilder(View, wrongQName)
   231  	require.NoError(err)
   232  	expectedError := typeIsNotDefinedInWorkspaceWithDescriptor(wrongQName, testWSDescriptorQName)
   233  
   234  	t.Run("App() should return value", func(t *testing.T) {
   235  		app := s.App()
   236  		require.NotNil(app)
   237  		require.Equal(testAppQName, app)
   238  	})
   239  
   240  	t.Run("State should supports istructs.IPkgNameResolver interface", func(t *testing.T) {
   241  		const (
   242  			pkgName = "test"
   243  			pkgPath = "test.com/test"
   244  		)
   245  		require.Equal(pkgName, s.PackageLocalName(pkgPath))
   246  		require.Equal(pkgPath, s.PackageFullPath(pkgName))
   247  	})
   248  
   249  	t.Run("NewValue should validate for unavailable views", func(t *testing.T) {
   250  		value, err := s.NewValue(wrongKb)
   251  		require.EqualError(err, expectedError.Error())
   252  		require.Nil(value)
   253  	})
   254  
   255  	t.Run("UpdateValue should validate for unavailable workspaces", func(t *testing.T) {
   256  		value, err := s.UpdateValue(wrongKb, nil)
   257  		require.EqualError(err, expectedError.Error())
   258  		require.Nil(value)
   259  	})
   260  
   261  	t.Run("CanExist should validate for unavailable views", func(t *testing.T) {
   262  		value, ok, err := s.CanExist(wrongKb)
   263  		require.EqualError(err, expectedError.Error())
   264  		require.Nil(value)
   265  		require.False(ok)
   266  	})
   267  
   268  	t.Run("MustExist should validate for unavailable views", func(t *testing.T) {
   269  		value, err := s.MustExist(wrongKb)
   270  		require.EqualError(err, expectedError.Error())
   271  		require.Nil(value)
   272  	})
   273  
   274  	t.Run("MustNotExist should validate for unavailable views", func(t *testing.T) {
   275  		err := s.MustNotExist(wrongKb)
   276  		require.EqualError(err, expectedError.Error())
   277  	})
   278  
   279  	t.Run("CanExistAll should validate for unavailable views", func(t *testing.T) {
   280  		correctKb, err := s.KeyBuilder(View, testViewRecordQName1)
   281  		require.NoError(err)
   282  		err = s.CanExistAll([]istructs.IStateKeyBuilder{wrongKb, correctKb}, nil)
   283  		require.EqualError(err, expectedError.Error())
   284  	})
   285  
   286  	t.Run("MustExistAll should validate for unavailable views", func(t *testing.T) {
   287  		correctKb, err := s.KeyBuilder(View, testViewRecordQName1)
   288  		require.NoError(err)
   289  		err = s.MustExistAll([]istructs.IStateKeyBuilder{wrongKb, correctKb}, nil)
   290  		require.EqualError(err, expectedError.Error())
   291  	})
   292  
   293  	t.Run("MustNotExistAll should validate for unavailable views", func(t *testing.T) {
   294  		correctKb, err := s.KeyBuilder(View, testViewRecordQName1)
   295  		require.NoError(err)
   296  		err = s.MustNotExistAll([]istructs.IStateKeyBuilder{wrongKb, correctKb})
   297  		require.EqualError(err, expectedError.Error())
   298  	})
   299  
   300  }