fixed client state after file abort bug ; test scripts

svn path=/trunk/boinc/; revision=1600
This commit is contained in:
Karl Chen 2003-06-26 23:53:37 +00:00
parent b780baa4ba
commit 054eb0521a
8 changed files with 146 additions and 63 deletions

View File

@ -5069,3 +5069,17 @@ Karl 2003/06/25
cronjob - complains if anything fails.
./testbase (new)
Karl 2003/06/26
- fixed bug that caused client state to transition to
RESULT_FILES_UPLOADING even when file info(s) had errors; now it stays
in RESULT_COMPUTE_DONE.
- test makefile should rebuild version.py and boinc_db.py if necessary
- test_sanity should make sure proxy setup works
- test_masterurl_failure
test/
Makefile.am
test_sanity.py
boinc.py
test_masterurl_failure.py

View File

@ -1344,18 +1344,20 @@ bool CLIENT_STATE::update_results() {
action = true;
}
break;
case RESULT_FILES_DOWNLOADED:
// The transition to COMPUTE_DONE is performed
// in app_finished()
break;
case RESULT_COMPUTE_DONE:
// Once the computation has been done, check
// that the necessary files have been uploaded
// before moving on
rp->state = RESULT_FILES_UPLOADING;
action = true;
break;
// app_finished() transitions to either RESULT_COMPUTE_DONE or
// RESULT_FILES_UPLOADING. RESULT_COMPUTE_DONE is a dead-end state
// indicating we had an error at the end of computation.
// case RESULT_FILES_DOWNLOADED:
// break;
// case RESULT_COMPUTE_DONE:
// rp->state = RESULT_FILES_UPLOADING;
// action = true;
// break;
case RESULT_FILES_UPLOADING:
// Once the computation has been done, check that the necessary
// files have been uploaded before moving on
if (rp->is_upload_done()) {
rp->ready_to_ack = true;
rp->state = RESULT_FILES_UPLOADED;

View File

@ -1,19 +1,19 @@
// The contents of this file are subject to the Mozilla Public License
// Version 1.0 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://www.mozilla.org/MPL/
//
// http://www.mozilla.org/MPL/
//
// Software distributed under the License is distributed on an "AS IS"
// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
// License for the specific language governing rights and limitations
// under the License.
//
// The Original Code is the Berkeley Open Infrastructure for Network Computing.
//
// under the License.
//
// The Original Code is the Berkeley Open Infrastructure for Network Computing.
//
// The Initial Developer of the Original Code is the SETI@home project.
// Portions created by the SETI@home project are Copyright (C) 2002
// University of California at Berkeley. All Rights Reserved.
//
// Portions created by the SETI@home project are Copyright (C) 2002, 2003
// University of California at Berkeley. All Rights Reserved.
//
// Contributor(s):
//
@ -93,40 +93,53 @@ int CLIENT_STATE::app_finished(ACTIVE_TASK& at) {
int retval;
double size;
bool had_error = false;
for (i=0; i<rp->output_files.size(); i++) {
fip = rp->output_files[i].file_info;
get_pathname(fip, path);
retval = file_size(path, size);
if (retval) {
// an output file is unexpectedly absent.
//
//
fip->status = retval;
} else {
if (size > fip->max_nbytes) {
msg_printf(at.result->project, MSG_INFO, "Output file %s for result %s exceeds size limit.",
fip->name, at.result->name);
had_error = true;
} else if (size > fip->max_nbytes) {
// Note: this is only checked when the application finishes. there
// is also a check_max_disk_exceeded that is checked while the
// application is running.
msg_printf(rp->project, MSG_INFO, "Output file %s for result %s exceeds size limit.",
fip->name, rp->name);
fip->delete_file();
fip->status = ERR_FILE_TOO_BIG;
fip->delete_file();
fip->status = ERR_FILE_TOO_BIG;
had_error = true;
} else {
if (!fip->upload_when_present && !fip->sticky) {
fip->delete_file(); // sets status to NOT_PRESENT
} else {
if (!fip->upload_when_present && !fip->sticky) {
fip->delete_file(); // sets status to NOT_PRESENT
retval = md5_file(path, fip->md5_cksum, fip->nbytes);
if (retval) {
fip->status = retval;
had_error = true;
} else {
retval = md5_file(path, fip->md5_cksum, fip->nbytes);
if (retval) {
fip->status = retval;
} else {
fip->status = FILE_PRESENT;
}
fip->status = FILE_PRESENT;
}
}
}
}
at.result->is_active = false;
at.result->state = RESULT_COMPUTE_DONE;
update_avg_cpu(at.result->project);
at.result->project->exp_avg_cpu += at.result->final_cpu_time;
rp->is_active = false;
if (had_error) {
// dead-end state indicating we had an error at end of computation;
// do not move to RESULT_FILES_UPLOADING
rp->state = RESULT_COMPUTE_DONE;
} else {
// can now upload files.
rp->state = RESULT_FILES_UPLOADING;
}
update_avg_cpu(rp->project);
rp->project->exp_avg_cpu += rp->final_cpu_time;
return 0;
}

View File

@ -20,6 +20,8 @@ noinst_SCRIPTS = \
BUILT_SOURCES = boinc_db.inc boinc_db.py
$(TESTS): version.py boinc_db.py
boinc_db.inc: ../db/boinc_db.h
./db_def_to_php < ../db/boinc_db.h > boinc_db.inc

View File

@ -415,6 +415,8 @@ uninstall-am: uninstall-info-am
$(LIBRSA):
cd $(top_builddir)/RSAEuro/source; ${MAKE} librsaeuro.a
$(TESTS): version.py boinc_db.py
boinc_db.inc: ../db/boinc_db.h
./db_def_to_php < ../db/boinc_db.h > boinc_db.inc

View File

@ -66,20 +66,24 @@ def verbose_sleep(msg, wait):
verbose_echo(1, msg + ' [sleep ' + ('.'*i).ljust(wait) + ']')
time.sleep(1)
def shell_call(cmd, failok=False):
def shell_call(cmd, doexec=False, failok=False):
if doexec:
os.execl('/bin/sh', 'sh', '-c', cmd)
error("Command failed: "+cmd)
os._exit(1)
if os.system(cmd):
error("Command failed: "+cmd, fatal=(not failok))
return 1
return 0
def verbose_shell_call(cmd, failok=False):
def verbose_shell_call(cmd, doexec=False, failok=False):
verbose_echo(2, " "+cmd)
return shell_call(cmd, failok)
return shell_call(cmd, doexec, failok)
def proxerize(url, t):
def proxerize(url, t=True):
if t:
r = re.compile('http://[^/]*/')
return r.sub('http://localhost:080/', url)
return r.sub('http://localhost:8080/', url)
else:
return url
@ -94,8 +98,10 @@ HTML_DIR = get_env_var("BOINC_HTML_DIR")
HOSTS_DIR = get_env_var("BOINC_HOSTS_DIR")
def use_cgi_proxy():
global CGI_URL
CGI_URL = proxerize(CGI_URL)
def use_html_proxy():
global HTML_URL
HTML_URL = proxerize(HTML_URL)
def check_exists(file):
@ -889,23 +895,32 @@ def run_check_all():
all_projects.check()
# all_projects.stop()
proxy_pid = 0
def start_proxy(code):
global proxy_pid
pid = os.fork()
if not pid:
os._exit(verbose_shell_call("./testproxy 8080 localhost:80 '$code' 2>testproxy.log"))
verbose_sleep("Starting proxy server", 1)
proxy_pid = pid
# check if child process died
(pid,status) = os.waitpid(pid, os.WNOHANG)
if pid:
fatal_error("testproxy failed")
def stop_proxy():
global proxy_pid
if proxy_pid:
os.kill(2, proxy_pid)
class Proxy:
def __init__(self, code, cgi=0, html=0, start=1):
self.pid = 0
self.code = code
if cgi: use_cgi_proxy()
if html: use_html_proxy()
if start: self.start()
def start(self):
self.pid = os.fork()
if not self.pid:
verbose_shell_call("exec ./testproxy 8080 localhost:80 '%s' 2>testproxy.log"%self.code,
doexec=True)
verbose_sleep("Starting proxy server", 1)
# check if child process died
(pid,status) = os.waitpid(self.pid, os.WNOHANG)
if pid:
fatal_error("testproxy failed")
atexit.register(self.stop)
def stop(self):
verbose_echo(1, "Stopping proxy server")
if self.pid:
try:
os.kill(self.pid, 2)
except OSError:
verbose_echo(0, "Couldn't kill pid %d" % self.pid)
self.pid = 0
def test_msg(msg):
print

15
test/test_masterurl_failure.py Executable file
View File

@ -0,0 +1,15 @@
#!/usr/bin/env python
## $Id$
from test_uc import *
if __name__ == '__main__':
test_msg("scheduler exponential backoff (master url failure)")
proxy = Proxy('exit 1 if $nconnections < 4; if_done_kill(); if_done_ping();',
html=1)
ProjectUC()
run_check_all()
## TODO: verify it took ??? seconds
## TODO: time out after ??? seconds and fail this test

View File

@ -7,12 +7,14 @@ from boinc import *
# test makes sure that testing framework is sane
def read_url(url):
def read_url(url, quiet=False):
'''return 1 line from url'''
verbose_echo(2, " reading url: "+url)
try:
return urllib.URLopener().open(url).readline().strip()
except IOError, e:
error("couldn't access HTML_URL: %s %s" % (HTML_URL, e))
if not quiet:
error("couldn't access url: %s %s" % (url, e))
return ''
if __name__ == '__main__':
@ -35,6 +37,7 @@ if __name__ == '__main__':
html_path = os.path.join(HTML_DIR, 'test_sanity.txt')
html_url = os.path.join(HTML_URL, 'test_sanity.txt')
html_proxy_url = proxerize(html_url)
cgi_path = os.path.join(CGI_DIR, 'test_sanity_cgi')
cgi_url = os.path.join(CGI_URL, 'test_sanity_cgi')
@ -43,6 +46,23 @@ if __name__ == '__main__':
if read_url(html_url) != magic:
error("couldn't access a file I just wrote: "+html_path+"\n using url: "+html_url)
verbose_echo(1, "Checking proxy setup")
if read_url(html_proxy_url, quiet=True):
error("Another proxy already running")
else:
proxy = Proxy('')
if read_url(html_proxy_url) != magic:
error("couldn't access file using proxy url: "+html_proxy_url)
else:
proxy.stop()
proxy = Proxy('exit 1 if $nconnections < 2; if_done_kill(); if_done_ping();')
if read_url(html_proxy_url, quiet=True):
error("Proxy should have closed connection #1")
if read_url(html_proxy_url) != magic:
error("Proxy should have allowed connection #2")
proxy.stop()
os.unlink(html_path)
verbose_echo(1, "Checking webserver setup: cgi")