github.com/hasnat/dolt/go@v0.0.0-20210628190320-9eb5d843fbb7/libraries/utils/async/action_executor_test.go (about) 1 // Copyright 2020 Dolthub, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package async 16 17 import ( 18 "context" 19 "errors" 20 "sync/atomic" 21 "testing" 22 23 "github.com/stretchr/testify/assert" 24 "github.com/stretchr/testify/require" 25 ) 26 27 func TestActionExecutorOrdered(t *testing.T) { 28 expectedStr := "abcdefghijklmnopqrstuvwxyz" 29 outStr := "" 30 actionExecutor := NewActionExecutor(context.Background(), func(ctx context.Context, val interface{}) error { 31 str := val.(string) 32 outStr += str 33 return nil 34 }, 1, 0) 35 for _, char := range expectedStr { 36 actionExecutor.Execute(string(char)) 37 } 38 err := actionExecutor.WaitForEmpty() 39 require.NoError(t, err) 40 assert.Equal(t, expectedStr, outStr) 41 } 42 43 func TestActionExecutorOrderedBuffered(t *testing.T) { 44 expectedStr := "abcdefghijklmnopqrstuvwxyz" 45 outStr := "" 46 actionExecutor := NewActionExecutor(context.Background(), func(ctx context.Context, val interface{}) error { 47 str := val.(string) 48 outStr += str 49 return nil 50 }, 1, 3) 51 for _, char := range expectedStr { 52 actionExecutor.Execute(string(char)) 53 } 54 err := actionExecutor.WaitForEmpty() 55 require.NoError(t, err) 56 assert.Equal(t, expectedStr, outStr) 57 } 58 59 func TestActionExecutorUnordered(t *testing.T) { 60 expectedValue := int64(50005000) 61 outValue := int64(0) 62 actionExecutor := NewActionExecutor(context.Background(), func(ctx context.Context, val interface{}) error { 63 atomic.AddInt64(&outValue, val.(int64)) 64 return nil 65 }, 5, 0) 66 for i := int64(1); i <= 10000; i++ { 67 actionExecutor.Execute(i) 68 } 69 err := actionExecutor.WaitForEmpty() 70 require.NoError(t, err) 71 assert.Equal(t, expectedValue, outValue) 72 } 73 74 func TestActionExecutorUnorderedBuffered(t *testing.T) { 75 expectedValue := int64(50005000) 76 outValue := int64(0) 77 actionExecutor := NewActionExecutor(context.Background(), func(ctx context.Context, val interface{}) error { 78 atomic.AddInt64(&outValue, val.(int64)) 79 return nil 80 }, 5, 10) 81 for i := int64(1); i <= 10000; i++ { 82 actionExecutor.Execute(i) 83 } 84 err := actionExecutor.WaitForEmpty() 85 require.NoError(t, err) 86 assert.Equal(t, expectedValue, outValue) 87 } 88 89 func TestActionExecutorUnnecessaryWaits(t *testing.T) { 90 outValue := int64(0) 91 actionExecutor := NewActionExecutor(context.Background(), func(ctx context.Context, val interface{}) error { 92 atomic.AddInt64(&outValue, val.(int64)) 93 return nil 94 }, 5, 10) 95 for i := int64(1); i <= 10000; i++ { 96 actionExecutor.Execute(i) 97 } 98 for i := 0; i < 10; i++ { 99 err := actionExecutor.WaitForEmpty() 100 assert.NoError(t, err) 101 } 102 } 103 104 func TestActionExecutorError(t *testing.T) { 105 for _, conBuf := range []struct { 106 concurrency uint32 107 maxBuffer uint64 108 }{ 109 {1, 0}, 110 {5, 0}, 111 {10, 0}, 112 {1, 1}, 113 {5, 1}, 114 {10, 1}, 115 {1, 5}, 116 {5, 5}, 117 {10, 5}, 118 {1, 10}, 119 {5, 10}, 120 {10, 10}, 121 } { 122 actionExecutor := NewActionExecutor(context.Background(), func(ctx context.Context, val interface{}) error { 123 if val.(int64) == 11 { 124 return errors.New("hey there") 125 } 126 return nil 127 }, conBuf.concurrency, conBuf.maxBuffer) 128 for i := int64(1); i <= 100; i++ { 129 actionExecutor.Execute(i) 130 } 131 err := actionExecutor.WaitForEmpty() 132 assert.Error(t, err) 133 err = actionExecutor.WaitForEmpty() 134 assert.NoError(t, err) 135 } 136 } 137 138 func TestActionExecutorPanicRecovery(t *testing.T) { 139 for _, conBuf := range []struct { 140 concurrency uint32 141 maxBuffer uint64 142 }{ 143 {1, 0}, 144 {5, 0}, 145 {10, 0}, 146 {1, 1}, 147 {5, 1}, 148 {10, 1}, 149 {1, 5}, 150 {5, 5}, 151 {10, 5}, 152 {1, 10}, 153 {5, 10}, 154 {10, 10}, 155 } { 156 actionExecutor := NewActionExecutor(context.Background(), func(ctx context.Context, val interface{}) error { 157 if val.(int64) == 22 { 158 panic("hey there") 159 } 160 return nil 161 }, conBuf.concurrency, conBuf.maxBuffer) 162 for i := int64(1); i <= 100; i++ { 163 actionExecutor.Execute(i) 164 } 165 err := actionExecutor.WaitForEmpty() 166 require.Error(t, err) 167 } 168 }