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 }