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 }