python locust 压力测试web 利用flask编写
#主程序
from flask import Flask from flask import request import subprocess import json htmltemp=""" <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="description" content=""> <meta name="author" content=""> <link rel="icon" href="../../favicon.ico"> <title>Jumbotron Template for Bootstrap</title> <!-- Bootstrap core CSS --> <link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"> <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries --> <!--[if lt IE 9]> <script src="https://cdn.bootcss.com/html5shiv/3.7.3/html5shiv.min.js"></script> <script src="https://cdn.bootcss.com/respond.js/1.4.2/respond.min.js"></script> <![endif]--> </head> <body> <nav class="navbar navbar-inverse navbar-fixed-top"> <div class="container"> <div class="navbar-header"> <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="#">Python Locust 压力测试服务平台 </a> </div> <div id="navbar" class="navbar-collapse collapse"> <!-- <form class="navbar-form navbar-right"> <div class="form-group"> <input type="text" placeholder="Email" class="form-control"> </div> <div class="form-group"> <input type="password" placeholder="Password" class="form-control"> </div> <button type="submit" class="btn btn-success">Sign in</button> </form> --> </div><!--/.navbar-collapse --> </div> </nav> <!-- Main jumbotron for a primary marketing message or call to action --> <div class="jumbotron"> <div class="container"> <h2>压力测试利器!</h2> <p>利用测试平台的web功能来达到快速控制后端Python Locust服务器,填写需要的测试数据通过后台运行Locust实例在线完成测试的调试工作,解决测试组工作电脑性能不足的问题.</p> <p><a class="btn btn-primary btn-lg" href="#" role="button">Learn more »</a></p> </div> </div> <div class="container"> <!-- Example row of columns --> <div class="row"> <div class="col-md-6"> <h2>脚本配置</h2> <form action="http://10.101.0.xx:xxxx/locust" method="post"> <p><label for="host">host</label> <input type="text" class="form-control" id="host" name="host" placeholder="例:http://www.x.com 或 http://10.10.2.0"></p> <p><label for="test-url">测试URL</label> <input type="text" class="form-control" id="test-url" name="test-url" placeholder="例:/index 或 /e.php?a=1"></p> <p><label for="meth">提交方法</label> <!-- <input type="text" class="form-control" id="meth" name="meth" placeholder="GET 或 POST"></p> --> <select class="form-control" id="meth" name="meth"> <option value ="GET">GET</option> <option value ="POST">POST</option> </select> <p><label for="addp">附加参数</label> <input type="text" class="form-control" id="addp" name="addp" placeholder=" 例1{'k1':'1','k2':'2'} 例2{'k':['1','2','3']} 如果没有参数不用填写"></p> <button id="subyc" type="submit" class="btn btn-info btn-sm">提交配置</button> </form> </div> <div class="col-md-6"> <!-- <h2>正在运行的测试需关闭才能重新开启新的测试实例<h2><span class="label-warning">http://10.101.0.xx:xxx</span></br> <button id="subyc" type="submit" class="btn btn-info btn-sm">关闭Locust后台进程</button> --> <table class="table table-striped" id="infotable" style="display:none"> <thead> <tr> <th>正在运行</th> <th>运行地址</th> <th>操作</th> </tr> </thead> <tbody> <tr> <td>实例1</td> <td>http://10.101.0.xx:xxxx</td> <td><button id="closelocust" type="submit" class="btn btn-info btn-sm">关闭Locust后台进程</button></td> </tr> </tbody> </table> </div> </div> </div> </div> <hr> <footer> <p>© 2016 Company, Inc.</p> </footer> </div> <!-- /container --> <!-- Bootstrap core JavaScript ================================================== --> <!-- Placed at the end of the document so the pages load faster --> <script src="https://cdn.bootcss.com/jquery/1.12.4/jquery.min.js"></script> <script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script> <script> $(function(){ function loadStatus(){ $.ajax({ url: "/status", data: "", success:function(res){ if(res.status==1){ $('#infotable').show(); $('#subyc').attr("disabled", true); } } }) }; loadStatus();}) $('#closelocust').click(function(){ $.ajax({ url: "/closelocust", type: "POST", data: "", success: function(data){ if(data=="OK"){ $('#infotable').hide(); location.reload(); }else{ } } }) }) </script> </body> </html> """ resphtml=""" <!DOCTYPE html> <html lang="zh-CN"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="description" content=""> <meta name="author" content=""> <link rel="icon" href="../../favicon.ico"> <title>Jumbotron Template for Bootstrap</title> <link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"> <script src="https://cdn.bootcss.com/html5shiv/3.7.3/html5shiv.min.js"></script> <script src="https://cdn.bootcss.com/respond.js/1.4.2/respond.min.js"></script> </head> <body> <div class="jumbotron"> <h1>Locust 测试网地址</h1> <p style="display:none" id="hostip">http://10.101.0.xx:xxx</p> <p><a class="btn btn-primary btn-lg" href="http://10.101.0.xx:xxxx" role="button" id="tiaozhuan">点击跳转到 http://10.101.0.xx:xxxx</a></p> <span class="label label-info">测试网站地址,点击进入</span> </div> <script src="https://cdn.bootcss.com/jquery/1.12.4/jquery.min.js"></script> <script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script> <script> /* $(function(){ function loadStatus(){ $.ajax({ url: "/status", dataType: "json", data: {'status': 1}, success:function(res){ if(data == "OK"){ }else{ } } }) }; loadStatus(); }) */ </script> </body> </html> """ def do_mk_pyfile(): testurl=request.form['test-url'] meth = request.form['meth'] if request.form['addp']: addp="\"" + str(request.form['addp']) + "\"" ss = "sh /opt/web-server/locustpy.sh {meth} {url} {addp}".format(url=testurl, meth=meth, addp=addp) else: ss = "sh /opt/web-server/locustpy.sh {meth} {url} ".format(url=testurl, meth=meth) subprocess.Popen(ss,shell=True) sdata={} app = Flask(__name__) @app.route('/') def index(): return htmltemp @app.route('/locust', methods=['POST']) def locust(): print(request.form['addp']) do_mk_pyfile() ss = "nohup locust -f /opt/web-server/usecase.py --host={host} --port=xxxx 2>&1 &".format(host=request.form['host']) subprocess.Popen(ss,shell=True) sdata['status']=1 return resphtml @app.route('/status') def status(): return sdata @app.route('/closelocust', methods=['POST']) def closeLocust(): sdata['status']=0 ss = "ps aux |grep locust|grep -v grep|awk '{print $2}'|xargs kill -9" subprocess.Popen(ss,shell=True) return "OK" if __name__ == '__main__': app.debug = True # 设置调试模式,生产模式的时候要关掉debug app.run(host="10.101.0.xx", debug=True)
shell脚本
#!/bin/bash echo "" > /opt/web-server/usecase.py method=$1 taskurl=$2 echo $3 if [ $method == "GET" ];then cat << EOF > /opt/web-server/usecase.py from locust import HttpLocust, TaskSet, task class MyTaskSet(TaskSet): @task() def test(self): self.client.get("${taskurl}") class MyLocust(HttpLocust): task_set = MyTaskSet min_wait = 5000 max_wait = 15000 EOF else if [ ! -n "${3}" ]; then cat << EOF > /opt/web-server/usecase.py from locust import HttpLocust, TaskSet, task class MyTaskSet(TaskSet): @task() def test(self): self.client.post("${taskurl}") class MyLocust(HttpLocust): task_set = MyTaskSet min_wait = 3000 max_wait = 5000 EOF else cat << EOF > /opt/web-server/usecase.py from locust import HttpLocust, TaskSet, task class MyTaskSet(TaskSet): @task() def test(self): self.client.post("${taskurl}",${3}) class MyLocust(HttpLocust): task_set = MyTaskSet min_wait = 3000 max_wait = 5000 EOF fi fi
locust脚本:
from locust import HttpLocust, TaskSet, task class MyTaskSet(TaskSet): @task() def test(self): self.client.get("") class MyLocust(HttpLocust): task_set = MyTaskSet min_wait = 5000 max_wait = 15000