github.com/theQRL/go-zond@v0.1.1/event/feed_test.go (about)

     1  // Copyright 2016 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package event
    18  
    19  import (
    20  	"errors"
    21  	"fmt"
    22  	"reflect"
    23  	"sync"
    24  	"testing"
    25  	"time"
    26  )
    27  
    28  func TestFeedPanics(t *testing.T) {
    29  	{
    30  		var f Feed
    31  		f.Send(2)
    32  		want := feedTypeError{op: "Send", got: reflect.TypeOf(uint64(0)), want: reflect.TypeOf(0)}
    33  		if err := checkPanic(want, func() { f.Send(uint64(2)) }); err != nil {
    34  			t.Error(err)
    35  		}
    36  	}
    37  	{
    38  		var f Feed
    39  		ch := make(chan int)
    40  		f.Subscribe(ch)
    41  		want := feedTypeError{op: "Send", got: reflect.TypeOf(uint64(0)), want: reflect.TypeOf(0)}
    42  		if err := checkPanic(want, func() { f.Send(uint64(2)) }); err != nil {
    43  			t.Error(err)
    44  		}
    45  	}
    46  	{
    47  		var f Feed
    48  		f.Send(2)
    49  		want := feedTypeError{op: "Subscribe", got: reflect.TypeOf(make(chan uint64)), want: reflect.TypeOf(make(chan<- int))}
    50  		if err := checkPanic(want, func() { f.Subscribe(make(chan uint64)) }); err != nil {
    51  			t.Error(err)
    52  		}
    53  	}
    54  	{
    55  		var f Feed
    56  		if err := checkPanic(errBadChannel, func() { f.Subscribe(make(<-chan int)) }); err != nil {
    57  			t.Error(err)
    58  		}
    59  	}
    60  	{
    61  		var f Feed
    62  		if err := checkPanic(errBadChannel, func() { f.Subscribe(0) }); err != nil {
    63  			t.Error(err)
    64  		}
    65  	}
    66  }
    67  
    68  func checkPanic(want error, fn func()) (err error) {
    69  	defer func() {
    70  		panic := recover()
    71  		if panic == nil {
    72  			err = errors.New("didn't panic")
    73  		} else if !reflect.DeepEqual(panic, want) {
    74  			err = fmt.Errorf("panicked with wrong error: got %q, want %q", panic, want)
    75  		}
    76  	}()
    77  	fn()
    78  	return nil
    79  }
    80  
    81  func TestFeed(t *testing.T) {
    82  	var feed Feed
    83  	var done, subscribed sync.WaitGroup
    84  	subscriber := func(i int) {
    85  		defer done.Done()
    86  
    87  		subchan := make(chan int)
    88  		sub := feed.Subscribe(subchan)
    89  		timeout := time.NewTimer(2 * time.Second)
    90  		defer timeout.Stop()
    91  		subscribed.Done()
    92  
    93  		select {
    94  		case v := <-subchan:
    95  			if v != 1 {
    96  				t.Errorf("%d: received value %d, want 1", i, v)
    97  			}
    98  		case <-timeout.C:
    99  			t.Errorf("%d: receive timeout", i)
   100  		}
   101  
   102  		sub.Unsubscribe()
   103  		select {
   104  		case _, ok := <-sub.Err():
   105  			if ok {
   106  				t.Errorf("%d: error channel not closed after unsubscribe", i)
   107  			}
   108  		case <-timeout.C:
   109  			t.Errorf("%d: unsubscribe timeout", i)
   110  		}
   111  	}
   112  
   113  	const n = 1000
   114  	done.Add(n)
   115  	subscribed.Add(n)
   116  	for i := 0; i < n; i++ {
   117  		go subscriber(i)
   118  	}
   119  	subscribed.Wait()
   120  	if nsent := feed.Send(1); nsent != n {
   121  		t.Errorf("first send delivered %d times, want %d", nsent, n)
   122  	}
   123  	if nsent := feed.Send(2); nsent != 0 {
   124  		t.Errorf("second send delivered %d times, want 0", nsent)
   125  	}
   126  	done.Wait()
   127  }
   128  
   129  func TestFeedSubscribeSameChannel(t *testing.T) {
   130  	var (
   131  		feed Feed
   132  		done sync.WaitGroup
   133  		ch   = make(chan int)
   134  		sub1 = feed.Subscribe(ch)
   135  		sub2 = feed.Subscribe(ch)
   136  		_    = feed.Subscribe(ch)
   137  	)
   138  	expectSends := func(value, n int) {
   139  		if nsent := feed.Send(value); nsent != n {
   140  			t.Errorf("send delivered %d times, want %d", nsent, n)
   141  		}
   142  		done.Done()
   143  	}
   144  	expectRecv := func(wantValue, n int) {
   145  		for i := 0; i < n; i++ {
   146  			if v := <-ch; v != wantValue {
   147  				t.Errorf("received %d, want %d", v, wantValue)
   148  			}
   149  		}
   150  	}
   151  
   152  	done.Add(1)
   153  	go expectSends(1, 3)
   154  	expectRecv(1, 3)
   155  	done.Wait()
   156  
   157  	sub1.Unsubscribe()
   158  
   159  	done.Add(1)
   160  	go expectSends(2, 2)
   161  	expectRecv(2, 2)
   162  	done.Wait()
   163  
   164  	sub2.Unsubscribe()
   165  
   166  	done.Add(1)
   167  	go expectSends(3, 1)
   168  	expectRecv(3, 1)
   169  	done.Wait()
   170  }
   171  
   172  func TestFeedSubscribeBlockedPost(t *testing.T) {
   173  	var (
   174  		feed   Feed
   175  		nsends = 2000
   176  		ch1    = make(chan int)
   177  		ch2    = make(chan int)
   178  		wg     sync.WaitGroup
   179  	)
   180  	defer wg.Wait()
   181  
   182  	feed.Subscribe(ch1)
   183  	wg.Add(nsends)
   184  	for i := 0; i < nsends; i++ {
   185  		go func() {
   186  			feed.Send(99)
   187  			wg.Done()
   188  		}()
   189  	}
   190  
   191  	sub2 := feed.Subscribe(ch2)
   192  	defer sub2.Unsubscribe()
   193  
   194  	// We're done when ch1 has received N times.
   195  	// The number of receives on ch2 depends on scheduling.
   196  	for i := 0; i < nsends; {
   197  		select {
   198  		case <-ch1:
   199  			i++
   200  		case <-ch2:
   201  		}
   202  	}
   203  }
   204  
   205  func TestFeedUnsubscribeBlockedPost(t *testing.T) {
   206  	var (
   207  		feed   Feed
   208  		nsends = 200
   209  		chans  = make([]chan int, 2000)
   210  		subs   = make([]Subscription, len(chans))
   211  		bchan  = make(chan int)
   212  		bsub   = feed.Subscribe(bchan)
   213  		wg     sync.WaitGroup
   214  	)
   215  	for i := range chans {
   216  		chans[i] = make(chan int, nsends)
   217  	}
   218  
   219  	// Queue up some Sends. None of these can make progress while bchan isn't read.
   220  	wg.Add(nsends)
   221  	for i := 0; i < nsends; i++ {
   222  		go func() {
   223  			feed.Send(99)
   224  			wg.Done()
   225  		}()
   226  	}
   227  	// Subscribe the other channels.
   228  	for i, ch := range chans {
   229  		subs[i] = feed.Subscribe(ch)
   230  	}
   231  	// Unsubscribe them again.
   232  	for _, sub := range subs {
   233  		sub.Unsubscribe()
   234  	}
   235  	// Unblock the Sends.
   236  	bsub.Unsubscribe()
   237  	wg.Wait()
   238  }
   239  
   240  // Checks that unsubscribing a channel during Send works even if that
   241  // channel has already been sent on.
   242  func TestFeedUnsubscribeSentChan(t *testing.T) {
   243  	var (
   244  		feed Feed
   245  		ch1  = make(chan int)
   246  		ch2  = make(chan int)
   247  		sub1 = feed.Subscribe(ch1)
   248  		sub2 = feed.Subscribe(ch2)
   249  		wg   sync.WaitGroup
   250  	)
   251  	defer sub2.Unsubscribe()
   252  
   253  	wg.Add(1)
   254  	go func() {
   255  		feed.Send(0)
   256  		wg.Done()
   257  	}()
   258  
   259  	// Wait for the value on ch1.
   260  	<-ch1
   261  	// Unsubscribe ch1, removing it from the send cases.
   262  	sub1.Unsubscribe()
   263  
   264  	// Receive ch2, finishing Send.
   265  	<-ch2
   266  	wg.Wait()
   267  
   268  	// Send again. This should send to ch2 only, so the wait group will unblock
   269  	// as soon as a value is received on ch2.
   270  	wg.Add(1)
   271  	go func() {
   272  		feed.Send(0)
   273  		wg.Done()
   274  	}()
   275  	<-ch2
   276  	wg.Wait()
   277  }
   278  
   279  func TestFeedUnsubscribeFromInbox(t *testing.T) {
   280  	var (
   281  		feed Feed
   282  		ch1  = make(chan int)
   283  		ch2  = make(chan int)
   284  		sub1 = feed.Subscribe(ch1)
   285  		sub2 = feed.Subscribe(ch1)
   286  		sub3 = feed.Subscribe(ch2)
   287  	)
   288  	if len(feed.inbox) != 3 {
   289  		t.Errorf("inbox length != 3 after subscribe")
   290  	}
   291  	if len(feed.sendCases) != 1 {
   292  		t.Errorf("sendCases is non-empty after unsubscribe")
   293  	}
   294  
   295  	sub1.Unsubscribe()
   296  	sub2.Unsubscribe()
   297  	sub3.Unsubscribe()
   298  	if len(feed.inbox) != 0 {
   299  		t.Errorf("inbox is non-empty after unsubscribe")
   300  	}
   301  	if len(feed.sendCases) != 1 {
   302  		t.Errorf("sendCases is non-empty after unsubscribe")
   303  	}
   304  }
   305  
   306  func BenchmarkFeedSend1000(b *testing.B) {
   307  	var (
   308  		done  sync.WaitGroup
   309  		feed  Feed
   310  		nsubs = 1000
   311  	)
   312  	subscriber := func(ch <-chan int) {
   313  		for i := 0; i < b.N; i++ {
   314  			<-ch
   315  		}
   316  		done.Done()
   317  	}
   318  	done.Add(nsubs)
   319  	for i := 0; i < nsubs; i++ {
   320  		ch := make(chan int, 200)
   321  		feed.Subscribe(ch)
   322  		go subscriber(ch)
   323  	}
   324  
   325  	// The actual benchmark.
   326  	b.ResetTimer()
   327  	for i := 0; i < b.N; i++ {
   328  		if feed.Send(i) != nsubs {
   329  			panic("wrong number of sends")
   330  		}
   331  	}
   332  
   333  	b.StopTimer()
   334  	done.Wait()
   335  }