diff options
author | Eric Wong <normalperson@yhbt.net> | 2008-12-22 17:37:02 -0800 |
---|---|---|
committer | Eric Wong <normalperson@yhbt.net> | 2008-12-22 18:24:42 -0800 |
commit | b7ba273a043633c01d9ae8cda8ae9db4cc5dcf07 (patch) | |
tree | d70359793d59061597655f21cc39ac9d54abe076 | |
parent | df2af32f01bc995e9f311b51d3351ee042e23483 (diff) | |
download | mogilefs-client-b7ba273a043633c01d9ae8cda8ae9db4cc5dcf07.tar.gz |
These tests forced us to use TCPSocket, which wasn't friendly to sockets created with Socket.new (for asynchronous connect(2) calls). No changes to the core MogileFS components have been made. I want to verify the new TempServer implementation performs correctly with the current code.
-rw-r--r-- | test/setup.rb | 111 | ||||
-rw-r--r-- | test/test_backend.rb | 101 | ||||
-rw-r--r-- | test/test_mogilefs.rb | 160 | ||||
-rw-r--r-- | test/test_utils.rb | 52 |
4 files changed, 203 insertions, 221 deletions
diff --git a/test/setup.rb b/test/setup.rb index b0dc53f..d8d213d 100644 --- a/test/setup.rb +++ b/test/setup.rb @@ -1,3 +1,4 @@ +STDIN.sync = STDOUT.sync = STDERR.sync = true require 'test/unit' require 'fileutils' @@ -48,95 +49,36 @@ class FakeBackend end -class FakeSocket - - attr_reader :read_s - attr_reader :write_s - attr_reader :sync - - def initialize(read = '', write = StringIO.new) - @read_s = read.class.method_defined?(:sysread) ? read : StringIO.new(read) - @write_s = write - @closed = false - @sync = false - end - - def sync=(do_sync) - @sync = do_sync - @write_s.sync = do_sync - @read_s.sync = do_sync - end - - def closed? - @closed - end - - def close - @closed = true - return nil - end - - def gets - @read_s.gets - end - - def peeraddr - ['AF_INET', 6001, 'localhost', '127.0.0.1'] - end - - def read(bytes = nil) - @read_s.read bytes - end - - def sysread(bytes, buf = '') - @read_s.sysread bytes, buf - end - - def recv_nonblock(bytes, flags = 0) - ret = @read_s.sysread(bytes) - # Ruby doesn't expose pread(2) - if (flags & Socket::MSG_PEEK) != 0 - if @read_s.respond_to?(:sysseek) - @read_s.sysseek(-ret.size, IO::SEEK_CUR) - else - @read_s.seek(-ret.size, IO::SEEK_CUR) - end - end - ret - end - alias_method :recv, :recv_nonblock - - def write(data) - @write_s.write data - end - - def syswrite(data) - @write_s.syswrite data - end - -end - class MogileFS::Client attr_writer :readonly end -class TCPSocket - - class << self - - attr_accessor :connections - attr_accessor :sockets - - alias old_new new - - def new(host, port) - raise Errno::ECONNREFUSED if @sockets.empty? - @connections << [host, port] - @sockets.pop +require 'socket' +class TempServer + attr_reader :port + + def self.destroy_all! + ObjectSpace.each_object(TempServer) { |t| t.destroy! } + end + + def initialize(server_proc) + @port = @sock = nil + retries = 0 + begin + @port = 5000 + $$ % 1000 + rand(60000) + @sock = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0) + @sock.bind(Socket.pack_sockaddr_in(@port, '127.0.0.1')) + @sock.listen(5) + rescue Errno::EADDRINUSE + @sock.close rescue nil + retry if (retries += 1) < 10 end + @thr = Thread.new(@sock, @port) { |s,p| server_proc.call(s, p) } + end - alias open new - + def destroy! + @sock.close rescue nil + Thread.kill(@thr) rescue nil end end @@ -154,9 +96,6 @@ class TestMogileFS < Test::Unit::TestCase :root => @root @backend = FakeBackend.new @client.instance_variable_set '@backend', @backend - - TCPSocket.sockets = [] - TCPSocket.connections = [] end def teardown diff --git a/test/test_backend.rb b/test/test_backend.rb index 5db8189..8306984 100644 --- a/test/test_backend.rb +++ b/test/test_backend.rb @@ -16,8 +16,6 @@ end class TestBackend < Test::Unit::TestCase def setup - TCPSocket.connections = [] - TCPSocket.sockets = [] @backend = MogileFS::Backend.new :hosts => ['localhost:1'] end @@ -37,17 +35,21 @@ class TestBackend < Test::Unit::TestCase end def test_do_request - socket_request = '' - socket = Object.new - def socket.closed?() false end - def socket.send(request, flags) return request.length end - def @backend.select(*args) return [true] end - def socket.gets() return 'OK 1 you=win' end + received = '' + tmp = TempServer.new(Proc.new do |serv, port| + client, client_addr = serv.accept + client.sync = true + received = client.recv 4096 + client.send "OK 1 you=win\r\n", 0 + end) - @backend.instance_variable_set '@socket', socket + @backend.hosts = "127.0.0.1:#{tmp.port}" assert_equal({'you' => 'win'}, @backend.do_request('go!', { 'fight' => 'team fight!' })) + assert_equal "go! fight=team+fight%21\r\n", received + ensure + TempServer.destroy_all! end def test_do_request_send_error @@ -116,31 +118,36 @@ class TestBackend < Test::Unit::TestCase end def test_readable_eh_readable - socket = Object.new - def socket.closed?() false end - def @backend.select(*args) return [true] end - @backend.instance_variable_set '@socket', socket - + accept_nr = 0 + tmp = TempServer.new(Proc.new do |serv, port| + client, client_addr = serv.accept + client.sync = true + accept_nr += 1 + client.send('.', 0) + sleep + end) + + @backend = MogileFS::Backend.new :hosts => [ "127.0.0.1:#{tmp.port}" ] assert_equal true, @backend.readable? + assert_equal 1, accept_nr + ensure + TempServer.destroy_all! end def test_readable_eh_not_readable - socket = FakeSocket.new - def socket.closed?() false end - def @backend.select(r=nil, w=nil, e=nil, t=1) - Kernel.sleep(t.to_f + 0.1) - [] - end - @backend.instance_variable_set '@socket', socket + tmp = TempServer.new(Proc.new { |a,b| sleep }) + @backend = MogileFS::Backend.new :hosts => [ "127.0.0.1:#{tmp.port}" ] begin @backend.readable? rescue MogileFS::UnreadableSocketError => e - assert_equal '127.0.0.1:6001 never became readable', e.message + assert_equal "127.0.0.1:#{tmp.port} never became readable", e.message rescue Exception => err flunk "MogileFS::UnreadableSocketError not raised #{err} #{err.backtrace}" else flunk "MogileFS::UnreadableSocketError not raised" + ensure + TempServer.destroy_all! end end @@ -151,23 +158,51 @@ class TestBackend < Test::Unit::TestCase end def test_socket_robust - @backend.hosts = ['localhost:6001', 'localhost:6002'] - def @backend.connect_to(host, port) - @first = (defined? @first) ? false : true - raise Errno::ECONNREFUSED if @first + bad_accept_nr = accept_nr = 0 + bad = Proc.new { |serv,port| sleep; bad_accept_nr += 1 } + good = Proc.new do |serv,port| + client, client_addr = serv.accept + client.sync = true + accept_nr += 1 + client.send '.', 0 + client.flush + sleep end - - assert_equal({}, @backend.dead) - @backend.socket - assert_equal false, @backend.dead.keys.empty? + nr = 10 + + nr.times do + begin + t1 = TempServer.new(bad) + t2 = TempServer.new(good) + hosts = ["0:#{t1.port}", "0:#{t2.port}"] + @backend = MogileFS::Backend.new(:hosts => hosts) + assert_equal({}, @backend.dead) + t1.destroy! + @backend.socket + ensure + TempServer.destroy_all! + end + end # nr.times + assert_equal 0, bad_accept_nr + assert_equal nr, accept_nr end def test_shutdown - fake_socket = FakeSocket.new - @backend.socket = fake_socket - assert_equal fake_socket, @backend.socket + accept_nr = 0 + tmp = TempServer.new(Proc.new do |serv,port| + client, client_addr = serv.accept + accept_nr += 1 + sleep + end) + @backend = MogileFS::Backend.new :hosts => [ "127.0.0.1:#{tmp.port}" ] + assert @backend.socket + assert ! @backend.socket.closed? @backend.shutdown assert_equal nil, @backend.instance_variable_get(:@socket) + assert_equal 1, accept_nr + + ensure + TempServer.destroy_all! end def test_url_decode diff --git a/test/test_mogilefs.rb b/test/test_mogilefs.rb index 6765452..7ffcd8a 100644 --- a/test/test_mogilefs.rb +++ b/test/test_mogilefs.rb @@ -20,16 +20,28 @@ class TestMogileFS__MogileFS < TestMogileFS end def test_get_file_data_http - socket = FakeSocket.new("HTTP/1.0 200 OK\r\n" \ - "Content-Length: 5\r\n\r\ndata!") - TCPSocket.sockets << socket - - path1 = 'http://rur-1/dev1/0/000/000/0000000062.fid' - path2 = 'http://rur-2/dev2/0/000/000/0000000062.fid' + accept_nr = 0 + svr = Proc.new do |serv, port| + client, client_addr = serv.accept + client.sync = true + readed = client.recv(4096, 0) + assert(readed =~ \ + %r{\AGET /dev[12]/0/000/000/0000000062\.fid HTTP/1.[01]\r\n\r\n\Z}) + client.send("HTTP/1.0 200 OK\r\nContent-Length: 5\r\n\r\ndata!", 0) + accept_nr += 1 + client.close + end + t1 = TempServer.new(svr) + t2 = TempServer.new(svr) + path1 = "http://127.0.0.1:#{t1.port}/dev1/0/000/000/0000000062.fid" + path2 = "http://127.0.0.1:#{t2.port}/dev2/0/000/000/0000000062.fid" @backend.get_paths = { 'paths' => 2, 'path1' => path1, 'path2' => path2 } assert_equal 'data!', @client.get_file_data('key') + assert_equal 1, accept_nr + ensure + TempServer.destroy_all! end def test_get_file_data_http_block @@ -43,11 +55,22 @@ class TestMogileFS__MogileFS < TestMogileFS nr.times { assert_equal chunk_size, tmpfp.syswrite(' ' * chunk_size) } assert_equal expect_size + header.size, File.size(tmpfp.path) tmpfp.sysseek(0) - socket = FakeSocket.new(tmpfp) - TCPSocket.sockets << socket - path1 = 'http://rur-1/dev1/0/000/000/0000000062.fid' - path2 = 'http://rur-2/dev2/0/000/000/0000000062.fid' + accept_nr = 0 + svr = Proc.new do |serv, port| + client, client_addr = serv.accept + client.sync = true + accept_nr += 1 + readed = client.recv(4096, 0) + assert(readed =~ \ + %r{\AGET /dev[12]/0/000/000/0000000062\.fid HTTP/1.[01]\r\n\r\n\Z}) + syswrloop(tmpfp, client) + client.close + end + t1 = TempServer.new(svr) + t2 = TempServer.new(svr) + path1 = "http://127.0.0.1:#{t1.port}/dev1/0/000/000/0000000062.fid" + path2 = "http://127.0.0.1:#{t2.port}/dev2/0/000/000/0000000062.fid" @backend.get_paths = { 'paths' => 2, 'path1' => path1, 'path2' => path2 } @@ -66,6 +89,7 @@ class TestMogileFS__MogileFS < TestMogileFS end end assert_equal expect_size, nr, "size mismatch" + assert_equal 1, accept_nr end end @@ -136,12 +160,22 @@ class TestMogileFS__MogileFS < TestMogileFS @backend.list_keys = { 'key_count' => 2, 'next_after' => 'new_key_2', 'key_1' => 'new_key_1', 'key_2' => 'new_key_2' } http_resp = "HTTP/1.0 200 OK\r\nContent-Length: %u\r\n" - TCPSocket.sockets << FakeSocket.new(http_resp % 10) - TCPSocket.sockets << FakeSocket.new(http_resp % 5) - - @backend.get_paths = { 'paths' => 2, 'path1' => 'http://a', - 'path2' => 'http://b' } - @backend.get_paths = { 'paths' => 1, 'path1' => 'http://c' } + srv = Proc.new do |serv, port, size| + client, client_addr = serv.accept + client.sync = true + readed = client.readpartial(4096) + assert %r{\AHEAD } =~ readed + client.send(http_resp % size, 0) + client.close + end + t1 = TempServer.new(Proc.new { |serv, port| srv.call(serv, port, 5) }) + t2 = TempServer.new(Proc.new { |serv, port| srv.call(serv, port, 5) }) + t3 = TempServer.new(Proc.new { |serv, port| srv.call(serv, port, 10) }) + @backend.get_paths = { 'paths' => 2, + 'path1' => "http://127.0.0.1:#{t1.port}/", + 'path2' => "http://127.0.0.1:#{t2.port}/" } + @backend.get_paths = { 'paths' => 1, + 'path1' => "http://127.0.0.1:#{t3.port}/" } res = [] keys, next_after = @client.list_keys('new') do |key,length,devcount| @@ -152,6 +186,8 @@ class TestMogileFS__MogileFS < TestMogileFS assert_equal expect_res, res assert_equal ['new_key_1', 'new_key_2'], keys.sort assert_equal 'new_key_2', next_after + ensure + TempServer.destroy_all! end def test_new_file_http @@ -169,25 +205,22 @@ class TestMogileFS__MogileFS < TestMogileFS end def test_size_http - socket = FakeSocket.new <<-EOF -HTTP/1.0 200 OK\r -Content-Length: 5\r - EOF - - TCPSocket.sockets << socket - - path = 'http://example.com/path' - + accept_nr = 0 + t = TempServer.new(Proc.new do |serv,port| + client, client_addr = serv.accept + client.sync = true + readed = client.recv(4096, 0) rescue nil + assert_equal "HEAD /path HTTP/1.0\r\n\r\n", readed + client.send("HTTP/1.0 200 OK\r\nContent-Length: 5\r\n\r\n", 0) + accept_nr += 1 + client.close + end) + + path = "http://127.0.0.1:#{t.port}/path" @backend.get_paths = { 'paths' => 1, 'path1' => path } assert_equal 5, @client.size('key') - - socket.write_s.rewind - - assert_equal "HEAD /path HTTP/1.0\r\n", socket.write_s.gets - - assert_equal ['example.com', 80], TCPSocket.connections.shift - assert_empty TCPSocket.connections + assert_equal 1, accept_nr end def test_size_nfs @@ -201,36 +234,41 @@ Content-Length: 5\r end def test_store_content_http - socket = FakeSocket.new 'HTTP/1.0 200 OK' + received = '' + expected = "PUT /path HTTP/1.0\r\nContent-Length: 4\r\n\r\ndata" - TCPSocket.sockets << socket + t = TempServer.new(Proc.new do |serv, accept| + client, client_addr = serv.accept + client.sync = true + received = client.recv(4096, 0) + client.send("HTTP/1.0 200 OK\r\n\r\n", 0) + client.close + end) @backend.create_open = { 'devid' => '1', - 'path' => 'http://example.com/path', + 'path' => "http://127.0.0.1:#{t.port}/path", } @client.store_content 'new_key', 'test', 'data' - expected = <<-EOF.chomp -PUT /path HTTP/1.0\r -Content-Length: 4\r -\r -data - EOF - - assert_equal expected, socket.write_s.string - - assert_equal ['example.com', 80], TCPSocket.connections.shift - assert_empty TCPSocket.connections + assert_equal expected, received + ensure + TempServer.destroy_all! end def test_store_content_http_fail - TCPSocket.sockets << FakeSocket.new('HTTP/1.0 500 Internal Server Error') + t = TempServer.new(Proc.new do |serv, accept| + client, client_addr = serv.accept + client.sync = true + client.recv(4096, 0) + client.send("HTTP/1.0 500 Internal Server Error\r\n\r\n", 0) + client.close + end) @backend.create_open = { 'devid' => '1', - 'path' => 'http://example.com/path', + 'path' => "http://127.0.0.1:#{t.port}/path", } assert_raises MogileFS::HTTPFile::BadResponseError do @@ -239,27 +277,23 @@ data end def test_store_content_http_empty - socket = FakeSocket.new 'HTTP/1.0 200 OK' - - TCPSocket.sockets << socket + received = '' + expected = "PUT /path HTTP/1.0\r\nContent-Length: 0\r\n\r\n" + t = TempServer.new(Proc.new do |serv, accept| + client, client_addr = serv.accept + client.sync = true + received = client.recv(4096, 0) + client.send("HTTP/1.0 200 OK\r\n\r\n", 0) + client.close + end) @backend.create_open = { 'devid' => '1', - 'path' => 'http://example.com/path', + 'path' => "http://127.0.0.1:#{t.port}/path", } @client.store_content 'new_key', 'test', '' - - expected = <<-EOF -PUT /path HTTP/1.0\r -Content-Length: 0\r -\r - EOF - - assert_equal expected, socket.write_s.string - - assert_equal ['example.com', 80], TCPSocket.connections.shift - assert_empty TCPSocket.connections + assert_equal expected, received end def test_store_content_nfs diff --git a/test/test_utils.rb b/test/test_utils.rb index 3f8819c..146d420 100644 --- a/test/test_utils.rb +++ b/test/test_utils.rb @@ -1,7 +1,4 @@ -require 'test/unit' -require 'pp' -require 'socket' -$TESTING = true +require 'test/setup' require 'mogilefs' require 'mogilefs/util' @@ -9,45 +6,22 @@ class TestUtils < Test::Unit::TestCase include MogileFS::Util def test_verify_uris - good_serv, good_port = server_start - good_acceptor = Thread.new do - good_client, good_client_addr = good_serv.accept - good_client.readpartial(4096) - good_client.syswrite("HTTP/1.0 200 OK\r\nContent-Length: 0\r\n\r\n") - end - bad_serv, bad_port = server_start - bad_acceptor = Thread.new do - bad_client, bad_client_addr = bad_serv.accept - bad_client.close rescue nil - end + good = TempServer.new(Proc.new do |serv,port| + client,client_addr = serv.accept + client.readpartial(4096) + client.syswrite("HTTP/1.0 200 OK\r\nContent-Length: 0\r\n\r\n") + end) + bad = TempServer.new(Proc.new do |serv,port| + client, client_addr = serv.accept + client.close rescue nil + end) - good_uri = URI.parse("http://127.0.0.1:#{good_port}/") - bad_uri = URI.parse("http://127.0.0.1:#{bad_port}/") + good_uri = URI.parse("http://127.0.0.1:#{good.port}/") + bad_uri = URI.parse("http://127.0.0.1:#{bad.port}/") ok = verify_uris([ good_uri, bad_uri ]) assert_equal [ good_uri ], ok ensure - Thread.kill(good_acceptor) rescue nil - Thread.kill(bad_acceptor) rescue nil - good_serv.close rescue nil - bad_serv.close rescue nil + TempServer.destroy_all! end - private - - def server_start - port = nil - sock = nil - retries = 0 - begin - port = 5000 + $$ % 1000 + rand(60000) - sock = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0) - sock.bind(Socket.pack_sockaddr_in(port, '127.0.0.1')) - sock.listen(5) - rescue Errno::EADDRINUSE - sock.close rescue nil - retry if (retries += 1) < 10 - end - [ sock, port ] - end - end |