github.com/zhiqiangxu/util@v0.0.0-20230112053021-0a7aee056cd5/mutex/crwmutex_test.go (about) 1 package mutex 2 3 import ( 4 "context" 5 "testing" 6 "time" 7 ) 8 9 func TestCRWMutex(t *testing.T) { 10 crwm := NewCRWMutex() 11 // test RLock/RUnlock 12 err := crwm.RLock(context.Background()) 13 if err != nil { 14 t.FailNow() 15 } 16 17 crwm.RUnlock() 18 19 // test Lock/Unlock 20 err = crwm.Lock(context.Background()) 21 if err != nil { 22 t.FailNow() 23 } 24 crwm.Unlock() 25 26 // test TryLock/Unlock 27 ok := crwm.TryLock() 28 if !ok { 29 t.FailNow() 30 } 31 crwm.Unlock() 32 33 // test TryRLock/Unlock 34 ok = crwm.TryRLock() 35 if !ok { 36 t.FailNow() 37 } 38 crwm.RUnlock() 39 40 // test RLock/canceled Lock/RUnlock 41 err = crwm.RLock(context.Background()) 42 if err != nil { 43 t.FailNow() 44 } 45 46 ctx, cancelFunc := context.WithTimeout(context.Background(), time.Millisecond*300) 47 defer cancelFunc() 48 err = crwm.Lock(ctx) 49 if err == nil { 50 t.FailNow() 51 } 52 53 crwm.RUnlock() 54 55 } 56 57 func TestSemaphoreBug(t *testing.T) { 58 crwm := NewCRWMutex() 59 // hold 1 read lock 60 crwm.RLock(context.Background()) 61 62 go func() { 63 ctx, cancelFunc := context.WithTimeout(context.Background(), time.Millisecond*300) 64 defer cancelFunc() 65 // start a Lock request that will giveup after 300ms 66 err := crwm.Lock(ctx) 67 if err == nil { 68 t.FailNow() 69 } 70 }() 71 72 // sleep 100ms, long enough for the Lock request to be queued 73 time.Sleep(time.Millisecond * 100) 74 // this channel will be closed if the following RLock succeeded 75 doneCh := make(chan struct{}) 76 go func() { 77 // try to grab a read lock, it will be queued after the Lock request 78 // but should be notified when the Lock request is canceled 79 // this doesn't happen because there's a bug in semaphore 80 err := crwm.RLock(context.Background()) 81 if err != nil { 82 t.FailNow() 83 } 84 crwm.RUnlock() 85 close(doneCh) 86 }() 87 88 // because of the bug in semaphore, doneCh is never closed 89 select { 90 case <-doneCh: 91 case <-time.After(time.Second): 92 t.FailNow() 93 } 94 95 }