mirror of
https://github.com/etcd-io/etcd.git
synced 2024-09-27 06:25:44 +00:00
integration: test client watchers with overlapped context cancels
This commit is contained in:
parent
c016325647
commit
deef16b376
@ -759,3 +759,63 @@ func TestWatchCancelOnServer(t *testing.T) {
|
||||
t.Fatalf("expected 0 watchers, got %q", watchers)
|
||||
}
|
||||
}
|
||||
|
||||
// TestWatchOverlapContextCancel stresses the watcher stream teardown path by
|
||||
// creating/canceling watchers to ensure that new watchers are not taken down
|
||||
// by a torn down watch stream. The sort of race that's being detected:
|
||||
// 1. create w1 using a cancelable ctx with %v as "ctx"
|
||||
// 2. cancel ctx
|
||||
// 3. watcher client begins tearing down watcher grpc stream since no more watchers
|
||||
// 3. start creating watcher w2 using a new "ctx" (not canceled), attaches to old grpc stream
|
||||
// 4. watcher client finishes tearing down stream on "ctx"
|
||||
// 5. w2 comes back canceled
|
||||
func TestWatchOverlapContextCancel(t *testing.T) {
|
||||
defer testutil.AfterTest(t)
|
||||
clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 1})
|
||||
defer clus.Terminate(t)
|
||||
|
||||
cli := clus.RandClient()
|
||||
if _, err := cli.Put(context.TODO(), "abc", "def"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// each unique context "%v" has a unique grpc stream
|
||||
n := 100
|
||||
ctxs, ctxc := make([]context.Context, 5), make([]chan struct{}, 5)
|
||||
for i := range ctxs {
|
||||
// make "%v" unique
|
||||
ctxs[i] = context.WithValue(context.TODO(), "key", i)
|
||||
// limits the maximum number of outstanding watchers per stream
|
||||
ctxc[i] = make(chan struct{}, 2)
|
||||
}
|
||||
ch := make(chan struct{}, n)
|
||||
// issue concurrent watches with cancel
|
||||
for i := 0; i < n; i++ {
|
||||
go func() {
|
||||
defer func() { ch <- struct{}{} }()
|
||||
idx := rand.Intn(len(ctxs))
|
||||
ctx, cancel := context.WithCancel(ctxs[idx])
|
||||
ctxc[idx] <- struct{}{}
|
||||
ch := cli.Watch(ctx, "abc", clientv3.WithRev(1))
|
||||
if _, ok := <-ch; !ok {
|
||||
t.Fatalf("unexpected closed channel")
|
||||
}
|
||||
// randomize how cancel overlaps with watch creation
|
||||
if rand.Intn(2) == 0 {
|
||||
<-ctxc[idx]
|
||||
cancel()
|
||||
} else {
|
||||
cancel()
|
||||
<-ctxc[idx]
|
||||
}
|
||||
}()
|
||||
}
|
||||
// join on watches
|
||||
for i := 0; i < n; i++ {
|
||||
select {
|
||||
case <-ch:
|
||||
case <-time.After(time.Second):
|
||||
t.Fatalf("timed out waiting for completed watch")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user