master
luziqi 3 years ago
parent 8b4246ea9d
commit 940cdfc0e7

@ -101,6 +101,281 @@ var doc = `{
}
}
},
"/api/monkey/v1/devices": {
"get": {
"description": "获取安卓设备列表",
"consumes": [
"application/x-www-form-urlencoded"
],
"tags": [
"Monkey相关 /api/monkey/v1/"
],
"summary": "获取设备列表",
"parameters": [
{
"type": "integer",
"description": "平台ios/adr",
"name": "platform",
"in": "query"
}
],
"responses": {
"200": {
"description": "返回设备信息",
"schema": {
"$ref": "#/definitions/models.Response"
}
}
}
}
},
"/api/monkey/v1/task": {
"get": {
"description": "根据id获取monkey任务信息",
"consumes": [
"application/x-www-form-urlencoded"
],
"tags": [
"Monkey相关 /api/monkey/v1/"
],
"summary": "获取monkey任务信息",
"parameters": [
{
"type": "integer",
"description": "任务id",
"name": "id",
"in": "query"
}
],
"responses": {
"200": {
"description": "返回monkey任务信息",
"schema": {
"$ref": "#/definitions/models.Response"
}
}
}
}
},
"/api/monkey/v1/task/activity": {
"get": {
"description": "通过monkey任务id获取覆盖的活动页面",
"consumes": [
"application/x-www-form-urlencoded"
],
"tags": [
"Monkey相关 /api/monkey/v1/"
],
"summary": "获取覆盖页面列表",
"parameters": [
{
"type": "integer",
"description": "任务id",
"name": "task_id",
"in": "query",
"required": true
}
],
"responses": {
"200": {
"description": "返回任务覆盖的活动页",
"schema": {
"$ref": "#/definitions/models.Response"
}
}
}
},
"post": {
"description": "Android上报activity名",
"consumes": [
"application/x-www-form-urlencoded"
],
"tags": [
"Monkey相关 /api/monkey/v1/"
],
"summary": "上报Monkey应用页",
"parameters": [
{
"type": "integer",
"description": "任务id",
"name": "task_id",
"in": "formData",
"required": true
},
{
"type": "string",
"description": "设备id",
"name": "device_name",
"in": "formData"
},
{
"type": "string",
"description": "页面名称",
"name": "activity_name",
"in": "formData"
}
],
"responses": {
"200": {
"description": "返回更新后的任务信息",
"schema": {
"$ref": "#/definitions/models.Response"
}
}
}
}
},
"/api/monkey/v1/task/crash_count": {
"post": {
"description": "更新Monkey任务崩溃数量",
"consumes": [
"application/x-www-form-urlencoded"
],
"tags": [
"Monkey相关 /api/monkey/v1/"
],
"summary": "更新Monkey任务崩溃数量",
"parameters": [
{
"type": "integer",
"description": "任务id",
"name": "task_id",
"in": "formData",
"required": true
},
{
"type": "string",
"description": "要更新的崩溃数量",
"name": "crash_count",
"in": "formData"
}
],
"responses": {
"200": {
"description": "返回更新后的任务信息",
"schema": {
"$ref": "#/definitions/models.Response"
}
}
}
}
},
"/api/monkey/v1/task/pid": {
"post": {
"description": "上传进程id并关联到任务",
"consumes": [
"application/x-www-form-urlencoded"
],
"tags": [
"Monkey相关 /api/monkey/v1/"
],
"summary": "上报进程id",
"parameters": [
{
"type": "integer",
"description": "任务id",
"name": "task_id",
"in": "formData",
"required": true
},
{
"type": "integer",
"description": "进程id",
"name": "pid",
"in": "formData",
"required": true
}
],
"responses": {
"200": {
"description": "返回成功或失败",
"schema": {
"$ref": "#/definitions/models.Response"
}
}
}
}
},
"/api/monkey/v1/task/result": {
"get": {
"description": "通过任务id获取Monkey结果",
"consumes": [
"application/x-www-form-urlencoded"
],
"tags": [
"Monkey相关 /api/monkey/v1/"
],
"summary": "获取Monkey结果",
"parameters": [
{
"type": "integer",
"description": "任务id",
"name": "task_id",
"in": "query",
"required": true
}
],
"responses": {
"200": {
"description": "返回任务结果",
"schema": {
"$ref": "#/definitions/models.Response"
}
}
}
},
"post": {
"description": "上报Monkey结果",
"consumes": [
"application/x-www-form-urlencoded"
],
"tags": [
"Monkey相关 /api/monkey/v1/"
],
"summary": "上报Monkey结果",
"parameters": [
{
"type": "integer",
"description": "任务id",
"name": "task_id",
"in": "formData",
"required": true
},
{
"type": "string",
"description": "要更新的任务状态",
"name": "crash_log_list",
"in": "formData"
},
{
"type": "string",
"description": "要更新的任务状态",
"name": "activity_name_info",
"in": "formData"
},
{
"type": "string",
"description": "要更新的任务状态",
"name": "device_name",
"in": "formData"
},
{
"type": "string",
"description": "要更新的任务状态",
"name": "status",
"in": "formData"
}
],
"responses": {
"200": {
"description": "返回更新后的任务信息",
"schema": {
"$ref": "#/definitions/models.Response"
}
}
}
}
},
"/api/monkey/v1/task/status": {
"post": {
"description": "更新Monkey任务状态进行中为RUNNING已完成为FINIASHED如有错误为ERROR",
@ -114,7 +389,7 @@ var doc = `{
"parameters": [
{
"type": "integer",
"description": "项目名",
"description": "任务id",
"name": "task_id",
"in": "formData",
"required": true
@ -136,6 +411,35 @@ var doc = `{
}
}
},
"/api/monkey/v1/task/stop": {
"post": {
"description": "停止monkey任务杀死所有关联任务的进程id",
"consumes": [
"application/x-www-form-urlencoded"
],
"tags": [
"Monkey相关 /api/monkey/v1/"
],
"summary": "停止monkey任务",
"parameters": [
{
"type": "integer",
"description": "任务id",
"name": "task_id",
"in": "formData",
"required": true
}
],
"responses": {
"200": {
"description": "返回成功或失败",
"schema": {
"$ref": "#/definitions/models.Response"
}
}
}
}
},
"/api/monkey/v1/tasks": {
"get": {
"description": "获取任务列表",
@ -169,6 +473,26 @@ var doc = `{
}
}
}
},
"/webdav/monkey/task/:id/:filename": {
"put": {
"description": "上传Logcat日志",
"consumes": [
"application/x-www-form-urlencoded"
],
"tags": [
"Monkey相关 /api/monkey/v1/"
],
"summary": "上传Logcat日志",
"responses": {
"200": {
"description": "返回成功或失败",
"schema": {
"$ref": "#/definitions/models.Response"
}
}
}
}
}
},
"definitions": {

@ -82,6 +82,281 @@
}
}
},
"/api/monkey/v1/devices": {
"get": {
"description": "获取安卓设备列表",
"consumes": [
"application/x-www-form-urlencoded"
],
"tags": [
"Monkey相关 /api/monkey/v1/"
],
"summary": "获取设备列表",
"parameters": [
{
"type": "integer",
"description": "平台ios/adr",
"name": "platform",
"in": "query"
}
],
"responses": {
"200": {
"description": "返回设备信息",
"schema": {
"$ref": "#/definitions/models.Response"
}
}
}
}
},
"/api/monkey/v1/task": {
"get": {
"description": "根据id获取monkey任务信息",
"consumes": [
"application/x-www-form-urlencoded"
],
"tags": [
"Monkey相关 /api/monkey/v1/"
],
"summary": "获取monkey任务信息",
"parameters": [
{
"type": "integer",
"description": "任务id",
"name": "id",
"in": "query"
}
],
"responses": {
"200": {
"description": "返回monkey任务信息",
"schema": {
"$ref": "#/definitions/models.Response"
}
}
}
}
},
"/api/monkey/v1/task/activity": {
"get": {
"description": "通过monkey任务id获取覆盖的活动页面",
"consumes": [
"application/x-www-form-urlencoded"
],
"tags": [
"Monkey相关 /api/monkey/v1/"
],
"summary": "获取覆盖页面列表",
"parameters": [
{
"type": "integer",
"description": "任务id",
"name": "task_id",
"in": "query",
"required": true
}
],
"responses": {
"200": {
"description": "返回任务覆盖的活动页",
"schema": {
"$ref": "#/definitions/models.Response"
}
}
}
},
"post": {
"description": "Android上报activity名",
"consumes": [
"application/x-www-form-urlencoded"
],
"tags": [
"Monkey相关 /api/monkey/v1/"
],
"summary": "上报Monkey应用页",
"parameters": [
{
"type": "integer",
"description": "任务id",
"name": "task_id",
"in": "formData",
"required": true
},
{
"type": "string",
"description": "设备id",
"name": "device_name",
"in": "formData"
},
{
"type": "string",
"description": "页面名称",
"name": "activity_name",
"in": "formData"
}
],
"responses": {
"200": {
"description": "返回更新后的任务信息",
"schema": {
"$ref": "#/definitions/models.Response"
}
}
}
}
},
"/api/monkey/v1/task/crash_count": {
"post": {
"description": "更新Monkey任务崩溃数量",
"consumes": [
"application/x-www-form-urlencoded"
],
"tags": [
"Monkey相关 /api/monkey/v1/"
],
"summary": "更新Monkey任务崩溃数量",
"parameters": [
{
"type": "integer",
"description": "任务id",
"name": "task_id",
"in": "formData",
"required": true
},
{
"type": "string",
"description": "要更新的崩溃数量",
"name": "crash_count",
"in": "formData"
}
],
"responses": {
"200": {
"description": "返回更新后的任务信息",
"schema": {
"$ref": "#/definitions/models.Response"
}
}
}
}
},
"/api/monkey/v1/task/pid": {
"post": {
"description": "上传进程id并关联到任务",
"consumes": [
"application/x-www-form-urlencoded"
],
"tags": [
"Monkey相关 /api/monkey/v1/"
],
"summary": "上报进程id",
"parameters": [
{
"type": "integer",
"description": "任务id",
"name": "task_id",
"in": "formData",
"required": true
},
{
"type": "integer",
"description": "进程id",
"name": "pid",
"in": "formData",
"required": true
}
],
"responses": {
"200": {
"description": "返回成功或失败",
"schema": {
"$ref": "#/definitions/models.Response"
}
}
}
}
},
"/api/monkey/v1/task/result": {
"get": {
"description": "通过任务id获取Monkey结果",
"consumes": [
"application/x-www-form-urlencoded"
],
"tags": [
"Monkey相关 /api/monkey/v1/"
],
"summary": "获取Monkey结果",
"parameters": [
{
"type": "integer",
"description": "任务id",
"name": "task_id",
"in": "query",
"required": true
}
],
"responses": {
"200": {
"description": "返回任务结果",
"schema": {
"$ref": "#/definitions/models.Response"
}
}
}
},
"post": {
"description": "上报Monkey结果",
"consumes": [
"application/x-www-form-urlencoded"
],
"tags": [
"Monkey相关 /api/monkey/v1/"
],
"summary": "上报Monkey结果",
"parameters": [
{
"type": "integer",
"description": "任务id",
"name": "task_id",
"in": "formData",
"required": true
},
{
"type": "string",
"description": "要更新的任务状态",
"name": "crash_log_list",
"in": "formData"
},
{
"type": "string",
"description": "要更新的任务状态",
"name": "activity_name_info",
"in": "formData"
},
{
"type": "string",
"description": "要更新的任务状态",
"name": "device_name",
"in": "formData"
},
{
"type": "string",
"description": "要更新的任务状态",
"name": "status",
"in": "formData"
}
],
"responses": {
"200": {
"description": "返回更新后的任务信息",
"schema": {
"$ref": "#/definitions/models.Response"
}
}
}
}
},
"/api/monkey/v1/task/status": {
"post": {
"description": "更新Monkey任务状态进行中为RUNNING已完成为FINIASHED如有错误为ERROR",
@ -95,7 +370,7 @@
"parameters": [
{
"type": "integer",
"description": "项目名",
"description": "任务id",
"name": "task_id",
"in": "formData",
"required": true
@ -117,6 +392,35 @@
}
}
},
"/api/monkey/v1/task/stop": {
"post": {
"description": "停止monkey任务杀死所有关联任务的进程id",
"consumes": [
"application/x-www-form-urlencoded"
],
"tags": [
"Monkey相关 /api/monkey/v1/"
],
"summary": "停止monkey任务",
"parameters": [
{
"type": "integer",
"description": "任务id",
"name": "task_id",
"in": "formData",
"required": true
}
],
"responses": {
"200": {
"description": "返回成功或失败",
"schema": {
"$ref": "#/definitions/models.Response"
}
}
}
}
},
"/api/monkey/v1/tasks": {
"get": {
"description": "获取任务列表",
@ -150,6 +454,26 @@
}
}
}
},
"/webdav/monkey/task/:id/:filename": {
"put": {
"description": "上传Logcat日志",
"consumes": [
"application/x-www-form-urlencoded"
],
"tags": [
"Monkey相关 /api/monkey/v1/"
],
"summary": "上传Logcat日志",
"responses": {
"200": {
"description": "返回成功或失败",
"schema": {
"$ref": "#/definitions/models.Response"
}
}
}
}
}
},
"definitions": {

@ -62,13 +62,194 @@ paths:
summary: 新建Monkey任务
tags:
- Monkey相关 /api/monkey/v1/
/api/monkey/v1/devices:
get:
consumes:
- application/x-www-form-urlencoded
description: 获取安卓设备列表
parameters:
- description: 平台ios/adr
in: query
name: platform
type: integer
responses:
"200":
description: 返回设备信息
schema:
$ref: '#/definitions/models.Response'
summary: 获取设备列表
tags:
- Monkey相关 /api/monkey/v1/
/api/monkey/v1/task:
get:
consumes:
- application/x-www-form-urlencoded
description: 根据id获取monkey任务信息
parameters:
- description: 任务id
in: query
name: id
type: integer
responses:
"200":
description: 返回monkey任务信息
schema:
$ref: '#/definitions/models.Response'
summary: 获取monkey任务信息
tags:
- Monkey相关 /api/monkey/v1/
/api/monkey/v1/task/activity:
get:
consumes:
- application/x-www-form-urlencoded
description: 通过monkey任务id获取覆盖的活动页面
parameters:
- description: 任务id
in: query
name: task_id
required: true
type: integer
responses:
"200":
description: 返回任务覆盖的活动页
schema:
$ref: '#/definitions/models.Response'
summary: 获取覆盖页面列表
tags:
- Monkey相关 /api/monkey/v1/
post:
consumes:
- application/x-www-form-urlencoded
description: Android上报activity名
parameters:
- description: 任务id
in: formData
name: task_id
required: true
type: integer
- description: 设备id
in: formData
name: device_name
type: string
- description: 页面名称
in: formData
name: activity_name
type: string
responses:
"200":
description: 返回更新后的任务信息
schema:
$ref: '#/definitions/models.Response'
summary: 上报Monkey应用页
tags:
- Monkey相关 /api/monkey/v1/
/api/monkey/v1/task/crash_count:
post:
consumes:
- application/x-www-form-urlencoded
description: 更新Monkey任务崩溃数量
parameters:
- description: 任务id
in: formData
name: task_id
required: true
type: integer
- description: 要更新的崩溃数量
in: formData
name: crash_count
type: string
responses:
"200":
description: 返回更新后的任务信息
schema:
$ref: '#/definitions/models.Response'
summary: 更新Monkey任务崩溃数量
tags:
- Monkey相关 /api/monkey/v1/
/api/monkey/v1/task/pid:
post:
consumes:
- application/x-www-form-urlencoded
description: 上传进程id并关联到任务
parameters:
- description: 任务id
in: formData
name: task_id
required: true
type: integer
- description: 进程id
in: formData
name: pid
required: true
type: integer
responses:
"200":
description: 返回成功或失败
schema:
$ref: '#/definitions/models.Response'
summary: 上报进程id
tags:
- Monkey相关 /api/monkey/v1/
/api/monkey/v1/task/result:
get:
consumes:
- application/x-www-form-urlencoded
description: 通过任务id获取Monkey结果
parameters:
- description: 任务id
in: query
name: task_id
required: true
type: integer
responses:
"200":
description: 返回任务结果
schema:
$ref: '#/definitions/models.Response'
summary: 获取Monkey结果
tags:
- Monkey相关 /api/monkey/v1/
post:
consumes:
- application/x-www-form-urlencoded
description: 上报Monkey结果
parameters:
- description: 任务id
in: formData
name: task_id
required: true
type: integer
- description: 要更新的任务状态
in: formData
name: crash_log_list
type: string
- description: 要更新的任务状态
in: formData
name: activity_name_info
type: string
- description: 要更新的任务状态
in: formData
name: device_name
type: string
- description: 要更新的任务状态
in: formData
name: status
type: string
responses:
"200":
description: 返回更新后的任务信息
schema:
$ref: '#/definitions/models.Response'
summary: 上报Monkey结果
tags:
- Monkey相关 /api/monkey/v1/
/api/monkey/v1/task/status:
post:
consumes:
- application/x-www-form-urlencoded
description: 更新Monkey任务状态进行中为RUNNING已完成为FINIASHED如有错误为ERROR
parameters:
- description: 项目名
- description: 任务id
in: formData
name: task_id
required: true
@ -85,6 +266,25 @@ paths:
summary: 更新Monkey任务状态
tags:
- Monkey相关 /api/monkey/v1/
/api/monkey/v1/task/stop:
post:
consumes:
- application/x-www-form-urlencoded
description: 停止monkey任务杀死所有关联任务的进程id
parameters:
- description: 任务id
in: formData
name: task_id
required: true
type: integer
responses:
"200":
description: 返回成功或失败
schema:
$ref: '#/definitions/models.Response'
summary: 停止monkey任务
tags:
- Monkey相关 /api/monkey/v1/
/api/monkey/v1/tasks:
get:
consumes:
@ -107,4 +307,17 @@ paths:
summary: 获取任务列表
tags:
- Monkey相关 /api/monkey/v1/
/webdav/monkey/task/:id/:filename:
put:
consumes:
- application/x-www-form-urlencoded
description: 上传Logcat日志
responses:
"200":
description: 返回成功或失败
schema:
$ref: '#/definitions/models.Response'
summary: 上传Logcat日志
tags:
- Monkey相关 /api/monkey/v1/
swagger: "2.0"

@ -0,0 +1,10 @@
package global
import "time"
type MODEL struct {
ID uint `json:"id" gorm:"column:id;type:int(11);primary_key;not null;autoIncrement;comment:主键"`
CreateTime time.Time `json:"create_time" gorm:"column:create_time;type:int(11);not null;autoCreateTime;comment:创建时间"`
UpdateTime time.Time `json:"update_time" gorm:"column:update_time;type:int(11);not null;autoUpdateTime;comment:更新时间"`
IsDel int `json:"-" gorm:"column:is_del;type:int(1);not null;comment:是否已删除"`
}

@ -56,7 +56,17 @@ func main() {
// monkey
r.POST("/api/monkey/v1/create_task", monkey.CreateTask)
r.POST("/api/monkey/v1/task/status", monkey.UpdateTaskStatus)
r.POST("/api/monkey/v1/task/result", monkey.UploadMonkeyResult)
r.POST("/api/monkey/v1/task/stop", monkey.StopMonkeyTask)
r.POST("/api/monkey/v1/task/pid", monkey.UpdatePids)
r.GET("/api/monkey/v1/task/result", monkey.GetMonkeyResult)
r.POST("/api/monkey/v1/task/activity", monkey.UpdataActivity)
r.GET("/api/monkey/v1/task/activity", monkey.GetMonkeyActivities)
r.GET("/api/monkey/v1/tasks", monkey.GetTasks)
r.GET("/api/monkey/v1/task", monkey.GetTaskById)
r.GET("/api/monkey/v1/devices", monkey.GetDevices)
r.POST("/api/monkey/v1/task/crash_count", monkey.UpdateTaskCrashCount)
r.PUT("/webdav/monkey/task/:id/:filename", monkey.TaskReport)
r.Run(port)

@ -0,0 +1,14 @@
package models
import "goqs/global"
type MonkeyActivity struct {
global.MODEL
TaskId int `json:"task_id"`
DeviceName string `json:"device_name"`
ActivityName string `json:"activity_name"`
}
func (m *MonkeyActivity) TableName() string {
return "monkey_activity"
}

@ -0,0 +1,26 @@
package models
import "goqs/global"
type Device struct {
global.MODEL
Project string `json:"project"`
ProductName string `json:"product_name" gorm:"product_name"`
Udid string `json:"udid" gorm:"udid"`
Status string `json:"status" gorm:"status"`
Platform string `json:"platform" gorm:"platform"`
}
func (d *Device) TableName() string {
return "device"
}
type MonkeyDevice struct {
// global.MODEL
// Project string `json:"project"`
// AppName string `json:"app_name" gorm:"app_name"`
Udid string `json:"udid" gorm:"udid"`
Status string `json:"status" gorm:"status"`
Platform string `json:"platform" gorm:"platform"`
ProductName string `json:"product_name" gorm:"product_name"`
}

@ -0,0 +1,13 @@
package models
import "goqs/global"
type MonkeyPid struct {
global.MODEL
TaskId int `json:"task_id" column:"task_id"`
PId int `json:"pid" gorm:"column:pid"`
}
func (m *MonkeyPid) TableName() string {
return "monkey_pid"
}

@ -0,0 +1,19 @@
package models
import "goqs/global"
type MonkeyResult struct {
global.MODEL
TaskId int `json:"task_id"`
CrashLogs string `json:"-"`
CrashLogList []string `json:"crash_log_list" gorm:"-"`
ActivityNameInfo string `json:"-"`
ActivityList []string `json:"activity_list" gorm:"-"`
DeviceName string `json:"device_name"`
Logs string `json:"-"`
LogList []string `json:"log_list" gorm:"-"`
}
func (m *MonkeyResult) TableName() string {
return "monkey_result"
}

@ -1,20 +1,22 @@
package models
type MonkeyTask struct {
Id int `json:"id" gorm:"column:id;type:int(11);primary_key;not null;autoIncrement;comment:主键"`
Project string `json:"project" gorm:"column:project;type:varchar(255);not null;comment:项目名"`
PackageURL string `json:"package_url" gorm:"column:package_url;type:varchar(255);not null;comment:应用包下载链接"`
PackageName string `json:"package_name" gorm:"column:package_name;type:varchar(255);not null;comment:应用包名"`
LaunchActivity string `json:"launch_activity" gorm:"column:launch_activity;type:varchar(255);comment:启动Activity页"`
DeviceAmount int `json:"device_amount" gorm:"column:device_amount;type:int(11);not null;comment:运行设备数"`
RunTime int `json:"run_time" gorm:"column:run_time;type:int(11);not null;comment:运行时间(秒)"`
Platform string `json:"platform" gorm:"column:platform;type:varchar(255);comment:平台adr/ios"`
CrashCount int `json:"crash_count" gorm:"column:crash_count;type:int(11);not null;comment:崩溃次数"`
Creator string `json:"creator" gorm:"column:creator;type:varchar(255);comment:创建人"`
Status string `json:"status" gorm:"column:status;type:varchar(255);not null;comment:运行状态"`
CreateTime int `json:"create_time" gorm:"column:create_time;type:int(11);not null;autoCreateTime;comment:创建时间"`
UpdateTime int `json:"update_time" gorm:"column:update_time;type:int(11);not null;autoUpdateTime;comment:更新时间"`
IsDel int `json:"is_del" gorm:"column:is_del;type:int(1);not null;comment:是否已删除"`
Id int `json:"id" gorm:"column:id;type:int(11);primary_key;not null;autoIncrement;comment:主键"`
Project string `json:"project" gorm:"column:project;type:varchar(255);not null;comment:项目名"`
PackageURL string `json:"package_url" gorm:"column:package_url;type:varchar(255);not null;comment:应用包下载链接"`
PackageName string `json:"package_name" gorm:"column:package_name;type:varchar(255);not null;comment:应用包名"`
LaunchActivity string `json:"launch_activity" gorm:"column:launch_activity;type:varchar(255);comment:启动Activity页"`
DeviceAmount int `json:"device_amount" gorm:"column:device_amount;type:int(11);not null;comment:运行设备数"`
RunTime int `json:"run_time" gorm:"column:run_time;type:int(11);not null;comment:运行时间(秒)"`
RunPids string `json:"run_pids" gorm:"column:run_pids;type:varchar(255);comment:数组形式存放运行进程pid"`
Platform string `json:"platform" gorm:"column:platform;type:varchar(255);comment:平台adr/ios"`
CoveredAcitvities int `json:"covered_activities" gorm:"-"`
CrashCount int `json:"crash_count" gorm:"column:crash_count;type:int(11);not null;comment:崩溃次数"`
Creator string `json:"creator" gorm:"column:creator;type:varchar(255);comment:创建人"`
Status string `json:"status" gorm:"column:status;type:varchar(255);not null;comment:运行状态"`
CreateTime int `json:"create_time" gorm:"column:create_time;type:int(11);not null;autoCreateTime;comment:创建时间"`
UpdateTime int `json:"update_time" gorm:"column:update_time;type:int(11);not null;autoUpdateTime;comment:更新时间"`
IsDel int `json:"is_del" gorm:"column:is_del;type:int(1);not null;comment:是否已删除"`
}
func (m *MonkeyTask) TableName() string {

@ -0,0 +1,84 @@
package monkey
import (
"goqs/controllers"
"goqs/dbsql"
"goqs/models"
"net/http"
"github.com/gin-gonic/gin"
"github.com/spf13/cast"
)
// @Tags Monkey相关 /api/monkey/v1/
// @Summary 上报Monkey应用页
// @Description Android上报activity名
// @accept x-www-form-urlencoded
// @Param task_id formData int true "任务id"
// @Param device_name formData string false "设备id"
// @Param activity_name formData string false "页面名称"
// @Success 200 {object} models.Response "返回更新后的任务信息"
// @Router /api/monkey/v1/task/activity [post]
func UpdataActivity(c *gin.Context) {
rsp := controllers.NewResponse()
var res models.MonkeyActivity
res.TaskId = cast.ToInt(c.PostForm("task_id"))
if res.TaskId < 1 {
rsp.Error("task_id error:" + c.PostForm("task_id"))
c.JSON(http.StatusOK, rsp)
}
res.DeviceName = c.PostForm("device_name")
if res.DeviceName == "" {
rsp.Error("device_name不能为空")
c.JSON(http.StatusOK, rsp)
}
res.ActivityName = c.PostForm("activity_name")
if res.ActivityName == "" {
rsp.Error("activity_name不能为空")
c.JSON(http.StatusOK, rsp)
}
db, err := dbsql.GetConn(dbsql.DSN)
if err != nil {
rsp.Error(err.Error())
c.JSON(http.StatusOK, rsp)
return
}
defer dbsql.Close(db)
db.Create(&res)
if res.ID < 1 {
rsp.Error("记录activity应用页失败")
c.JSON(http.StatusOK, rsp)
return
}
rsp.Success()
rsp.Data = res
c.JSON(http.StatusOK, rsp)
}
// @Tags Monkey相关 /api/monkey/v1/
// @Summary 获取覆盖页面列表
// @Description 通过monkey任务id获取覆盖的活动页面
// @accept x-www-form-urlencoded
// @Param task_id query int true "任务id"
// @Success 200 {object} models.Response "返回任务覆盖的活动页"
// @Router /api/monkey/v1/task/activity [get]
func GetMonkeyActivities(c *gin.Context) {
rsp := controllers.NewResponse()
var list []models.MonkeyActivity
db, err := dbsql.GetConn(dbsql.DSN)
if err != nil {
rsp.Error(err.Error())
c.JSON(http.StatusOK, rsp)
return
}
defer dbsql.Close(db)
db.Where("task_id = ?", c.Query("task_id")).Find(&list)
rsp.Success()
rsp.Data = list
c.JSON(http.StatusOK, rsp)
}

@ -0,0 +1,54 @@
package monkey
import (
"bufio"
"errors"
"os"
)
func HasDir(path string) (bool, error) {
_, err := os.Stat(path)
if err == nil {
return true, nil
}
if os.IsNotExist(err) {
return false, nil
}
return false, err
}
func CreateDir(path string) error {
exist, err := HasDir(path)
if err != nil {
return err
}
if exist {
return errors.New("文件夹已存在")
} else {
err := os.Mkdir(path, os.ModePerm)
if err != nil {
return err
} else {
return nil
}
}
}
func CreateAndWriteFile(file_path string, data []byte) error {
file, err := os.OpenFile(file_path, os.O_WRONLY|os.O_CREATE, 0755)
if err != nil {
return err
}
defer file.Close()
write := bufio.NewWriter(file)
_, err = write.Write(data)
if err != nil {
return err
}
err = write.Flush()
if err != nil {
return err
}
return nil
}

@ -1,33 +0,0 @@
package monkey
import (
"goqs/models"
"os/exec"
"time"
log "github.com/sirupsen/logrus"
"github.com/spf13/cast"
)
func runAndroidMonkeyCmd(task models.MonkeyTask) {
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)
}
log.Debug("下载完毕开始调用monkey服务安装包路径", pkg_path)
cmd_content := "cd /home/app/aimonkey && python3 main_run.py" +
" -task_id " + cast.ToString(task.Id) +
" -pkg_path " + pkg_path +
" -package " + task.PackageName +
" -activity " + task.LaunchActivity +
" -count " + cast.ToString(task.DeviceAmount) +
" -time " + cast.ToString(task.RunTime)
log.Debug(cmd_content)
cmd := exec.Command("bash", "-c", cmd_content)
err = cmd.Run()
if err != nil {
log.Error(err)
}
}

@ -0,0 +1,124 @@
package monkey
import (
"fmt"
"goqs/models"
"os/exec"
"strings"
"time"
log "github.com/sirupsen/logrus"
"github.com/spf13/cast"
)
func runAndroidMonkeyCmd(task models.MonkeyTask) {
cmd_content := "cd /home/app/aimonkey && nohup python3 main_run.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 +
" -activity " + task.LaunchActivity +
" -count " + cast.ToString(task.DeviceAmount) +
" -time " + cast.ToString(task.RunTime) +
" >> /home/app/logs/task_output/task_" + cast.ToString(task.Id) + ".log 2>&1"
log.Debug("开始调用monkey服务")
log.Debug(cmd_content)
cmd := exec.Command("bash", "-c", cmd_content)
err := cmd.Run()
if err != nil {
log.Error(err)
}
}
func GetAndroidDevices() map[string]string {
udid_map := make(map[string]string)
cmd := exec.Command("adb", "devices")
out, err := cmd.CombinedOutput()
if err != nil {
fmt.Println(err)
}
list := strings.Split(string(out), "\n")[1:]
for _, v := range list {
if len(v) < 1 {
continue
}
fmt.Println(v)
name := strings.Split(strings.Trim(strings.Trim(v, "\r"), "\t"), "\t")[0]
status := strings.Split(strings.Trim(strings.Trim(v, "\r"), "\t"), "\t")[1]
udid_map[name] = status
// devices = append(devices, getAndroidDeviceInfo(strings.Split(strings.Trim(strings.Trim(v, "\r"), "\t"), "\t")...))
}
return udid_map
}
type DeviceInfo struct {
Udid string `json:"string"`
Status string `json:"status"`
}
func getAndroidDeviceInfo(args ...string) models.MonkeyDevice {
var di models.MonkeyDevice
di.Platform = "adr"
di.Udid = args[0]
if args[1] == "device" {
di.Status = "online"
} else {
di.Status = args[1]
}
di.ProductName = getAndroidDeviceName(di.Udid)
return di
}
func getAndroidDeviceName(udid string) string {
command := `getprop` // | grep product.marketname'
cmd := exec.Command("adb", "-s", udid, "shell", command)
out, err := cmd.CombinedOutput()
if err != nil {
fmt.Println(err)
return udid
}
strs := strings.Split(string(out), "\n")
device_name := ""
for _, v := range strs {
if strings.Contains(v, "product.brand") {
str := strings.Split(strings.Trim(v, "\r"), ": ")[1]
device_name = str[1 : len(str)-1]
break
}
}
fmt.Println(device_name)
return device_name
}
func killPid(pid int) error {
cmd := exec.Command("kill", "-9", cast.ToString(pid))
err := cmd.Run()
return err
}
func checkTaskPids(pids []models.MonkeyPid) int {
if len(pids) == 0 {
return -1
}
var strs []string
for _, v := range pids {
strs = append(strs, cast.ToString(v.PId))
}
pids_str := strings.Join(strs, "|")
cmd_str := "ps -ef | grep -v -E 'bash|grep' | grep -E '" + pids_str + "'"
fmt.Println(cmd_str)
cmd := exec.Command("bash", "-c", cmd_str)
cmd.Run()
return cmd.ProcessState.ExitCode()
}

@ -0,0 +1,31 @@
package monkey
import (
"goqs/controllers"
"net/http"
"github.com/gin-gonic/gin"
)
// @Tags Monkey相关 /api/monkey/v1/
// @Summary 获取设备列表
// @Description 获取安卓设备列表
// @accept x-www-form-urlencoded
// @Param platform query int false "平台ios/adr"
// @Success 200 {object} models.Response "返回设备信息"
// @Router /api/monkey/v1/devices [get]
func GetDevices(c *gin.Context) {
rsp := controllers.NewResponse()
// var list []models.MonkeyDevice
// db, err := dbsql.GetConn(dbsql.DSN)
// if err != nil {
// rsp.Error(err.Error())
// c.JSON(http.StatusOK, rsp)
// return
// }
// defer dbsql.Close(db)
rsp.Success()
rsp.Data = GetAndroidDevices()
c.JSON(http.StatusOK, rsp)
}

@ -0,0 +1,96 @@
package monkey
import (
"encoding/json"
"goqs/controllers"
"goqs/dbsql"
"goqs/models"
"net/http"
"github.com/gin-gonic/gin"
"github.com/spf13/cast"
)
// @Tags Monkey相关 /api/monkey/v1/
// @Summary 上报Monkey结果
// @Description 上报Monkey结果
// @accept x-www-form-urlencoded
// @Param task_id formData int true "任务id"
// @Param crash_log_list formData string false "要更新的任务状态"
// @Param activity_name_info formData string false "要更新的任务状态"
// @Param device_name formData string false "要更新的任务状态"
// @Param status formData string false "要更新的任务状态"
// @Success 200 {object} models.Response "返回更新后的任务信息"
// @Router /api/monkey/v1/task/result [post]
func UploadMonkeyResult(c *gin.Context) {
rsp := controllers.NewResponse()
var res models.MonkeyResult
res.TaskId = cast.ToInt(c.PostForm("task_id"))
if res.TaskId < 1 {
rsp.Error("task_id error:" + c.PostForm("task_id"))
c.JSON(http.StatusOK, rsp)
}
res.CrashLogs = c.PostForm("crash_log_list")
res.ActivityNameInfo = c.PostForm("activity_name_info")
res.DeviceName = c.PostForm("device_name")
res.Logs = c.PostForm("log_list")
db, err := dbsql.GetConn(dbsql.DSN)
if err != nil {
rsp.Error(err.Error())
c.JSON(http.StatusOK, rsp)
return
}
defer dbsql.Close(db)
db.Create(&res)
if res.ID < 1 {
rsp.Error("保存Monkey任务失败")
c.JSON(http.StatusOK, rsp)
return
}
rsp.Success()
rsp.Data = res
c.JSON(http.StatusOK, rsp)
}
// @Tags Monkey相关 /api/monkey/v1/
// @Summary 获取Monkey结果
// @Description 通过任务id获取Monkey结果
// @accept x-www-form-urlencoded
// @Param task_id query int true "任务id"
// @Success 200 {object} models.Response "返回任务结果"
// @Router /api/monkey/v1/task/result [get]
func GetMonkeyResult(c *gin.Context) {
rsp := controllers.NewResponse()
var list []models.MonkeyResult
db, err := dbsql.GetConn(dbsql.DSN)
if err != nil {
rsp.Error(err.Error())
c.JSON(http.StatusOK, rsp)
return
}
defer dbsql.Close(db)
db.Where("task_id = ?", c.Query("task_id")).Find(&list)
for i, _ := range list {
var strs []string
json.Unmarshal([]byte(list[i].CrashLogs), &strs)
if len(strs) > 0 {
list[i].CrashLogList = strs
}
json.Unmarshal([]byte(list[i].ActivityNameInfo), &strs)
if len(strs) > 0 {
list[i].ActivityList = strs
}
json.Unmarshal([]byte(list[i].Logs), &strs)
if len(strs) > 0 {
list[i].LogList = strs
}
}
rsp.Success()
rsp.Data = list
c.JSON(http.StatusOK, rsp)
}

@ -1,6 +1,7 @@
package monkey
import (
"fmt"
"goqs/controllers"
"goqs/dbsql"
"goqs/models"
@ -34,6 +35,7 @@ func CreateTask(c *gin.Context) {
rsp.Error(err.Error())
c.JSON(http.StatusOK, rsp)
}
defer dbsql.Close(db)
var task models.MonkeyTask
task.Project = c.PostForm("project")
@ -49,13 +51,34 @@ func CreateTask(c *gin.Context) {
// || task.Creator == ""
if task.PackageName == "" || task.LaunchActivity == "" ||
task.DeviceAmount <= 0 || task.Platform == "" ||
task.RunTime <= 10 || task.PackageURL == "" {
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())
@ -73,7 +96,7 @@ func CreateTask(c *gin.Context) {
// @Summary 更新Monkey任务状态
// @Description 更新Monkey任务状态进行中为RUNNING已完成为FINIASHED如有错误为ERROR
// @accept x-www-form-urlencoded
// @Param task_id formData int true "项目名"
// @Param task_id formData int true "任务id"
// @Param status formData string false "要更新的任务状态"
// @Success 200 {object} models.Response "返回更新后的任务信息"
// @Router /api/monkey/v1/task/status [post]
@ -92,7 +115,10 @@ func UpdateTaskStatus(c *gin.Context) {
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 {
@ -108,6 +134,53 @@ func UpdateTaskStatus(c *gin.Context) {
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 获取任务列表
@ -146,8 +219,32 @@ func GetTasks(c *gin.Context) {
var count int64
db = db.Count(&count)
db = dbsql.SetPageQuery(db, pageIndex, pageSize)
db.Order("id desc").Find(&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)
p.MaxPage = count/(int64(p.Size)+1) + 1
p.List = list
@ -157,3 +254,138 @@ func GetTasks(c *gin.Context) {
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.MonkeyActivity{}).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 停止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)
}

@ -0,0 +1,21 @@
package main
import (
"fmt"
"goqs/monkey"
)
func main() {
err := monkey.CreateDir("files")
if err != nil {
fmt.Println(err)
}
err = monkey.CreateDir("files/1")
if err != nil {
fmt.Println(err)
}
err = monkey.CreateAndWriteFile("files/1/2.txt", []byte("hidiuniduini"))
if err != nil {
fmt.Println(err)
}
}
Loading…
Cancel
Save