github.com/voedger/voedger@v0.0.0-20240520144910-273e84102129/pkg/sys/collection/race_test.go (about) 1 /* 2 * Copyright (c) 2021-present unTill Pro, Ltd. 3 * 4 */ 5 6 package collection 7 8 import ( 9 "strconv" 10 "sync" 11 "testing" 12 13 "github.com/stretchr/testify/require" 14 "github.com/voedger/voedger/pkg/appdef" 15 "github.com/voedger/voedger/pkg/istructs" 16 ) 17 18 const ( 19 cntItems = 20 20 ) 21 22 type TSidsGeneratorType struct { 23 lock sync.Mutex 24 idmap map[istructs.RecordID]istructs.RecordID 25 nextID istructs.RecordID 26 nextPlogOffset istructs.Offset 27 } 28 29 func (me *TSidsGeneratorType) NextID(tempId istructs.RecordID, _ appdef.IType) (storageID istructs.RecordID, err error) { 30 me.lock.Lock() 31 defer me.lock.Unlock() 32 storageID = me.nextID 33 me.nextID++ 34 me.idmap[tempId] = storageID 35 return storageID, nil 36 } 37 38 func (me *TSidsGeneratorType) UpdateOnSync(_ istructs.RecordID, _ appdef.IType) { 39 panic("must not be called") 40 } 41 42 func (me *TSidsGeneratorType) nextOffset() (offset istructs.Offset) { 43 me.lock.Lock() 44 defer me.lock.Unlock() 45 offset = me.nextPlogOffset 46 me.nextPlogOffset++ 47 return 48 } 49 50 func newTSIdsGenerator() *TSidsGeneratorType { 51 return &TSidsGeneratorType{ 52 idmap: make(map[istructs.RecordID]istructs.RecordID), 53 nextID: istructs.FirstBaseRecordID, 54 nextPlogOffset: test.plogStartOfs, 55 } 56 } 57 58 func Test_Race_SimpleInsertOne(t *testing.T) { 59 req := require.New(t) 60 61 _, appStructs, cleanup := deployTestApp(t) 62 defer cleanup() 63 64 idGen := newTSIdsGenerator() 65 wg := sync.WaitGroup{} 66 for i := 0; i < cntItems; i++ { 67 wg.Add(1) 68 go func(areq *require.Assertions, _ istructs.IAppStructs, aidGen *TSidsGeneratorType) { 69 defer wg.Done() 70 saveEvent(areq, appStructs, idGen, newTSModify(appStructs, aidGen, func(event istructs.IRawEventBuilder) { 71 newDepartmentCUD(event, 1, 1, "Cold Drinks") 72 })) 73 }(req, appStructs, idGen) 74 } 75 wg.Wait() 76 } 77 78 func Test_Race_SimpleInsertMany(t *testing.T) { 79 req := require.New(t) 80 81 _, appStructs, cleanup := deployTestApp(t) 82 defer cleanup() 83 84 idGen := newTSIdsGenerator() 85 wg := sync.WaitGroup{} 86 for i := 0; i < cntItems; i++ { 87 wg.Add(1) 88 go func(areq *require.Assertions, _ istructs.IAppStructs, aidGen *TSidsGeneratorType, ai int) { 89 defer wg.Done() 90 saveEvent(areq, appStructs, idGen, newTSModify(appStructs, aidGen, func(event istructs.IRawEventBuilder) { 91 newDepartmentCUD(event, istructs.RecordID(ai), int32(ai), "Hot Drinks"+strconv.Itoa(ai)) 92 })) 93 }(req, appStructs, idGen, i+1) 94 } 95 wg.Wait() 96 } 97 98 func newTSModify(app istructs.IAppStructs, gen *TSidsGeneratorType, cb eventCallback) istructs.IRawEventBuilder { 99 newOffset := gen.nextOffset() 100 builder := app.Events().GetSyncRawEventBuilder( 101 istructs.SyncRawEventBuilderParams{ 102 GenericRawEventBuilderParams: istructs.GenericRawEventBuilderParams{ 103 HandlingPartition: test.partition, 104 Workspace: test.workspace, 105 QName: appdef.NewQName("test", "modify"), 106 PLogOffset: newOffset, 107 WLogOffset: newOffset, 108 }, 109 }) 110 cb(builder) 111 return builder 112 }