github.com/supragya/TendermintConnector@v0.0.0-20210619045051-113e32b84fb1/_deprecated_chains/cosmos/libs/common/async_test.go (about) 1 package common 2 3 import ( 4 "errors" 5 "fmt" 6 "sync/atomic" 7 "testing" 8 "time" 9 10 "github.com/stretchr/testify/assert" 11 ) 12 13 func TestParallel(t *testing.T) { 14 15 // Create tasks. 16 var counter = new(int32) 17 var tasks = make([]Task, 100*1000) 18 for i := 0; i < len(tasks); i++ { 19 tasks[i] = func(i int) (res interface{}, err error, abort bool) { 20 atomic.AddInt32(counter, 1) 21 return -1 * i, nil, false 22 } 23 } 24 25 // Run in parallel. 26 var trs, ok = Parallel(tasks...) 27 assert.True(t, ok) 28 29 // Verify. 30 assert.Equal(t, int(*counter), len(tasks), "Each task should have incremented the counter already") 31 var failedTasks int 32 for i := 0; i < len(tasks); i++ { 33 taskResult, ok := trs.LatestResult(i) 34 if !ok { 35 assert.Fail(t, "Task #%v did not complete.", i) 36 failedTasks++ 37 } else if taskResult.Error != nil { 38 assert.Fail(t, "Task should not have errored but got %v", taskResult.Error) 39 failedTasks++ 40 } else if !assert.Equal(t, -1*i, taskResult.Value.(int)) { 41 assert.Fail(t, "Task should have returned %v but got %v", -1*i, taskResult.Value.(int)) 42 failedTasks++ 43 } else { 44 // Good! 45 } 46 } 47 assert.Equal(t, failedTasks, 0, "No task should have failed") 48 assert.Nil(t, trs.FirstError(), "There should be no errors") 49 assert.Equal(t, 0, trs.FirstValue(), "First value should be 0") 50 } 51 52 func TestParallelAbort(t *testing.T) { 53 54 var flow1 = make(chan struct{}, 1) 55 var flow2 = make(chan struct{}, 1) 56 var flow3 = make(chan struct{}, 1) // Cap must be > 0 to prevent blocking. 57 var flow4 = make(chan struct{}, 1) 58 59 // Create tasks. 60 var tasks = []Task{ 61 func(i int) (res interface{}, err error, abort bool) { 62 assert.Equal(t, i, 0) 63 flow1 <- struct{}{} 64 return 0, nil, false 65 }, 66 func(i int) (res interface{}, err error, abort bool) { 67 assert.Equal(t, i, 1) 68 flow2 <- <-flow1 69 return 1, errors.New("some error"), false 70 }, 71 func(i int) (res interface{}, err error, abort bool) { 72 assert.Equal(t, i, 2) 73 flow3 <- <-flow2 74 return 2, nil, true 75 }, 76 func(i int) (res interface{}, err error, abort bool) { 77 assert.Equal(t, i, 3) 78 <-flow4 79 return 3, nil, false 80 }, 81 } 82 83 // Run in parallel. 84 var taskResultSet, ok = Parallel(tasks...) 85 assert.False(t, ok, "ok should be false since we aborted task #2.") 86 87 // Verify task #3. 88 // Initially taskResultSet.chz[3] sends nothing since flow4 didn't send. 89 waitTimeout(t, taskResultSet.chz[3], "Task #3") 90 91 // Now let the last task (#3) complete after abort. 92 flow4 <- <-flow3 93 94 // Wait until all tasks have returned or panic'd. 95 taskResultSet.Wait() 96 97 // Verify task #0, #1, #2. 98 checkResult(t, taskResultSet, 0, 0, nil, nil) 99 checkResult(t, taskResultSet, 1, 1, errors.New("some error"), nil) 100 checkResult(t, taskResultSet, 2, 2, nil, nil) 101 checkResult(t, taskResultSet, 3, 3, nil, nil) 102 } 103 104 func TestParallelRecover(t *testing.T) { 105 106 // Create tasks. 107 var tasks = []Task{ 108 func(i int) (res interface{}, err error, abort bool) { 109 return 0, nil, false 110 }, 111 func(i int) (res interface{}, err error, abort bool) { 112 return 1, errors.New("some error"), false 113 }, 114 func(i int) (res interface{}, err error, abort bool) { 115 panic(2) 116 }, 117 } 118 119 // Run in parallel. 120 var taskResultSet, ok = Parallel(tasks...) 121 assert.False(t, ok, "ok should be false since we panic'd in task #2.") 122 123 // Verify task #0, #1, #2. 124 checkResult(t, taskResultSet, 0, 0, nil, nil) 125 checkResult(t, taskResultSet, 1, 1, errors.New("some error"), nil) 126 checkResult(t, taskResultSet, 2, nil, nil, 2) 127 } 128 129 // Wait for result 130 func checkResult(t *testing.T, taskResultSet *TaskResultSet, index int, val interface{}, err error, pnk interface{}) { 131 taskResult, ok := taskResultSet.LatestResult(index) 132 taskName := fmt.Sprintf("Task #%v", index) 133 assert.True(t, ok, "TaskResultCh unexpectedly closed for %v", taskName) 134 assert.Equal(t, val, taskResult.Value, taskName) 135 if err != nil { 136 assert.Equal(t, err, taskResult.Error, taskName) 137 } else if pnk != nil { 138 assert.Equal(t, pnk, taskResult.Error.(Error).Data(), taskName) 139 } else { 140 assert.Nil(t, taskResult.Error, taskName) 141 } 142 } 143 144 // Wait for timeout (no result) 145 func waitTimeout(t *testing.T, taskResultCh TaskResultCh, taskName string) { 146 select { 147 case _, ok := <-taskResultCh: 148 if !ok { 149 assert.Fail(t, "TaskResultCh unexpectedly closed (%v)", taskName) 150 } else { 151 assert.Fail(t, "TaskResultCh unexpectedly returned for %v", taskName) 152 } 153 case <-time.After(1 * time.Second): 154 // Good! 155 } 156 }