Merge
This commit is contained in:
@@ -13,6 +13,19 @@
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifdef DEBUG
|
||||
# define LOG_LEVEL 0
|
||||
#else
|
||||
# define LOG_LEVEL 2
|
||||
#endif
|
||||
|
||||
|
||||
/* Need these because libcheck is braindead and doesn't
|
||||
* run teardown after a failing test
|
||||
*/
|
||||
#define myfail( msg ) do { teardown(); fail(msg); } while (0)
|
||||
#define myfail_if( tst, msg ) do { if( tst ) { myfail( msg ); } } while (0)
|
||||
#define myfail_unless( tst, msg ) myfail_if( !(tst), msg )
|
||||
|
||||
char * dummy_file;
|
||||
|
||||
@@ -45,13 +58,6 @@ void teardown( void )
|
||||
dummy_file = NULL;
|
||||
}
|
||||
|
||||
/* Need these because libcheck is braindead and doesn't
|
||||
* run teardown after a failing test
|
||||
*/
|
||||
#define myfail( msg ) do { teardown(); fail(msg); } while (0)
|
||||
#define myfail_if( tst, msg ) do { if( tst ) { myfail( msg ); } } while (0)
|
||||
#define myfail_unless( tst, msg ) myfail_if( !(tst), msg )
|
||||
|
||||
|
||||
START_TEST( test_replaces_acl )
|
||||
{
|
||||
@@ -80,13 +86,16 @@ START_TEST( test_signals_acl_updated )
|
||||
END_TEST
|
||||
|
||||
|
||||
int connect_client( char *addr, int actual_port )
|
||||
int connect_client( char *addr, int actual_port, char *source_addr )
|
||||
{
|
||||
int client_fd;
|
||||
|
||||
struct addrinfo hint;
|
||||
struct addrinfo *ailist, *aip;
|
||||
|
||||
|
||||
|
||||
|
||||
memset( &hint, '\0', sizeof( struct addrinfo ) );
|
||||
hint.ai_socktype = SOCK_STREAM;
|
||||
|
||||
@@ -96,6 +105,16 @@ int connect_client( char *addr, int actual_port )
|
||||
for( aip = ailist; aip; aip = aip->ai_next ) {
|
||||
((struct sockaddr_in *)aip->ai_addr)->sin_port = htons( actual_port );
|
||||
client_fd = socket( aip->ai_family, aip->ai_socktype, aip->ai_protocol );
|
||||
|
||||
if (source_addr) {
|
||||
struct sockaddr src;
|
||||
if( !parse_ip_to_sockaddr(&src, source_addr)) {
|
||||
close(client_fd);
|
||||
continue;
|
||||
}
|
||||
bind(client_fd, &src, sizeof(struct sockaddr_in6));
|
||||
}
|
||||
|
||||
if( client_fd == -1) { continue; }
|
||||
if( connect( client_fd, aip->ai_addr, aip->ai_addrlen) == 0 ) {
|
||||
connected = 1;
|
||||
@@ -135,7 +154,7 @@ START_TEST( test_acl_update_closes_bad_client )
|
||||
serve_open_server_socket( s );
|
||||
actual_port = server_port( s );
|
||||
|
||||
client_fd = connect_client( "127.0.0.7", actual_port );
|
||||
client_fd = connect_client( "127.0.0.7", actual_port, "127.0.0.1" );
|
||||
server_accept( s );
|
||||
entry = &s->nbd_client[0];
|
||||
c = entry->client;
|
||||
@@ -166,9 +185,8 @@ START_TEST( test_acl_update_leaves_good_client )
|
||||
{
|
||||
struct server * s = server_create( "127.0.0.7", "0", dummy_file, NULL, 0, 0, NULL );
|
||||
|
||||
// Client source address may be IPv4 or IPv6 localhost. Should be explicit
|
||||
char *lines[] = {"127.0.0.1", "::1"};
|
||||
struct acl * new_acl = acl_create( 2, lines, 1 );
|
||||
char *lines[] = {"127.0.0.1"};
|
||||
struct acl * new_acl = acl_create( 1, lines, 1 );
|
||||
struct client * c;
|
||||
struct client_tbl_entry * entry;
|
||||
|
||||
@@ -176,12 +194,10 @@ START_TEST( test_acl_update_leaves_good_client )
|
||||
int client_fd;
|
||||
int server_fd;
|
||||
|
||||
myfail_if(new_acl->len != 2, "sanity: new_acl length is not 2");
|
||||
|
||||
serve_open_server_socket( s );
|
||||
actual_port = server_port( s );
|
||||
|
||||
client_fd = connect_client( "127.0.0.7", actual_port );
|
||||
client_fd = connect_client( "127.0.0.7", actual_port, "127.0.0.1" );
|
||||
server_accept( s );
|
||||
entry = &s->nbd_client[0];
|
||||
c = entry->client;
|
||||
@@ -211,22 +227,22 @@ Suite* serve_suite(void)
|
||||
Suite *s = suite_create("serve");
|
||||
TCase *tc_acl_update = tcase_create("acl_update");
|
||||
|
||||
tcase_add_checked_fixture( tc_acl_update, setup, teardown );
|
||||
tcase_add_checked_fixture( tc_acl_update, setup, NULL );
|
||||
|
||||
tcase_add_test(tc_acl_update, test_replaces_acl);
|
||||
tcase_add_test(tc_acl_update, test_signals_acl_updated);
|
||||
tcase_add_test(tc_acl_update, test_acl_update_closes_bad_client);
|
||||
|
||||
tcase_add_test(tc_acl_update, test_acl_update_leaves_good_client);
|
||||
tcase_add_exit_test(tc_acl_update, test_acl_update_closes_bad_client, 0);
|
||||
tcase_add_exit_test(tc_acl_update, test_acl_update_leaves_good_client, 0);
|
||||
|
||||
suite_add_tcase(s, tc_acl_update);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
int main(void)
|
||||
{
|
||||
log_level = 0;
|
||||
log_level = LOG_LEVEL;
|
||||
int number_failed;
|
||||
Suite *s = serve_suite();
|
||||
SRunner *sr = srunner_create(s);
|
||||
|
@@ -147,7 +147,7 @@ class FlexNBD
|
||||
|
||||
|
||||
def debug?
|
||||
!@debug.empty?
|
||||
!@debug.empty? || ENV['DEBUG']
|
||||
end
|
||||
|
||||
def debug( msg )
|
||||
@@ -186,6 +186,14 @@ class FlexNBD
|
||||
end
|
||||
|
||||
|
||||
def mirror_cmd(dest_ip, dest_port)
|
||||
"#{@bin} mirror "\
|
||||
"--addr #{dest_ip} "\
|
||||
"--port #{dest_port} "\
|
||||
"--sock #{ctrl} "\
|
||||
"#{@debug} "
|
||||
end
|
||||
|
||||
def serve(file, *acl)
|
||||
File.unlink(ctrl) if File.exists?(ctrl)
|
||||
cmd =serve_cmd( file, acl )
|
||||
@@ -205,7 +213,10 @@ class FlexNBD
|
||||
def start_wait_thread( pid )
|
||||
Thread.start do
|
||||
Process.waitpid2( pid )
|
||||
unless @kill
|
||||
if @kill
|
||||
fail "flexnbd quit with a bad status #{$?.exitstatus}" unless
|
||||
$?.exitstatus == @kill
|
||||
else
|
||||
$stderr.puts "flexnbd quit"
|
||||
fail "flexnbd quit early"
|
||||
end
|
||||
@@ -213,9 +224,18 @@ class FlexNBD
|
||||
end
|
||||
|
||||
|
||||
def can_die(status=0)
|
||||
@kill = status
|
||||
end
|
||||
|
||||
def kill
|
||||
@kill = true
|
||||
Process.kill("INT", @pid)
|
||||
can_die()
|
||||
begin
|
||||
Process.kill("INT", @pid)
|
||||
rescue Errno::ESRCH => e
|
||||
# already dead. Presumably this means it went away after a
|
||||
# can_die() call.
|
||||
end
|
||||
end
|
||||
|
||||
def read(offset, length)
|
||||
@@ -240,8 +260,12 @@ class FlexNBD
|
||||
nil
|
||||
end
|
||||
|
||||
def mirror(bandwidth=nil, action=nil)
|
||||
control_command("mirror", ip, port, ip, bandwidth, action)
|
||||
def mirror(dest_ip, dest_port, bandwidth=nil, action=nil)
|
||||
cmd = mirror_cmd( dest_ip, dest_port)
|
||||
debug( cmd )
|
||||
system cmd
|
||||
raise IOError.new( "Migrate command failed") unless $?.success?
|
||||
nil
|
||||
end
|
||||
|
||||
def acl(*acl)
|
||||
|
@@ -14,6 +14,7 @@ class NBDScenarios < Test::Unit::TestCase
|
||||
@port1 = @available_ports.shift
|
||||
@port2 = @available_ports.shift
|
||||
@nbd1 = FlexNBD.new("../build/flexnbd", @ip, @port1)
|
||||
@nbd2 = FlexNBD.new("../build/flexnbd", @ip, @port2)
|
||||
end
|
||||
|
||||
def teardown
|
||||
@@ -70,15 +71,43 @@ class NBDScenarios < Test::Unit::TestCase
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def test_mirror
|
||||
writefile1( "f"*4 )
|
||||
serve1
|
||||
|
||||
writefile2( "0"*4 )
|
||||
serve2
|
||||
|
||||
@nbd1.can_die
|
||||
mirror12
|
||||
assert_equal(@file1.read_original( 0, @blocksize ),
|
||||
@file2.read( 0, @blocksize ) )
|
||||
end
|
||||
|
||||
protected
|
||||
def serve1(*acl)
|
||||
@nbd1.serve(@filename1, *acl)
|
||||
end
|
||||
|
||||
def serve2(*acl)
|
||||
@nbd2.serve(@filename2, *acl)
|
||||
end
|
||||
|
||||
def mirror12
|
||||
@nbd1.mirror( @nbd2.ip, @nbd2.port )
|
||||
end
|
||||
|
||||
def writefile1(data)
|
||||
@file1 = TestFileWriter.new(@filename1, @blocksize).write(data)
|
||||
end
|
||||
|
||||
def writefile2(data)
|
||||
@file2 = TestFileWriter.new(@filename2, @blocksize).write(data)
|
||||
end
|
||||
|
||||
|
||||
|
||||
def listening_ports
|
||||
`netstat -ltn`.
|
||||
split("\n").
|
||||
|
@@ -27,20 +27,15 @@ class TestFileWriter
|
||||
self
|
||||
end
|
||||
|
||||
|
||||
# Returns what the data ought to be at the given offset and length
|
||||
#
|
||||
def read_original(off, len)
|
||||
r=""
|
||||
current = 0
|
||||
@pattern.split("").each do |block|
|
||||
if off >= current && (off+len) < current + blocksize
|
||||
current += data(block, current)[
|
||||
current-off..(current+blocksize)-(off+len)
|
||||
]
|
||||
end
|
||||
current += @blocksize
|
||||
end
|
||||
r
|
||||
def read_original( off, len )
|
||||
patterns = @pattern.split( "" )
|
||||
patterns.zip( (0...patterns.length).to_a ).
|
||||
map { |blk, blk_off|
|
||||
data(blk, blk_off)
|
||||
}.join[off...(off+len)]
|
||||
end
|
||||
|
||||
# Read what's actually in the file
|
||||
@@ -51,7 +46,7 @@ class TestFileWriter
|
||||
end
|
||||
|
||||
def untouched?(offset, len)
|
||||
read(off, len) == read_original(off, len)
|
||||
read(offset, len) == read_original(offset, len)
|
||||
end
|
||||
|
||||
def close
|
||||
@@ -81,3 +76,48 @@ class TestFileWriter
|
||||
|
||||
end
|
||||
|
||||
if __FILE__==$0
|
||||
require 'tempfile'
|
||||
require 'test/unit'
|
||||
|
||||
class TestFileWriterTest < Test::Unit::TestCase
|
||||
def test_read_original_zeros
|
||||
Tempfile.open("test_read_original_zeros") do |tempfile|
|
||||
tempfile.close
|
||||
file = TestFileWriter.new( tempfile.path, 4096 )
|
||||
file.write( "0" )
|
||||
assert_equal file.read( 0, 4096 ), file.read_original( 0, 4096 )
|
||||
assert( file.untouched?(0,4096) , "Untouched file was touched." )
|
||||
end
|
||||
end
|
||||
|
||||
def test_read_original_offsets
|
||||
Tempfile.open("test_read_original_offsets") do |tempfile|
|
||||
tempfile.close
|
||||
file = TestFileWriter.new( tempfile.path, 4096 )
|
||||
file.write( "f" )
|
||||
assert_equal file.read( 0, 4096 ), file.read_original( 0, 4096 )
|
||||
assert( file.untouched?(0,4096) , "Untouched file was touched." )
|
||||
end
|
||||
end
|
||||
|
||||
def test_file_size
|
||||
Tempfile.open("test_file_size") do |tempfile|
|
||||
tempfile.close
|
||||
file = TestFileWriter.new( tempfile.path, 4096 )
|
||||
file.write( "f" )
|
||||
assert_equal 4096, File.stat( tempfile.path ).size
|
||||
end
|
||||
end
|
||||
|
||||
def test_read_original_size
|
||||
Tempfile.open("test_read_original_offsets") do |tempfile|
|
||||
tempfile.close
|
||||
file = TestFileWriter.new( tempfile.path, 4)
|
||||
file.write( "f"*4 )
|
||||
assert_equal 4, file.read_original(0, 4).length
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
Reference in New Issue
Block a user