Add mboxes
This commit is contained in:
@@ -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
42
tests/check_control.c
Normal 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
47
tests/check_flexnbd.c
Normal 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;
|
||||
}
|
||||
|
@@ -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
104
tests/check_mbox.c
Normal 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;
|
||||
}
|
||||
|
@@ -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);
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -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
|
||||
|
Reference in New Issue
Block a user