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 }