gitee.com/KyleChenSource/lib-robot@v1.0.2/robottest/robot/robot_config.go (about)

     1  package robot
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"strings"
     8  
     9  	ts "gitee.com/KyleChenSource/lib-robot/robottest/robot/testcase"
    10  
    11  	"github.com/valyala/fastjson"
    12  	"google.golang.org/protobuf/reflect/protoreflect"
    13  )
    14  
    15  const DefaultRobotFile = "robot.json"
    16  
    17  type TestRobots struct {
    18  	Count   int     `json:"count"`
    19  	File    string  `json:"file"`
    20  	Robot   string  `json:"robot"`
    21  	Monitor bool    `json:"msg_monitor"` // 是否打印消息内容
    22  	Ignores []int32 `json:"msg_ignore"`  // 忽略的消息清单
    23  	Focus   []int32 `json:"msg_focus"`   // 只显示的msg,如果非空,则Ignores失效
    24  }
    25  
    26  type TestConfig struct {
    27  	Config        string          `json:"config"`
    28  	AccountPre    string          `json:"account_pre"`
    29  	AccountOffset int32           `json:"account_off"`
    30  	Server        string          `json:"server"`
    31  	Brute         *BruteCnf       `json:"brutetest"`
    32  	Statistic     StatisticConfig `json:"statistic"`
    33  	Robots        []*TestRobots   `json:"robots"`
    34  }
    35  
    36  type BruteCnf struct {
    37  	File       string `json:"file"`
    38  	RobotCnt   int    `json:"robot_max"`
    39  	File_Login string `json:"login_file"`
    40  	Login      string `json:"case_login"`
    41  	Relogin    string `json:"case_relogin"`
    42  }
    43  
    44  type StatisticConfig struct {
    45  	StatisticTickInterval int64 `json:"stick"`
    46  	StatisticTotTime      int64 `json:"stot"`
    47  	ActionTimeOver        int64 `json:"action_timeover"`
    48  }
    49  
    50  const DefaultTestcaseFile = "testcase.json"
    51  
    52  type TestCaseRunnerConfig struct {
    53  	File  string `json:"file"`
    54  	Do    string `json:"do"`
    55  	Count int    `json:"count"`
    56  }
    57  
    58  type RobotConfig struct {
    59  	Name         string
    60  	Relogin      bool                    `json:"relogin"` // 如果true, 则断开连接后,会保存现场,先进行重连,然后进行login, 然后回复测试流程。 如果false,则直接清理退出
    61  	File_Login   string                  `json:"login_file"`
    62  	Case_Login   string                  `json:"case_login"`   // 登录case
    63  	Case_Relogin string                  `json:"case_relogin"` // 重登case
    64  	Cases        []*TestCaseRunnerConfig `json:"cases"`
    65  }
    66  
    67  type ProtoMsgConfig struct {
    68  	Comment string      `json:"comment"` // 备注
    69  	MsgId   int         `json:"msg_id"`  // 协议id
    70  	Msg     interface{} `json:"msg"`     // 协议数据json字符串
    71  }
    72  
    73  type ProtoMsg struct {
    74  	Name    string                    `json:"name"`
    75  	Comment string                    `json:"comment"` // 备注
    76  	MsgId   int                       `json:"msg_id"`  // 协议id
    77  	Msg     protoreflect.ProtoMessage `json:"msg"`     // 协议数据json字符串
    78  }
    79  
    80  var MsgFactory map[int]protoreflect.ProtoMessage
    81  
    82  var msg_cnf map[string]*ProtoMsgConfig
    83  var MSG_DATA map[string]*ProtoMsg
    84  var TESTCASE_CNF map[string]*ts.TestcaseConfig
    85  var ROBOT_CNF map[string]*RobotConfig
    86  var TEST_CNF TestConfig
    87  
    88  var loadFiles = make(map[string]bool)
    89  
    90  func testcaseCnfLoad(cnfPath string, file string) error {
    91  	filename := fmt.Sprintf("%s%s", cnfPath, file)
    92  	if _, ok := loadFiles[filename]; ok {
    93  		// 已经加载
    94  		return nil
    95  	}
    96  	loadFiles[filename] = true
    97  
    98  	var readFile []byte
    99  	readFile, err := ioutil.ReadFile(filename)
   100  	if err != nil {
   101  		return fmt.Errorf("TestCase:%s ReadFile err:%s", filename, err.Error())
   102  	}
   103  
   104  	j, err := fastjson.ParseBytes(readFile)
   105  	if err != nil {
   106  		return fmt.Errorf("TestCase:%s jsonParse err:%s", filename, err.Error())
   107  	}
   108  
   109  	objs, err := j.Object()
   110  	if err != nil {
   111  		return fmt.Errorf("TestCase:%s Object Root err:%s", filename, err.Error())
   112  	}
   113  
   114  	var errBuilder strings.Builder
   115  	bErr := false
   116  	objs.Visit(func(tsK []byte, tsV *fastjson.Value) {
   117  		tfs := tsV.GetArray("testflows")
   118  		if tfs == nil {
   119  			bErr = true
   120  			errBuilder.WriteString(fmt.Sprintf("TestCase:%s %s without testflows\n", filename, tsK))
   121  			return
   122  		}
   123  
   124  		tsCnf := ts.TestcaseConfig{
   125  			Name:     string(tsK),
   126  			TestFlow: make([][]ts.TestcaseActionCnf, 0),
   127  		}
   128  
   129  		for tfK, tfV := range tfs {
   130  			tf := tfV.GetArray()
   131  			var tfCnf []ts.TestcaseActionCnf
   132  			for aK, aV := range tf {
   133  				aName := aV.GetStringBytes("name")
   134  				f, ok := ts.TESTCASEACTION_MGR.Find(string(aName))
   135  				if !ok {
   136  					if err == nil {
   137  						bErr = true
   138  						errBuilder.WriteString(fmt.Sprintf("TestCase:%s %s[%d][%d] Action:%s nil\n", filename, tsK, tfK, aK, aName))
   139  					} else {
   140  						bErr = true
   141  						errBuilder.WriteString(fmt.Sprintf("TestCase:%s %s\n%s[%d][%d] Action:%s nil\n", filename, err.Error(), tsK, tfK, aK, aName))
   142  					}
   143  
   144  					return
   145  				}
   146  
   147  				aCnf := f.Cnf()
   148  				errUnmarshal := json.Unmarshal([]byte(aV.String()), aCnf)
   149  				if errUnmarshal != nil {
   150  					if err == nil {
   151  						bErr = true
   152  						errBuilder.WriteString(fmt.Sprintf("TestCase:%s %s[%d][%d] Action:%s Unmarshal err:%s\n", filename, tsK, tfK, aK, aName, errUnmarshal.Error()))
   153  					} else {
   154  						bErr = true
   155  						errBuilder.WriteString(fmt.Sprintf("TestCase:%s %s\n%s[%d][%d] Action:%s Unmarshal err:%s\n", filename, err.Error(), tsK, tfK, aK, aName, errUnmarshal.Error()))
   156  					}
   157  					return
   158  				}
   159  
   160  				tfCnf = append(tfCnf, aCnf)
   161  			}
   162  			tsCnf.TestFlow = append(tsCnf.TestFlow, tfCnf)
   163  		}
   164  
   165  		TESTCASE_CNF[fmt.Sprintf("%s/%s", file, string(tsK))] = &tsCnf
   166  	})
   167  
   168  	if bErr {
   169  		return fmt.Errorf(errBuilder.String())
   170  	}
   171  
   172  	return nil
   173  }
   174  
   175  func robotDescLoad(cnfPath string, file string) error {
   176  	filename := fmt.Sprintf("%s%s", cnfPath, file)
   177  	if _, ok := loadFiles[filename]; ok {
   178  		// 已经加载
   179  		return nil
   180  	}
   181  	loadFiles[filename] = true
   182  
   183  	readFile, err := ioutil.ReadFile(filename)
   184  	if err != nil {
   185  		return fmt.Errorf("RobotConfig:%s ReadFile err:%s", filename, err.Error())
   186  	}
   187  
   188  	robotCnf := make(map[string]*RobotConfig)
   189  	err = json.Unmarshal(readFile, &robotCnf)
   190  	if err != nil {
   191  		return fmt.Errorf("RobotConfig:%s Unmarshal err:%s", filename, err.Error())
   192  	}
   193  
   194  	var errBuilder strings.Builder
   195  	bErr := false
   196  	for n, c := range robotCnf {
   197  		if c.File_Login == "" {
   198  			c.File_Login = DefaultTestcaseFile
   199  		}
   200  		err = testcaseCnfLoad(cnfPath, c.File_Login)
   201  		if err != nil {
   202  			bErr = true
   203  			errBuilder.WriteString(fmt.Sprintf("RobotConfig:%s File_Login:%s testcaseCnfLoad err:%s\n", filename, c.File_Login, err.Error()))
   204  		}
   205  
   206  		for _, t := range c.Cases {
   207  			if t.File == "" {
   208  				t.File = DefaultTestcaseFile
   209  			}
   210  			err = testcaseCnfLoad(cnfPath, t.File)
   211  			if err != nil {
   212  				bErr = true
   213  				errBuilder.WriteString(fmt.Sprintf("RobotConfig:%s case:%s testcaseCnfLoad err:%s\n", filename, t.File, err.Error()))
   214  			}
   215  		}
   216  
   217  		ROBOT_CNF[fmt.Sprintf("%s/%s", file, n)] = c
   218  	}
   219  
   220  	if bErr {
   221  		return fmt.Errorf(errBuilder.String())
   222  	}
   223  
   224  	return nil
   225  }
   226  
   227  func ConfigLoad(cnfPath string, config string) error {
   228  	readFile, err := ioutil.ReadFile(fmt.Sprintf("%s%s", cnfPath, config))
   229  	if err != nil {
   230  		return err
   231  	}
   232  
   233  	err = json.Unmarshal(readFile, &TEST_CNF)
   234  	if err != nil {
   235  		return err
   236  	}
   237  
   238  	// 进行robot文件加载
   239  	var errBuilder strings.Builder
   240  	bErr := false
   241  	ROBOT_CNF = make(map[string]*RobotConfig)
   242  	TESTCASE_CNF = make(map[string]*ts.TestcaseConfig)
   243  	if TEST_CNF.Brute != nil {
   244  		if TEST_CNF.Brute.File_Login == "" {
   245  			TEST_CNF.Brute.File_Login = DefaultTestcaseFile
   246  		}
   247  
   248  		err = testcaseCnfLoad(cnfPath, TEST_CNF.Brute.File_Login)
   249  		if err != nil {
   250  			bErr = true
   251  			errBuilder.WriteString(fmt.Sprintf("Brute File_Login:%s testcaseCnfLoad err:%s\n", TEST_CNF.Brute.File_Login, err.Error()))
   252  		}
   253  	}
   254  
   255  	for _, r := range TEST_CNF.Robots {
   256  		if r.File == "" {
   257  			r.File = DefaultRobotFile
   258  		}
   259  		err = robotDescLoad(cnfPath, r.File)
   260  		if err != nil {
   261  			errBuilder.WriteString(fmt.Sprintln(err.Error()))
   262  			bErr = true
   263  		}
   264  	}
   265  
   266  	if bErr {
   267  		return fmt.Errorf(errBuilder.String())
   268  	}
   269  
   270  	return nil
   271  }
   272  
   273  func ProtoMsgLoad(cnfPath string) error {
   274  	msg_cnf = make(map[string]*ProtoMsgConfig)
   275  	MSG_DATA = make(map[string]*ProtoMsg)
   276  
   277  	readFile, err := ioutil.ReadFile(fmt.Sprintf("%sproto_msg.json", cnfPath))
   278  	if err != nil {
   279  		return err
   280  	}
   281  	err = json.Unmarshal(readFile, &msg_cnf)
   282  	if err != nil {
   283  		return err
   284  	}
   285  
   286  	for key, cnf := range msg_cnf {
   287  		msg_bytes, err := json.Marshal(cnf.Msg)
   288  		if err != nil {
   289  			return err
   290  		}
   291  
   292  		msgP, ok := MsgFactory[cnf.MsgId]
   293  		if !ok {
   294  			return fmt.Errorf("msgId:%d nil", cnf.MsgId)
   295  		}
   296  
   297  		msg := msgP.ProtoReflect().New().Interface()
   298  		err = json.Unmarshal(msg_bytes, msg)
   299  		if err != nil {
   300  			return err
   301  		}
   302  
   303  		MSG_DATA[key] = &ProtoMsg{
   304  			Name:    key,
   305  			Comment: cnf.Comment,
   306  			MsgId:   cnf.MsgId,
   307  			Msg:     msg,
   308  		}
   309  	}
   310  	return nil
   311  }
   312  
   313  func ProtoMsgSave(file string, data map[string]*ProtoMsg) error {
   314  	out, err := json.Marshal(data)
   315  	if err != nil {
   316  		return err
   317  	}
   318  
   319  	err = ioutil.WriteFile(file, out, 0666)
   320  	return err
   321  }