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  }