github.com/metacubex/mihomo@v1.18.5/common/observable/observable_test.go (about)

     1  package observable
     2  
     3  import (
     4  	"sync"
     5  	"testing"
     6  	"time"
     7  
     8  	"github.com/metacubex/mihomo/common/atomic"
     9  
    10  	"github.com/stretchr/testify/assert"
    11  )
    12  
    13  func iterator[T any](item []T) chan T {
    14  	ch := make(chan T)
    15  	go func() {
    16  		time.Sleep(100 * time.Millisecond)
    17  		for _, elm := range item {
    18  			ch <- elm
    19  		}
    20  		close(ch)
    21  	}()
    22  	return ch
    23  }
    24  
    25  func TestObservable(t *testing.T) {
    26  	iter := iterator[int]([]int{1, 2, 3, 4, 5})
    27  	src := NewObservable[int](iter)
    28  	data, err := src.Subscribe()
    29  	assert.Nil(t, err)
    30  	count := 0
    31  	for range data {
    32  		count++
    33  	}
    34  	assert.Equal(t, count, 5)
    35  }
    36  
    37  func TestObservable_MultiSubscribe(t *testing.T) {
    38  	iter := iterator[int]([]int{1, 2, 3, 4, 5})
    39  	src := NewObservable[int](iter)
    40  	ch1, _ := src.Subscribe()
    41  	ch2, _ := src.Subscribe()
    42  	count := atomic.NewInt32(0)
    43  
    44  	var wg sync.WaitGroup
    45  	wg.Add(2)
    46  	waitCh := func(ch <-chan int) {
    47  		for range ch {
    48  			count.Add(1)
    49  		}
    50  		wg.Done()
    51  	}
    52  	go waitCh(ch1)
    53  	go waitCh(ch2)
    54  	wg.Wait()
    55  	assert.Equal(t, int32(10), count.Load())
    56  }
    57  
    58  func TestObservable_UnSubscribe(t *testing.T) {
    59  	iter := iterator[int]([]int{1, 2, 3, 4, 5})
    60  	src := NewObservable[int](iter)
    61  	data, err := src.Subscribe()
    62  	assert.Nil(t, err)
    63  	src.UnSubscribe(data)
    64  	_, open := <-data
    65  	assert.False(t, open)
    66  }
    67  
    68  func TestObservable_SubscribeClosedSource(t *testing.T) {
    69  	iter := iterator[int]([]int{1})
    70  	src := NewObservable[int](iter)
    71  	data, _ := src.Subscribe()
    72  	<-data
    73  
    74  	_, closed := src.Subscribe()
    75  	assert.NotNil(t, closed)
    76  }
    77  
    78  func TestObservable_UnSubscribeWithNotExistSubscription(t *testing.T) {
    79  	sub := Subscription[int](make(chan int))
    80  	iter := iterator[int]([]int{1})
    81  	src := NewObservable[int](iter)
    82  	src.UnSubscribe(sub)
    83  }
    84  
    85  func TestObservable_SubscribeGoroutineLeak(t *testing.T) {
    86  	iter := iterator[int]([]int{1, 2, 3, 4, 5})
    87  	src := NewObservable[int](iter)
    88  	max := 100
    89  
    90  	var list []Subscription[int]
    91  	for i := 0; i < max; i++ {
    92  		ch, _ := src.Subscribe()
    93  		list = append(list, ch)
    94  	}
    95  
    96  	var wg sync.WaitGroup
    97  	wg.Add(max)
    98  	waitCh := func(ch <-chan int) {
    99  		for range ch {
   100  		}
   101  		wg.Done()
   102  	}
   103  
   104  	for _, ch := range list {
   105  		go waitCh(ch)
   106  	}
   107  	wg.Wait()
   108  
   109  	for _, sub := range list {
   110  		_, more := <-sub
   111  		assert.False(t, more)
   112  	}
   113  
   114  	_, more := <-list[0]
   115  	assert.False(t, more)
   116  }
   117  
   118  func Benchmark_Observable_1000(b *testing.B) {
   119  	ch := make(chan int)
   120  	o := NewObservable[int](ch)
   121  	num := 1000
   122  
   123  	subs := []Subscription[int]{}
   124  	for i := 0; i < num; i++ {
   125  		sub, _ := o.Subscribe()
   126  		subs = append(subs, sub)
   127  	}
   128  
   129  	wg := sync.WaitGroup{}
   130  	wg.Add(num)
   131  
   132  	b.ResetTimer()
   133  	for _, sub := range subs {
   134  		go func(s Subscription[int]) {
   135  			for range s {
   136  			}
   137  			wg.Done()
   138  		}(sub)
   139  	}
   140  
   141  	for i := 0; i < b.N; i++ {
   142  		ch <- i
   143  	}
   144  
   145  	close(ch)
   146  	wg.Wait()
   147  }