github.com/git-amp/amp-sdk-go@v0.7.5/stdlib/utils/channels_test.go (about) 1 package utils_test 2 3 import ( 4 "context" 5 "testing" 6 "time" 7 8 "github.com/git-amp/amp-sdk-go/stdlib/utils" 9 ) 10 11 func TestWaitGroupChan(t *testing.T) { 12 t.Parallel() 13 14 t.Run("with no context cancellation, releases only after sufficiently many calls to Done()", func(t *testing.T) { 15 t.Parallel() 16 17 wg := utils.NewWaitGroupChan(context.Background()) 18 defer wg.Close() 19 20 wg.Add(5) 21 22 select { 23 case <-wg.Wait(): 24 t.Fatal("ended too soon") 25 case <-time.After(1 * time.Second): 26 } 27 28 wg.Done() 29 30 select { 31 case <-wg.Wait(): 32 t.Fatal("ended too soon") 33 case <-time.After(1 * time.Second): 34 } 35 36 wg.Done() 37 38 select { 39 case <-wg.Wait(): 40 t.Fatal("ended too soon") 41 case <-time.After(1 * time.Second): 42 } 43 44 wg.Done() 45 46 select { 47 case <-wg.Wait(): 48 t.Fatal("ended too soon") 49 case <-time.After(1 * time.Second): 50 } 51 52 wg.Done() 53 54 select { 55 case <-wg.Wait(): 56 t.Fatal("ended too soon") 57 case <-time.After(1 * time.Second): 58 } 59 60 wg.Done() 61 62 select { 63 case <-wg.Wait(): 64 case <-time.After(1 * time.Second): 65 t.Fatal("did not end") 66 } 67 }) 68 69 t.Run("releases after the context expires, even if Done() has not been called enough", func(t *testing.T) { 70 t.Parallel() 71 72 ctx, cancel := context.WithCancel(context.Background()) 73 defer cancel() 74 75 wg := utils.NewWaitGroupChan(ctx) 76 defer wg.Close() 77 78 wg.Add(5) 79 80 select { 81 case <-wg.Wait(): 82 t.Fatal("ended too soon") 83 case <-time.After(1 * time.Second): 84 } 85 86 wg.Done() 87 88 select { 89 case <-wg.Wait(): 90 t.Fatal("ended too soon") 91 case <-time.After(1 * time.Second): 92 } 93 94 cancel() 95 96 select { 97 case <-wg.Wait(): 98 case <-time.After(1 * time.Second): 99 t.Fatal("did not end") 100 } 101 }) 102 } 103 104 func TestCombinedContext(t *testing.T) { 105 t.Parallel() 106 107 t.Run("cancels when an inner context is canceled", func(t *testing.T) { 108 t.Parallel() 109 110 innerCtx, innerCancel := context.WithCancel(context.Background()) 111 defer innerCancel() 112 113 chStop := make(chan struct{}) 114 115 ctx, cancel := utils.CombinedContext(innerCtx, chStop, 1*time.Hour) 116 defer cancel() 117 118 innerCancel() 119 120 select { 121 case <-ctx.Done(): 122 case <-time.After(5 * time.Second): 123 t.Fatal("context didn't cancel") 124 } 125 }) 126 127 t.Run("cancels when a channel is closed", func(t *testing.T) { 128 t.Parallel() 129 130 innerCtx, innerCancel := context.WithCancel(context.Background()) 131 defer innerCancel() 132 133 chStop := make(chan struct{}) 134 135 ctx, cancel := utils.CombinedContext(innerCtx, chStop, 1*time.Hour) 136 defer cancel() 137 138 close(chStop) 139 140 select { 141 case <-ctx.Done(): 142 case <-time.After(5 * time.Second): 143 t.Fatal("context didn't cancel") 144 } 145 }) 146 147 t.Run("cancels when a duration elapses", func(t *testing.T) { 148 t.Parallel() 149 150 innerCtx, innerCancel := context.WithCancel(context.Background()) 151 defer innerCancel() 152 153 chStop := make(chan struct{}) 154 155 ctx, cancel := utils.CombinedContext(innerCtx, chStop, 1*time.Second) 156 defer cancel() 157 158 select { 159 case <-ctx.Done(): 160 case <-time.After(5 * time.Second): 161 t.Fatal("context didn't cancel") 162 } 163 }) 164 165 t.Run("doesn't cancel if none of its children cancel", func(t *testing.T) { 166 t.Parallel() 167 168 innerCtx, innerCancel := context.WithCancel(context.Background()) 169 defer innerCancel() 170 171 chStop := make(chan struct{}) 172 173 ctx, cancel := utils.CombinedContext(innerCtx, chStop, 1*time.Hour) 174 defer cancel() 175 176 select { 177 case <-ctx.Done(): 178 t.Fatal("context canceled") 179 case <-time.After(5 * time.Second): 180 } 181 }) 182 } 183 184 func TestChanContext(t *testing.T) { 185 ctx := utils.ChanContext(make(chan struct{})) 186 187 go func() { 188 time.Sleep(1 * time.Second) 189 close(ctx) 190 }() 191 192 select { 193 case <-time.After(5 * time.Second): 194 t.Fatal("fail") 195 case <-ctx.Done(): 196 } 197 198 ctx = utils.ChanContext(make(chan struct{})) 199 ctx2, _ := context.WithTimeout(ctx, 1*time.Second) 200 201 select { 202 case <-time.After(5 * time.Second): 203 t.Fatal("fail") 204 case <-ctx2.Done(): 205 } 206 207 ctx = utils.ChanContext(make(chan struct{})) 208 ctx2, cancel := context.WithTimeout(ctx, 3*time.Second) 209 210 go func() { 211 time.Sleep(1 * time.Second) 212 cancel() 213 }() 214 215 select { 216 case <-time.After(5 * time.Second): 217 t.Fatal("fail") 218 case <-ctx2.Done(): 219 } 220 }