package monkey import ( "fmt" "goqs/controllers" "goqs/dbsql" "goqs/models" "net/http" "strconv" "strings" "github.com/gin-gonic/gin" "github.com/spf13/cast" ) // @Tags Monkey相关 /api/monkey/v1/ // @Summary 新建Monkey任务 // @Description 新建Monkey任务,创建成功后将会发送指令到monkey服务,初始status为WAITTING-等待中 // @accept x-www-form-urlencoded // @Param project formData string false "项目名" // @Param package_url formData string false "测试包下载链接" // @Param package_name formData string true "应用包名" // @Param launch_activity formData string false "启动activity页" // @Param platform formData string true "平台adr/ios" // @Param run_time formData string false "运行时间(s),默认两小时(7200s)" // @Param creator formData string false "任务创建者" // @Param mode formData string false "调用服务的方式,0-cli模式/1-api模式,默认cli" // @Success 200 {object} models.Response "返回创建的任务id" // @Router /api/monkey/v1/create_task [post] func CreateTask(c *gin.Context) { rsp := controllers.NewResponse() db, err := dbsql.GetConn(dbsql.DSN) if err != nil { rsp.Error(err.Error()) c.JSON(http.StatusOK, rsp) } defer dbsql.Close(db) var task models.MonkeyTask task.Project = c.PostForm("project") task.PackageURL = c.PostForm("package_url") task.PackageName = c.PostForm("package_name") task.LaunchActivity = c.PostForm("launch_activity") task.Platform = c.PostForm("platform") task.RunTime = cast.ToInt(c.DefaultPostForm("run_time", "7200")) task.Creator = c.PostForm("creator") task.Status = "WAITTING" // || task.Creator == "" if task.PackageName == "" || task.LaunchActivity == "" || task.Platform == "" || task.RunTime <= 10 { rsp.Error("get formdata error") rsp.Data = task c.JSON(http.StatusOK, rsp) return } var devices []models.Device is_online := false db.Model(models.Device{}).Where("project = ?", task.Project).Find(&devices) if len(devices) < 1 { rsp.Error("该产品没有注册设备,请检查") c.JSON(http.StatusOK, rsp) return } m := GetAndroidDevices() for _, v := range devices { if _, ok := m[v.Udid]; ok { is_online = true break } } if !is_online { rsp.Error("该产品没有设备在线,请检查") c.JSON(http.StatusOK, rsp) return } db.Model(models.MonkeyTask{}).Create(&task) if db.Error != nil { rsp.Error(db.Error.Error()) c.JSON(http.StatusOK, rsp) } rsp.Success() rsp.Data = task c.JSON(http.StatusOK, rsp) go runAndroidMonkeyCmd(task) } // @Tags Monkey相关 /api/monkey/v1/ // @Summary 更新Monkey任务状态 // @Description 更新Monkey任务状态,进行中为RUNNING,已完成为FINIASHED,如有错误为ERROR // @accept x-www-form-urlencoded // @Param task_id formData int true "任务id" // @Param status formData string false "要更新的任务状态" // @Success 200 {object} models.Response "返回更新后的任务信息" // @Router /api/monkey/v1/task/status [post] func UpdateTaskStatus(c *gin.Context) { rsp := controllers.NewResponse() task_id := cast.ToInt(c.PostForm("task_id")) status := c.PostForm("status") if task_id <= 0 { rsp.Error("task_id error") c.JSON(http.StatusOK, rsp) return } db, err := dbsql.GetConn(dbsql.DSN) if err != nil { rsp.Error(err.Error()) c.JSON(http.StatusOK, rsp) return } defer dbsql.Close(db) var task models.MonkeyTask db.Where("id = ?", task_id).Find(&task) if task.Id <= 0 { rsp.Error("任务不存在") c.JSON(http.StatusOK, rsp) return } task.Status = status db.Save(&task) rsp.Success() rsp.Data = task c.JSON(http.StatusOK, rsp) } // @Tags Monkey相关 /api/monkey/v1/ // @Summary 更新Monkey任务崩溃数量 // @Description 更新Monkey任务崩溃数量 // @accept x-www-form-urlencoded // @Param task_id formData int true "任务id" // @Param crash_count formData string false "要更新的崩溃数量" // @Success 200 {object} models.Response "返回更新后的任务信息" // @Router /api/monkey/v1/task/crash_count [post] func UpdateTaskCrashCount(c *gin.Context) { rsp := controllers.NewResponse() task_id := cast.ToInt(c.PostForm("task_id")) // crash_count := cast.ToInt(c.DefaultPostForm("crash_count", "0")) if task_id <= 0 { rsp.Error("task_id error") c.JSON(http.StatusOK, rsp) return } // if crash_count <= 0 { // rsp.Error("crash_count 错误或等于0,不更新") // c.JSON(http.StatusOK, rsp) // return // } db, err := dbsql.GetConn(dbsql.DSN) if err != nil { rsp.Error(err.Error()) c.JSON(http.StatusOK, rsp) } defer dbsql.Close(db) var count int64 db.Model(models.MonkeyResult{}).Where("task_id = ?", task_id).Count(&count) // var task models.MonkeyTask // db.Where("id = ?", task_id).Find(&task) // if task.Id <= 0 { // rsp.Error("任务不存在") // c.JSON(http.StatusOK, rsp) // return // } db.Model(models.MonkeyTask{}).Where("id = ?", task_id).Update("crash_count", count) rsp.Success() rsp.Data = count c.JSON(http.StatusOK, rsp) } // @Tags Monkey相关 /api/monkey/v1/ // @Summary 获取任务列表 // @Description 获取任务列表 // @accept x-www-form-urlencoded // @Param page_size query int false "每页大小,默认为10" // @Param page_index query int false "第几页,默认为第一页" // @Success 200 {object} models.Response "返回更新后的任务信息" // @Router /api/monkey/v1/tasks [get] func GetTasks(c *gin.Context) { var rsp models.Response var p models.Page pageIndex, err := strconv.Atoi(c.DefaultQuery("page_index", "1")) if rsp.CheckErr(err) { c.JSON(http.StatusOK, rsp) return } p.Index = pageIndex pageSize, err := strconv.Atoi(c.DefaultQuery("page_size", "10")) if rsp.CheckErr(err) { c.JSON(http.StatusOK, rsp) return } p.Size = pageSize db, err := dbsql.GetConn(dbsql.DSN) if rsp.CheckErr(err) { c.JSON(http.StatusOK, rsp) return } defer dbsql.Close(db) var list []models.MonkeyTask db = db.Model(&models.MonkeyTask{}) var lenght int64 db = db.Where("is_del = 0").Count(&lenght) db = dbsql.SetPageQuery(db, pageIndex, pageSize) db.Order("id desc").Find(&list) // lenght = len(list) dbsql.Close(db) db, _ = dbsql.GetConn(dbsql.DSN) for i, v := range list { var count int64 db.Model(models.MonkeyActivity{}).Where("task_id = ?", list[i].Id).Count(&count) list[i].CoveredAcitvities = int(count) // 如果状态在 进行中 or 取消中,则检查进程状态 if v.Status == "RUNNING" || v.Status == "CANCELING" { var pids []models.MonkeyPid db.Model(models.MonkeyPid{}).Where("task_id = ?", v.Id).Find(&pids) if code := checkTaskPids(pids); code == 0 { list[i].Status = "RUNNING" } else if code == 1 { if v.Status == "CANCELING" { list[i].Status = "CANCEL" db.Model(models.MonkeyTask{}).Where("id = ?", v.Id).Update("status", list[i].Status) } else if v.Status == "RUNNING" { list[i].Status = "FINISH" db.Model(models.MonkeyTask{}).Where("id = ?", v.Id).Update("status", list[i].Status) } } } } dbsql.Close(db) if p.Size >= int(lenght) { p.MaxPage = 1 } else { p.MaxPage = int64(lenght/int64(p.Size) + 1) } p.List = list p.Total = int(lenght) rsp.Success() rsp.Data = p c.JSON(http.StatusOK, rsp) } // @Tags Monkey相关 /api/monkey/v1/ // @Summary 获取monkey任务信息 // @Description 根据id获取monkey任务信息 // @accept x-www-form-urlencoded // @Param id query int false "任务id" // @Success 200 {object} models.Response "返回monkey任务信息" // @Router /api/monkey/v1/task [get] func GetTaskById(c *gin.Context) { var rsp models.Response db, err := dbsql.GetConn(dbsql.DSN) if rsp.CheckErr(err) { c.JSON(http.StatusOK, rsp) return } defer dbsql.Close(db) var data models.MonkeyTask db = db.Model(&models.MonkeyTask{}) db.Model(models.MonkeyTask{}).Where("id = ?", c.DefaultQuery("id", "0")).Last(&data) dbsql.Close(db) db, _ = dbsql.GetConn(dbsql.DSN) var count int64 db.Where("task_id = ?", data.Id).Count(&count) data.CoveredAcitvities = int(count) dbsql.Close(db) if data.Id < 1 { rsp.Error("查找不到monkey任务信息,id=" + c.Query("id")) c.JSON(http.StatusOK, rsp) return } rsp.Success() rsp.Data = data c.JSON(http.StatusOK, rsp) } // @Tags Monkey相关 /api/monkey/v1/ // @Summary 上传Logcat日志 // @Description 上传Logcat日志 // @accept x-www-form-urlencoded // @Success 200 {object} models.Response "返回成功或失败" // @Router /webdav/monkey/task/:id/:filename [put] func TaskReport(c *gin.Context) { fmt.Println(c.Request.Header) data, err := c.GetRawData() if err != nil { fmt.Println(err) c.String(http.StatusOK, "OK") return } fmt.Println(len(data)) CreateDir("./files") CreateDir("./files/monkey") CreateDir("./files/monkey/log") CreateDir("./files/monkey/log/" + c.Param("id")) CreateAndWriteFile("./files//monkey/log/"+c.Param("id")+"/"+c.Param("filename"), data) c.String(http.StatusOK, "OK") } // @Tags Monkey相关 /api/monkey/v1/ // @Summary 上报进程id // @Description 上传进程id并关联到任务 // @accept x-www-form-urlencoded // @Param task_id formData int true "任务id" // @Param pid formData int true "进程id" // @Success 200 {object} models.Response "返回成功或失败" // @Router /api/monkey/v1/task/pid [post] func UpdatePids(c *gin.Context) { var rsp models.Response db, err := dbsql.GetConn(dbsql.DSN) if rsp.CheckErr(err) { c.JSON(http.StatusOK, rsp) return } defer dbsql.Close(db) var obj models.MonkeyPid if task_id := cast.ToInt(c.PostForm("task_id")); task_id > 0 { obj.TaskId = task_id } else { rsp.Error("task_id获取失败") c.JSON(http.StatusOK, rsp) return } if pid := cast.ToInt(c.PostForm("pid")); pid > 0 { obj.PId = pid } else { rsp.Error("pid获取失败") c.JSON(http.StatusOK, rsp) return } db.Create(&obj) rsp.Success() rsp.Data = obj c.JSON(http.StatusOK, rsp) } // @Tags Monkey相关 /api/monkey/v1/ // @Summary 上报运行设备 // @Description 上报运行设备Udid,调用后追加到指定任务的设备字段中 // @accept x-www-form-urlencoded // @Param task_id formData int true "任务id" // @Param udid formData string true "设备udid" // @Success 200 {object} models.Response "返回成功或失败" // @Router /api/monkey/v1/task/update_devices [post] func UpdateDevices(c *gin.Context) { var rsp models.Response task_id := cast.ToInt(c.PostForm("task_id")) if task_id < 1 { rsp.Error("task_id获取失败") c.JSON(http.StatusOK, rsp) return } udid := c.PostForm("udid") if udid == "" { rsp.Error("pid获取失败") c.JSON(http.StatusOK, rsp) return } db, err := dbsql.GetConn(dbsql.DSN) if rsp.CheckErr(err) { c.JSON(http.StatusOK, rsp) return } defer dbsql.Close(db) var data models.MonkeyTask db = db.Model(&models.MonkeyTask{}) db.Model(models.MonkeyTask{}).Where("id = ?", task_id).Last(&data) // 处理 if strings.Contains(data.Devices, ",") || len(data.Devices) > 0 { data.Devices += "," + udid } else { data.Devices = udid } db.Model(models.MonkeyTask{}).Where("id = ?", task_id).Update("devices", data.Devices) rsp.Success() rsp.Data = data c.JSON(http.StatusOK, rsp) } // @Tags Monkey相关 /api/monkey/v1/ // @Summary 停止monkey任务 // @Description 停止monkey任务,杀死所有关联任务的进程id // @accept x-www-form-urlencoded // @Param task_id formData int true "任务id" // @Success 200 {object} models.Response "返回成功或失败" // @Router /api/monkey/v1/task/stop [post] func StopMonkeyTask(c *gin.Context) { var rsp models.Response var pids []int if task_id := cast.ToInt(c.PostForm("task_id")); task_id > 0 { db, err := dbsql.GetConn(dbsql.DSN) if rsp.CheckErr(err) { c.JSON(http.StatusOK, rsp) return } defer dbsql.Close(db) db.Model(models.MonkeyTask{}).Where("id = ?", task_id).Update("status", "CANCELING") var list []models.MonkeyPid db.Where("task_id = ? and is_del = 0", task_id).Find(&list) for _, v := range list { killPid(v.PId) pids = append(pids, v.PId) } } rsp.Success() rsp.Data = pids c.JSON(http.StatusOK, rsp) }