github.com/spotmaxtech/k8s-apimachinery-v0260@v0.0.1/pkg/watch/mux_test.go (about) 1 /* 2 Copyright 2014 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package watch 18 19 import ( 20 "reflect" 21 "sync" 22 "testing" 23 "time" 24 25 "github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/runtime" 26 "github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/runtime/schema" 27 "github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/util/wait" 28 "github.com/stretchr/testify/assert" 29 ) 30 31 type myType struct { 32 ID string 33 Value string 34 } 35 36 func (obj *myType) GetObjectKind() schema.ObjectKind { return schema.EmptyObjectKind } 37 func (obj *myType) DeepCopyObject() runtime.Object { 38 if obj == nil { 39 return nil 40 } 41 clone := *obj 42 return &clone 43 } 44 45 func TestBroadcaster(t *testing.T) { 46 table := []Event{ 47 {Type: Added, Object: &myType{"foo", "hello world 1"}}, 48 {Type: Added, Object: &myType{"bar", "hello world 2"}}, 49 {Type: Modified, Object: &myType{"foo", "goodbye world 3"}}, 50 {Type: Deleted, Object: &myType{"bar", "hello world 4"}}, 51 } 52 53 // The broadcaster we're testing 54 m := NewBroadcaster(0, WaitIfChannelFull) 55 56 // Add a bunch of watchers 57 const testWatchers = 2 58 wg := sync.WaitGroup{} 59 wg.Add(testWatchers) 60 for i := 0; i < testWatchers; i++ { 61 w, err := m.Watch() 62 if err != nil { 63 t.Fatalf("Unable start event watcher: '%v' (will not retry!)", err) 64 } 65 // Verify that each watcher gets the events in the correct order 66 go func(watcher int, w Interface) { 67 tableLine := 0 68 for { 69 event, ok := <-w.ResultChan() 70 if !ok { 71 break 72 } 73 if e, a := table[tableLine], event; !reflect.DeepEqual(e, a) { 74 t.Errorf("Watcher %v, line %v: Expected (%v, %#v), got (%v, %#v)", 75 watcher, tableLine, e.Type, e.Object, a.Type, a.Object) 76 } else { 77 t.Logf("Got (%v, %#v)", event.Type, event.Object) 78 } 79 tableLine++ 80 } 81 wg.Done() 82 }(i, w) 83 } 84 85 for i, item := range table { 86 t.Logf("Sending %v", i) 87 m.Action(item.Type, item.Object) 88 } 89 90 m.Shutdown() 91 92 wg.Wait() 93 } 94 95 func TestBroadcasterWatcherClose(t *testing.T) { 96 m := NewBroadcaster(0, WaitIfChannelFull) 97 w, err := m.Watch() 98 if err != nil { 99 t.Fatalf("Unable start event watcher: '%v' (will not retry!)", err) 100 } 101 w2, err := m.Watch() 102 if err != nil { 103 t.Fatalf("Unable start event watcher: '%v' (will not retry!)", err) 104 } 105 w.Stop() 106 m.Shutdown() 107 if _, open := <-w.ResultChan(); open { 108 t.Errorf("Stop didn't work?") 109 } 110 if _, open := <-w2.ResultChan(); open { 111 t.Errorf("Shutdown didn't work?") 112 } 113 // Extra stops don't hurt things 114 w.Stop() 115 w2.Stop() 116 } 117 118 func TestBroadcasterWatcherStopDeadlock(t *testing.T) { 119 done := make(chan bool) 120 m := NewBroadcaster(0, WaitIfChannelFull) 121 w, err := m.Watch() 122 if err != nil { 123 t.Fatalf("Unable start event watcher: '%v' (will not retry!)", err) 124 } 125 w2, err := m.Watch() 126 if err != nil { 127 t.Fatalf("Unable start event watcher: '%v' (will not retry!)", err) 128 } 129 go func(w0, w1 Interface) { 130 // We know Broadcaster is in the distribute loop once one watcher receives 131 // an event. Stop the other watcher while distribute is trying to 132 // send to it. 133 select { 134 case <-w0.ResultChan(): 135 w1.Stop() 136 case <-w1.ResultChan(): 137 w0.Stop() 138 } 139 close(done) 140 }(w, w2) 141 m.Action(Added, &myType{}) 142 select { 143 case <-time.After(wait.ForeverTestTimeout): 144 t.Error("timeout: deadlocked") 145 case <-done: 146 } 147 m.Shutdown() 148 } 149 150 func TestBroadcasterDropIfChannelFull(t *testing.T) { 151 m := NewBroadcaster(1, DropIfChannelFull) 152 153 event1 := Event{Type: Added, Object: &myType{"foo", "hello world 1"}} 154 event2 := Event{Type: Added, Object: &myType{"bar", "hello world 2"}} 155 156 // Add a couple watchers 157 watches := make([]Interface, 2) 158 var err error 159 for i := range watches { 160 watches[i], err = m.Watch() 161 if err != nil { 162 t.Fatalf("Unable start event watcher: '%v' (will not retry!)", err) 163 } 164 } 165 166 // Send a couple events before closing the broadcast channel. 167 t.Log("Sending event 1") 168 m.Action(event1.Type, event1.Object) 169 t.Log("Sending event 2") 170 m.Action(event2.Type, event2.Object) 171 m.Shutdown() 172 173 // Pull events from the queue. 174 wg := sync.WaitGroup{} 175 wg.Add(len(watches)) 176 for i := range watches { 177 // Verify that each watcher only gets the first event because its watch 178 // queue of length one was full from the first one. 179 go func(watcher int, w Interface) { 180 defer wg.Done() 181 e1, ok := <-w.ResultChan() 182 if !ok { 183 t.Errorf("Watcher %v failed to retrieve first event.", watcher) 184 } 185 if e, a := event1, e1; !reflect.DeepEqual(e, a) { 186 t.Errorf("Watcher %v: Expected (%v, %#v), got (%v, %#v)", 187 watcher, e.Type, e.Object, a.Type, a.Object) 188 } 189 t.Logf("Got (%v, %#v)", e1.Type, e1.Object) 190 e2, ok := <-w.ResultChan() 191 if ok { 192 t.Errorf("Watcher %v received second event (%v, %#v) even though it shouldn't have.", 193 watcher, e2.Type, e2.Object) 194 } 195 }(i, watches[i]) 196 } 197 wg.Wait() 198 } 199 200 func BenchmarkBroadCaster(b *testing.B) { 201 event1 := Event{Type: Added, Object: &myType{"foo", "hello world 1"}} 202 m := NewBroadcaster(0, WaitIfChannelFull) 203 b.ResetTimer() 204 b.RunParallel(func(pb *testing.PB) { 205 for pb.Next() { 206 m.Action(event1.Type, event1.Object) 207 } 208 }) 209 b.StopTimer() 210 } 211 212 func TestBroadcasterWatchAfterShutdown(t *testing.T) { 213 event1 := Event{Type: Added, Object: &myType{"foo", "hello world 1"}} 214 event2 := Event{Type: Added, Object: &myType{"bar", "hello world 2"}} 215 216 m := NewBroadcaster(0, WaitIfChannelFull) 217 m.Shutdown() 218 219 _, err := m.Watch() 220 assert.EqualError(t, err, "broadcaster already stopped", "Watch should report error id broadcaster is shutdown") 221 222 _, err = m.WatchWithPrefix([]Event{event1, event2}) 223 assert.EqualError(t, err, "broadcaster already stopped", "WatchWithPrefix should report error id broadcaster is shutdown") 224 } 225 226 func TestBroadcasterSendEventAfterShutdown(t *testing.T) { 227 m := NewBroadcaster(1, DropIfChannelFull) 228 229 event := Event{Type: Added, Object: &myType{"foo", "hello world"}} 230 231 // Add a couple watchers 232 watches := make([]Interface, 2) 233 for i := range watches { 234 watches[i], _ = m.Watch() 235 } 236 m.Shutdown() 237 238 // Send a couple events after closing the broadcast channel. 239 t.Log("Sending event") 240 241 err := m.Action(event.Type, event.Object) 242 assert.EqualError(t, err, "broadcaster already stopped", "ActionOrDrop should report error id broadcaster is shutdown") 243 244 sendOnClosed, err := m.ActionOrDrop(event.Type, event.Object) 245 assert.Equal(t, sendOnClosed, false, "ActionOrDrop should return false if broadcaster is already shutdown") 246 assert.EqualError(t, err, "broadcaster already stopped", "ActionOrDrop should report error id broadcaster is shutdown") 247 } 248 249 // Test this since we see usage patterns where the broadcaster and watchers are 250 // stopped simultaneously leading to races. 251 func TestBroadcasterShutdownRace(t *testing.T) { 252 m := NewBroadcaster(1, WaitIfChannelFull) 253 stopCh := make(chan struct{}) 254 255 // Add a bunch of watchers 256 const testWatchers = 2 257 for i := 0; i < testWatchers; i++ { 258 i := i 259 260 _, err := m.Watch() 261 if err != nil { 262 t.Fatalf("Unable start event watcher: '%v' (will not retry!)", err) 263 } 264 // This is how we force the watchers to close down independently of the 265 // eventbroadcaster, see real usage pattern in startRecordingEvents() 266 go func() { 267 <-stopCh 268 t.Log("Stopping Watchers") 269 m.stopWatching(int64(i)) 270 }() 271 } 272 273 event := Event{Type: Added, Object: &myType{"foo", "hello world"}} 274 err := m.Action(event.Type, event.Object) 275 if err != nil { 276 t.Fatalf("error sending event: %v", err) 277 } 278 279 // Manually simulate m.Shutdown() but change it to force a race scenario 280 // 1. Close watcher stopchannel, so watchers are closed independently of the 281 // eventBroadcaster 282 // 2. Shutdown the m.incoming slightly Before m.stopped so that the watcher's 283 // call of Blockqueue can pass the m.stopped check. 284 m.blockQueue(func() { 285 close(stopCh) 286 close(m.incoming) 287 time.Sleep(1 * time.Millisecond) 288 close(m.stopped) 289 }) 290 m.distributing.Wait() 291 }