github.com/kaisenlinux/docker.io@v0.0.0-20230510090727-ea55db55fac7/swarmkit/watch/watch_test.go (about) 1 package watch 2 3 import ( 4 "context" 5 "sync" 6 "testing" 7 "time" 8 9 "github.com/docker/go-events" 10 "github.com/stretchr/testify/require" 11 ) 12 13 func TestTimeoutLimitWatch(t *testing.T) { 14 require := require.New(t) 15 q := NewQueue(WithTimeout(time.Second), WithLimit(5), WithCloseOutChan()) 16 defer q.Close() 17 ctx, cancel := context.WithCancel(context.Background()) 18 19 // Cancelling a watcher's context should remove the watcher from the queue and 20 // close its channel. 21 doneChan := make(chan struct{}) 22 go func() { 23 events := q.WatchContext(ctx) 24 for range events { 25 } 26 close(doneChan) 27 }() 28 cancel() 29 <-doneChan 30 31 // Test a scenario with a faster write rate than read rate The queue 32 // should eventually fill up and the channel will be closed. 33 readerSleepDuration := 100 * time.Millisecond 34 writerSleepDuration := 10 * time.Millisecond 35 36 events, cancel := q.Watch() 37 defer cancel() 38 39 receivedChan := make(chan struct{}) 40 eventsClosed := make(chan struct{}) 41 42 go func() { 43 closed := false 44 for range events { 45 if !closed { 46 close(receivedChan) 47 closed = true 48 } 49 time.Sleep(readerSleepDuration) 50 } 51 close(eventsClosed) 52 }() 53 54 // Publish one event and wait for the watcher to receive it 55 q.Publish("new event") 56 <-receivedChan 57 58 timeoutTimer := time.NewTimer(time.Minute) 59 selectLoop: 60 for { 61 select { 62 case <-timeoutTimer.C: 63 require.Fail("Timeout exceeded") 64 case <-time.After(writerSleepDuration): 65 q.Publish("new event") 66 case <-eventsClosed: 67 break selectLoop 68 } 69 } 70 71 _, ok := <-events 72 require.False(ok) 73 } 74 75 func TestWatch(t *testing.T) { 76 // Create a queue 77 q := NewQueue() 78 defer q.Close() 79 80 type testEvent struct { 81 tags []string 82 str string 83 } 84 85 tagFilter := func(t string) events.Matcher { 86 return events.MatcherFunc(func(event events.Event) bool { 87 testEvent := event.(testEvent) 88 for _, itemTag := range testEvent.tags { 89 if t == itemTag { 90 return true 91 } 92 } 93 return false 94 }) 95 } 96 97 // Create filtered watchers 98 c1, c1cancel := q.CallbackWatch(tagFilter("t1")) 99 defer c1cancel() 100 c2, c2cancel := q.CallbackWatch(tagFilter("t2")) 101 defer c2cancel() 102 103 // Publish items on the queue 104 q.Publish(testEvent{tags: []string{"t1"}, str: "foo"}) 105 q.Publish(testEvent{tags: []string{"t2"}, str: "bar"}) 106 q.Publish(testEvent{tags: []string{"t1", "t2"}, str: "foobar"}) 107 q.Publish(testEvent{tags: []string{"t3"}, str: "baz"}) 108 109 if (<-c1).(testEvent).str != "foo" { 110 t.Fatal(`expected "foo" on c1`) 111 } 112 113 ev := (<-c1).(testEvent) 114 if ev.str != "foobar" { 115 t.Fatal(`expected "foobar" on c1`, ev) 116 } 117 if (<-c2).(testEvent).str != "bar" { 118 t.Fatal(`expected "bar" on c2`) 119 } 120 if (<-c2).(testEvent).str != "foobar" { 121 t.Fatal(`expected "foobar" on c2`) 122 } 123 124 c1cancel() 125 126 select { 127 case _, ok := <-c1: 128 if ok { 129 t.Fatal("unexpected value on c1") 130 } 131 default: 132 // operation does not proceed after cancel 133 } 134 135 q.Publish(testEvent{tags: []string{"t1", "t2"}, str: "foobar"}) 136 137 if (<-c2).(testEvent).str != "foobar" { 138 t.Fatal(`expected "foobar" on c2`) 139 } 140 141 c2cancel() 142 143 select { 144 case _, ok := <-c2: 145 if ok { 146 t.Fatal("unexpected value on c2") 147 } 148 default: 149 // operation does not proceed after cancel 150 } 151 } 152 153 func BenchmarkPublish10(b *testing.B) { 154 benchmarkWatch(b, 10, 1, false) 155 } 156 157 func BenchmarkPublish100(b *testing.B) { 158 benchmarkWatch(b, 100, 1, false) 159 } 160 161 func BenchmarkPublish1000(b *testing.B) { 162 benchmarkWatch(b, 1000, 1, false) 163 } 164 165 func BenchmarkPublish10000(b *testing.B) { 166 benchmarkWatch(b, 10000, 1, false) 167 } 168 169 func BenchmarkPublish10Listeners4Publishers(b *testing.B) { 170 benchmarkWatch(b, 10, 4, false) 171 } 172 173 func BenchmarkPublish100Listeners8Publishers(b *testing.B) { 174 benchmarkWatch(b, 100, 8, false) 175 } 176 177 func BenchmarkPublish1000Listeners4Publishers(b *testing.B) { 178 benchmarkWatch(b, 1000, 4, false) 179 } 180 181 func BenchmarkPublish1000Listeners64Publishers(b *testing.B) { 182 benchmarkWatch(b, 1000, 64, false) 183 } 184 185 func BenchmarkWatch10(b *testing.B) { 186 benchmarkWatch(b, 10, 1, true) 187 } 188 189 func BenchmarkWatch100(b *testing.B) { 190 benchmarkWatch(b, 100, 1, true) 191 } 192 193 func BenchmarkWatch1000(b *testing.B) { 194 benchmarkWatch(b, 1000, 1, true) 195 } 196 197 func BenchmarkWatch10000(b *testing.B) { 198 benchmarkWatch(b, 10000, 1, true) 199 } 200 201 func BenchmarkWatch10Listeners4Publishers(b *testing.B) { 202 benchmarkWatch(b, 10, 4, true) 203 } 204 205 func BenchmarkWatch100Listeners8Publishers(b *testing.B) { 206 benchmarkWatch(b, 100, 8, true) 207 } 208 209 func BenchmarkWatch1000Listeners4Publishers(b *testing.B) { 210 benchmarkWatch(b, 1000, 4, true) 211 } 212 213 func BenchmarkWatch1000Listeners64Publishers(b *testing.B) { 214 benchmarkWatch(b, 1000, 64, true) 215 } 216 217 func benchmarkWatch(b *testing.B, nlisteners, npublishers int, waitForWatchers bool) { 218 q := NewQueue() 219 defer q.Close() 220 benchmarkWatchForQueue(q, b, nlisteners, npublishers, waitForWatchers) 221 } 222 223 func benchmarkWatchForQueue(q *Queue, b *testing.B, nlisteners, npublishers int, waitForWatchers bool) { 224 var ( 225 watchersAttached sync.WaitGroup 226 watchersRunning sync.WaitGroup 227 publishersRunning sync.WaitGroup 228 ) 229 230 for i := 0; i < nlisteners; i++ { 231 watchersAttached.Add(1) 232 watchersRunning.Add(1) 233 go func(n int) { 234 w, cancel := q.Watch() 235 defer cancel() 236 watchersAttached.Done() 237 238 for i := 0; i != n; i++ { 239 <-w 240 } 241 if waitForWatchers { 242 watchersRunning.Done() 243 } 244 }(b.N / npublishers * npublishers) 245 } 246 247 // Wait for watchers to be in place before we start publishing events. 248 watchersAttached.Wait() 249 250 b.ResetTimer() 251 252 for i := 0; i < npublishers; i++ { 253 publishersRunning.Add(1) 254 go func(n int) { 255 for i := 0; i < n; i++ { 256 q.Publish("myevent") 257 } 258 publishersRunning.Done() 259 }(b.N / npublishers) 260 } 261 262 publishersRunning.Wait() 263 264 if waitForWatchers { 265 watchersRunning.Wait() 266 } 267 }