github.com/klaytn/klaytn@v1.12.1/event/event_test.go (about)

     1  // Modifications Copyright 2018 The klaytn Authors
     2  // Copyright 2014 The go-ethereum Authors
     3  // This file is part of the go-ethereum library.
     4  //
     5  // The go-ethereum library is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU Lesser General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // The go-ethereum library is distributed in the hope that it will be useful,
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    13  // GNU Lesser General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Lesser General Public License
    16  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    17  //
    18  // This file is derived from event/event_test.go (2018/06/04).
    19  // Modified and improved for the klaytn development.
    20  
    21  package event
    22  
    23  import (
    24  	"math/rand"
    25  	"sync"
    26  	"testing"
    27  	"time"
    28  )
    29  
    30  type testEvent int
    31  
    32  func TestSubCloseUnsub(t *testing.T) {
    33  	// the point of this test is **not** to panic
    34  	var mux TypeMux
    35  	mux.Stop()
    36  	sub := mux.Subscribe(int(0))
    37  	sub.Unsubscribe()
    38  }
    39  
    40  func TestSub(t *testing.T) {
    41  	mux := new(TypeMux)
    42  	defer mux.Stop()
    43  
    44  	sub := mux.Subscribe(testEvent(0))
    45  	go func() {
    46  		if err := mux.Post(testEvent(5)); err != nil {
    47  			t.Errorf("Post returned unexpected error: %v", err)
    48  		}
    49  	}()
    50  	ev := <-sub.Chan()
    51  
    52  	if ev.Data.(testEvent) != testEvent(5) {
    53  		t.Errorf("Got %v (%T), expected event %v (%T)",
    54  			ev, ev, testEvent(5), testEvent(5))
    55  	}
    56  }
    57  
    58  func TestMuxErrorAfterStop(t *testing.T) {
    59  	mux := new(TypeMux)
    60  	mux.Stop()
    61  
    62  	sub := mux.Subscribe(testEvent(0))
    63  	if _, isopen := <-sub.Chan(); isopen {
    64  		t.Errorf("subscription channel was not closed")
    65  	}
    66  	if err := mux.Post(testEvent(0)); err != ErrMuxClosed {
    67  		t.Errorf("Post error mismatch, got: %s, expected: %s", err, ErrMuxClosed)
    68  	}
    69  }
    70  
    71  func TestUnsubscribeUnblockPost(t *testing.T) {
    72  	mux := new(TypeMux)
    73  	defer mux.Stop()
    74  
    75  	sub := mux.Subscribe(testEvent(0))
    76  	unblocked := make(chan bool)
    77  	go func() {
    78  		mux.Post(testEvent(5))
    79  		unblocked <- true
    80  	}()
    81  
    82  	select {
    83  	case <-unblocked:
    84  		t.Errorf("Post returned before Unsubscribe")
    85  	default:
    86  		sub.Unsubscribe()
    87  		<-unblocked
    88  	}
    89  }
    90  
    91  func TestSubscribeDuplicateType(t *testing.T) {
    92  	mux := new(TypeMux)
    93  	expected := "event: duplicate type event.testEvent in Subscribe"
    94  
    95  	defer func() {
    96  		err := recover()
    97  		if err == nil {
    98  			t.Errorf("Subscribe didn't panic for duplicate type")
    99  		} else if err != expected {
   100  			t.Errorf("panic mismatch: ɡot %#v, expected %#v", err, expected)
   101  		}
   102  	}()
   103  	mux.Subscribe(testEvent(1), testEvent(2))
   104  }
   105  
   106  func TestMuxConcurrent(t *testing.T) {
   107  	rand.Seed(time.Now().Unix())
   108  	mux := new(TypeMux)
   109  	defer mux.Stop()
   110  
   111  	recv := make(chan int)
   112  	poster := func() {
   113  		for {
   114  			err := mux.Post(testEvent(0))
   115  			if err != nil {
   116  				return
   117  			}
   118  		}
   119  	}
   120  	sub := func(i int) {
   121  		time.Sleep(time.Duration(rand.Intn(99)) * time.Millisecond)
   122  		sub := mux.Subscribe(testEvent(0))
   123  		<-sub.Chan()
   124  		sub.Unsubscribe()
   125  		recv <- i
   126  	}
   127  
   128  	go poster()
   129  	go poster()
   130  	go poster()
   131  	nsubs := 1000
   132  	for i := 0; i < nsubs; i++ {
   133  		go sub(i)
   134  	}
   135  
   136  	// wait until everyone has been served
   137  	counts := make(map[int]int, nsubs)
   138  	for i := 0; i < nsubs; i++ {
   139  		counts[<-recv]++
   140  	}
   141  	for i, count := range counts {
   142  		if count != 1 {
   143  			t.Errorf("receiver %d called %d times, expected only 1 call", i, count)
   144  		}
   145  	}
   146  }
   147  
   148  func emptySubscriber(mux *TypeMux) {
   149  	s := mux.Subscribe(testEvent(0))
   150  	go func() {
   151  		for range s.Chan() {
   152  		}
   153  	}()
   154  }
   155  
   156  func BenchmarkPost1000(b *testing.B) {
   157  	var (
   158  		mux              = new(TypeMux)
   159  		subscribed, done sync.WaitGroup
   160  		nsubs            = 1000
   161  	)
   162  	subscribed.Add(nsubs)
   163  	done.Add(nsubs)
   164  	for i := 0; i < nsubs; i++ {
   165  		go func() {
   166  			s := mux.Subscribe(testEvent(0))
   167  			subscribed.Done()
   168  			for range s.Chan() {
   169  			}
   170  			done.Done()
   171  		}()
   172  	}
   173  	subscribed.Wait()
   174  
   175  	// The actual benchmark.
   176  	b.ResetTimer()
   177  	for i := 0; i < b.N; i++ {
   178  		mux.Post(testEvent(0))
   179  	}
   180  
   181  	b.StopTimer()
   182  	mux.Stop()
   183  	done.Wait()
   184  }
   185  
   186  func BenchmarkPostConcurrent(b *testing.B) {
   187  	mux := new(TypeMux)
   188  	defer mux.Stop()
   189  	emptySubscriber(mux)
   190  	emptySubscriber(mux)
   191  	emptySubscriber(mux)
   192  
   193  	var wg sync.WaitGroup
   194  	poster := func() {
   195  		for i := 0; i < b.N; i++ {
   196  			mux.Post(testEvent(0))
   197  		}
   198  		wg.Done()
   199  	}
   200  	wg.Add(5)
   201  	for i := 0; i < 5; i++ {
   202  		go poster()
   203  	}
   204  	wg.Wait()
   205  }
   206  
   207  // for comparison
   208  func BenchmarkChanSend(b *testing.B) {
   209  	c := make(chan interface{})
   210  	closed := make(chan struct{})
   211  	go func() {
   212  		for range c {
   213  		}
   214  	}()
   215  
   216  	for i := 0; i < b.N; i++ {
   217  		select {
   218  		case c <- i:
   219  		case <-closed:
   220  		}
   221  	}
   222  }