From 9d731958707368f7afeaba7f99c8380d884aac8b Mon Sep 17 00:00:00 2001 From: Karl Chen Date: Tue, 17 Jun 2003 01:36:47 +0000 Subject: [PATCH] testing upload and connection failures svn path=/trunk/boinc/; revision=1510 --- checkin_notes | 11 ++ test/test.inc | 30 ++++- test/test_masterurl_failure.php | 62 ++------- test/test_uc.inc | 75 +++++++++++ test/test_uc.php | 60 +-------- test/test_upload_backoff.php | 65 +++------ test/test_upload_resume.php | 21 +++ test/testproxy | 224 ++++++++++++++++++++++++++++++++ 8 files changed, 389 insertions(+), 159 deletions(-) create mode 100644 test/test_uc.inc create mode 100644 test/test_upload_resume.php create mode 100755 test/testproxy diff --git a/checkin_notes b/checkin_notes index d242bd313f..d38c157bd6 100755 --- a/checkin_notes +++ b/checkin_notes @@ -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 diff --git a/test/test.inc b/test/test.inc index e54ad5b6d6..54906683ff 100644 --- a/test/test.inc +++ b/test/test.inc @@ -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"; diff --git a/test/test_masterurl_failure.php b/test/test_masterurl_failure.php index 9c54bfb3bc..3cfec6d516 100644 --- a/test/test_masterurl_failure.php +++ b/test/test_masterurl_failure.php @@ -1,56 +1,22 @@ -#! /usr/local/bin/php -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(); +} ?> diff --git a/test/test_uc.inc b/test/test_uc.inc new file mode 100644 index 0000000000..5f9d44b4dc --- /dev/null +++ b/test/test_uc.inc @@ -0,0 +1,75 @@ +Project(); + $this->add_core_and_version(); + $this->add_app_and_version("upper_case"); + + $this->user = new User(); + $this->user->project_prefs = "\nfoobar\n\n"; + $this->user->global_prefs = "\n". + "0\n". + "2\n". + "1\n". + "\n". + "400000\n". + "\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(); + } + } +} ?> diff --git a/test/test_uc.php b/test/test_uc.php index 12c08488e1..4034b484d3 100644 --- a/test/test_uc.php +++ b/test/test_uc.php @@ -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 = "\nfoobar\n\n"; - $user->global_prefs = "\n". - "0\n". - "2\n". - "1\n". - "\n". - "400000\n". - "\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(); } ?> diff --git a/test/test_upload_backoff.php b/test/test_upload_backoff.php index 6539cd00c5..2d491628ed 100644 --- a/test/test_upload_backoff.php +++ b/test/test_upload_backoff.php @@ -1,58 +1,23 @@ -#! /usr/local/bin/php -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(); +} ?> diff --git a/test/test_upload_resume.php b/test/test_upload_resume.php new file mode 100644 index 0000000000..9788748c3e --- /dev/null +++ b/test/test_upload_resume.php @@ -0,0 +1,21 @@ +#!/usr/local/bin/php -q +start_servers_and_host(); + $project->validate_all_and_stop(); + + test_done(); +} ?> diff --git a/test/testproxy b/test/testproxy new file mode 100755 index 0000000000..c436f639b2 --- /dev/null +++ b/test/testproxy @@ -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 < 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(); +}