You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

511 lines
15 KiB
Go

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package monkey
import (
"autogo/common"
"autogo/controllers"
"autogo/dbsql"
"autogo/models"
"fmt"
"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已完成为FINISH如有错误为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)
fmt.Println("更新设备状态为", status)
if status == "FINISH" {
common.PushMonkeyResult(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 "第几页,默认为第一页"
// @Param project 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 err != nil {
c.JSON(http.StatusOK, rsp.Error(err.Error()))
return
}
p.Index = pageIndex
pageSize, err := strconv.Atoi(c.DefaultQuery("page_size", "10"))
if err != nil {
c.JSON(http.StatusOK, rsp.Error(err.Error()))
return
}
p.Size = pageSize
project := c.DefaultQuery("project", "")
db, err := dbsql.GetConn(dbsql.DSN)
if err != nil {
c.JSON(http.StatusOK, rsp.Error(err.Error()))
return
}
defer dbsql.Close(db)
var list []models.MonkeyTask
db = db.Model(&models.MonkeyTask{})
var lenght int64
if project != "" {
db = db.Where("project = ?", project)
}
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, _ := 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 err != nil {
c.JSON(http.StatusOK, rsp.Error(err.Error()))
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 文件相关 /webdav
// @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 err != nil {
c.JSON(http.StatusOK, rsp.Error(err.Error()))
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 err != nil {
c.JSON(http.StatusOK, rsp.Error(err.Error()))
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
task_id := cast.ToInt(c.PostForm("task_id"))
if task_id < 1 {
c.JSON(http.StatusOK, rsp.Error("task_id error: "+c.PostForm("task_id")))
return
}
db, err := dbsql.GetConn(dbsql.DSN)
if err != nil {
c.JSON(http.StatusOK, rsp.Error(err.Error()))
return
}
defer dbsql.Close(db)
list := GetTaskFromDocker(task_id)
for _, v := range list {
if StopDockerContainer(v.Name) {
db.Table("device").Model(models.Device{}).Where("udid = ?", v.Device).Update("status", "online")
}
}
db.Table("monkey_task").Model(models.MonkeyTask{}).Where("id = ?", task_id).Update("status", "CANCEL")
rsp.Data = "done"
c.JSON(http.StatusOK, rsp.Success())
return
var pids []int
if task_id := cast.ToInt(c.PostForm("task_id")); task_id > 0 {
db, err := dbsql.GetConn(dbsql.DSN)
if err != nil {
c.JSON(http.StatusOK, rsp.Error(err.Error()))
return
}
defer dbsql.Close(db)
var task models.MonkeyTask
db.Model(models.MonkeyTask{}).Where("id = ?", task_id).First(&task)
// 如果monkey任务未开始(status=WAITTING,INIT)直接更新状态为CANCEL
if task.Status == "WAITTING" || task.Status == "INIT" {
db.Model(models.MonkeyTask{}).Where("id = ?", task_id).Update("status", "CANCEL")
rsp.Success()
rsp.Data = "from " + task.Status + " to CANCEL"
c.JSON(http.StatusOK, rsp)
return
}
db.Model(models.MonkeyTask{}).Where("id = ?", task_id).Update("status", "CANCELING")
// 更新设备状态
db.Model(models.MonkeyTask{}).Where("id = ?", task_id).Last(&task)
if strings.Contains(task.Devices, ",") {
} else {
var device models.Device
db.Table("device").Model(models.Device{}).Where("udid = ?", task.Devices).Last(&device)
if device.Status == "busy" {
db.Table("device").Model(models.Device{}).Where("udid = ?", task.Devices).Update("status", "online")
}
}
var list []models.MonkeyPid
db.Table("monkey_pid").Model(models.MonkeyPid{}).Where("task_id = ? and is_del = 0", task_id).Find(&list)
for _, v := range list {
killPid(v.PId)
pids = append(pids, v.PId)
}
//判断是否停止成功
var pids []models.MonkeyPid
db.Table("monkey_pid").Model(models.MonkeyPid{}).Where("task_id = ?", task.Id).Find(&pids)
if code := checkTaskPids(pids); code == 1 {
task.Status = "CANCEL"
db.Model(models.MonkeyTask{}).Where("id = ?", task.Id).Update("status", task.Status)
}
}
rsp.Success()
rsp.Data = pids
c.JSON(http.StatusOK, rsp)
}