testing upload and connection failures

svn path=/trunk/boinc/; revision=1510
This commit is contained in:
Karl Chen 2003-06-17 01:36:47 +00:00
parent 23d43298b0
commit 9d73195870
8 changed files with 389 additions and 159 deletions

View File

@ -4689,3 +4689,14 @@ Karl 2003/06/16
_autosetup
configure.ac
Karl 2003/06/16
Testing upload and connection failures (work in progress)
test.inc
test_uc.inc
test_uc.php
test_masterurl_failure.php
test_upload_resume.php
test_upload_backoff.php
testproxy

View File

@ -108,11 +108,20 @@ function verbose_XPassThru($cmd, $failok=0)
return XPassThru($cmd, $failok);
}
function proxerize($s, $t)
{
if ($t) {
return preg_replace(",http://[^/]*/,", "http://localhost:8080/", $s);
} else {
return $s;
}
}
define("KEY_DIR" , get_env_var("BOINC_KEY_DIR"));
define("SHMEM_KEY" , get_env_var("BOINC_SHMEM_KEY"));
define("PROJECTS_DIR" , get_env_var("BOINC_PROJECTS_DIR"));
define("CGI_URL" , get_env_var("BOINC_CGI_URL"));
define("HTML_URL" , get_env_var("BOINC_HTML_URL"));
define("CGI_URL" , proxerize(get_env_var("BOINC_CGI_URL"), $use_proxy_cgi));
define("HTML_URL" , proxerize(get_env_var("BOINC_HTML_URL"), $use_proxy_html));
define("USER_NAME" , get_env_var("BOINC_USER_NAME", get_env_var("USER","")));
define("CGI_DIR" , get_env_var("BOINC_CGI_DIR"));
define("HTML_DIR" , get_env_var("BOINC_HTML_DIR"));
@ -927,6 +936,7 @@ class Host {
// get_new_boincpid() must be called and kill() must be called on it.
//
function run_asynch($args) {
// TODO: just use shell & to background?
$pid = pcntl_fork();
if ($pid == -1) {
return -1;
@ -935,9 +945,11 @@ class Host {
} else { //we are the child
verbose_echo(1, "Running core client asynch");
$source_dir = SRC_DIR;
$platform = PLATFORM;
$exec_name = CLIENT_BIN_FILENAME;
XPassThru("cd $this->host_dir; $source_dir/client/$exec_name $args > client.out");
assert($source_dir && 1);
assert($exec_name && 1);
assert($this->host_dir && 1);
verbose_XPassThru("cd $this->host_dir; $source_dir/client/$exec_name $args > client.out");
exit(0);
}
}
@ -959,7 +971,10 @@ class Host {
verbose_echo(1, "Running core client");
$source_dir = SRC_DIR;
$exec_name = CLIENT_BIN_FILENAME;
XPassThru("cd $this->host_dir; $source_dir/client/$exec_name $args > client.out", $ret);
assert($source_dir && 1);
assert($exec_name && 1);
assert($this->host_dir && 1);
verbose_XPassThru("cd $this->host_dir; $source_dir/client/$exec_name $args > client.out", $ret);
assert ($ret == 0);
}
@ -1070,6 +1085,11 @@ class Work {
}
}
function start_proxy($code)
{
verbose_XPassThru("./testproxy 8080 localhost:80 '$code' 2>/dev/null &");
}
function test_msg($msg)
{
echo "-- Testing " . $msg . ' ' . str_repeat('-', 78 - strlen($msg)-12) . "\n";

View File

@ -1,56 +1,22 @@
#! /usr/local/bin/php
<?php
//This tests the exponential backoff mechanism on the client in case of master IURL failures
//This test is not automated. It has to be run, and then client.out (in the host directory) must be looked at to examine wether everything is working correctly.
include_once("test.inc");
#!/usr/local/bin/php -q
<?php {
// $Id$
$project = new Project;
$user = new User();
$host = new Host($user);
$use_proxy_html = 1;
$app = new App("upper_case");
$app_version = new App_Version($app);
include_once("test_uc.inc");
test_msg("master url failure");
// the following is optional (makes client web download possible)
$core_app = new App("core client");
$core_app_version = new App_Version($core_app);
$project->add_app($core_app);
$project->add_app_version($core_app_version);
$project = new ProjectUC;
$project->add_user($user);
$project->add_app($app);
$project->add_app_version($app_version);
start_proxy('exit 1 if $nconnections < 4; if_done_kill(); if_done_ping();');
$project->install(); // must install projects before adding to hosts
// TODO: verify it took ??? seconds
$host->log_flags = "log_flags.xml";
$host->add_project($project);
$host->install();
// TODO: time out after ??? seconds and fail this test
echo "adding work\n";
$project->start_servers_and_host();
$project->validate_all_and_stop();
$work = new Work($app);
$work->wu_template = "uc_wu";
$work->result_template = "uc_result";
$work->redundancy = 2;
$work->delay_bound = 10;
array_push($work->input_files, "input");
$work->install($project);
$project->start_feeder();
$project->delete_masterindex();
$pid = $host->run_asynch("-exit_when_idle");
echo "sleeping for 100 seconds\n";
sleep(100);
$project->reestablish_masterindex();
$status = 0;
pcntl_waitpid($pid,$status,0);
$project->stop();
$result->server_state = RESULT_SERVER_STATE_OVER;
$result->stderr_out = "APP: upper_case: starting, argc 1";
$result->exit_status = 0;
$project->check_results(2, $result);
$project->compare_file("uc_wu_0_0", "uc_correct_output");
$project->compare_file("uc_wu_1_0", "uc_correct_output");
?>
test_done();
} ?>

75
test/test_uc.inc Normal file
View File

@ -0,0 +1,75 @@
<?php {
// $Id$
include_once("test.inc");
class ProjectUC extends Project
{
var $work;
var $host;
var $user;
function ProjectUC() {
$this->Project();
$this->add_core_and_version();
$this->add_app_and_version("upper_case");
$this->user = new User();
$this->user->project_prefs = "<project_specific>\nfoobar\n</project_specific>\n";
$this->user->global_prefs = "<venue name=\"home\">\n".
"<work_buf_min_days>0</work_buf_min_days>\n".
"<work_buf_max_days>2</work_buf_max_days>\n".
"<disk_interval>1</disk_interval>\n".
"<run_on_batteries/>\n".
"<max_bytes_sec_down>400000</max_bytes_sec_down>\n".
"</venue>\n";
$this->add_user($this->user);
$this->install(); // must install projects before adding to hosts
$this->install_feeder();
$this->host = new Host();
$this->host->add_user($this->user, $this);
$this->host->install();
$this->work = new Work();
$this->work->wu_template = "uc_wu";
$this->work->result_template = "uc_result";
$this->work->redundancy = 2;
$this->work->delay_bound = 10;
// Say that 1 WU takes 1 day on a ref comp
$this->work->rsc_fpops = 86400*1e9/2;
$this->work->rsc_iops = 86400*1e9/2;
$this->work->rsc_disk = 10e8;
array_push($this->work->input_files, "input");
$this->work->install($this);
}
function start_servers_and_host()
{
$this->start_servers();
$this->host->run("-exit_when_idle -skip_cpu_benchmarks");
}
function validate_all_and_stop()
{
$this->validate($this->work->redundancy);
$result->server_state = RESULT_SERVER_STATE_OVER;
$result->stderr_out = "APP: upper_case: starting, argc 1
APP: upper_case: argv[0] is upper_case
APP: upper_case ending, wrote ";
$result->exit_status = 0;
$this->check_results(2, $result);
$this->compare_file("uc_wu_0_0", "uc_correct_output");
$this->compare_file("uc_wu_1_0", "uc_correct_output");
$this->assimilate();
$this->file_delete();
$this->check_server_deleted("download/input");
$this->check_server_deleted("upload/uc_wu_0_0");
$this->check_server_deleted("upload/uc_wu_1_0");
$this->stop();
}
}
} ?>

View File

@ -6,64 +6,12 @@
// Also whether stderr output is reported correctly
// Also tests if water levels are working correctly
include_once("test.inc");
include_once("test_uc.inc");
test_msg("standard upper_case application");
$project = new Project;
$project->add_core_and_version();
$project->add_app_and_version("upper_case");
$user = new User();
$user->project_prefs = "<project_specific>\nfoobar\n</project_specific>\n";
$user->global_prefs = "<venue name=\"home\">\n".
"<work_buf_min_days>0</work_buf_min_days>\n".
"<work_buf_max_days>2</work_buf_max_days>\n".
"<disk_interval>1</disk_interval>\n".
"<run_on_batteries/>\n".
"<max_bytes_sec_down>400000</max_bytes_sec_down>\n".
"</venue>\n";
$project->add_user($user);
$project->install(); // must install projects before adding to hosts
$project->install_feeder();
$host = new Host();
$host->add_user($user, $project);
$host->install();
$work = new Work();
$work->wu_template = "uc_wu";
$work->result_template = "uc_result";
$work->redundancy = 2;
$work->delay_bound = 10;
// Say that 1 WU takes 1 day on a ref comp
$work->rsc_fpops = 86400*1e9/2;
$work->rsc_iops = 86400*1e9/2;
$work->rsc_disk = 10e8;
array_push($work->input_files, "input");
$work->install($project);
$project->start_servers();
$host->run("-exit_when_idle -skip_cpu_benchmarks");
$project->validate(2);
$result->server_state = RESULT_SERVER_STATE_OVER;
$result->stderr_out = "APP: upper_case: starting, argc 1
APP: upper_case: argv[0] is upper_case
APP: upper_case ending, wrote ";
$result->exit_status = 0;
$project->check_results(2, $result);
$project->compare_file("uc_wu_0_0", "uc_correct_output");
$project->compare_file("uc_wu_1_0", "uc_correct_output");
$project->assimilate();
$project->file_delete();
$project->check_server_deleted("download/input");
$project->check_server_deleted("upload/uc_wu_0_0");
$project->check_server_deleted("upload/uc_wu_1_0");
$project->stop();
$project = new ProjectUC;
$project->start_servers_and_host();
$project->validate_all_and_stop();
test_done();
} ?>

View File

@ -1,58 +1,23 @@
#! /usr/local/bin/php
<?php
//This tests the exponential backoff mechanism on the client in case of downloadURLs going down
//This test is not automated. It has to be run, and then client.out (in the host directory) must be looked at to examine wether everything is working correctly.
include_once("test.inc");
#!/usr/local/bin/php -q
<?php {
// $Id$
$project = new Project;
$user = new User();
$host = new Host($user);
// This tests whether upload resuming works correctly.
$app = new App("upper_case");
$app_version = new App_Version($app);
$use_proxy_cgi = 1;
// the following is optional (makes client web download possible)
$core_app = new App("core client");
$core_app_version = new App_Version($core_app);
$project->add_app($core_app);
$project->add_app_version($core_app_version);
include_once("test_uc.inc");
test_msg("upload backoff");
$project->add_user($user);
$project->add_app($app);
$project->add_app_version($app_version);
$project = new ProjectUC;
$project->install(); // must install projects before adding to hosts
// TODO
// start_proxy('exit 1 if ($nconnections < 4); if_done_kill(); if_done_ping();');
$host->log_flags = "log_flags.xml";
$host->add_project($project);
$host->install();
// $pid = $host->run_asynch("-exit_when_idle");
echo "adding work\n";
$project->start_servers_and_host();
$project->validate_all_and_stop();
$work = new Work($app);
$work->wu_template = "uc_wu";
$work->result_template = "uc_result";
$work->redundancy = 2;
$work->delay_bound = 10;
array_push($work->input_files, "input");
$work->install($project);
$project->start_feeder();
$project->remove_file_upload_handler();
$pid = $host->run_asynch("-exit_when_idle");
echo "sleeping 20 secs\n";
sleep(20);
$project->reinstall_file_upload_handler(null);
$status = 0;
//wait until the host has stopped running
pcntl_waitpid($pid, $status,0);
$project->stop();
$result->server_state = RESULT_SERVER_STATE_OVER;
$result->stderr_out = "APP: upper_case: starting, argc 1";
$result->exit_status = 0;
$project->check_results(2, $result);
$project->compare_file("uc_wu_0_0", "uc_correct_output");
$project->compare_file("uc_wu_1_0", "uc_correct_output");
?>
test_done();
} ?>

View File

@ -0,0 +1,21 @@
#!/usr/local/bin/php -q
<?php {
// $Id$
// This tests whether upload resuming works correctly.
$use_proxy_cgi = 1;
include_once("test_uc.inc");
test_msg("upload resumes");
$project = new ProjectUC;
// TODO
// start_proxy('exit 1 if ($nconnections ==1 && $bytes_transferred==ZZZ); if_done_kill(); if_done_ping();');
$project->start_servers_and_host();
$project->validate_all_and_stop();
test_done();
} ?>

224
test/testproxy Executable file
View File

@ -0,0 +1,224 @@
#!/usr/bin/env perl
# -T
# $Id$
# 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/
#
# 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.
#
# The Initial Developer of the Original Code is the SETI@home project.
# Portions created by the SETI@home project are Copyright (C) 2002, 2003
# University of California at Berkeley. All Rights Reserved.
#
# Contributor(s):
#
# testproxy - proxy a TCP/IP connection with configurable mid-way
# disconnections, for simulating internet transfer failures
use strict;
use warnings;
use Carp;
use IO::Socket::INET;
my $listen_port = shift;
my $target_server = shift;
my $testcode = join(' ', @ARGV);
if (!$listen_port || !$target_server) {
print STDERR <<HELP;
syntax: $0 <listen_port> <target_server:port> CODE...
CODE is evaluated every 128 bytes transferred from server to client.
Some variables you can access/modify:
\$target, \$client : perl IO::Handle::INET objects
\$nconnections : number of connections so far
\$chars, \$nchars : characters & length about to send to client.
\$bytes_transferred : characters already sent to client
\$done, \$success : finished transfer; successful transfer
For more, view the code.
You can call functions like exit, sleep, \$target\->close, \$target\->print.
You should return 1 to indicate success (otherwise testproxy will warn).
Examples:
# fail connections for first 3 connections
$0 8080 localhost:80 'exit 1 if \$nconnections < 4; 1'
# sleep 5 seconds in the middle of transfer, and print "success" if
# transfer succeeds; kill the server after the first connection
$0 8080 localhost:80 'sleep 5 if \$bytes_transferred == 256;
if (\$done) { print "success\\n" if \$success; kill_server; \$success }
else { 1 }'
# equivalent to above:
$0 8080 localhost:80 'sleep 5 if \$bytes_transferred == 256;
if_done_kill(); if_done_ping();'
HELP
;
exit(1);
}
if ($target_server !~ /:/) {
$target_server .= ':http';
}
my $N = "\015\012";
sub proxy;
sub spawn;
sub logmsg { print STDERR "$0 $$: @_ at ", scalar localtime, "\n" }
my $server = IO::Socket::INET->new(Listen => 5,
LocalAddr => inet_ntoa(INADDR_ANY),
LocalPort => $listen_port,
Proto => 'tcp',
ReuseAddr => 1)
or die "$0: creating socket on port $listen_port: $!";
logmsg "server started on port $listen_port proxy to $target_server";
my $waitedpid = 0;
my $paddr;
my $server_pid = $$;
use POSIX ":sys_wait_h";
sub REAPER {
my $child;
while (($waitedpid = waitpid(-1,WNOHANG)) > 0) {
# logmsg "reaped $waitedpid" . ($? ? " with exit $?" : '');
}
$SIG{CHLD} = \&REAPER; # loathe sysV
}
$SIG{CHLD} = \&REAPER;
my $nconnections = 0;
my $client;
for ( $waitedpid = 0;
($client = $server->accept()) || $waitedpid;
$waitedpid = 0)
{
next if $waitedpid and not $client;
die unless $client;
my $paddr = $client->peername();
my($port,$iaddr) = sockaddr_in($paddr);
my $name = gethostbyaddr($iaddr,AF_INET);
logmsg "connection from $name", "[", inet_ntoa($iaddr), "]:$port";
++$nconnections;
spawn \&proxy, $client;
}
sub spawn {
my $coderef = shift;
unless ($coderef && ref($coderef) eq 'CODE') {
confess "usage: spawn CODEREF";
}
my $pid;
if (!defined($pid = fork)) {
logmsg "cannot fork: $!";
return;
} elsif ($pid) {
# logmsg "begat $pid";
return; # I'm the parent
}
# else I'm the child -- go spawn
exit &$coderef(@_);
}
sub kill_server()
{
kill "INT", $server_pid;
}
my $done = 0;
my $success = 0;
sub if_done_ping()
{
if ($done) {
if ($success) {
print "success\n";
} else {
print "failed\n";
return 0;
}
}
1;
}
sub if_done_kill()
{
if ($done) {
kill_server();
}
1;
}
sub proxy {
my $client = shift or die;
my $target = IO::Socket::INET->new(PeerAddr => $target_server)
or die "$0: couldn't connect to $target_server: $!";
$client->autoflush(1);
$target->autoflush(1);
# transfer lines from client -> server until we get an empty line
while (my $line = $client->getline()) {
$target->print($line);
$line =~ s/[\015\012]+$//;
last unless $line;
}
# transfer from server->client
my $bytes_transferred = 0;
# while (my $line = $target->getline()) {
# $bytes_transferred += length($line);
# print "[$bytes_transferred] $line";
# $client->print($line);
# }
$done = 0;
$success = 0;
my $chars;
my $nchars;
while ($nchars = $target->read($chars, 128)) {
eval $testcode || warn;
$bytes_transferred += $nchars;
$client->write($chars, $nchars);
}
{
$chars = undef; $nchars = 0;
$done = 1;
$success = $client->connected() && 1;
eval $testcode || warn;
}
$target->close();
$client->close();
}