github.com/fholzer/ordered-concurrently/v3@v3.0.0-20221001131746-406a6eece748/main_test.go (about) 1 package orderedconcurrently 2 3 import ( 4 "context" 5 "math/rand" 6 "sort" 7 "sync" 8 "testing" 9 "time" 10 ) 11 12 type zeroLoadWorker int 13 14 func zeroLoadWorkerRun(w interface{}) interface{} { 15 return w.(zeroLoadWorker) * 2 16 } 17 18 type loadWorker int 19 20 func loadWorkerRun(w interface{}) interface{} { 21 time.Sleep(time.Millisecond * time.Duration(rand.Intn(100))) 22 return w.(loadWorker) * 2 23 } 24 25 func processGeneratorGenerator(wf ProcessFunc) processFuncGenerator { 26 return func(int) (ProcessFunc, error) { 27 return wf, nil 28 } 29 } 30 31 func Test1(t *testing.T) { 32 t.Run("Test with Preset Pool Size", func(t *testing.T) { 33 ctx := context.Background() 34 max := 10 35 inputChan := make(chan interface{}) 36 wg := &sync.WaitGroup{} 37 38 outChan, err := Process(ctx, inputChan, processGeneratorGenerator(loadWorkerRun), &Options{PoolSize: 10}) 39 if err != nil { 40 panic(err) 41 } 42 counter := 0 43 go func(t *testing.T) { 44 for out := range outChan { 45 if _, ok := out.Value.(loadWorker); !ok { 46 t.Error("Invalid output") 47 } else { 48 counter++ 49 } 50 wg.Done() 51 } 52 }(t) 53 54 // Create work and the associated order 55 for work := 0; work < max; work++ { 56 wg.Add(1) 57 inputChan <- loadWorker(work) 58 } 59 close(inputChan) 60 wg.Wait() 61 if counter != max { 62 t.Error("Input count does not match output count") 63 } 64 t.Log("Test with Preset Pool Size Completed") 65 }) 66 } 67 68 func Test2(t *testing.T) { 69 t.Run("Test with default Pool Size", func(t *testing.T) { 70 ctx := context.Background() 71 72 max := 10 73 inputChan := make(chan interface{}) 74 wg := &sync.WaitGroup{} 75 76 outChan, err := Process(ctx, inputChan, processGeneratorGenerator(loadWorkerRun), &Options{OutChannelBuffer: 2}) 77 if err != nil { 78 panic(err) 79 } 80 counter := 0 81 go func(t *testing.T) { 82 for out := range outChan { 83 if _, ok := out.Value.(loadWorker); !ok { 84 t.Error("Invalid output") 85 } else { 86 counter++ 87 } 88 wg.Done() 89 } 90 }(t) 91 92 // Create work and the associated order 93 for work := 0; work < max; work++ { 94 wg.Add(1) 95 inputChan <- loadWorker(work) 96 } 97 close(inputChan) 98 wg.Wait() 99 if counter != max { 100 t.Error("Input count does not match output count") 101 } 102 t.Log("Test with Default Pool Size Completed") 103 }) 104 } 105 106 func Test3(t *testing.T) { 107 t.Run("Test Zero Load", func(t *testing.T) { 108 ctx := context.Background() 109 110 max := 10 111 inputChan := make(chan interface{}) 112 wg := &sync.WaitGroup{} 113 114 outChan, err := Process(ctx, inputChan, processGeneratorGenerator(zeroLoadWorkerRun), &Options{OutChannelBuffer: 2}) 115 if err != nil { 116 panic(err) 117 } 118 counter := 0 119 go func(t *testing.T) { 120 for out := range outChan { 121 if _, ok := out.Value.(zeroLoadWorker); !ok { 122 t.Error("Invalid output") 123 } else { 124 counter++ 125 } 126 wg.Done() 127 } 128 }(t) 129 130 // Create work and the associated order 131 for work := 0; work < max; work++ { 132 wg.Add(1) 133 inputChan <- zeroLoadWorker(work) 134 } 135 close(inputChan) 136 wg.Wait() 137 if counter != max { 138 t.Error("Input count does not match output count") 139 } 140 t.Log("Test with Default Pool Size and Zero Load Completed") 141 }) 142 143 } 144 145 func Test4(t *testing.T) { 146 t.Run("Test without workgroup", func(t *testing.T) { 147 ctx := context.Background() 148 149 max := 10 150 inputChan := make(chan interface{}) 151 output, err := Process(ctx, inputChan, processGeneratorGenerator(zeroLoadWorkerRun), &Options{PoolSize: 10, OutChannelBuffer: 10}) 152 if err != nil { 153 panic(err) 154 } 155 go func() { 156 for work := 0; work < max; work++ { 157 inputChan <- zeroLoadWorker(work) 158 } 159 close(inputChan) 160 }() 161 counter := 0 162 for out := range output { 163 if _, ok := out.Value.(zeroLoadWorker); !ok { 164 t.Error("Invalid output") 165 } else { 166 counter++ 167 } 168 } 169 if counter != max { 170 t.Error("Input count does not match output count") 171 } 172 t.Log("Test without workgroup Completed") 173 }) 174 } 175 176 func TestSortedData(t *testing.T) { 177 t.Run("Test if response is sorted", func(t *testing.T) { 178 ctx := context.Background() 179 180 max := 10 181 inputChan := make(chan interface{}) 182 output, err := Process(ctx, inputChan, processGeneratorGenerator(loadWorkerRun), &Options{PoolSize: 10, OutChannelBuffer: 10}) 183 if err != nil { 184 panic(err) 185 } 186 go func() { 187 for work := 0; work < max; work++ { 188 inputChan <- loadWorker(work) 189 } 190 close(inputChan) 191 }() 192 var res []loadWorker 193 for out := range output { 194 res = append(res, out.Value.(loadWorker)) 195 } 196 isSorted := sort.SliceIsSorted(res, func(i, j int) bool { 197 return res[i] < res[j] 198 }) 199 if !isSorted { 200 t.Error("output is not sorted") 201 } 202 t.Log("Test if response is sorted") 203 }) 204 } 205 206 func TestSortedDataMultiple(t *testing.T) { 207 for i := 0; i < 50; i++ { 208 t.Run("Test if response is sorted", func(t *testing.T) { 209 ctx := context.Background() 210 211 max := 10 212 inputChan := make(chan interface{}) 213 output, err := Process(ctx, inputChan, processGeneratorGenerator(loadWorkerRun), &Options{PoolSize: 10, OutChannelBuffer: 10}) 214 if err != nil { 215 panic(err) 216 } 217 go func() { 218 for work := 0; work < max; work++ { 219 inputChan <- loadWorker(work) 220 } 221 close(inputChan) 222 }() 223 var res []loadWorker 224 for out := range output { 225 res = append(res, out.Value.(loadWorker)) 226 } 227 isSorted := sort.SliceIsSorted(res, func(i, j int) bool { 228 return res[i] < res[j] 229 }) 230 if !isSorted { 231 t.Error("output is not sorted") 232 } 233 t.Log("Test if response is sorted") 234 }) 235 } 236 } 237 238 func TestStreamingInput(t *testing.T) { 239 t.Run("Test streaming input", func(t *testing.T) { 240 ctx := context.Background() 241 inputChan := make(chan interface{}, 10) 242 output, err := Process(ctx, inputChan, processGeneratorGenerator(zeroLoadWorkerRun), &Options{PoolSize: 10, OutChannelBuffer: 10}) 243 if err != nil { 244 panic(err) 245 } 246 247 ticker := time.NewTicker(100 * time.Millisecond) 248 done := make(chan bool) 249 wg := &sync.WaitGroup{} 250 go func() { 251 input := 0 252 for { 253 select { 254 case <-done: 255 return 256 case <-ticker.C: 257 inputChan <- zeroLoadWorker(input) 258 wg.Add(1) 259 input++ 260 default: 261 } 262 } 263 }() 264 265 var res []zeroLoadWorker 266 267 go func() { 268 for out := range output { 269 res = append(res, out.Value.(zeroLoadWorker)) 270 wg.Done() 271 } 272 }() 273 274 time.Sleep(1600 * time.Millisecond) 275 ticker.Stop() 276 done <- true 277 close(inputChan) 278 wg.Wait() 279 isSorted := sort.SliceIsSorted(res, func(i, j int) bool { 280 return res[i] < res[j] 281 }) 282 if !isSorted { 283 t.Error("output is not sorted") 284 } 285 t.Log("Test streaming input") 286 }) 287 } 288 289 func BenchmarkOC(b *testing.B) { 290 max := 100000 291 inputChan := make(chan interface{}) 292 output, err := Process(context.Background(), inputChan, processGeneratorGenerator(zeroLoadWorkerRun), &Options{PoolSize: 10, OutChannelBuffer: 10}) 293 if err != nil { 294 panic(err) 295 } 296 go func() { 297 for work := 0; work < max; work++ { 298 inputChan <- zeroLoadWorker(work) 299 } 300 close(inputChan) 301 }() 302 for out := range output { 303 _ = out 304 } 305 } 306 307 func BenchmarkOCLoad(b *testing.B) { 308 max := 10 309 inputChan := make(chan interface{}) 310 output, err := Process(context.Background(), inputChan, processGeneratorGenerator(loadWorkerRun), &Options{PoolSize: 10, OutChannelBuffer: 10}) 311 if err != nil { 312 panic(err) 313 } 314 go func() { 315 for work := 0; work < max; work++ { 316 inputChan <- loadWorker(work) 317 } 318 close(inputChan) 319 }() 320 for out := range output { 321 _ = out 322 } 323 } 324 325 func BenchmarkOC2(b *testing.B) { 326 for i := 0; i < 100; i++ { 327 max := 1000 328 inputChan := make(chan interface{}) 329 output, err := Process(context.Background(), inputChan, processGeneratorGenerator(zeroLoadWorkerRun), &Options{PoolSize: 10, OutChannelBuffer: 10}) 330 if err != nil { 331 panic(err) 332 } 333 go func() { 334 for work := 0; work < max; work++ { 335 inputChan <- zeroLoadWorker(work) 336 } 337 close(inputChan) 338 }() 339 for out := range output { 340 _ = out 341 } 342 } 343 }