Commit ac1ea4e6 authored by Daniel Brown's avatar Daniel Brown
Browse files

added view of previous tests run and test rerun functionality, will reuse...

added view of previous tests run and test rerun functionality, will reuse Finesse build if available and just process the kats
parent 82f4c06f
...@@ -14,7 +14,7 @@ import time ...@@ -14,7 +14,7 @@ import time
import pickle import pickle
from datetime import datetime from datetime import datetime
from pykat.testing import utils from pykat.testing import utils
import sys import sys, traceback
class RunException(Exception): class RunException(Exception):
def __init__(self, returncode, args, err, out): def __init__(self, returncode, args, err, out):
...@@ -53,11 +53,12 @@ class FinesseTestProcess(Thread): ...@@ -53,11 +53,12 @@ class FinesseTestProcess(Thread):
running_kat = "" running_kat = ""
running_suite = "" running_suite = ""
cancelling = False cancelling = False
errorOccurred = None
def __init__(self, TEST_DIR, BASE_DIR, test_commit, def __init__(self, TEST_DIR, BASE_DIR, test_commit,
run_fast=False, suites=[], test_id="0", run_fast=False, suites=[], test_id="0",
git_bin="",emails="", nobuild=True,*args, **kqwargs): git_bin="",emails="", nobuild=True,*args, **kqwargs):
Thread.__init__(self) Thread.__init__(self)
self.git_commit = test_commit self.git_commit = test_commit
...@@ -224,12 +225,10 @@ class FinesseTestProcess(Thread): ...@@ -224,12 +225,10 @@ class FinesseTestProcess(Thread):
run_times[suite] = {} run_times[suite] = {}
os.chdir(os.path.join(self.TEST_DIR,"kat_test",suite)) os.chdir(os.path.join(self.TEST_DIR,"kat_test",suite))
print suite
for files in os.listdir("."): for files in os.listdir("."):
if files.endswith(".kat"): if files.endswith(".kat"):
self.total_kats += 1 self.total_kats += 1
print self.total_kats
for suite in self.suites: for suite in self.suites:
self.cancelCheck() self.cancelCheck()
...@@ -321,7 +320,7 @@ class FinesseTestProcess(Thread): ...@@ -321,7 +320,7 @@ class FinesseTestProcess(Thread):
ix = np.where(rel_diff >= self.diff_rel_eps)[0][0] ix = np.where(rel_diff >= self.diff_rel_eps)[0][0]
output_differences[suite][out] = (ref_arr[ix], out_arr[ix], np.max(rel_diff)) output_differences[suite][out] = (ref_arr[ix], out_arr[ix], np.max(rel_diff))
os.chdir(BASE_DIR) os.chdir(self.BASE_DIR)
if not os.path.exists("reports"): if not os.path.exists("reports"):
os.mkdir("reports") os.mkdir("reports")
...@@ -385,9 +384,14 @@ class FinesseTestProcess(Thread): ...@@ -385,9 +384,14 @@ class FinesseTestProcess(Thread):
def run(self): def run(self):
try: try:
self.startFinesseTest() self.startFinesseTest()
except Exception as ex:
exc_type, exc_value, exc_traceback = sys.exc_info()
errorOccurred = dict(type=exc_type, value=exc_value, traceback=exc_traceback)
print "*** Exception for test_id = " + str(self.test_id)
traceback.print_exception(exc_type, exc_value, exc_traceback,
limit=5, file=sys.stdout)
finally: finally:
finished_test = True finished_test = True
......
import subprocess as sub import subprocess as sub
import os import os
GIT_BIN = "/usr/bin/git" try:
GIT_BIN = os.environ["GIT_BIN"]
except:
GIT_BIN = "/usr/bin/git"
print "GIT_BIN = " + GIT_BIN
class RunException(Exception): class RunException(Exception):
def __init__(self, returncode, args, err, out): def __init__(self, returncode, args, err, out):
self.returncode = returncode self.returncode = returncode
...@@ -23,7 +28,7 @@ def git(args, git_bin=GIT_BIN): ...@@ -23,7 +28,7 @@ def git(args, git_bin=GIT_BIN):
print os.getcwd() print os.getcwd()
p = sub.Popen(cmd, stdout=sub.PIPE, stderr=sub.PIPE,shell=True) p = sub.Popen(cmd, stdout=sub.PIPE, stderr=sub.PIPE)
out, err = p.communicate() out, err = p.communicate()
if p.returncode != 0: if p.returncode != 0:
......
<!DOCTYPE html>
<html> <html>
<head> <head>
<!--<link rel="stylesheet" type="text/css" href="/css/style.css"/>--> <!--<link rel="stylesheet" type="text/css" href="/css/style.css"/>-->
<link rel="stylesheet" type="text/css" href="http://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css"/> <link rel="stylesheet" type="text/css" href="http://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css"/>
<link rel="stylesheet" type="text/css" href="http://ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.4/css/jquery.dataTables.css">
</head> </head>
<body> <body>
...@@ -35,35 +35,48 @@ ...@@ -35,35 +35,48 @@
</table> </table>
</div> </div>
<div class="new_test">
<h2>Start new test</h2>
<select id="branch_list" style="width: 100px;">
<option text="develop" value="develop"/>
</select>
<select id="commit_list" style="width: 300px;"> <div class="new_test">
</select> <h2>Start new test</h2>
<input type="button" value="Refresh" id="btnGetLogs"/> <select id="branch_list" style="width: 100px;">
<option text="develop" value="develop"/>
</select>
<select id="commit_list" style="width: 300px;">
</select>
<input type="button" value="Refresh" id="btnGetLogs"/>
<input type="button" value="Start new FINESSSE test" id="btnStartTest"/>
</div>
<input type="button" value="Start new FINESSSE test" id="btnStartTest"/> <div class="prev_test">
<h2>Previous Tests</h2>
<input type="button" value="Refresh" id="btnGetPrevTests"/>
<div id="tblPrevTests" />
</div> </div>
</div> </div>
<script type="text/JavaScript" src="http://code.jquery.com/jquery-1.10.1.min.js"></script> <script type="text/JavaScript" src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
<script type="text/JavaScript" src="http://code.jquery.com/ui/1.10.3/jquery-ui.js"></script> <script type="text/JavaScript" src="http://code.jquery.com/ui/1.10.3/jquery-ui.js"></script>
<script type="text/javascript" charset="utf8" src="http://ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.4/jquery.dataTables.min.js"></script>
<script type="text/JavaScript"> <script type="text/JavaScript">
$(document).ready(function(){ $(document).ready(function(){
updateBranches(); updateBranches();
getPreviousTests();
window.setInterval(function(){ window.setInterval(function(){
updateQueuedTests(); updateQueuedTests();
updateProgress(); updateProgress();
}, 1000); }, 1000);
});
$('#btnGetPrevTests').click(function(){
getPreviousTests();
}); });
$( "#current_test_progress" ).progressbar({ $( "#current_test_progress" ).progressbar({
...@@ -94,6 +107,66 @@ ...@@ -94,6 +107,66 @@
updateProgress(); updateProgress();
}); });
function getPreviousTests() {
$.ajax({
type: "POST",
url: "/finesse/get_100_prev_tests",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: buildPreviousTestTable,
error: function(o,a,err){
alert("Error getting previous tests : " + err);
}
});
}
function buildPreviousTestTable(data) {
var tbl = $('#tblPrevTests');
tbl.html('<table cellpadding="0" cellspacing="0" border="0" id="bTable" class="style1 datatable"></table>');
gtable = $('#bTable').dataTable({
"bPaginate": true,
"sPaginationType": "full_numbers",
"bAutoWidth": true,
"bLengthChange": true,
"aaData": data.tests,
"bJQueryUI": true,
"aoColumns": [
{
"fnCreatedCell": function (nTd, sData, oData, iRow, iCol) {
var a = $('<button type="button" style="margin: 0">View</button>').button().on('click', function () {
});
var b = $('<button type="button" style="margin: 0">Rerun</button>').button().on('click', function () {
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
url: "/finesse/rerun_test_" + oData["test_id"],
success: function () {
updateQueuedTests();
updateProgress();
},
error: function(jqXHR, textStatus, err){
console.log('error: ' + err);
},
dataType: "json"
});
});
$(nTd).empty();
$(nTd).append(a);
$(nTd).append(b);
}, "mDataProp": "test_id", "sWidth": "30%", "bSearchable": false, "sTitle": "", "bSortable": false
},
{ "mDataProp": "test_id", "sTitle": "Test ID","bSearchable": true, "bVisible": true, "sClass": "center" },
{ "mDataProp": "git_commit", "sTitle": "Git Commit", "bSearchable": true, "bVisible": true, "sClass": "center" },
{ "mDataProp": "startTime", "sTitle": "Start Time", "bSearchable": false, "bVisible": true, "sClass": "center" },
{ "mDataProp": "endTime", "sTitle": "End Time", "bSearchable": false, "bVisible": true, "sClass": "center" }
]
});
}
function updateProgress(){ function updateProgress(){
$.ajax({ $.ajax({
......
...@@ -13,7 +13,12 @@ from pykat.testing import test as finesse_test ...@@ -13,7 +13,12 @@ from pykat.testing import test as finesse_test
import shutil import shutil
from pykat.testing.web import app from pykat.testing.web import app
import os from CodernityDB.database_thread_safe import ThreadSafeDatabase
from CodernityDB.database import RecordNotFound
from hashlib import md5
from pykat.testing.web.database_indices import TestIDIndex
import os, sys
global current_test, scheduled_tests, schedule_lock global current_test, scheduled_tests, schedule_lock
...@@ -23,8 +28,51 @@ scheduled_tests = [] ...@@ -23,8 +28,51 @@ scheduled_tests = []
schedule_lock = Lock() schedule_lock = Lock()
watcher = None watcher = None
print "Starting up database"
DB_PATH = os.path.join(app.instance_path,"db")
db = ThreadSafeDatabase(DB_PATH)
if db.exists():
db.open()
print db.get_db_details()
print "Reindexing..."
db.reindex()
print "Done reindexing"
# update the test_id from the previous tests that have been run
for a in db.all('testid'):
key = int(a['key'])
if key > test_id:
test_id = key
print "Current test_id: " + str(test_id)
else:
db.create()
db.add_index(TestIDIndex(db.path, 'testid'))
print "loading web interface" print "loading web interface"
# should be called with the correct locks already
# applied
def __run_new(test):
global current_test,watcher,scheduled_tests
# check if anything is running and if it
# isn't start this test off
if current_test is None:
print "running test"
current_test = test
# create watcher thread which will start the test
watcher = FinesseProcessWatcher()
watcher.setProcessToWatch(test)
watcher.start()
else:
print "queuing test"
scheduled_tests.append(test)
class FinesseProcessWatcher(Thread): class FinesseProcessWatcher(Thread):
process_to_watch = None process_to_watch = None
...@@ -48,10 +96,20 @@ class FinesseProcessWatcher(Thread): ...@@ -48,10 +96,20 @@ class FinesseProcessWatcher(Thread):
# raise Exception("Tried to watch something which wasn't a FinesseTestProcess") # raise Exception("Tried to watch something which wasn't a FinesseTestProcess")
print "Watcher is watching", self.process_to_watch print "Watcher is watching", self.process_to_watch
start = datetime.now()
self.process_to_watch.start() self.process_to_watch.start()
self.process_to_watch.join() self.process_to_watch.join()
print "Watcher is continuing" print "Watcher is continuing"
doc = db.get('testid', self.process_to_watch.test_id,with_doc=True)["doc"]
doc["cancelled"] = self.process_to_watch.cancelling
doc["error"] = self.process_to_watch.errorOccurred
doc["startTime"] = str(start)
doc["endTime"] = str(datetime.now())
db.update(doc)
try: try:
# once done check if any other tests need to be ran # once done check if any other tests need to be ran
schedule_lock.acquire() schedule_lock.acquire()
...@@ -82,11 +140,8 @@ def finesse_cancel_test(id): ...@@ -82,11 +140,8 @@ def finesse_cancel_test(id):
# get lock here so that watcher doesn't interfere # get lock here so that watcher doesn't interfere
# with removing/starting new tests # with removing/starting new tests
schedule_lock.acquire() schedule_lock.acquire()
print current_test
if current_test is not None: if current_test is not None:
print "cid " + str(current_test.test_id)
if current_test.test_id == id: if current_test.test_id == id:
current_test.cancelling = True current_test.cancelling = True
print "Cancelling Current Test" print "Cancelling Current Test"
...@@ -103,6 +158,7 @@ def finesse_cancel_test(id): ...@@ -103,6 +158,7 @@ def finesse_cancel_test(id):
if remove > -1: if remove > -1:
print "Cancelled queued test" print "Cancelled queued test"
scheduled_tests[remove].cancelling = True
scheduled_tests.pop(remove) scheduled_tests.pop(remove)
return str(id) return str(id)
...@@ -115,6 +171,49 @@ def finesse_cancel_test(id): ...@@ -115,6 +171,49 @@ def finesse_cancel_test(id):
def home_page(): def home_page():
return render_template("finesse_test.html") return render_template("finesse_test.html")
@app.route('/finesse/rerun_test_<id>', methods=["POST"])
def finesse_start_rerun(id):
id = int(id)
try:
schedule_lock.acquire()
test_prev_doc = db.get('testid', id, with_doc=True)["doc"]
if "rerun" in test_prev_doc:
test_prev_doc["rerun"] += 1
else:
test_prev_doc["rerun"] = 1
db.update(test_prev_doc)
TEST_OUTPUT_PATH = os.path.join(app.instance_path, "tests")
if not os.path.exists(TEST_OUTPUT_PATH):
raise Exception("Output path for rerun of test " + id + " does not exist")
TEST_RUN_PATH_OLD = os.path.join(TEST_OUTPUT_PATH, str(id))
TEST_RUN_PATH = os.path.join(TEST_OUTPUT_PATH, str(id) + "_rerun_" + str(test_prev_doc["rerun"]))
if not os.path.exists(TEST_RUN_PATH_OLD):
NOBUILD = True
shutil.copytree(os.path.join(TEST_RUN_PATH_OLD,"build"), os.path.join(TEST_RUN_PATH,"build"))
else:
NOBUILD = False
test = finesse_test.FinesseTestProcess(os.path.join(app.instance_path, "finesse_test"),
TEST_RUN_PATH,
test_prev_doc["git_commit"],
run_fast=True, suites=[], test_id=id,
emails="", nobuild=NOBUILD)
__run_new(test)
finally:
schedule_lock.release()
return "ok"
@app.route('/finesse/start_test', methods=["POST"]) @app.route('/finesse/start_test', methods=["POST"])
def finesse_start_test(): def finesse_start_test():
global current_test, test_id global current_test, test_id
...@@ -125,15 +224,12 @@ def finesse_start_test(): ...@@ -125,15 +224,12 @@ def finesse_start_test():
test_id += 1 test_id += 1
git_commit = request.json['git_commit'] git_commit = request.json['git_commit']
print app.instance_path
TEST_OUTPUT_PATH = os.path.join(app.instance_path, "tests") TEST_OUTPUT_PATH = os.path.join(app.instance_path, "tests")
if not os.path.exists(TEST_OUTPUT_PATH): if not os.path.exists(TEST_OUTPUT_PATH):
os.mkdir(TEST_OUTPUT_PATH) os.mkdir(TEST_OUTPUT_PATH)
TEST_RUN_PATH = os.path.join(TEST_OUTPUT_PATH, str(test_id)) TEST_RUN_PATH = os.path.join(TEST_OUTPUT_PATH, str(test_id))
print TEST_RUN_PATH
if os.path.exists(TEST_RUN_PATH): if os.path.exists(TEST_RUN_PATH):
shutil.rmtree(TEST_RUN_PATH) shutil.rmtree(TEST_RUN_PATH)
...@@ -143,21 +239,16 @@ def finesse_start_test(): ...@@ -143,21 +239,16 @@ def finesse_start_test():
test = finesse_test.FinesseTestProcess(os.path.join(app.instance_path, "finesse_test"), test = finesse_test.FinesseTestProcess(os.path.join(app.instance_path, "finesse_test"),
TEST_RUN_PATH, TEST_RUN_PATH,
git_commit, git_commit,
run_fast=False, suites=[], test_id=test_id, run_fast=True, suites=[], test_id=test_id,
emails="", nobuild=False) emails="", nobuild=False)
# check if anything is running and if it db.insert(dict(t="test",
# isn't start this test off test_id=test.test_id,
if current_test is None: git_commit=test.get_version(),
print "running test" cancelled=test.cancelling,
current_test = test error=test.errorOccurred))
# create watcher thread which will start the test
watcher = FinesseProcessWatcher() __run_new(test)
watcher.setProcessToWatch(test)
watcher.start()
else:
print "queuing test"
scheduled_tests.append(test)
finally: finally:
schedule_lock.release() schedule_lock.release()
...@@ -244,5 +335,51 @@ def finesse_get_log(count,branch): ...@@ -244,5 +335,51 @@ def finesse_get_log(count,branch):
return jsonify(logs=log2send) return jsonify(logs=log2send)
@app.route('/finesse/get_<count>_prev_tests', methods=["POST"])
\ No newline at end of file def finesse_get_prev_tests(count):
global test_id
rtn = list()
max = test_id
min = max - int(count)
if min < 0:
min = 0
if min > max:
min = max
try:
data = db.all('testid',with_doc=True)
#db.get_many('testid',start=min,end=max,limit=-1, with_doc=True)
for a in data:
i = a["doc"]
err = (not i['error'] is None)
if "startTime" in i:
startTime = i["startTime"]
else:
startTime = ""
if "endTime" in i:
endTime = i["endTime"]
else:
endTime = ""
obj = dict(test_id=i['test_id'],
git_commit=i['git_commit'],
error=err,
startTime=startTime,
endTime=endTime)
rtn.append(obj)
return jsonify(tests=rtn)
except RecordNotFound:
print "exception"
return jsonify(test=rtn)
\ No newline at end of file
import os import os
import sys import sys
from flask import Flask from flask import Flask
from pykat.testing import utils from optparse import OptionParser
def start(instance_path,port=5000, debug=True, ip="0.0.0.0"): def start(instance_path,port=5000, debug=True, ip="0.0.0.0", git_bin="/usr/bin/git"):
global app
os.environ["GIT_BIN"] = git_bin