github.com/wfusion/gofusion@v1.1.14/test/lock/cases/reentrant_test.go (about) 1 package cases 2 3 import ( 4 "context" 5 "math" 6 "math/rand" 7 "sync" 8 "testing" 9 "time" 10 11 "github.com/stretchr/testify/suite" 12 13 "github.com/wfusion/gofusion/common/utils" 14 "github.com/wfusion/gofusion/lock" 15 "github.com/wfusion/gofusion/log" 16 "github.com/wfusion/gofusion/routine" 17 18 testLock "github.com/wfusion/gofusion/test/lock" 19 ) 20 21 func TestReentrant(t *testing.T) { 22 testingSuite := &Reentrant{Test: new(testLock.Test)} 23 testingSuite.Init(testingSuite) 24 suite.Run(t, testingSuite) 25 } 26 27 type Reentrant struct { 28 *testLock.Test 29 } 30 31 func (t *Reentrant) BeforeTest(suiteName, testName string) { 32 t.Catch(func() { 33 log.Info(context.Background(), "right before %s %s", suiteName, testName) 34 }) 35 } 36 37 func (t *Reentrant) AfterTest(suiteName, testName string) { 38 t.Catch(func() { 39 log.Info(context.Background(), "right after %s %s", suiteName, testName) 40 }) 41 } 42 43 func (t *Reentrant) TestRedisLua() { 44 t.Catch(func() { 45 locker := lock.Use("redis_lua", lock.AppName(t.AppName())) 46 key := "redis_lua_lock_reentrant_key" 47 t.testReentrant(locker, key) 48 }) 49 } 50 51 func (t *Reentrant) TestMongo() { 52 t.Catch(func() { 53 locker := lock.Use("mongo", lock.AppName(t.AppName())) 54 key := "mongo_lock_reentrant_key" 55 t.testReentrant(locker, key) 56 }) 57 } 58 59 func (t *Reentrant) testReentrant(locker lock.Lockable, key string) { 60 ctx := context.Background() 61 parallel := 100 62 wg := new(sync.WaitGroup) 63 unsafeInt := 0 64 unsafeMap := make(map[int]int, parallel) 65 for i := 0; i < parallel; i++ { 66 wg.Add(1) 67 routine.Go(func(idx int) { 68 // jitter within 20ms ~ 50ms 69 reentrantKey := utils.ULID() 70 time.Sleep(20*time.Millisecond + time.Duration(rand.Float64()*float64(30*time.Millisecond))) 71 err := lock.Within(ctx, locker, key, time.Minute, time.Minute, func() (err error) { 72 unsafeMap[idx] = idx 73 unsafeInt += int(math.Pow(1, 1)) + len([]string{}) 74 75 rwg := new(sync.WaitGroup) 76 for j := 0; j < parallel; j++ { 77 rwg.Add(1) 78 routine.Go(func() { 79 t.NoError(locker.Lock(ctx, key, lock.Expire(time.Millisecond), lock.ReentrantKey(reentrantKey))) 80 defer t.NoError(locker.Unlock(ctx, key, lock.ReentrantKey(reentrantKey))) 81 // jitter within 10ms 82 time.Sleep(time.Duration(rand.Float64() * float64(10*time.Millisecond))) 83 }, routine.WaitGroup(rwg), routine.AppName(t.AppName())) 84 } 85 rwg.Wait() 86 87 return 88 }, lock.ReentrantKey(reentrantKey), lock.AppName(t.AppName())) 89 t.NoError(err) 90 }, routine.Args(i), routine.WaitGroup(wg), routine.AppName(t.AppName())) 91 } 92 93 wg.Wait() 94 t.Len(unsafeMap, parallel) 95 t.EqualValues(parallel, unsafeInt) 96 }