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  }