diff --git a/webmeter/core/engine.py b/webmeter/core/engine.py
index 0f240d8..040ebf5 100644
--- a/webmeter/core/engine.py
+++ b/webmeter/core/engine.py
@@ -2,9 +2,9 @@
import datetime
import json
from loguru import logger
-from core.utils import Common
-from core.sqlhandle import crud
-from core.task import TaskBase
+from webmeter.core.utils import Common
+from webmeter.core.sqlhandle import crud
+from webmeter.core.task import TaskBase
class EngineServie(TaskBase):
diff --git a/webmeter/core/plan.py b/webmeter/core/plan.py
index 13fa829..fa7b035 100644
--- a/webmeter/core/plan.py
+++ b/webmeter/core/plan.py
@@ -1,7 +1,7 @@
import os
import shutil
from loguru import logger
-from core.utils import Common, JMX
+from webmeter.core.utils import Common, JMX
from fastapi import UploadFile
class Base(object):
diff --git a/webmeter/core/result.py b/webmeter/core/result.py
deleted file mode 100644
index 8015236..0000000
--- a/webmeter/core/result.py
+++ /dev/null
@@ -1,9 +0,0 @@
-
-class Manage(object):
- """test result management """
- pass
-
-
-class Analyse(object):
- """analyse test result"""
- pass
\ No newline at end of file
diff --git a/webmeter/core/sqlhandle/crud.py b/webmeter/core/sqlhandle/crud.py
index 03b4273..3fbd8a2 100644
--- a/webmeter/core/sqlhandle/crud.py
+++ b/webmeter/core/sqlhandle/crud.py
@@ -2,7 +2,7 @@
from typing import Optional
from loguru import logger
import os, shutil, datetime
-from core.plan import TestPlan
+from webmeter.core.plan import TestPlan
def create_task(tasks: dict):
with database.dbConnect() as session:
@@ -32,21 +32,31 @@ def update_task(tasks: dict):
else:
raise Exception('{} is not existed'.format(result.task))
-def query_task_one(tasks: schemas.taskQuery):
+def query_task_one(plan: str, task: str) -> dict:
with database.dbConnect() as session:
- results = session.query(models.Task).filter(models.Task.plan == tasks.plan).all()
- result_dict = [result.task for result in results]
+ results = session.query(models.Task).filter(models.Task.plan == plan,
+ models.Task.task == task).first()
+ result_dict = dict()
+ result_dict['plan'] = results.plan
+ result_dict['task'] = results.task
+ result_dict['model'] = results.model
+ result_dict['status'] = results.status
+ result_dict['threads'] = results.threads
+ result_dict['success_num'] = results.success_num
+ result_dict['fail_num'] = results.fail_num
+ result_dict['stime'] = results.stime
+ result_dict['etime'] = results.etime
return result_dict
-def query_task_all():
+def query_task_all() -> list:
with database.dbConnect() as session:
results = session.query(models.Task).order_by(models.Task.stime.desc()).all()
- result_dict = [{'plan': result.plan, 'task':result.task,
+ result_list = [{'plan': result.plan, 'task':result.task,
'model': result.model, 'status': result.status,
'threads': result.threads, 'success_num': result.success_num,
'fail_num': result.fail_num, 'stime': result.stime,
'etime': result.etime} for result in results]
- return result_dict
+ return result_list
def remove_task_one(plan: str, task: str):
logger.warning('remove task data : {}'.format(task))
diff --git a/webmeter/core/sqlhandle/database.py b/webmeter/core/sqlhandle/database.py
index a93731f..395439a 100644
--- a/webmeter/core/sqlhandle/database.py
+++ b/webmeter/core/sqlhandle/database.py
@@ -4,7 +4,7 @@
from contextlib import contextmanager
from loguru import logger
import os
-from core.utils import Common
+from webmeter.core.utils import Common
SQL_DIR = Common.make_dir(os.path.join(os.getcwd(), 'webmeter'))
SQLALCHEMY_DATABASE_URL = "sqlite:///{}/webmeter_app.db".format(SQL_DIR)
diff --git a/webmeter/core/sqlhandle/models.py b/webmeter/core/sqlhandle/models.py
index 9e0978d..039bc7a 100644
--- a/webmeter/core/sqlhandle/models.py
+++ b/webmeter/core/sqlhandle/models.py
@@ -1,5 +1,5 @@
from sqlalchemy import Boolean, Column, Integer, String, DateTime, Float
-from core.sqlhandle.database import Base
+from webmeter.core.sqlhandle.database import Base
import datetime
diff --git a/webmeter/core/task.py b/webmeter/core/task.py
index 22de421..456c08a 100644
--- a/webmeter/core/task.py
+++ b/webmeter/core/task.py
@@ -2,6 +2,8 @@
import json, os
from core.utils import Common
from typing import Optional
+from webmeter.core.sqlhandle import crud
+
class TaskBase(object):
@@ -18,17 +20,17 @@ def read_statistics_file(cls, plan: str, task: str) -> dict:
raise Exception('No content found in the statistics.json')
@classmethod
- def read_result_file(cls, plan: str, task: str):
+ def read_result_file(cls, plan: str, task: str) -> list:
"""read result.jtl content"""
result_file_path = os.path.join(cls.ROOT_DIR, plan, 'report', task,'result.jtl')
- content = Common.read_file_content(result_file_path)
- if content:
+ content = Common.read_file_lines(result_file_path)
+ if content.__len__() > 0:
return content
else:
raise Exception('No content found in the result.jtl')
@classmethod
- def read_log(cls, plan: str, task: str) -> Optional[str]:
+ def read_log_file(cls, plan: str, task: str) -> Optional[str]:
"""read result.log content"""
log_file_path = os.path.join(cls.ROOT_DIR, plan, 'log', task,'result.log')
content = Common.read_file_content(log_file_path)
@@ -36,3 +38,30 @@ def read_log(cls, plan: str, task: str) -> Optional[str]:
return content
else:
raise Exception('No content found in the result.log')
+
+class TaskDetail(TaskBase):
+
+ @classmethod
+ def getTestAndReportInfo(cls, plan: str, task: str) -> dict:
+ result = dict()
+ summary_dict = crud.query_task_one(plan, task)
+ result['source_file'] = os.path.join(TaskBase.ROOT_DIR, plan, 'report', task, 'result.jtl')
+ result['stime'] = summary_dict.get('stime')
+ result['etime'] = summary_dict.get('etime')
+ return result
+
+ @classmethod
+ def getRequestSummary(cls, plan: str, task: str) -> list:
+ jtlContent = TaskBase.read_result_file(plan, task)
+ jtlContent.pop(0)
+ jtlList = [{'lable':item.split(',')[2],
+ 'responseCode':item.split(',')[3],
+ 'responseMessage':item.split(',')[4],
+ 'threadName': item.split(',')[5],
+ 'failureMessage':item.split(',')[8],
+ 'bytes': item.split(',')[9],
+ 'sentBytes': item.split(',')[10],
+ 'allThreads':item.split(',')[12],
+ 'URL': item.split(',')[13]} for item in jtlContent]
+ return jtlList
+
diff --git a/webmeter/core/utils.py b/webmeter/core/utils.py
index 5baf324..4c9186a 100644
--- a/webmeter/core/utils.py
+++ b/webmeter/core/utils.py
@@ -71,7 +71,13 @@ def make_dir_file(cls, dir : str, filename: str, content: str) -> str:
def read_file_content(cls, file_path) -> str:
with open(file=file_path, mode='r', encoding='utf-8') as f:
content = f.read()
- return content
+ return content
+
+ @classmethod
+ def read_file_lines(cls, file_path) -> list:
+ with open(file=file_path, mode='r', encoding='utf-8') as f:
+ content = f.readlines()
+ return content
@classmethod
def pc_platform(cls) -> Optional[str]:
diff --git a/webmeter/static/js/common.js b/webmeter/static/js/common.js
new file mode 100644
index 0000000..dfbce13
--- /dev/null
+++ b/webmeter/static/js/common.js
@@ -0,0 +1,44 @@
+
+const getLocationParams = () => {
+ let href = window.location.href;
+ let query = href.substring(href.indexOf("?") + 1);
+ let vars = query.split("&");
+ let obj = {};
+ for (let i = 0; i < vars.length; i++) {
+ let pair = vars[i].split("=");
+ obj[pair[0]] = pair[1];
+ }
+ return obj;
+ };
+
+
+const elMessage = (type, message) => {
+ switch(type){
+ case 'success':
+ ElementPlus.ElMessage({
+ showClose: true,
+ message: message,
+ type: 'success',
+ })
+ break;
+ case 'warning':
+ ElementPlus.ElMessage({
+ showClose: true,
+ message: message,
+ type: 'warning',
+ })
+ break;
+ case 'error':
+ ElementPlus.ElMessage({
+ showClose: true,
+ message: message,
+ type: 'error',
+ })
+ break;
+ default:
+ ElementPlus.ElMessage({
+ showClose: true,
+ message: message,
+ })
+ };
+}
diff --git a/webmeter/static/js/lan.js b/webmeter/static/js/lan.js
index 1501ffa..22e6746 100644
--- a/webmeter/static/js/lan.js
+++ b/webmeter/static/js/lan.js
@@ -1,6 +1,6 @@
const ENGLISH = {
'plan_page_title':'TEST PLAN',
- 'result_page_title':'TEST RESULT',
+ 'task_page_title':'TASK RESULT',
'monitor': 'Monitor',
'star_me': 'Star Me',
'documentation': 'Documentation',
@@ -61,7 +61,7 @@ const ENGLISH = {
const CHINESE = {
'plan_page_title':'测试计划',
- 'result_page_title':'测试结果',
+ 'task_page_title':'任务管理',
'monitor': '资源监控',
'star_me': 'Github点赞',
'documentation': '文档',
diff --git a/webmeter/templates/analysis.html b/webmeter/templates/analysis.html
new file mode 100644
index 0000000..e45f541
--- /dev/null
+++ b/webmeter/templates/analysis.html
@@ -0,0 +1,487 @@
+
+
+
+
+
+
+
+
+
+
+ WebMeter - TASK ANALYSIS
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Data Source |
+ |
+
+
+ Start Time |
+ |
+
+
+ End Time |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ lable |
+ thread Name |
+ URL |
+ all Threads |
+ response Code |
+ response Message |
+ failure Message |
+ bytes |
+ sent Bytes |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+ lable |
+ samplers |
+ errors |
+ error(%) |
+ avg ResTime |
+ median ResTime |
+ min ResTime |
+ max ResTime |
+ 90th pct |
+ 95th pct |
+ 99th pct |
+ throughput(s) |
+ sent(KB/s) |
+ recieve(KB/s) |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
+
+
+
+
+ Charts
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/webmeter/templates/plan.html b/webmeter/templates/plan.html
index 3171dee..6f326d5 100644
--- a/webmeter/templates/plan.html
+++ b/webmeter/templates/plan.html
@@ -1,4 +1,5 @@
+
@@ -45,7 +45,7 @@
-
+
@@ -118,13 +118,15 @@
|
|
|
- Running |
+
+ Running
+ |
Done |
|
|
-
+
@@ -188,7 +190,7 @@
- . V1.0.0
+
@@ -303,6 +305,10 @@ Are you sure?
initTaskData()
});
+ const analysisClick = (plan, task) =>{
+ window.location.href = '/analysis/'+ plan + '/'+ task
+ }
+
const setLanguage = (language) => {
loading.value = true
axios.post('/api/language/set', {
@@ -469,7 +475,8 @@ Are you sure?
setLanguage,
removeClick,
removeOneTask,
- removeAllTask
+ removeAllTask,
+ analysisClick
};
}
});
diff --git a/webmeter/view/api.py b/webmeter/view/api.py
index 706f33a..cf4e60e 100644
--- a/webmeter/view/api.py
+++ b/webmeter/view/api.py
@@ -1,10 +1,11 @@
from loguru import logger
from typing import Union
from fastapi import APIRouter, UploadFile, File, Form
-from core.plan import TestPlan
-from core.engine import EngineServie
-from core.sqlhandle import crud, models, schemas
-from core.sqlhandle.database import engine
+from webmeter.core.plan import TestPlan
+from webmeter.core.engine import EngineServie
+from webmeter.core.sqlhandle import crud, models, schemas
+from webmeter.core.sqlhandle.database import engine
+from webmeter.core.task import TaskDetail
router = APIRouter()
test_plan = TestPlan()
models.Base.metadata.create_all(bind=engine)
@@ -141,16 +142,6 @@ async def run_plan(content: dict):
result = {'status':0, 'msg': str(e)}
return result
-@router.post("/api/task/query/one")
-async def query_task_one(tasks: schemas.taskQuery):
- try:
- data = crud.query_task_one(tasks=tasks)
- result = {'status':1, 'msg': 'success', 'data': data}
- except Exception as e:
- logger.exception(e)
- result = {'status':0, 'msg': str(e)}
- return result
-
@router.post("/api/task/query/all")
async def query_task_all():
try:
@@ -181,4 +172,40 @@ async def remove_task_all():
except Exception as e:
logger.exception(e)
result = {'status':0, 'msg': str(e)}
+ return result
+
+@router.post("/api/task/analysis/base_info")
+async def analysis(content: dict):
+ plan = content.get('plan')
+ task = content.get('task')
+ try:
+ data = TaskDetail.getTestAndReportInfo(plan, task)
+ result = {'status':1, 'msg': 'success', 'data': data}
+ except Exception as e:
+ logger.exception(e)
+ result = {'status':0, 'msg': str(e)}
+ return result
+
+@router.post("/api/task/analysis/request_summary")
+async def requests_summary(content: dict):
+ plan = content.get('plan')
+ task = content.get('task')
+ try:
+ data = TaskDetail.getRequestSummary(plan, task)
+ result = {'status':1, 'msg': 'success', 'data': data}
+ except Exception as e:
+ logger.exception(e)
+ result = {'status':0, 'msg': str(e)}
+ return result
+
+@router.post("/api/task/analysis/statistics")
+async def statistics(content: dict):
+ plan = content.get('plan')
+ task = content.get('task')
+ try:
+ data = TaskDetail.read_statistics_file(plan, task)
+ result = {'status':1, 'msg': 'success', 'data': data}
+ except Exception as e:
+ logger.exception(e)
+ result = {'status':0, 'msg': str(e)}
return result
\ No newline at end of file
diff --git a/webmeter/view/page.py b/webmeter/view/page.py
index 172c8f9..389e4a0 100644
--- a/webmeter/view/page.py
+++ b/webmeter/view/page.py
@@ -21,4 +21,8 @@ async def plan(request: Request):
@router.get("/result", response_class=HTMLResponse)
async def result(request: Request):
- return templates.TemplateResponse("result.html", {"request": request})
\ No newline at end of file
+ return templates.TemplateResponse("result.html", {"request": request})
+
+@router.get("/analysis/{plan}/{task}", response_class=HTMLResponse)
+async def result(request: Request, plan: str, task: str):
+ return templates.TemplateResponse("analysis.html", {"request": request, "plan": plan, "task": task})
\ No newline at end of file
diff --git a/webmeter/web.py b/webmeter/web.py
index 21ccfa2..fe28786 100644
--- a/webmeter/web.py
+++ b/webmeter/web.py
@@ -1,7 +1,7 @@
import uvicorn
from fastapi import FastAPI
from webmeter.view import page,api
-from webmeter.core.utils import Utils
+from webmeter.core.utils import Common
import requests
import webbrowser
import multiprocessing
@@ -25,7 +25,7 @@ def open_url(host: str, port: int) -> None:
flag = status(host, port)
webbrowser.open('http://{}:{}/plan'.format(host, port), new=2)
-def main(host=Utils.ip(), port=6006) -> None:
+def main(host=Common.ip(), port=6006) -> None:
pool = multiprocessing.Pool(processes=2)
pool.apply_async(start, (host, port))
pool.apply_async(open_url, (host, port))
|