github.com/theQRL/go-zond@v0.1.1/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(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  	mux := new(TypeMux)
   104  	defer mux.Stop()
   105  
   106  	recv := make(chan int)
   107  	poster := func() {
   108  		for {
   109  			err := mux.Post(testEvent(0))
   110  			if err != nil {
   111  				return
   112  			}
   113  		}
   114  	}
   115  	sub := func(i int) {
   116  		time.Sleep(time.Duration(rand.Intn(99)) * time.Millisecond)
   117  		sub := mux.Subscribe(testEvent(0))
   118  		<-sub.Chan()
   119  		sub.Unsubscribe()
   120  		recv <- i
   121  	}
   122  
   123  	go poster()
   124  	go poster()
   125  	go poster()
   126  	nsubs := 1000
   127  	for i := 0; i < nsubs; i++ {
   128  		go sub(i)
   129  	}
   130  
   131  	// wait until everyone has been served
   132  	counts := make(map[int]int, nsubs)
   133  	for i := 0; i < nsubs; i++ {
   134  		counts[<-recv]++
   135  	}
   136  	for i, count := range counts {
   137  		if count != 1 {
   138  			t.Errorf("receiver %d called %d times, expected only 1 call", i, count)
   139  		}
   140  	}
   141  }
   142  
   143  func emptySubscriber(mux *TypeMux) {
   144  	s := mux.Subscribe(testEvent(0))
   145  	go func() {
   146  		for range s.Chan() {
   147  		}
   148  	}()
   149  }
   150  
   151  func BenchmarkPost1000(b *testing.B) {
   152  	var (
   153  		mux              = new(TypeMux)
   154  		subscribed, done sync.WaitGroup
   155  		nsubs            = 1000
   156  	)
   157  	subscribed.Add(nsubs)
   158  	done.Add(nsubs)
   159  	for i := 0; i < nsubs; i++ {
   160  		go func() {
   161  			s := mux.Subscribe(testEvent(0))
   162  			subscribed.Done()
   163  			for range s.Chan() {
   164  			}
   165  			done.Done()
   166  		}()
   167  	}
   168  	subscribed.Wait()
   169  
   170  	// The actual benchmark.
   171  	b.ResetTimer()
   172  	for i := 0; i < b.N; i++ {
   173  		mux.Post(testEvent(0))
   174  	}
   175  
   176  	b.StopTimer()
   177  	mux.Stop()
   178  	done.Wait()
   179  }
   180  
   181  func BenchmarkPostConcurrent(b *testing.B) {
   182  	var mux = new(TypeMux)
   183  	defer mux.Stop()
   184  	emptySubscriber(mux)
   185  	emptySubscriber(mux)
   186  	emptySubscriber(mux)
   187  
   188  	var wg sync.WaitGroup
   189  	poster := func() {
   190  		for i := 0; i < b.N; i++ {
   191  			mux.Post(testEvent(0))
   192  		}
   193  		wg.Done()
   194  	}
   195  	wg.Add(5)
   196  	for i := 0; i < 5; i++ {
   197  		go poster()
   198  	}
   199  	wg.Wait()
   200  }
   201  
   202  // for comparison
   203  func BenchmarkChanSend(b *testing.B) {
   204  	c := make(chan interface{})
   205  	defer close(c)
   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  }