github.com/luckypickle/go-ethereum-vet@v1.14.2/event/event_test.go (about)

     1  // Copyright 2014 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  	"math/rand"
    21  	"sync"
    22  	"testing"
    23  	"time"
    24  )
    25  
    26  type testEvent int
    27  
    28  func TestSubCloseUnsub(t *testing.T) {
    29  	// the point of this test is **not** to panic
    30  	var mux TypeMux
    31  	mux.Stop()
    32  	sub := mux.Subscribe(int(0))
    33  	sub.Unsubscribe()
    34  }
    35  
    36  func TestSub(t *testing.T) {
    37  	mux := new(TypeMux)
    38  	defer mux.Stop()
    39  
    40  	sub := mux.Subscribe(testEvent(0))
    41  	go func() {
    42  		if err := mux.Post(testEvent(5)); err != nil {
    43  			t.Errorf("Post returned unexpected error: %v", err)
    44  		}
    45  	}()
    46  	ev := <-sub.Chan()
    47  
    48  	if ev.Data.(testEvent) != testEvent(5) {
    49  		t.Errorf("Got %v (%T), expected event %v (%T)",
    50  			ev, ev, testEvent(5), testEvent(5))
    51  	}
    52  }
    53  
    54  func TestMuxErrorAfterStop(t *testing.T) {
    55  	mux := new(TypeMux)
    56  	mux.Stop()
    57  
    58  	sub := mux.Subscribe(testEvent(0))
    59  	if _, isopen := <-sub.Chan(); isopen {
    60  		t.Errorf("subscription channel was not closed")
    61  	}
    62  	if err := mux.Post(testEvent(0)); err != ErrMuxClosed {
    63  		t.Errorf("Post error mismatch, got: %s, expected: %s", err, ErrMuxClosed)
    64  	}
    65  }
    66  
    67  func TestUnsubscribeUnblockPost(t *testing.T) {
    68  	mux := new(TypeMux)
    69  	defer mux.Stop()
    70  
    71  	sub := mux.Subscribe(testEvent(0))
    72  	unblocked := make(chan bool)
    73  	go func() {
    74  		mux.Post(testEvent(5))
    75  		unblocked <- true
    76  	}()
    77  
    78  	select {
    79  	case <-unblocked:
    80  		t.Errorf("Post returned before Unsubscribe")
    81  	default:
    82  		sub.Unsubscribe()
    83  		<-unblocked
    84  	}
    85  }
    86  
    87  func TestSubscribeDuplicateType(t *testing.T) {
    88  	mux := new(TypeMux)
    89  	expected := "event: duplicate type event.testEvent in Subscribe"
    90  
    91  	defer func() {
    92  		err := recover()
    93  		if err == nil {
    94  			t.Errorf("Subscribe didn't panic for duplicate type")
    95  		} else if err != expected {
    96  			t.Errorf("panic mismatch: got %#v, expected %#v", err, expected)
    97  		}
    98  	}()
    99  	mux.Subscribe(testEvent(1), testEvent(2))
   100  }
   101  
   102  func TestMuxConcurrent(t *testing.T) {
   103  	rand.Seed(time.Now().Unix())
   104  	mux := new(TypeMux)
   105  	defer mux.Stop()
   106  
   107  	recv := make(chan int)
   108  	poster := func() {
   109  		for {
   110  			err := mux.Post(testEvent(0))
   111  			if err != nil {
   112  				return
   113  			}
   114  		}
   115  	}
   116  	sub := func(i int) {
   117  		time.Sleep(time.Duration(rand.Intn(99)) * time.Millisecond)
   118  		sub := mux.Subscribe(testEvent(0))
   119  		<-sub.Chan()
   120  		sub.Unsubscribe()
   121  		recv <- i
   122  	}
   123  
   124  	go poster()
   125  	go poster()
   126  	go poster()
   127  	nsubs := 1000
   128  	for i := 0; i < nsubs; i++ {
   129  		go sub(i)
   130  	}
   131  
   132  	// wait until everyone has been served
   133  	counts := make(map[int]int, nsubs)
   134  	for i := 0; i < nsubs; i++ {
   135  		counts[<-recv]++
   136  	}
   137  	for i, count := range counts {
   138  		if count != 1 {
   139  			t.Errorf("receiver %d called %d times, expected only 1 call", i, count)
   140  		}
   141  	}
   142  }
   143  
   144  func emptySubscriber(mux *TypeMux, types ...interface{}) {
   145  	s := mux.Subscribe(testEvent(0))
   146  	go func() {
   147  		for range s.Chan() {
   148  		}
   149  	}()
   150  }
   151  
   152  func BenchmarkPost1000(b *testing.B) {
   153  	var (
   154  		mux              = new(TypeMux)
   155  		subscribed, done sync.WaitGroup
   156  		nsubs            = 1000
   157  	)
   158  	subscribed.Add(nsubs)
   159  	done.Add(nsubs)
   160  	for i := 0; i < nsubs; i++ {
   161  		go func() {
   162  			s := mux.Subscribe(testEvent(0))
   163  			subscribed.Done()
   164  			for range s.Chan() {
   165  			}
   166  			done.Done()
   167  		}()
   168  	}
   169  	subscribed.Wait()
   170  
   171  	// The actual benchmark.
   172  	b.ResetTimer()
   173  	for i := 0; i < b.N; i++ {
   174  		mux.Post(testEvent(0))
   175  	}
   176  
   177  	b.StopTimer()
   178  	mux.Stop()
   179  	done.Wait()
   180  }
   181  
   182  func BenchmarkPostConcurrent(b *testing.B) {
   183  	var mux = new(TypeMux)
   184  	defer mux.Stop()
   185  	emptySubscriber(mux, testEvent(0))
   186  	emptySubscriber(mux, testEvent(0))
   187  	emptySubscriber(mux, testEvent(0))
   188  
   189  	var wg sync.WaitGroup
   190  	poster := func() {
   191  		for i := 0; i < b.N; i++ {
   192  			mux.Post(testEvent(0))
   193  		}
   194  		wg.Done()
   195  	}
   196  	wg.Add(5)
   197  	for i := 0; i < 5; i++ {
   198  		go poster()
   199  	}
   200  	wg.Wait()
   201  }
   202  
   203  // for comparison
   204  func BenchmarkChanSend(b *testing.B) {
   205  	c := make(chan interface{})
   206  	closed := make(chan struct{})
   207  	go func() {
   208  		for range c {
   209  		}
   210  	}()
   211  
   212  	for i := 0; i < b.N; i++ {
   213  		select {
   214  		case c <- i:
   215  		case <-closed:
   216  		}
   217  	}
   218  }