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

added cancellation of test and branch picker

parent 93ba0dd3
...@@ -29,14 +29,15 @@ class DiffException(Exception): ...@@ -29,14 +29,15 @@ class DiffException(Exception):
self.outfile = outfile self.outfile = outfile
def runcmd(args): def runcmd(args):
p = sub.Popen(args, stdout=sub.PIPE, stderr=sub.PIPE) p = sub.Popen(args, stdout=sub.PIPE, stderr=sub.PIPE)
out, err = p.communicate() out, err = p.communicate()
if p.returncode != 0: if p.returncode != 0:
print err print "STDERR: " + err
raise RunException(p.returncode, args, err, out) print "STDOUT: " + out
raise RunException(p.returncode, args, err, out)
return [out,err] return [out,err]
class FinesseTestProcess(Thread): class FinesseTestProcess(Thread):
...@@ -51,13 +52,18 @@ class FinesseTestProcess(Thread): ...@@ -51,13 +52,18 @@ class FinesseTestProcess(Thread):
diff_rel_eps = 1e-13 diff_rel_eps = 1e-13
running_kat = "" running_kat = ""
running_suite = "" running_suite = ""
cancelling = False
def __init__(self, TEST_DIR, BASE_DIR, git_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 = git_commit self.git_commit = test_commit
if test_commit is None:
raise Exception("A git commit ID must be provided for the test")
self.queue_time = datetime.now() self.queue_time = datetime.now()
self.test_id = test_id self.test_id = test_id
self.TEST_DIR = TEST_DIR self.TEST_DIR = TEST_DIR
...@@ -102,7 +108,11 @@ class FinesseTestProcess(Thread): ...@@ -102,7 +108,11 @@ class FinesseTestProcess(Thread):
self.suites.extend(suites) self.suites.extend(suites)
self.GIT_BIN = git_bin self.GIT_BIN = git_bin
def cancelCheck(self):
if self.cancelling:
raise SystemExit()
def percent_done(self): def percent_done(self):
if self.total_kats == 0: if self.total_kats == 0:
return 0.0 return 0.0
...@@ -126,29 +136,44 @@ class FinesseTestProcess(Thread): ...@@ -126,29 +136,44 @@ class FinesseTestProcess(Thread):
self.built = False self.built = False
print type(self.nobuild), self.nobuild BUILD_PATH = os.path.join(self.BASE_DIR, "build")
if not os.path.exists("build"):
os.mkdir("build")
# Firstly we need to build the latest version of finesse # Firstly we need to build the latest version of finesse
if os.path.isdir("build") and not self.nobuild: if not self.nobuild:
print "deleting build dir..." print "deleting build dir..." + BUILD_PATH
shutil.rmtree("build") if os.path.exists(BUILD_PATH):
shutil.rmtree(BUILD_PATH)
print "Checking out finesse base..." print "Checking out finesse base..."
utils.git(["clone","git://gitmaster.atlas.aei.uni-hannover.de/finesse/base.git","build"]) utils.git(["clone","git://gitmaster.atlas.aei.uni-hannover.de/finesse/base.git",BUILD_PATH])
os.chdir("build") os.chdir(BUILD_PATH)
print "Checking out and building develop version of finesse..." print "Checking out and building develop version of finesse " + self.git_commit
SRC_PATH = os.path.join(BUILD_PATH,"src")
if sys.platform == "win32": if sys.platform == "win32":
runcmd(["bash","./finesse.sh","--checkout","develop"]) runcmd(["bash","./finesse.sh","--checkout"])
self.cancelCheck()
os.chdir(SRC_PATH)
utils.git(["checkout",self.git_commit])
self.cancelCheck()
os.chdir(BUILD_PATH)
runcmd(["bash","./finesse.sh","--build"]) runcmd(["bash","./finesse.sh","--build"])
self.cancelCheck()
else: else:
EXE = ""
runcmd(["./finesse.sh","--checkout","develop"]) runcmd(["./finesse.sh","--checkout","develop"])
self.cancelCheck()
os.chdir(SRC_PATH)
utils.git(["checkout",self.git_commit])
self.cancelCheck()
os.chdir(BUILD_PATH)
runcmd(["./finesse.sh","--build"]) runcmd(["./finesse.sh","--build"])
self.cancelCheck()
os.chdir(self.BASE_DIR) os.chdir(self.BASE_DIR)
...@@ -156,7 +181,7 @@ class FinesseTestProcess(Thread): ...@@ -156,7 +181,7 @@ class FinesseTestProcess(Thread):
# check if kat runs # check if kat runs
if not os.path.exists(FINESSE_EXE): if not os.path.exists(FINESSE_EXE):
raise Exception("Kat file was not found") raise Exception("Kat file was not found in " + FINESSE_EXE)
self.built = True self.built = True
...@@ -172,14 +197,18 @@ class FinesseTestProcess(Thread): ...@@ -172,14 +197,18 @@ class FinesseTestProcess(Thread):
os.environ["KATINI"] = os.path.join(self.TEST_DIR,"kat.ini") os.environ["KATINI"] = os.path.join(self.TEST_DIR,"kat.ini")
self.cancelCheck()
# Clean up and pull latest test repository # Clean up and pull latest test repository
print "Cleaning test repository..." print "Cleaning test repository..."
os.chdir(self.TEST_DIR) os.chdir(self.TEST_DIR)
utils.git(["clean","-xdf"]) utils.git(["clean","-xdf"])
self.cancelCheck()
utils.git(["reset","--hard"]) utils.git(["reset","--hard"])
self.cancelCheck()
print "Pulling latest test..." print "Pulling latest test..."
utils.git(["pull"]) utils.git(["pull"])
self.cancelCheck()
# Define storage structures for generating report later # Define storage structures for generating report later
kat_run_exceptions = {} kat_run_exceptions = {}
output_differences = {} output_differences = {}
...@@ -201,8 +230,9 @@ class FinesseTestProcess(Thread): ...@@ -201,8 +230,9 @@ class FinesseTestProcess(Thread):
if files.endswith(".kat"): if files.endswith(".kat"):
self.total_kats += 1 self.total_kats += 1
print self.total_kats print self.total_kats
for suite in self.suites: for suite in self.suites:
self.cancelCheck()
print "Running suite: " + suite + "..." print "Running suite: " + suite + "..."
kats = [] kats = []
os.chdir(os.path.join(self.TEST_DIR,"kat_test",suite)) os.chdir(os.path.join(self.TEST_DIR,"kat_test",suite))
...@@ -217,6 +247,7 @@ class FinesseTestProcess(Thread): ...@@ -217,6 +247,7 @@ class FinesseTestProcess(Thread):
self.running_suite = suite self.running_suite = suite
for kat in kats: for kat in kats:
self.cancelCheck()
self.running_kat = kat self.running_kat = kat
print self.get_progress() print self.get_progress()
...@@ -237,6 +268,8 @@ class FinesseTestProcess(Thread): ...@@ -237,6 +268,8 @@ class FinesseTestProcess(Thread):
finally: finally:
self.done_kats += 1 self.done_kats += 1
self.cancelCheck()
for suite in self.suites: for suite in self.suites:
if len(kat_run_exceptions[suite].keys()) > 0: if len(kat_run_exceptions[suite].keys()) > 0:
print "Could not run the following kats:\n" + "\n".join(kat_run_exceptions.keys()) + " in " + suite print "Could not run the following kats:\n" + "\n".join(kat_run_exceptions.keys()) + " in " + suite
...@@ -246,6 +279,7 @@ class FinesseTestProcess(Thread): ...@@ -246,6 +279,7 @@ class FinesseTestProcess(Thread):
# Now we have generated the output files compare them to the references # Now we have generated the output files compare them to the references
for suite in self.suites: for suite in self.suites:
self.cancelCheck()
print "Diffing suite: " + suite + "..." print "Diffing suite: " + suite + "..."
outs = [] outs = []
...@@ -259,7 +293,9 @@ class FinesseTestProcess(Thread): ...@@ -259,7 +293,9 @@ class FinesseTestProcess(Thread):
if not os.path.exists(REF_DIR): if not os.path.exists(REF_DIR):
raise Exception("Suite reference directory doesn't exist: " + REF_DIR) raise Exception("Suite reference directory doesn't exist: " + REF_DIR)
for out in outs: for out in outs:
self.cancelCheck()
#print "Diffing " + out #print "Diffing " + out
ref_file = os.path.join(REF_DIR,out) ref_file = os.path.join(REF_DIR,out)
...@@ -295,6 +331,8 @@ class FinesseTestProcess(Thread): ...@@ -295,6 +331,8 @@ class FinesseTestProcess(Thread):
reportname = today.strftime('%d%m%y') reportname = today.strftime('%d%m%y')
print "Writing report to " + reportname print "Writing report to " + reportname
self.cancelCheck()
f = open(reportname,'w') f = open(reportname,'w')
f.write("Python Nightly Test\n") f.write("Python Nightly Test\n")
f.write(today.strftime('%A, %d. %B %Y %I:%M%p') + "\n") f.write(today.strftime('%A, %d. %B %Y %I:%M%p') + "\n")
...@@ -326,6 +364,8 @@ class FinesseTestProcess(Thread): ...@@ -326,6 +364,8 @@ class FinesseTestProcess(Thread):
f.close() f.close()
self.cancelCheck()
if self.emails: if self.emails:
if isError: if isError:
......
...@@ -19,11 +19,16 @@ def git(args): ...@@ -19,11 +19,16 @@ def git(args):
else: else:
cmd = GIT_BIN + " " + args cmd = GIT_BIN + " " + args
print cmd
print os.getcwd()
p = sub.Popen(cmd, stdout=sub.PIPE, stderr=sub.PIPE) 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:
print err print "STDERR: " + err
print "STDOUT: " + err
raise RunException(p.returncode, args, err, out) raise RunException(p.returncode, args, err, out)
return [out, err] return [out, err]
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
Test status: <span id="txtStatus"></span> Test status: <span id="txtStatus"></span>
<div id="current_test_progress" style="width:500px;"></div> <div id="current_test_progress" style="width:500px;"></div>
<input type="button" value="Refresh" id="btnGetProgress"/> <input type="button" value="Refresh" id="btnGetProgress"/>
<input type="button" value="Cancel" id="btnCancelCurrent"/>
</div> </div>
<div class="queued_tests"> <div class="queued_tests">
...@@ -37,10 +38,14 @@ ...@@ -37,10 +38,14 @@
<div class="new_test"> <div class="new_test">
<h2>Start new test</h2> <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;"> <select id="commit_list" style="width: 300px;">
</select> </select>
<input type="button" value="Refresh log entries" id="btnGetLogs"/> <input type="button" value="Refresh" id="btnGetLogs"/>
<input type="button" value="Start new FINESSSE test" id="btnStartTest"/> <input type="button" value="Start new FINESSSE test" id="btnStartTest"/>
</div> </div>
...@@ -52,7 +57,7 @@ ...@@ -52,7 +57,7 @@
<script type="text/JavaScript"> <script type="text/JavaScript">
$(document).ready(function(){ $(document).ready(function(){
updateLogEntries(); updateBranches();
window.setInterval(function(){ window.setInterval(function(){
updateQueuedTests(); updateQueuedTests();
...@@ -70,6 +75,12 @@ ...@@ -70,6 +75,12 @@
}); });
$("#btnGetLogs").click(function(){ $("#btnGetLogs").click(function(){
$("#branch_list").empty();
updateBranches();
});
$("#branch_list").change(function(){
$("#commit_list").empty();
updateLogEntries(); updateLogEntries();
}); });
...@@ -81,6 +92,7 @@ ...@@ -81,6 +92,7 @@
updateProgress(); updateProgress();
}); });
function updateProgress(){ function updateProgress(){
$.ajax({ $.ajax({
type: "POST", type: "POST",
...@@ -88,14 +100,28 @@ ...@@ -88,14 +100,28 @@
url: "/finesse/get_test_progress", url: "/finesse/get_test_progress",
success: function (data) { success: function (data) {
if(data.running){ if(data.cancelling){
$('#btnCancelCurrent').attr("disabled", true);
$('#txtGitVersion').text(data.version); $('#txtGitVersion').text(data.version);
$('#txtStatus').text(data.status); $('#txtStatus').text("CANCELLING AT NEXT CHANCE - " + data.status);
$( "#current_test_progress" ).progressbar({ value: data.percent }); $( "#current_test_progress" ).progressbar({ value: data.percent });
} else { } else {
$('#txtGitVersion').text("N/A"); if(data.running){
$('#txtStatus').text("No test running"); $('#txtGitVersion').text(data.version);
$( "#current_test_progress" ).progressbar({ value: false }); $('#txtStatus').text(data.status);
$("#current_test_progress").progressbar({ value: data.percent });
$('#btnCancelCurrent').attr("disabled", false);
$('#btnCancelCurrent').unbind('click');
$('#btnCancelCurrent').click(function(){
$('#btnCancelCurrent').attr("disabled", true);
cancelTest(data.id);
});
} else {
$('#btnCancelCurrent').attr("disabled", true);
$('#txtGitVersion').text("N/A");
$('#txtStatus').text("No test running");
$( "#current_test_progress" ).progressbar({ value: false });
}
} }
}, },
error: function(jqXHR, textStatus, err){ error: function(jqXHR, textStatus, err){
...@@ -105,6 +131,20 @@ ...@@ -105,6 +131,20 @@
}); });
} }
function cancelTest(id){
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
url: "/finesse/cancel_test_" + id,
success: function () {
},
error: function(jqXHR, textStatus, err){
console.log('error: ' + err);
},
dataType: "json"
});
}
function startNewTest(){ function startNewTest(){
list = $("#commit_list"); list = $("#commit_list");
...@@ -160,7 +200,7 @@ ...@@ -160,7 +200,7 @@
rows += '<td>'+ tests[i].id + '</td>'; rows += '<td>'+ tests[i].id + '</td>';
rows += '<td>'+ tests[i].queue_time +'</td>'; rows += '<td>'+ tests[i].queue_time +'</td>';
rows += '<td>'+ tests[i].git_commit +'</td>'; rows += '<td>'+ tests[i].git_commit +'</td>';
rows += '<td>'; rows += '<td><input type="button" value="Cancel" onclick="cancelTest(' + tests[i].id + ');"'+ +'</td>';
rows += '</tr>'; rows += '</tr>';
tbl.append(rows); tbl.append(rows);
...@@ -176,21 +216,48 @@ ...@@ -176,21 +216,48 @@
}); });
} }
function updateBranches(){
$("#btnStartTest").attr("disabled", true);
blist = $("#branch_list");
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
url: "/finesse/get_branches",
success: function (data) {
branches = data.branches;
blist.empty();
for(var i=0; i<branches.length; i++){
blist.append($('<option>', { value: branches[i], text: branches[i]}));
}
updateLogEntries();
},
error: function(jqXHR, textStatus, err){
console.log('error: ' + err);
},
dataType: "json"
});
}
function updateLogEntries(){ function updateLogEntries(){
$("#btnStartTest").attr("disabled", true);
list = $("#commit_list"); list = $("#commit_list");
list.empty();
$.ajax({ $.ajax({
type: "POST", type: "POST",
contentType: "application/json; charset=utf-8", contentType: "application/json; charset=utf-8",
url: "/finesse/get_50_logs", url: "/finesse/get_50_" + $("#branch_list").val() + "_logs",
success: function (data) { success: function (data) {
logs = data.logs; logs = data.logs;
list.empty();
for(var i=0; i<logs.length; i++){ for(var i=0; i<logs.length; i++){
list.append($('<option>', { value: logs[i].commit, text: logs[i].commit + " - " + logs[i].message})); list.append($('<option>', { value: logs[i].commit, text: logs[i].commit + " - " + logs[i].message}));
} }
$("#btnStartTest").attr("disabled", false);
}, },
error: function(jqXHR, textStatus, err){ error: function(jqXHR, textStatus, err){
console.log('error: ' + err); console.log('error: ' + err);
......
...@@ -68,9 +68,47 @@ class FinesseProcessWatcher(Thread): ...@@ -68,9 +68,47 @@ class FinesseProcessWatcher(Thread):
current_test = None current_test = None
schedule_lock.release() schedule_lock.release()
@app.route('/finesse/cancel_test_<id>', methods=["POST"])
def finesse_cancel_test(id):
print id
if int(id) >= 0:
id = int(id)
print "Cancelling " + str(id)
try:
# get lock here so that watcher doesn't interfere
# with removing/starting new tests
schedule_lock.acquire()
print current_test
if current_test is not None:
print "cid " + str(current_test.test_id)
if current_test.test_id == id:
current_test.cancelling = True
print "Cancelling Current Test"
return str(id)
ix = 0
remove = -1;
for t in scheduled_tests:
if t.test_id == id:
remove = ix
break
ix += 1
if remove > -1:
print "Cancelled queued test"
scheduled_tests.pop(remove)
return str(id)
print "Nothing cancelled"
return "0"
finally:
schedule_lock.release()
@app.route('/') @app.route('/')
def home_page(): def home_page():
...@@ -105,7 +143,7 @@ def finesse_start_test(): ...@@ -105,7 +143,7 @@ def finesse_start_test():
TEST_RUN_PATH, TEST_RUN_PATH,
git_commit, git_commit,
run_fast=False, suites=[], test_id=test_id, run_fast=False, suites=[], test_id=test_id,
emails="", nobuild=True) emails="", nobuild=False)
# check if anything is running and if it # check if anything is running and if it
# isn't start this test off # isn't start this test off
...@@ -148,21 +186,46 @@ def finesse_get_test_progress(): ...@@ -148,21 +186,46 @@ def finesse_get_test_progress():
return jsonify(running=False) return jsonify(running=False)
else: else:
test_id = current_test.test_id
cancelling = current_test.cancelling