diff --git a/crontask/corn.go b/crontask/corn.go index af7976c..0544c32 100644 --- a/crontask/corn.go +++ b/crontask/corn.go @@ -8,6 +8,7 @@ import ( "fmt" "os/exec" "strings" + "time" "github.com/robfig/cron/v3" "github.com/spf13/cast" @@ -93,16 +94,27 @@ func CheckTaskStatus() { var list []models.MonkeyTask db.Model(models.MonkeyTask{}).Where("status = ?", "RUNNING").Find(&list) 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) - var pids []models.MonkeyPid - db.Model(models.MonkeyPid{}).Where("task_id = ?", v.Id).Find(&pids) - if code := checkTaskPids(pids); code != 0 { - list[i].Status = "FINISH" - db.Model(models.MonkeyTask{}).Where("id = ?", v.Id).Update("status", list[i].Status) - common.PushMonkeyResult(v) + // 如果无对应正在运行的容器,判断为【结束】或【异常停止】 + if len(monkey.GetTaskFromDocker(v.Id)) == 0 { + // 如果预期结束时间(任务开始时间+运行时间) < 当前时间,判断任务为运行正常结束 + if v.UpdateTime+v.RunTime < int(time.Now().Unix()) { + list[i].Status = "FINISH" + db.Table(v.TableName()).Model(models.MonkeyTask{}).Where("id = ?", v.Id).Update("status", list[i].Status) + } else { + common.PushCorntaskLog("任务状态似乎异常,task_id=" + cast.ToString(v.Id)) + } } + continue + // var count int64 + // db.Model(models.MonkeyActivity{}).Where("task_id = ?", list[i].Id).Count(&count) + // list[i].CoveredAcitvities = int(count) + // var pids []models.MonkeyPid + // db.Model(models.MonkeyPid{}).Where("task_id = ?", v.Id).Find(&pids) + // if code := checkTaskPids(pids); code != 0 { + // list[i].Status = "FINISH" + // db.Model(models.MonkeyTask{}).Where("id = ?", v.Id).Update("status", list[i].Status) + // common.PushMonkeyResult(v) + // } } } diff --git a/crontask/monkey.go b/crontask/monkey.go index 61e71f1..b630426 100644 --- a/crontask/monkey.go +++ b/crontask/monkey.go @@ -6,6 +6,9 @@ import ( "autogo/models" "autogo/monkey" "strings" + "time" + + "github.com/spf13/cast" ) func CheckMonkeyTasks() { @@ -34,15 +37,26 @@ func CheckMonkeyTasks() { common.PushCorntaskLog("执行Monkey任务:" + task.Project + "-" + device.Udid) } db.Model(models.MonkeyTask{}).Where("status = ? AND is_del = 0", "RUNNING").Find(&list) - for _, task := range list { - var pids []models.MonkeyPid - db.Model(models.MonkeyPid{}).Where("task_id = ?", task.Id).Find(&pids) - if code := checkTaskPids(pids); code == 0 { - task.Status = "RUNNING" - } else if code == 1 { - task.Status = "FINISH" - db.Model(models.MonkeyTask{}).Where("id = ?", task.Id).Update("status", task.Status) - common.PushMonkeyResult(task) + for i, v := range list { + // 如果无对应正在运行的容器,判断为【结束】或【异常停止】 + if len(monkey.GetTaskFromDocker(v.Id)) == 0 { + // 如果预期结束时间(任务开始时间+运行时间) < 当前时间,判断任务为运行正常结束 + if v.UpdateTime+v.RunTime < int(time.Now().Unix()) { + list[i].Status = "FINISH" + db.Table(v.TableName()).Model(models.MonkeyTask{}).Where("id = ?", v.Id).Update("status", list[i].Status) + common.PushMonkeyResult(v) + } else { + common.PushCorntaskLog("任务状态似乎异常,task_id=" + cast.ToString(v.Id)) + } } + // var pids []models.MonkeyPid + // db.Model(models.MonkeyPid{}).Where("task_id = ?", task.Id).Find(&pids) + // if code := checkTaskPids(pids); code == 0 { + // task.Status = "RUNNING" + // } else if code == 1 { + // task.Status = "FINISH" + // db.Model(models.MonkeyTask{}).Where("id = ?", task.Id).Update("status", task.Status) + // common.PushMonkeyResult(task) + // } } } diff --git a/models/monkey_task.go b/models/monkey_task.go index 835c905..38c9ff1 100644 --- a/models/monkey_task.go +++ b/models/monkey_task.go @@ -1,6 +1,10 @@ package models -import "errors" +import ( + "errors" + + "github.com/spf13/cast" +) type MonkeyTask struct { Id int `json:"id" gorm:"column:id;type:int(11);primary_key;not null;autoIncrement;comment:主键"` @@ -31,6 +35,41 @@ func (m *MonkeyTask) TableName() string { return "monkey_task" } +func (task *MonkeyTask) Cmd(udid string, filename string) string { + cmd_str := "" + switch task.Platform { + case "adr": + + cmd_str = "docker run -d --rm --name monkey_task_" + cast.ToString(task.Id) + "_" + udid + " --net=host " + cmd_str += "-e TASK_ID=" + cast.ToString(task.Id) + " " + cmd_str += "-e PACKAGE=" + task.PackageName + " " + cmd_str += "-e RUN_TIME=" + cast.ToString(task.RunTime) + " " + cmd_str += "-e DEVICE=" + udid + " " + cmd_str += "-v /home/tmp/pkg/" + filename + ":/tmp/test.apk" + " " + cmd_str += "-v /home/app/uat:/home/app/uat" + " " + cmd_str += "monkey-adr" + + // cmd_str = "cd /home/app/monkey && nohup python3 main_adr.py" + + // " -task_id " + cast.ToString(task.Id) + // if task.PackageURL != "" { + + // cmd_str += " -pkg_path " + filename + + // } + // cmd_str += " -package " + task.PackageName + // if task.LaunchActivity != "" { + // cmd_str += " -launch_activity " + task.LaunchActivity + // } + // cmd_str += " -run_time " + cast.ToString(task.RunTime) + // if udid != "" { + // cmd_str += " -device_udid " + udid + // } + // cmd_str += " >> /home/app/logs/task_output/task_" + cast.ToString(task.Id) + ".log 2>&1" + + } + return cmd_str +} + func (t *MonkeyTask) Check() error { if t.Project == "" { return errors.New("task.Project为空") diff --git a/monkey/cli_adr.go b/monkey/cli_adr.go index 6513726..d5be4fc 100644 --- a/monkey/cli_adr.go +++ b/monkey/cli_adr.go @@ -18,6 +18,15 @@ import ( // } func RunAndroidMonkeyCmd(task models.MonkeyTask, udid string) { + filename := cast.ToString(time.Now().Unix()) + ".apk" + pkg_path := "/home/tmp/pkg/" + filename + log.Debug("正在下载apk:", task.PackageURL) + err := exec.Command("wget", task.PackageURL, "-O", pkg_path).Run() + if err != nil { + log.Error(err) + } + log.Debug("下载完毕,安装包路径", pkg_path) + db, err := dbsql.GetConn(dbsql.DSN) if err != nil { return @@ -25,27 +34,7 @@ func RunAndroidMonkeyCmd(task models.MonkeyTask, udid string) { defer dbsql.Close(db) db.Model(models.MonkeyTask{}).Where("id = ?", task.Id).Update("status", "INIT") // python main_adr.py -package music.hising.live.dev -launch_activity sing.lagufun.social.live.ui.activity.SplashActivity - cmd_content := "cd /home/app/monkey && nohup python3 main_adr.py" + - " -task_id " + cast.ToString(task.Id) - if task.PackageURL != "" { - pkg_path := "/home/tmp/pkg/" + cast.ToString(time.Now().Unix()) + ".apk" - log.Debug("正在下载apk:", task.PackageURL) - err := exec.Command("wget", task.PackageURL, "-O", pkg_path).Run() - if err != nil { - log.Error(err) - } - cmd_content += " -pkg_path " + pkg_path - log.Debug("下载完毕,安装包路径", pkg_path) - } - cmd_content += " -package " + task.PackageName - if task.LaunchActivity != "" { - cmd_content += " -launch_activity " + task.LaunchActivity - } - cmd_content += " -run_time " + cast.ToString(task.RunTime) - if udid != "" { - cmd_content += " -device_udid " + udid - } - cmd_content += " >> /home/app/logs/task_output/task_" + cast.ToString(task.Id) + ".log 2>&1" + cmd_content := task.Cmd(udid, filename) db.Model(models.MonkeyTask{}).Where("id = ?", task.Id).Last(&task) if task.Status != "INIT" { diff --git a/monkey/cli_docker.go b/monkey/cli_docker.go new file mode 100644 index 0000000..1d16a5a --- /dev/null +++ b/monkey/cli_docker.go @@ -0,0 +1,57 @@ +package monkey + +import ( + "fmt" + "os/exec" + "strings" + + "github.com/spf13/cast" +) + +type DockerContainer struct { + ID string `json:"id"` + Name string `json:"name"` + Device string `json:"device"` +} + +// 根据任务id获取关联容器,由于后续可能支持一个任务绑定多个设备执行,所以返回数组 +func GetTaskFromDocker(task_id int) []DockerContainer { + var list []DockerContainer + cmd := exec.Command("docker", "ps") + output, err := cmd.Output() + if err != nil { + fmt.Println(err) + return list + } + + lines := strings.Split(string(output), "\n") + for i, line := range lines { + if i == 0 { + continue // skip header line + } + fields := strings.Fields(line) + if len(fields) >= 7 { + // fmt.Printf("Container ID: %s, Name: %s\n", fields[0], fields[len(fields)-1]) + var c DockerContainer + c.ID = fields[0] + c.Name = fields[len(fields)-1] + _strs := strings.Split(c.Name, "_") + c.Device = _strs[len(_strs)-1] + if strings.Contains(c.Name, "monkey_task_"+cast.ToString(task_id)+"_") { + list = append(list, c) + } + } + } + return list +} + +func StopDockerContainer(container_name string) bool { + cmd := exec.Command("docker", "stop", "-t", "0", container_name) + out, err := cmd.CombinedOutput() + if err != nil { + fmt.Println("[docker] Error stopping container:", err) + return false + } + fmt.Println("[docker] Container stopped successfully:", string(out)) + return true +} diff --git a/monkey/task.go b/monkey/task.go index d4b06f9..ccafde0 100644 --- a/monkey/task.go +++ b/monkey/task.go @@ -426,8 +426,33 @@ func UpdateDevices(c *gin.Context) { // @Router /api/monkey/v1/task/stop [post] func StopMonkeyTask(c *gin.Context) { var rsp models.Response - var pids []int + 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("monkey_task").Model(models.MonkeyTask{}).Where("id = ?", task_id).Update("status", "CANCEL") + db.Table("device").Model(models.Device{}).Where("udid = ?", v.Device).Update("status", "online") + } + } + + rsp.Data = list + 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 { diff --git a/test/test.go b/test/test.go index 7a79745..ea98d65 100644 --- a/test/test.go +++ b/test/test.go @@ -3,12 +3,72 @@ package main import ( "autogo/common" "autogo/dbsql" + "autogo/device" "autogo/models" "autogo/monkey" "fmt" + "os/exec" + "strings" + "time" ) func main() { + cmd := exec.Command("docker", "ps") + output, err := cmd.Output() + if err != nil { + fmt.Println(err) + return + } + + lines := strings.Split(string(output), "\n") + for i, line := range lines { + if i == 0 { + continue // skip header line + } + fields := strings.Fields(line) + if len(fields) >= 7 { + fmt.Printf("Container ID: %s, Name: %s\n", fields[0], fields[len(fields)-1]) + getRuntime(fields[0]) + } + } + fmt.Println("end") +} + +func getRuntime(containerID string) { + + // 执行 docker inspect 命令获取容器创建时间 + cmd := exec.Command("docker", "inspect", "-f", "{{.Created}}", containerID) + output, err := cmd.Output() + if err != nil { + fmt.Println(err) + return + } + + // 将输出结果转换为时间格式 + createdTime, err := time.Parse(time.RFC3339Nano, strings.TrimSpace(string(output))) + if err != nil { + fmt.Println(err) + return + } + + // 计算容器已经运行的时间 + uptime := time.Since(createdTime) + + // 将容器运行时间转换为秒级时间戳输出 + uptimeInSeconds := int64(uptime.Seconds()) + fmt.Printf("Container %s has been running for %d seconds\n", containerID, uptimeInSeconds) +} + +func sib() { + if device.CheckSib() { + fmt.Println("sib已安装") + fmt.Println(device.GetIOSDevices()) + } else { + fmt.Println("sib未安装") + } +} + +func tmp1() { dbsql.DSN = dbsql.DSN_local db, err := dbsql.GetConn(dbsql.DSN) if err != nil { @@ -42,7 +102,6 @@ func main() { } } } - // // common.GetBranch("", "") } func Dir() {