
First, Leaving off the source address caused a segfault in the command-sending process because there was no NULL check on the ARGV entry. Second, while the migration thread sent a signal to the server to close on successful completion, it didn't wait until the close actually happened before releasing the IO lock. This meant that any client thread waiting on that IO lock could have a read or a write queued up which could succeed despite the server shutdown. This would have meant dataloss as the guest would see a successful write to the wrong instance of the file. This patch adds a noddy serve_wait_for_close() function which the mirror_runner calls to ensure that any clients will reject operations they're waiting to complete. This patch also adds a simple scenario test for migration, and fixes TempFileWriter#read_original.
119 lines
2.4 KiB
Ruby
119 lines
2.4 KiB
Ruby
#!/usr/bin/ruby
|
|
|
|
require 'test/unit'
|
|
require 'flexnbd'
|
|
require 'test_file_writer'
|
|
|
|
class NBDScenarios < Test::Unit::TestCase
|
|
def setup
|
|
@blocksize = 1024
|
|
@filename1 = ".flexnbd.test.#{$$}.#{Time.now.to_i}.1"
|
|
@filename2 = ".flexnbd.test.#{$$}.#{Time.now.to_i}.2"
|
|
@ip = "127.0.0.1"
|
|
@available_ports = [*40000..41000] - listening_ports
|
|
@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
|
|
[@filename1, @filename2].each do |f|
|
|
File.unlink(f) if File.exists?(f)
|
|
end
|
|
end
|
|
|
|
def test_read1
|
|
writefile1("f"*64)
|
|
serve1
|
|
|
|
[0, 12, 63].each do |num|
|
|
|
|
assert_equal(
|
|
@nbd1.read(num*@blocksize, @blocksize),
|
|
@file1.read(num*@blocksize, @blocksize)
|
|
)
|
|
end
|
|
|
|
[124, 1200, 10028, 25488].each do |num|
|
|
assert_equal(@nbd1.read(num, 4), @file1.read(num, 4))
|
|
end
|
|
end
|
|
|
|
# Check that we're not
|
|
#
|
|
def test_writeread1
|
|
writefile1("0"*64)
|
|
serve1
|
|
|
|
[0, 12, 63].each do |num|
|
|
data = "X"*@blocksize
|
|
@nbd1.write(num*@blocksize, data)
|
|
assert_equal(data, @file1.read(num*@blocksize, data.size))
|
|
assert_equal(data, @nbd1.read(num*@blocksize, data.size))
|
|
end
|
|
end
|
|
|
|
# Check that we're not overstepping or understepping where our writes end
|
|
# up.
|
|
#
|
|
def test_writeread2
|
|
writefile1("0"*1024)
|
|
serve1
|
|
|
|
d0 = "\0"*@blocksize
|
|
d1 = "X"*@blocksize
|
|
(0..63).each do |num|
|
|
@nbd1.write(num*@blocksize*2, d1)
|
|
end
|
|
(0..63).each do |num|
|
|
assert_equal(d0, @nbd1.read(((2*num)+1)*@blocksize, d0.size))
|
|
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").
|
|
map { |x| x.split(/\s+/) }[2..-1].
|
|
map { |l| l[3].split(":")[-1].to_i }
|
|
end
|
|
end
|
|
|