github.com/igoogolx/clash@v1.19.8/common/observable/observable_test.go (about)

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