go_dreamfactory/cmd/robot/robot.go

262 lines
5.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package robot
import (
"bytes"
"encoding/json"
"fmt"
"go_dreamfactory/comm"
"go_dreamfactory/pb"
"io/ioutil"
"log"
"net/http"
"sync"
"time"
"github.com/gorilla/websocket"
jsoniter "github.com/json-iterator/go"
"google.golang.org/protobuf/proto"
)
type Robot struct {
ws *websocket.Conn
opts *Options
user *pb.DBUser
builders []*TestCase //测试用例
linkCase *LinkCase //测试用例链,适应于用例跑批
wg sync.WaitGroup
}
func NewRobot(opts *Options) *Robot {
ws, _, err := websocket.DefaultDialer.Dial(opts.WsUrl, nil)
if err != nil {
log.Fatal(err)
}
r := &Robot{
ws: ws,
opts: opts,
linkCase: NewLinkCase(),
}
return r
}
func (r *Robot) Run() {
log.Print("Robot running...")
log.Printf("websocket %s \n", r.opts.WsUrl)
if r.opts.Create { //创建新用户
r.AccountRegister(r.opts.Account, int32(r.opts.ServerId))
} else {
if r.opts.Account == "" {
log.Fatal("WARNNING: account is required !!!")
}
r.AccountLogin()
}
//处理响应
go func() {
for {
var msg *pb.UserMessage = &pb.UserMessage{}
_, data, err := r.ws.ReadMessage()
if err != nil {
log.Println(err)
}
if err = proto.Unmarshal(data, msg); err != nil {
log.Fatal(err)
}
r.batchhandleRsp(msg)
}
}()
// select {}
r.wg.Wait()
}
type TestCase struct {
desc string
mainType string
subType string
req proto.Message
rsp proto.Message
enabled bool
start time.Time
requested bool //请求标识 true已发
print func(rsp proto.Message) //定义打印
next func(rsp proto.Message, handle func(nextCase *TestCase))
}
func (r *Robot) addBuilders(builders []*TestCase) {
for _, b := range builders {
if b.enabled {
r.builders = append(r.builders, b)
}
}
}
func (r *Robot) handleReq(b *TestCase) {
b.requested = true
b.start = time.Now()
head := &pb.UserMessage{MainType: b.mainType, SubType: b.subType}
defer traceFunc(head.MainType, head.SubType, r.user.GetUid(), b.req)
err := r.SendToClient(head, b.req)
if err != nil {
log.Fatal(err)
}
}
//执行请求
func (r *Robot) batchHandleReq() {
for _, b := range r.builders {
if b.req != nil && !b.requested {
r.wg.Add(1)
time.Sleep(time.Second * 1)
r.handleReq(b)
}
}
}
//执行响应
func (r *Robot) batchhandleRsp(msg *pb.UserMessage) {
for i, b := range r.builders {
if b.enabled && (msg.MainType == b.mainType &&
msg.SubType == b.subType) {
if !comm.ProtoUnmarshal(msg, b.rsp) {
return
}
if b.print == nil {
printReply(msg, b)
} else {
fmt.Printf("===== %s [%s.%s] =====\n", b.desc, msg.MainType, msg.SubType)
b.print(b.rsp)
fmt.Println("==============================")
}
if b.next != nil {
b.next(b.rsp, r.handleReq)
}
if msg.MainType == "user" && msg.SubType == "login" {
r.loginCallback(b.rsp)
} else {
if b.requested {
r.builders = append(r.builders[:i], r.builders[i+1:]...)
}
}
r.wg.Done()
}
}
}
//登录回调
func (r *Robot) loginCallback(rsp proto.Message) {
r.builders = append(r.builders[:0], r.builders[1:]...)
lr := rsp.(*pb.UserLoginResp)
if lr.Data != nil {
r.user = lr.Data
r.onUserLoaded()
} else {
r.AccountRegister(r.opts.Account, int32(r.opts.ServerId)) //请求Http接口模拟创建新账号
}
}
func (r *Robot) SendToClient(msg *pb.UserMessage, rsp proto.Message) error {
//模拟客户端 每次请求都会生成新的秘钥
msg.Sec = r.BuildSecStr()
if comm.ProtoMarshal(rsp, msg) {
data, _ := proto.Marshal(msg)
return r.ws.WriteMessage(websocket.BinaryMessage, data)
}
return nil
}
//在这里添加玩家成功登录以后的测试方法
//次方法在用户登录成功后调用
func (r *Robot) onUserLoaded() {
//notify
r.RunNotify()
//user
r.RunUser()
//hero
r.RunHero()
//friend
r.RunFriend()
//pack
// r.RunPack()
//task
r.RunTask()
// story
r.RunStory()
}
//注册账号
func (r *Robot) AccountRegister(account string, sid int32) {
if account == "" {
log.Fatal("account value is empty")
}
//http
regReq := &pb.UserRegisterReq{Account: account, Sid: sid}
jsonByte, _ := json.Marshal(regReq)
req, err := http.NewRequest("POST", r.opts.RegUrl, bytes.NewReader(jsonByte))
if err != nil {
log.Fatalf("account register err %v", err)
}
req.Header.Set("Content-Type", "application/json;charset=UTF-8")
httpClient := &http.Client{}
rsp, err := httpClient.Do(req)
if err != nil {
panic(err)
}
defer rsp.Body.Close()
body, _ := ioutil.ReadAll(rsp.Body)
regRsp := &pb.UserRegisterResp{}
err = jsoniter.Unmarshal(body, regRsp)
if regRsp.Code == pb.ErrorCode_Success { //注册成功
fmt.Printf("account:%s 注册成功", regRsp.Account)
//登录
var user_builders = []*TestCase{
{
desc: "登录",
mainType: "user",
subType: "login",
req: &pb.UserLoginReq{
Account: account,
Sid: sid,
},
rsp: &pb.UserLoginResp{},
enabled: true,
},
}
r.addBuilders(user_builders)
r.batchHandleReq()
}
}
//打印响应
func printReply(msg *pb.UserMessage, builder *TestCase) {
if m, ok := builder.rsp.(*pb.NotifyErrorNotifyPush); ok {
var tt time.Duration
if builder.start.IsZero() {
tt = time.Duration(0)
} else {
tt = time.Since(builder.start)
}
log.Printf("rsp %s [%v] [%s.%s] [%v:%v]", builder.desc, tt, m.ReqMainType, m.ReqSubType, int32(m.Code), m.Data)
} else {
log.Printf("rsp %s [%v] [%s.%s] [%v]", builder.desc, time.Since(builder.start), msg.MainType, msg.SubType, builder.rsp)
}
}
//方法参数跟踪
func traceFunc(module string, funcName string, uid string, funcArgs interface{}) {
log.Printf("req [%s.%s] [%s] [%v]", module, funcName, uid, funcArgs)
}