github.com/turingchain2020/turingchain@v1.1.21/cmd/autotest/testflow/flow.go (about) 1 // Copyright Turing Corp. 2018 All Rights Reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Package testflow test flow, Add=>HandleDepend=>Send=>Check 6 package testflow 7 8 import ( 9 "container/list" 10 "fmt" 11 "reflect" 12 "sync" 13 "time" 14 15 "github.com/turingchain2020/turingchain/cmd/autotest/types" 16 "github.com/turingchain2020/turingchain/common/log/log15" 17 ) 18 19 //TestOperator 测试操作符 20 type TestOperator struct { 21 addDone chan bool 22 sendDone chan bool 23 checkDone chan bool 24 depEmpty chan bool 25 sendBuf chan types.CaseFunc 26 checkBuf chan types.PackFunc 27 addDepBuf chan types.CaseFunc 28 delDepBuf chan types.PackFunc 29 depCaseMap map[string][]types.CaseFunc //key:TestID, val: array of testCases depending on the key 30 depCountMap map[string]int //key:TestID, val: dependency count 31 32 fLog log15.Logger 33 tLog log15.Logger 34 35 dapp string 36 totalCase int 37 totalFail int 38 failID []string 39 } 40 41 //AddCaseArray 添加用例 42 func (tester *TestOperator) AddCaseArray(caseArrayList ...interface{}) { 43 44 for i := range caseArrayList { 45 46 caseArray := reflect.ValueOf(caseArrayList[i]) 47 48 if caseArray.Kind() != reflect.Slice { 49 continue 50 } 51 52 for j := 0; j < caseArray.Len(); j++ { 53 54 testCase := caseArray.Index(j).Addr().Interface().(types.CaseFunc) 55 baseCase := testCase.GetBaseCase() 56 57 if len(baseCase.Dep) > 0 { 58 59 tester.addDepBuf <- testCase 60 } else { 61 62 tester.sendBuf <- testCase 63 } 64 65 tester.depCountMap[baseCase.ID] = len(baseCase.Dep) 66 } 67 } 68 69 tester.addDone <- true 70 71 } 72 73 //HandleDependency 管理依赖 74 func (tester *TestOperator) HandleDependency() { 75 76 keepLoop := true 77 addDoneFlag := false 78 for keepLoop { 79 select { 80 81 case testCase := <-tester.addDepBuf: 82 83 baseCase := testCase.GetBaseCase() 84 85 for _, depID := range baseCase.Dep { 86 87 testArr := append(tester.depCaseMap[depID], testCase) 88 tester.depCaseMap[depID] = testArr 89 } 90 91 case testPack := <-tester.delDepBuf: 92 93 packID := testPack.GetPackID() 94 //取出依赖于该用例的所有用例 95 caseArr, exist := tester.depCaseMap[packID] 96 if exist { 97 98 for i := range caseArr { 99 100 caseArr[i].SetDependData(testPack.GetDependData()) 101 baseCase := caseArr[i].GetBaseCase() 102 tester.depCountMap[baseCase.ID]-- 103 if tester.depCountMap[baseCase.ID] == 0 { 104 tester.sendBuf <- caseArr[i] 105 delete(tester.depCountMap, baseCase.ID) 106 } 107 } 108 delete(tester.depCaseMap, packID) 109 } 110 case <-tester.addDone: 111 112 addDoneFlag = true 113 //check dependency validity 114 115 for depID := range tester.depCaseMap { 116 117 _, exist := tester.depCountMap[depID] 118 if !exist { 119 //depending testCase not exist 120 for i := range tester.depCaseMap[depID] { 121 tester.tLog.Error("CheckCaseDependencyValid", "TestID", tester.depCaseMap[depID][i].GetID(), "DependTestID", depID, "Error", "DependCaseNotExist") 122 } 123 delete(tester.depCaseMap, depID) 124 } 125 } 126 127 case <-time.After(time.Second): 128 129 if addDoneFlag && len(tester.depCaseMap) == 0 { 130 131 tester.depEmpty <- true 132 keepLoop = false 133 break 134 } 135 } 136 } 137 138 //each case will send to delDepBuf after checking 139 for { 140 <-tester.delDepBuf 141 } 142 } 143 144 //RunSendFlow send 145 func (tester *TestOperator) RunSendFlow() { 146 147 depEmpty := false 148 keepLoop := true 149 sendWg := &sync.WaitGroup{} 150 sendList := (*list.List)(nil) 151 152 for keepLoop { 153 select { 154 155 case testCase := <-tester.sendBuf: 156 157 if sendList == nil { 158 sendList = list.New() 159 } 160 sendList.PushBack(testCase) 161 162 case <-tester.depEmpty: 163 depEmpty = true 164 165 case <-time.After(time.Second): 166 167 if depEmpty { 168 keepLoop = false 169 } 170 171 if sendList == nil { 172 break 173 } 174 175 sendWg.Add(1) 176 go func(c *list.List, wg *sync.WaitGroup) { 177 178 defer wg.Done() 179 var n *list.Element 180 for e := c.Front(); e != nil; e = n { 181 182 n = e.Next() 183 testCase := e.Value.(types.CaseFunc) 184 c.Remove(e) 185 baseCase := testCase.GetBaseCase() 186 187 repeat := baseCase.Repeat 188 if repeat <= 0 { //default val if empty in tomlFile 189 repeat = 1 190 } 191 192 tester.totalCase += repeat 193 packID := baseCase.ID 194 195 for i := 1; i <= repeat; i++ { 196 197 tester.fLog.Info("CommandExec", "TestID", packID, "Command", baseCase.Command) 198 pack, err := testCase.SendCommand(packID) 199 200 if err != nil { 201 202 if baseCase.Fail { //fail type case 203 204 tester.tLog.Info("TestCaseResult", "TestID", packID, "Result", "Succeed") 205 206 } else { 207 208 tester.totalFail++ 209 tester.failID = append(tester.failID, packID) 210 tester.tLog.Error("TestCaseResult", "TestID", packID, "Command", baseCase.Command, "Result", "") 211 fmt.Println(err.Error()) 212 } 213 tester.fLog.Info("CommandResult", "TestID", packID, "Result", err.Error()) 214 casePack := &types.BaseCasePack{} 215 casePack.SetPackID(packID) 216 tester.delDepBuf <- casePack 217 218 } else { 219 220 pack.SetLogger(tester.fLog, tester.tLog) 221 tester.checkBuf <- pack 222 tester.fLog.Info("CommandResult", "TestID", packID, "Result", pack.GetTxHash()) 223 } 224 225 //distinguish with different packID, format: [TestID_RepeatOrder] 226 packID = fmt.Sprintf("%s_%d", baseCase.ID, i) 227 } 228 } 229 }(sendList, sendWg) 230 231 sendList = nil 232 } 233 } 234 235 sendWg.Wait() 236 tester.sendDone <- true 237 } 238 239 //RunCheckFlow check 240 func (tester *TestOperator) RunCheckFlow() { 241 242 checkList := (*list.List)(nil) 243 sendDoneFlag := false 244 keepLoop := true 245 checkWg := &sync.WaitGroup{} 246 247 for keepLoop { 248 249 select { 250 251 case casePack := <-tester.checkBuf: 252 253 if checkList == nil { 254 checkList = list.New() 255 } 256 257 checkList.PushBack(casePack) 258 259 case <-tester.sendDone: 260 sendDoneFlag = true 261 262 case <-time.After(time.Second): //do check operation with an independent check list 263 264 if checkList == nil { 265 266 if sendDoneFlag { 267 keepLoop = false //no more case from send flow 268 } 269 break 270 } 271 272 checkWg.Add(1) 273 go func(c *list.List, wg *sync.WaitGroup) { 274 275 defer wg.Done() 276 for c.Len() > 0 { 277 278 var n *list.Element 279 //traversing checkList and check the result 280 281 for e := c.Front(); e != nil; e = n { 282 283 casePack := e.Value.(types.PackFunc) 284 checkOver, bSuccess := casePack.CheckResult(casePack.GetCheckHandlerMap()) 285 n = e.Next() 286 287 //have done checking 288 if checkOver { 289 290 c.Remove(e) 291 //find if any case depend 292 tester.delDepBuf <- casePack 293 isFailCase := casePack.GetBaseCase().Fail 294 295 if (bSuccess && !isFailCase) || (!bSuccess && isFailCase) { //some logs 296 297 tester.tLog.Info("TestCaseResult", "TestID", casePack.GetPackID(), "Result", "Succeed") 298 299 } else { 300 baseCase := casePack.GetBaseCase() 301 tester.totalFail++ 302 tester.failID = append(tester.failID, casePack.GetPackID()) 303 tester.tLog.Error("TestCaseFailDetail", "TestID", casePack.GetPackID(), "Command", baseCase.Command, "TxHash", casePack.GetTxHash(), "TxReceipt", "") 304 fmt.Println(casePack.GetTxReceipt()) 305 } 306 } 307 } 308 309 if c.Len() > 0 { 310 311 //tester.tLog.Info("CheckRoutineSleep", "SleepTime", CheckSleepTime*time.Second, "WaitCheckNum", c.Len()) 312 time.Sleep(time.Duration(checkSleepTime) * time.Second) 313 } 314 315 } 316 317 }(checkList, checkWg) 318 319 checkList = nil //always set nil for new list 320 } 321 } 322 323 checkWg.Wait() 324 tester.checkDone <- true 325 } 326 327 //WaitTest 等待测试 328 func (tester *TestOperator) WaitTest() *AutoTestResult { 329 330 <-tester.checkDone 331 return &AutoTestResult{ 332 dapp: tester.dapp, 333 totalCase: tester.totalCase, 334 failCase: tester.totalFail, 335 failCaseID: tester.failID, 336 } 337 } 338 339 //NewTestOperator new 340 func NewTestOperator(stdLog log15.Logger, fileLog log15.Logger, dapp string) (tester *TestOperator) { 341 342 tester = new(TestOperator) 343 344 tester.addDone = make(chan bool, 1) 345 tester.sendDone = make(chan bool, 1) 346 tester.checkDone = make(chan bool, 1) 347 tester.depEmpty = make(chan bool, 1) 348 tester.addDepBuf = make(chan types.CaseFunc, 1) 349 tester.delDepBuf = make(chan types.PackFunc, 1) 350 tester.sendBuf = make(chan types.CaseFunc, 1) 351 tester.checkBuf = make(chan types.PackFunc, 1) 352 tester.depCaseMap = make(map[string][]types.CaseFunc) 353 tester.depCountMap = make(map[string]int) 354 tester.fLog = fileLog.New("module", dapp) 355 tester.tLog = stdLog.New("module", dapp) 356 tester.dapp = dapp 357 tester.totalCase = 0 358 tester.totalFail = 0 359 return tester 360 361 }