Add mboxes

This commit is contained in:
Alex Young
2012-06-27 15:45:33 +01:00
parent 2078d17053
commit 94b4fa887c
34 changed files with 2534 additions and 1599 deletions

View File

@@ -1,13 +1,16 @@
#include <check.h>
#include <stdio.h>
#include "self_pipe.h"
#include "nbdtypes.h"
#include "serve.h"
#include "client.h"
#include <unistd.h>
#define FAKE_SERVER ((struct server *)23)
struct server fake_server = {0};
#define FAKE_SERVER &fake_server
#define FAKE_SOCKET (42)
START_TEST( test_assigns_socket )

42
tests/check_control.c Normal file
View File

@@ -0,0 +1,42 @@
#include "control.h"
#include "flexnbd.h"
#include <check.h>
START_TEST( test_assigns_sock_name )
{
struct flexnbd flexnbd = {0};
char csn[] = "foobar";
struct control * control = control_create(&flexnbd, csn );
fail_unless( csn == control->socket_name, "Socket name not assigned" );
}
END_TEST
Suite *control_suite(void)
{
Suite *s = suite_create("control");
TCase *tc_create = tcase_create("create");
tcase_add_test(tc_create, test_assigns_sock_name);
suite_add_tcase( s, tc_create );
return s;
}
int main(void)
{
int number_failed;
Suite *s = control_suite();
SRunner *sr = srunner_create(s);
srunner_run_all(sr, CK_NORMAL);
number_failed = srunner_ntests_failed(sr);
srunner_free(sr);
return (number_failed == 0) ? 0 : 1;
}

47
tests/check_flexnbd.c Normal file
View File

@@ -0,0 +1,47 @@
#include "flexnbd.h"
#include <check.h>
START_TEST( test_listening_assigns_sock )
{
struct flexnbd * flexnbd = flexnbd_create_listening(
"127.0.0.1",
NULL,
"4777",
NULL,
"fakefile",
"fakesock",
0,
0,
NULL,
1 );
fail_if( NULL == flexnbd->control->socket_name, "No socket was copied" );
}
END_TEST
Suite *flexnbd_suite(void)
{
Suite *s = suite_create("flexnbd");
TCase *tc_create = tcase_create("create");
tcase_add_test(tc_create, test_listening_assigns_sock);
suite_add_tcase( s, tc_create );
return s;
}
int main(void)
{
int number_failed;
Suite *s = flexnbd_suite();
SRunner *sr = srunner_create(s);
srunner_run_all(sr, CK_NORMAL);
number_failed = srunner_ntests_failed(sr);
srunner_free(sr);
return (number_failed == 0) ? 0 : 1;
}

View File

@@ -1,14 +1,16 @@
#include "serve.h"
#include "listen.h"
#include "util.h"
#include "flexnbd.h"
#include <check.h>
#include <string.h>
START_TEST( test_defaults_main_serve_opts )
{
struct listen * listen = listen_create( "127.0.0.1", NULL, "4777", NULL,
"foo", "bar", 0, 0, NULL, 1 );
struct flexnbd flexnbd;
struct listen * listen = listen_create( &flexnbd, "127.0.0.1", NULL, "4777", NULL,
"foo", 0, 0, NULL, 1 );
NULLCHECK( listen );
struct server *init_serve = listen->init_serve;
struct server *main_serve = listen->main_serve;
@@ -28,7 +30,7 @@ Suite* listen_suite(void)
Suite *s = suite_create("listen");
TCase *tc_create = tcase_create("create");
tcase_add_test(tc_create, test_defaults_main_serve_opts);
tcase_add_exit_test(tc_create, test_defaults_main_serve_opts, 0);
suite_add_tcase(s, tc_create);

104
tests/check_mbox.c Normal file
View File

@@ -0,0 +1,104 @@
#include "mbox.h"
#include "util.h"
#include <pthread.h>
#include <check.h>
START_TEST( test_allocs_cvar )
{
struct mbox * mbox = mbox_create();
fail_if( NULL == mbox, "Nothing allocated" );
pthread_cond_t cond_zero;
/* A freshly inited pthread_cond_t is set to {0} */
memset( &cond_zero, 'X', sizeof( cond_zero ) );
fail_if( memcmp( &cond_zero, &mbox->filled_cond, sizeof( cond_zero ) ) == 0 ,
"Condition variable not allocated" );
fail_if( memcmp( &cond_zero, &mbox->emptied_cond, sizeof( cond_zero ) ) == 0 ,
"Condition variable not allocated" );
}
END_TEST
START_TEST( test_post_stores_value )
{
struct mbox * mbox = mbox_create();
void * deadbeef = (void *)0xDEADBEEF;
mbox_post( mbox, deadbeef );
fail_unless( deadbeef == mbox_contents( mbox ),
"Contents were not posted" );
}
END_TEST
void * mbox_receive_runner( void * mbox_uncast )
{
struct mbox * mbox = (struct mbox *)mbox_uncast;
void * contents = NULL;
contents = mbox_receive( mbox );
return contents;
}
START_TEST( test_receive_blocks_until_post )
{
struct mbox * mbox = mbox_create();
pthread_t receiver;
pthread_create( &receiver, NULL, mbox_receive_runner, mbox );
void * deadbeef = (void *)0xDEADBEEF;
void * retval =NULL;
usleep(10000);
fail_unless( EBUSY == pthread_tryjoin_np( receiver, &retval ),
"Receiver thread wasn't blocked");
mbox_post( mbox, deadbeef );
fail_unless( 0 == pthread_join( receiver, &retval ),
"Failed to join the receiver thread" );
fail_unless( retval == deadbeef,
"Return value was wrong" );
}
END_TEST
Suite* acl_suite(void)
{
Suite *s = suite_create("acl");
TCase *tc_create = tcase_create("create");
TCase *tc_post = tcase_create("post");
tcase_add_test(tc_create, test_allocs_cvar);
tcase_add_test( tc_post, test_post_stores_value );
tcase_add_test( tc_post, test_receive_blocks_until_post);
suite_add_tcase(s, tc_create);
suite_add_tcase(s, tc_post);
return s;
}
int main(void)
{
#ifdef DEBUG
log_level = 0;
#else
log_level = 2;
#endif
int number_failed;
Suite *s = acl_suite();
SRunner *sr = srunner_create(s);
srunner_run_all(sr, CK_NORMAL);
log_level = 0;
number_failed = srunner_ntests_failed(sr);
srunner_free(sr);
return (number_failed == 0) ? 0 : 1;
}

View File

@@ -3,6 +3,7 @@
#include "self_pipe.h"
#include "client.h"
#include "flexnbd.h"
#include <stdlib.h>
#include <check.h>
@@ -61,7 +62,8 @@ void teardown( void )
START_TEST( test_replaces_acl )
{
struct server * s = server_create( "127.0.0.1", "0", dummy_file, NULL, 0, 0, NULL, 1);
struct flexnbd flexnbd;
struct server * s = server_create( &flexnbd, "127.0.0.1", "0", dummy_file, 0, 0, NULL, 1, 1 );
struct acl * new_acl = acl_create( 0, NULL, 0 );
server_replace_acl( s, new_acl );
@@ -74,7 +76,8 @@ END_TEST
START_TEST( test_signals_acl_updated )
{
struct server * s = server_create( "127.0.0.1", "0", dummy_file, NULL, 0, 0, NULL, 1 );
struct flexnbd flexnbd;
struct server * s = server_create( &flexnbd, "127.0.0.1", "0", dummy_file, 0, 0, NULL, 1, 1 );
struct acl * new_acl = acl_create( 0, NULL, 0 );
server_replace_acl( s, new_acl );
@@ -141,7 +144,8 @@ START_TEST( test_acl_update_closes_bad_client )
* and socket out of the server structure, we should be testing
* a client socket.
*/
struct server * s = server_create( "127.0.0.7", "0", dummy_file, NULL, 0, 0, NULL, 1 );
struct flexnbd flexnbd;
struct server * s = server_create( &flexnbd, "127.0.0.7", "0", dummy_file, 0, 0, NULL, 1, 1 );
struct acl * new_acl = acl_create( 0, NULL, 1 );
struct client * c;
struct client_tbl_entry * entry;
@@ -168,12 +172,12 @@ START_TEST( test_acl_update_closes_bad_client )
server_replace_acl( s, new_acl );
/* accept again, so that we can react to the acl replacement signal */
server_accept( s );
pthread_join( entry->thread, NULL );
/* Fail if we time out here */
while( !fd_is_closed( server_fd ) );
myfail_unless( fd_is_closed(server_fd),
"Client socket wasn't closed." );
close( client_fd );
server_close_clients( s );
server_destroy( s );
@@ -183,7 +187,8 @@ END_TEST
START_TEST( test_acl_update_leaves_good_client )
{
struct server * s = server_create( "127.0.0.7", "0", dummy_file, NULL, 0, 0, NULL, 1 );
struct flexnbd flexnbd;
struct server * s = server_create( &flexnbd, "127.0.0.7", "0", dummy_file, 0, 0, NULL, 1, 1 );
char *lines[] = {"127.0.0.1"};
struct acl * new_acl = acl_create( 1, lines, 1 );
@@ -243,6 +248,7 @@ Suite* serve_suite(void)
int main(void)
{
log_level = LOG_LEVEL;
error_init();
int number_failed;
Suite *s = serve_suite();
SRunner *sr = srunner_create(s);

View File

@@ -20,7 +20,11 @@ rescue Timeout::Error
exit 1
end
Timeout.timeout( 2 ) do
Timeout.timeout( 3 ) do
# Sleep to be sure we don't try to connect too soon. That wouldn't
# be a problem for the destination, but it would prevent us from
# determining success or failure here.
sleep 0.5
sock = TCPSocket.open( addr, port.to_i )
sock.close
end

View File

@@ -12,7 +12,7 @@ class Executor
attr_reader :pid
def run( cmd )
@pid = fork do exec @cmd end
@pid = fork do exec cmd end
end
end # class Executor
@@ -20,6 +20,15 @@ end # class Executor
class ValgrindExecutor
attr_reader :pid
def run( cmd )
@pid = fork do exec "valgrind --track-origins=yes #{cmd}" end
end
end # class ValgrindExecutor
class ValgrindKillingExecutor
attr_reader :pid
class Error
attr_accessor :what, :kind, :pid
attr_reader :backtrace
@@ -137,10 +146,15 @@ class ValgrindExecutor
private
def pick_listener
ENV['DEBUG'] ? DebugErrorListener : ErrorListener
end
def launch_watch_thread(pid, io_r)
Thread.start do
io_source = REXML::IOSource.new( io_r )
listener = DebugErrorListener.new( self )
listener = pick_listener.new( self )
REXML::Document.parse_stream( io_source, listener )
end
end
@@ -160,15 +174,28 @@ class FlexNBD
end
end
def pick_executor
kls = if ENV['VALGRIND']
if ENV['VALGRIND'] =~ /kill/
ValgrindKillingExecutor
else
ValgrindExecutor
end
else
Executor
end
end
def initialize(bin, ip, port)
@bin = bin
@debug = `#{@bin} serve --help` =~ /--verbose/ ? "--verbose" : ""
@debug = (ENV['DEBUG'] && `#{@bin} serve --help` =~ /--verbose/) ? "--verbose" : ""
raise "#{bin} not executable" unless File.executable?(bin)
@executor = ENV['VALGRIND'] ? ValgrindExecutor.new : Executor.new
@executor = pick_executor.new
@ctrl = "/tmp/.flexnbd.ctrl.#{Time.now.to_i}.#{rand}"
@ip = ip
@port = port
@kill = false
@kill = []
end
@@ -193,7 +220,7 @@ class FlexNBD
def listen_cmd( file, acl )
"#{@bin} listen "\
"#{bin} listen "\
"--addr #{ip} "\
"--port #{port} "\
"--file #{file} "\
@@ -270,8 +297,8 @@ class FlexNBD
_, status = Process.waitpid2( pid )
if @kill
fail "flexnbd quit with a bad status: #{status.to_i}" unless
@kill.include? status.to_i
fail "flexnbd quit with a bad status: #{status.exitstatus}" unless
@kill.include? status.exitstatus
else
$stderr.puts "flexnbd #{self.pid} quit"
fail "flexnbd #{self.pid} quit early with status #{status.to_i}"
@@ -281,8 +308,8 @@ class FlexNBD
def can_die(*status)
status << 0 if status.empty?
@kill = status
status = [0] if status.empty?
@kill += status
end
def kill
@@ -321,6 +348,10 @@ class FlexNBD
end
def join
@wait_thread.join
end
def mirror_unchecked( dest_ip, dest_port, bandwidth=nil, action=nil, timeout=nil )
cmd = mirror_cmd( dest_ip, dest_port)
debug( cmd )
@@ -364,8 +395,9 @@ class FlexNBD
cmd = status_cmd()
debug( cmd )
maybe_timeout( cmd, timeout )
o,e = maybe_timeout( cmd, timeout )
[parse_status(o), e]
end
@@ -379,5 +411,24 @@ class FlexNBD
return [code, message]
end
end
def parse_status( status )
hsh = {}
status.split(" ").each do |part|
next if part.strip.empty?
a,b = part.split("=")
b.strip!
b = true if b == "true"
b = false if b == "false"
hsh[a.strip] = b
end
hsh
end
end

View File

@@ -41,37 +41,12 @@ class Environment
end
def parse_status( status )
hsh = {}
status.split(" ").each do |part|
next if part.strip.empty?
a,b = part.split("=")
b.strip!
b = true if b == "true"
b = false if b == "false"
hsh[a.strip] = b
end
hsh
end
def status( nbd )
stdout, stderr = nbd.status
[parse_status(stdout), stderr]
end
def status1
status( @nbd1 )
@nbd1.status.first
end
def status2
puts "Getting status"
result = status( @nbd2 )
puts "Got status"
return result
@nbd2.status.first
end
@@ -153,6 +128,8 @@ class NBDScenarios < Test::Unit::TestCase
end
def teardown
@env.nbd1.can_die(0)
@env.nbd2.can_die(0)
@env.cleanup
end
@@ -216,6 +193,8 @@ class NBDScenarios < Test::Unit::TestCase
@env.nbd1.can_die
stdout, stderr = @env.mirror12
@env.nbd1.join
assert_equal(@env.file1.read_original( 0, @env.blocksize ),
@env.file2.read( 0, @env.blocksize ) )
assert @env.status2['has_control'], "destination didn't take control"
@@ -233,6 +212,7 @@ class NBDConnectSourceFailureScenarios < Test::Unit::TestCase
end
def teardown
@env.nbd1.can_die(0)
@env.cleanup
end
@@ -300,18 +280,21 @@ class NBDConnectDestFailureScenarios < Test::Unit::TestCase
def test_hello_blocked_by_disconnect_causes_error_not_fatal
@env.nbd1.can_die(1)
run_fake( "source/close_after_connect" )
assert_no_control
end
def test_hello_goes_astray_causes_timeout_error
@env.nbd1.can_die(1)
run_fake( "source/hang_after_hello" )
assert_no_control
end
def test_disconnect_after_hello_causes_error_not_fatal
@env.nbd1.can_die(1)
run_fake( "source/close_after_hello" )
assert_no_control
end