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  }