github.com/polarismesh/polaris@v1.17.8/common/batchjob/batch_test.go (about) 1 /** 2 * Tencent is pleased to support the open source community by making Polaris available. 3 * 4 * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. 5 * 6 * Licensed under the BSD 3-Clause License (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * https://opensource.org/licenses/BSD-3-Clause 11 * 12 * Unless required by applicable law or agreed to in writing, software distributed 13 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 14 * CONDITIONS OF ANY KIND, either express or implied. See the License for the 15 * specific language governing permissions and limitations under the License. 16 */ 17 18 package batchjob 19 20 import ( 21 "context" 22 "errors" 23 "fmt" 24 "math/rand" 25 "sync" 26 "sync/atomic" 27 "testing" 28 "time" 29 30 "github.com/stretchr/testify/assert" 31 ) 32 33 func TestNewBatchController(t *testing.T) { 34 total := 1000 35 36 totalTasks := int32(0) 37 testHandle := func(futures []Future) { 38 atomic.AddInt32(&totalTasks, int32(len(futures))) 39 time.Sleep(time.Duration(rand.Int63n(100)) * time.Millisecond) 40 for i := range futures { 41 futures[i].Reply(nil, nil) 42 } 43 } 44 45 ctrl := NewBatchController(context.Background(), CtrlConfig{ 46 QueueSize: 32, 47 MaxBatchCount: 16, 48 WaitTime: 32 * time.Millisecond, 49 Concurrency: 8, 50 Handler: testHandle, 51 }) 52 53 wg := &sync.WaitGroup{} 54 55 for i := 0; i < total; i++ { 56 wg.Add(1) 57 go func(i int) { 58 defer wg.Done() 59 future := ctrl.Submit(fmt.Sprintf("%d", i)) 60 _, _ = future.Done() 61 }(i) 62 } 63 64 wg.Wait() 65 assert.Equal(t, total, int(atomic.LoadInt32(&totalTasks))) 66 ctrl.Stop() 67 } 68 69 func TestNewBatchControllerTSubmitTimeout(t *testing.T) { 70 total := 1000 71 72 totalTasks := int32(0) 73 testHandle := func(futures []Future) { 74 time.Sleep(100 * time.Millisecond) 75 atomic.AddInt32(&totalTasks, int32(len(futures))) 76 for i := range futures { 77 futures[i].Reply(nil, nil) 78 } 79 } 80 81 ctrl := NewBatchController(context.Background(), CtrlConfig{ 82 QueueSize: 1, 83 MaxBatchCount: uint32(total * 2), 84 WaitTime: 32 * time.Millisecond, 85 Concurrency: 8, 86 Handler: testHandle, 87 }) 88 89 wg := &sync.WaitGroup{} 90 91 for i := 0; i < total; i++ { 92 wg.Add(1) 93 go func(i int) { 94 defer wg.Done() 95 future := ctrl.SubmitWithTimeout(fmt.Sprintf("%d", i), time.Millisecond) 96 _, err := future.Done() 97 if err != nil { 98 assert.True(t, errors.Is(err, ErrorSubmitTaskTimeout), err) 99 } 100 }(i) 101 } 102 103 wg.Wait() 104 ctrl.Stop() 105 } 106 107 func TestNewBatchControllerDoneTimeout(t *testing.T) { 108 total := 100 109 110 totalTasks := int32(0) 111 testHandle := func(futures []Future) { 112 time.Sleep(100 * time.Millisecond) 113 atomic.AddInt32(&totalTasks, int32(len(futures))) 114 } 115 116 ctrl := NewBatchController(context.Background(), CtrlConfig{ 117 QueueSize: 1, 118 MaxBatchCount: uint32(total * 2), 119 WaitTime: 32 * time.Millisecond, 120 Concurrency: 8, 121 Handler: testHandle, 122 }) 123 124 wg := &sync.WaitGroup{} 125 126 for i := 0; i < total; i++ { 127 wg.Add(1) 128 go func(i int) { 129 defer wg.Done() 130 future := ctrl.Submit(fmt.Sprintf("%d", i)) 131 _, err := future.DoneTimeout(time.Second) 132 assert.Error(t, err) 133 assert.True(t, errors.Is(err, context.DeadlineExceeded), err) 134 }(i) 135 } 136 137 t.Log("BatchController already stop") 138 wg.Wait() 139 ctrl.Stop() 140 } 141 142 func TestNewBatchControllerStop(t *testing.T) { 143 total := 1000 144 145 totalTasks := int32(0) 146 testHandle := func(futures []Future) { 147 atomic.AddInt32(&totalTasks, int32(len(futures))) 148 for i := range futures { 149 futures[i].Reply(atomic.LoadInt32(&totalTasks), nil) 150 } 151 } 152 153 ctrl := NewBatchController(context.Background(), CtrlConfig{ 154 QueueSize: uint32(total * 2), 155 MaxBatchCount: 64, 156 WaitTime: 32 * time.Millisecond, 157 Concurrency: 8, 158 Handler: testHandle, 159 }) 160 161 sbWg := &sync.WaitGroup{} 162 wg := &sync.WaitGroup{} 163 sbWg.Add(total) 164 wg.Add(total) 165 cancelTask := int32(0) 166 for i := 0; i < total; i++ { 167 go func(i int) { 168 defer func() { 169 wg.Done() 170 }() 171 future := ctrl.Submit(fmt.Sprintf("%d", i)) 172 sbWg.Done() 173 _, err := future.Done() 174 if err != nil { 175 if assert.ErrorIs(t, err, ErrorBatchControllerStopped) { 176 atomic.AddInt32(&cancelTask, 1) 177 } 178 } 179 }(i) 180 } 181 182 ctrl.Stop() 183 t.Log("BatchController already stop") 184 sbWg.Wait() 185 t.Logf("cancel jobs : %d", atomic.LoadInt32(&cancelTask)) 186 wg.Wait() 187 t.Log("finish all batch job") 188 } 189 190 func TestNewBatchControllerGracefulStop(t *testing.T) { 191 total := 1000 192 193 ctrl := NewBatchController(context.Background(), CtrlConfig{ 194 QueueSize: uint32(total * 2), 195 MaxBatchCount: 64, 196 WaitTime: 32 * time.Millisecond, 197 Concurrency: 8, 198 Handler: func(futures []Future) { 199 for i := range futures { 200 futures[i].Reply(nil, nil) 201 } 202 }, 203 }) 204 205 sbWg := &sync.WaitGroup{} 206 wg := &sync.WaitGroup{} 207 sbWg.Add(total) 208 wg.Add(total) 209 submitTask := int32(0) 210 cancelTask := int32(0) 211 for i := 0; i < total; i++ { 212 go func(i int) { 213 defer func() { 214 wg.Done() 215 }() 216 future := ctrl.Submit(fmt.Sprintf("%d", i)) 217 atomic.AddInt32(&submitTask, 1) 218 sbWg.Done() 219 _, err := future.Done() 220 if err != nil { 221 if assert.ErrorIs(t, err, ErrorBatchControllerStopped) { 222 atomic.AddInt32(&cancelTask, 1) 223 } 224 } 225 }(i) 226 } 227 228 ctrl.GracefulStop() 229 t.Log("BatchController already stop") 230 sbWg.Wait() 231 t.Logf("submit jobs : %d, cancel jobs : %d", atomic.LoadInt32(&submitTask), atomic.LoadInt32(&cancelTask)) 232 wg.Wait() 233 t.Log("finish all batch job") 234 }