github.com/JBoudou/Itero@v0.1.7/pkg/events/mux_test.go (about)

     1  // Itero - Online iterative vote application
     2  // Copyright (C) 2020 Joseph Boudou
     3  //
     4  // This program is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Affero General Public License as
     6  // published by the Free Software Foundation, either version 3 of the
     7  // License, or (at your option) any later version.
     8  //
     9  // This program 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 Affero General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Affero General Public License
    15  // along with this program.  If not, see <https://www.gnu.org/licenses/>.
    16  
    17  package events
    18  
    19  import (
    20  	"sync"
    21  	"testing"
    22  )
    23  
    24  type muxTestReceiver struct {
    25  	id  int
    26  	ch  chan<- [2]int
    27  	t   *testing.T
    28  	grp *sync.WaitGroup
    29  }
    30  
    31  func (self *muxTestReceiver) Receive(evt Event) {
    32  	i, ok := evt.(int)
    33  	if !ok {
    34  		self.t.Logf("Unknown event %v.", evt)
    35  		return
    36  	}
    37  	self.ch <- [2]int{self.id, i}
    38  }
    39  
    40  func (self *muxTestReceiver) Close() {
    41  	self.grp.Done()
    42  }
    43  
    44  type muxTestChecker struct {
    45  	missing  map[[2]int]bool
    46  	unwanted [][2]int
    47  	grp *sync.WaitGroup
    48  }
    49  
    50  func (self *muxTestChecker) Listen(ch <-chan [2]int) {
    51  	for result := range ch {
    52  		if _, found := self.missing[result]; found {
    53  			delete(self.missing, result)
    54  		} else {
    55  			self.unwanted = append(self.unwanted, result)
    56  		}
    57  	}
    58  	self.grp.Done()
    59  }
    60  
    61  func TestMux(t *testing.T) {
    62  	const chanSize = 128
    63  
    64  	tests := []struct {
    65  		name      string
    66  		receivers []int
    67  		events    []int
    68  		expect    [][2]int
    69  	}{
    70  		{
    71  			name:   "No receiver",
    72  			events: []int{27},
    73  		},
    74  		{
    75  			name:      "One receiver",
    76  			receivers: []int{1},
    77  			events:    []int{2, 3},
    78  			expect:    [][2]int{{1, 2}, {1, 3}},
    79  		},
    80  		{
    81  			name:      "Two receiver",
    82  			receivers: []int{1, 2},
    83  			events:    []int{2, 3},
    84  			expect:    [][2]int{{1, 2}, {1, 3}, {2, 2}, {2, 3}},
    85  		},
    86  	}
    87  	for _, tt := range tests {
    88  		t.Run(tt.name, func(t *testing.T) {
    89  			var grp sync.WaitGroup
    90  			grp.Add(len(tt.receivers))
    91  
    92  			checker := &muxTestChecker{missing: make(map[[2]int]bool, len(tt.expect)), grp: &grp}
    93  			for _, result := range tt.expect {
    94  				checker.missing[result] = true
    95  			}
    96  			resultCh := make(chan [2]int, 0)
    97  			go checker.Listen(resultCh)
    98  
    99  			manager := NewAsyncManager(chanSize)
   100  			for _, id := range tt.receivers {
   101  				manager.AddReceiver(&muxTestReceiver{id: id, ch: resultCh, t: t, grp: &grp})
   102  			}
   103  
   104  			for _, event := range tt.events {
   105  				manager.Send(event)
   106  			}
   107  			manager.Close()
   108  			grp.Wait()
   109  			grp.Add(1)
   110  			close(resultCh)
   111  			grp.Wait()
   112  
   113  			for result := range checker.missing {
   114  				t.Errorf("Missing %v.", result)
   115  			}
   116  			for result := range checker.unwanted {
   117  				t.Errorf("Unexpected %v.", result)
   118  			}
   119  		})
   120  	}
   121  }