Skip to content

Commit

Permalink
integration: prevent goroutines leaks in test (#11318)
Browse files Browse the repository at this point in the history
Some goroutines in test functions will be leaked in certain cases.
This patch stops these leaks no matter what happens in test, by
putting the blocking channel in select together with a new stopc
channel, or adding 1 buffer to the blocking channel.
  • Loading branch information
lzhfromustc authored and xiang90 committed Dec 5, 2019
1 parent fd2dddb commit 1f8764b
Show file tree
Hide file tree
Showing 5 changed files with 35 additions and 7 deletions.
9 changes: 8 additions & 1 deletion integration/v3_barrier_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,20 @@ func testBarrier(t *testing.T, waiters int, chooseClient func() *clientv3.Client
}

donec := make(chan struct{})
stopc := make(chan struct{})
defer close(stopc)

for i := 0; i < waiters; i++ {
go func() {
br := recipe.NewBarrier(chooseClient(), "test-barrier")
if err := br.Wait(); err != nil {
t.Errorf("could not wait on barrier (%v)", err)
}
donec <- struct{}{}
select {
case donec <- struct{}{}:
case <-stopc:
}

}()
}

Expand Down
8 changes: 7 additions & 1 deletion integration/v3_leadership_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,16 @@ func testMoveLeader(t *testing.T, auto bool) {

// ensure followers go through leader transition while learship transfer
idc := make(chan uint64)
stopc := make(chan struct{})
defer close(stopc)

for i := range clus.Members {
if oldLeadIdx != i {
go func(m *member) {
idc <- checkLeaderTransition(m, oldLeadID)
select {
case idc <- checkLeaderTransition(m, oldLeadID):
case <-stopc:
}
}(clus.Members[i])
}
}
Expand Down
21 changes: 18 additions & 3 deletions integration/v3_lock_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ func TestMutexLockMultiNode(t *testing.T) {
func testMutexLock(t *testing.T, waiters int, chooseClient func() *clientv3.Client) {
// stream lock acquisitions
lockedC := make(chan *concurrency.Mutex)
stopC := make(chan struct{})
defer close(stopC)

for i := 0; i < waiters; i++ {
go func() {
session, err := concurrency.NewSession(chooseClient())
Expand All @@ -59,7 +62,11 @@ func testMutexLock(t *testing.T, waiters int, chooseClient func() *clientv3.Clie
if err := m.Lock(context.TODO()); err != nil {
t.Errorf("could not wait on lock (%v)", err)
}
lockedC <- m
select {
case lockedC <- m:
case <-stopC:
}

}()
}
// unlock locked mutexes
Expand Down Expand Up @@ -103,6 +110,8 @@ func TestMutexTryLockMultiNode(t *testing.T) {
func testMutexTryLock(t *testing.T, lockers int, chooseClient func() *clientv3.Client) {
lockedC := make(chan *concurrency.Mutex)
notlockedC := make(chan *concurrency.Mutex)
stopC := make(chan struct{})
defer close(stopC)
for i := 0; i < lockers; i++ {
go func() {
session, err := concurrency.NewSession(chooseClient())
Expand All @@ -112,9 +121,15 @@ func testMutexTryLock(t *testing.T, lockers int, chooseClient func() *clientv3.C
m := concurrency.NewMutex(session, "test-mutex-try-lock")
err = m.TryLock(context.TODO())
if err == nil {
lockedC <- m
select {
case lockedC <- m:
case <-stopC:
}
} else if err == concurrency.ErrLocked {
notlockedC <- m
select {
case notlockedC <- m:
case <-stopC:
}
} else {
t.Errorf("Unexpected Error %v", err)
}
Expand Down
2 changes: 1 addition & 1 deletion integration/v3_watch_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1188,7 +1188,7 @@ func TestV3WatchWithPrevKV(t *testing.T) {
t.Fatal(err)
}

recv := make(chan *pb.WatchResponse)
recv := make(chan *pb.WatchResponse, 1)
go func() {
// check received PUT
resp, rerr := ws.Recv()
Expand Down
2 changes: 1 addition & 1 deletion integration/v3election_grpc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ func TestV3ElectionObserve(t *testing.T) {
lc := toGRPC(clus.Client(0)).Election

// observe leadership events
observec := make(chan struct{})
observec := make(chan struct{}, 1)
go func() {
defer close(observec)
s, err := lc.Observe(context.Background(), &epb.LeaderRequest{Name: []byte("foo")})
Expand Down

0 comments on commit 1f8764b

Please sign in to comment.