github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/x/watch/watch_test.go (about) 1 // Copyright (c) 2016 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 package watch 22 23 import ( 24 "fmt" 25 "math/rand" 26 "sync" 27 "testing" 28 "time" 29 30 "github.com/stretchr/testify/assert" 31 ) 32 33 func TestWatchable(t *testing.T) { 34 p := NewWatchable() 35 assert.Nil(t, p.Get()) 36 assert.Equal(t, 0, p.NumWatches()) 37 assert.NoError(t, p.Update(nil)) 38 assert.False(t, p.IsClosed()) 39 get := 100 40 p = NewWatchable() 41 p.Update(get) 42 assert.Equal(t, get, p.Get()) 43 v, s, err := p.Watch() 44 assert.NotNil(t, s) 45 assert.Equal(t, get, v) 46 assert.NoError(t, err) 47 assert.NoError(t, p.Update(get)) 48 assert.Equal(t, 1, p.NumWatches()) 49 50 p.Close() 51 assert.True(t, p.IsClosed()) 52 assert.Equal(t, 0, p.NumWatches()) 53 assert.Equal(t, get, p.Get()) 54 _, s, err = p.Watch() 55 assert.Nil(t, s) 56 assert.Equal(t, errClosed, err) 57 assert.Equal(t, errClosed, p.Update(get)) 58 assert.NotPanics(t, p.Close) 59 } 60 61 func TestWatch(t *testing.T) { 62 p := NewWatchable() 63 _, s, err := p.Watch() 64 assert.NoError(t, err) 65 66 err = p.Update(nil) 67 assert.NoError(t, err) 68 69 _, ok := <-s.C() 70 assert.True(t, ok) 71 assert.Nil(t, s.Get()) 72 73 assert.Equal(t, 1, p.NumWatches()) 74 s.Close() 75 _, ok = <-s.C() 76 assert.False(t, ok) 77 assert.Equal(t, 0, p.NumWatches()) 78 assert.NotPanics(t, s.Close) 79 80 get := 100 81 p = NewWatchable() 82 _, s, err = p.Watch() 83 assert.NoError(t, err) 84 85 err = p.Update(get) 86 assert.Equal(t, get, p.Get()) 87 assert.NoError(t, err) 88 _, ok = <-s.C() 89 assert.True(t, ok) 90 assert.Equal(t, get, s.Get()) 91 92 // sub.Close() after p.Close() 93 assert.Equal(t, 1, p.NumWatches()) 94 p.Close() 95 assert.Equal(t, 0, p.NumWatches()) 96 s.Close() 97 _, ok = <-s.C() 98 assert.False(t, ok) 99 assert.Equal(t, 0, p.NumWatches()) 100 101 // second watch has initial update 102 p = NewWatchable() 103 _, first, err := p.Watch() 104 assert.NoError(t, err) 105 assert.Equal(t, 0, len(first.C())) 106 107 p.Update(get) 108 <-first.C() 109 assert.Equal(t, get, first.Get()) 110 assert.Equal(t, 0, len(first.C())) 111 112 _, second, err := p.Watch() 113 assert.NoError(t, err) 114 assert.Equal(t, 0, len(first.C())) 115 <-second.C() 116 assert.Equal(t, get, second.Get()) 117 assert.Equal(t, 0, len(second.C())) 118 } 119 120 func TestMultiWatch(t *testing.T) { 121 p := NewWatchable() 122 subLen := 20 123 subMap := make(map[int]Watch, subLen) 124 valueMap := make(map[int]int, subLen) 125 for i := 0; i < subLen; i++ { 126 _, s, err := p.Watch() 127 assert.NoError(t, err) 128 subMap[i] = s 129 valueMap[i] = -1 130 } 131 132 for i := 0; i < subLen; i++ { 133 testWatchAndClose(t, p, subMap, valueMap, i) 134 } 135 136 assert.Equal(t, 0, p.NumWatches()) 137 p.Close() 138 } 139 140 func testWatchAndClose(t *testing.T, p Watchable, subMap map[int]Watch, valueMap map[int]int, value interface{}) { 141 err := p.Update(value) 142 assert.NoError(t, err) 143 144 for i, s := range subMap { 145 _, ok := <-s.C() 146 assert.True(t, ok) 147 v := s.Get().(int) 148 assert.True(t, v > valueMap[i], fmt.Sprintf("Get() value should be > than before: %v, %v", v, valueMap[i])) 149 valueMap[i] = v 150 } 151 152 l := p.NumWatches() 153 assert.Equal(t, len(subMap), l) 154 155 // randomly close 1 subscriber 156 for i, s := range subMap { 157 s.Close() 158 _, ok := <-s.C() 159 assert.False(t, ok) 160 p.Get() 161 delete(subMap, i) 162 delete(valueMap, i) 163 break 164 } 165 assert.Equal(t, l-1, p.NumWatches()) 166 } 167 168 func TestAsyncWatch(t *testing.T) { 169 p := NewWatchable() 170 171 subLen := 10 172 var wg sync.WaitGroup 173 174 for i := 0; i < subLen; i++ { 175 _, s, err := p.Watch() 176 assert.NoError(t, err) 177 178 wg.Add(1) 179 go func() { 180 for range s.C() { 181 r := rand.Int63n(100) 182 time.Sleep(time.Millisecond * time.Duration(r)) 183 } 184 _, ok := <-s.C() 185 // chan got closed 186 assert.False(t, ok) 187 // got the latest value 188 assert.Equal(t, subLen-1, s.Get()) 189 wg.Done() 190 }() 191 } 192 193 for i := 0; i < subLen; i++ { 194 err := p.Update(i) 195 assert.NoError(t, err) 196 } 197 p.Close() 198 assert.Equal(t, 0, p.NumWatches()) 199 wg.Wait() 200 }