6 require 'mogilefs/backend'
8 class MogileFS::Backend
11 attr_reader :timeout, :dead
12 attr_writer :lasterr, :lasterrstr, :socket
16 class TestBackend < Test::Unit::TestCase
19 @backend = MogileFS::Backend.new :hosts => ['localhost:1']
23 assert_raises ArgumentError do MogileFS::Backend.new end
24 assert_raises ArgumentError do MogileFS::Backend.new :hosts => [] end
25 assert_raises ArgumentError do MogileFS::Backend.new :hosts => [''] end
27 assert_equal ['localhost:1'], @backend.hosts
28 assert_equal 3, @backend.timeout
29 assert_equal nil, @backend.lasterr
30 assert_equal nil, @backend.lasterrstr
31 assert_equal({}, @backend.dead)
33 @backend = MogileFS::Backend.new :hosts => ['localhost:6001'], :timeout => 1
34 assert_equal 1, @backend.timeout
39 tmp = TempServer.new(Proc.new do |serv, port|
40 client, client_addr = serv.accept
42 received = client.recv 4096
43 client.send "OK 1 you=win\r\n", 0
46 @backend.hosts = "127.0.0.1:#{tmp.port}"
48 assert_equal({'you' => 'win'},
49 @backend.do_request('go!', { 'fight' => 'team fight!' }))
50 assert_equal "go! fight=team+fight%21\r\n", received
52 TempServer.destroy_all!
55 def test_do_request_send_error
58 def socket.closed?() false end
59 def socket.send(request, flags) raise SystemCallError, 'dummy' end
61 @backend.instance_variable_set '@socket', socket
63 assert_raises MogileFS::UnreachableBackendError do
64 @backend.do_request 'go!', { 'fight' => 'team fight!' }
67 assert_equal nil, @backend.instance_variable_get('@socket')
70 def test_automatic_exception
71 assert ! MogileFS::Backend.const_defined?('PebkacError')
72 assert @backend.error('pebkac')
73 assert_equal MogileFS::Error, @backend.error('PebkacError').superclass
74 assert MogileFS::Backend.const_defined?('PebkacError')
76 assert ! MogileFS::Backend.const_defined?('PebKacError')
77 assert @backend.error('peb_kac')
78 assert_equal MogileFS::Error, @backend.error('PebKacError').superclass
79 assert MogileFS::Backend.const_defined?('PebKacError')
82 def test_do_request_truncated
85 def socket.closed?() false end
86 def socket.send(request, flags) return request.length - 1 end
88 @backend.instance_variable_set '@socket', socket
90 assert_raises MogileFS::RequestTruncatedError do
91 @backend.do_request 'go!', { 'fight' => 'team fight!' }
96 assert_equal "go! fight=team+fight%21\r\n",
97 @backend.make_request('go!', { 'fight' => 'team fight!' })
100 def test_parse_response
101 assert_equal({'foo' => 'bar', 'baz' => 'hoge'},
102 @backend.parse_response('OK 1 foo=bar&baz=hoge'))
106 @backend.parse_response('ERR you totally suck')
107 rescue MogileFS::Error => err
108 assert_equal 'MogileFS::Backend::YouError', err.class.to_s
110 assert_equal 'MogileFS::Backend::YouError', err.class.to_s
112 assert_equal 'you', @backend.lasterr
113 assert_equal 'totally suck', @backend.lasterrstr
115 assert_raises MogileFS::InvalidResponseError do
116 @backend.parse_response 'garbage'
120 def test_readable_eh_readable
122 tmp = TempServer.new(Proc.new do |serv, port|
123 client, client_addr = serv.accept
130 @backend = MogileFS::Backend.new :hosts => [ "127.0.0.1:#{tmp.port}" ]
131 assert_equal true, @backend.readable?
132 assert_equal 1, accept_nr
134 TempServer.destroy_all!
137 def test_readable_eh_not_readable
138 tmp = TempServer.new(Proc.new { |a,b| sleep })
139 @backend = MogileFS::Backend.new :hosts => [ "127.0.0.1:#{tmp.port}" ]
143 rescue MogileFS::UnreadableSocketError => e
144 assert_equal "127.0.0.1:#{tmp.port} never became readable", e.message
145 rescue Exception => err
146 flunk "MogileFS::UnreadableSocketError not raised #{err} #{err.backtrace}"
148 flunk "MogileFS::UnreadableSocketError not raised"
150 TempServer.destroy_all!
155 assert_equal({}, @backend.dead)
156 assert_raises MogileFS::UnreachableBackendError do @backend.socket end
157 assert_equal(['localhost:1'], @backend.dead.keys)
160 def test_socket_robust
161 bad_accept_nr = accept_nr = 0
162 bad = Proc.new { |serv,port| sleep; bad_accept_nr += 1 }
163 good = Proc.new do |serv,port|
164 client, client_addr = serv.accept
175 t1 = TempServer.new(bad)
176 t2 = TempServer.new(good)
177 hosts = ["0:#{t1.port}", "0:#{t2.port}"]
178 @backend = MogileFS::Backend.new(:hosts => hosts)
179 assert_equal({}, @backend.dead)
183 TempServer.destroy_all!
186 assert_equal 0, bad_accept_nr
187 assert_equal nr, accept_nr
192 tmp = TempServer.new(Proc.new do |serv,port|
193 client, client_addr = serv.accept
197 @backend = MogileFS::Backend.new :hosts => [ "127.0.0.1:#{tmp.port}" ]
198 assert @backend.socket
199 assert ! @backend.socket.closed?
201 assert_equal nil, @backend.instance_variable_get(:@socket)
202 assert_equal 1, accept_nr
205 TempServer.destroy_all!
209 assert_equal({"\272z" => "\360opy", "f\000" => "\272r"},
210 @backend.url_decode("%baz=%f0opy&f%00=%bar"))
214 params = [["f\000", "\272r"], ["\272z", "\360opy"]]
215 assert_equal "f%00=%bar&%baz=%f0opy", @backend.url_encode(params)
218 def test_url_escape # \n for unit_diff
219 actual = (0..255).map { |c| @backend.url_escape c.chr }.join "\n"
222 expected.push(*(0..0x1f).map { |c| "%%%0.2x" % c })
224 expected.push(*(0x21..0x2b).map { |c| "%%%0.2x" % c })
225 expected.push(*%w[, - . /])
226 expected.push(*('0'..'9'))
227 expected.push(*%w[: %3b %3c %3d %3e %3f %40])
228 expected.push(*('A'..'Z'))
229 expected.push(*%w[%5b \\ %5d %5e _ %60])
230 expected.push(*('a'..'z'))
231 expected.push(*(0x7b..0xff).map { |c| "%%%0.2x" % c })
233 expected = expected.join "\n"
235 assert_equal expected, actual
238 def test_url_unescape
240 input.push(*(0..0x1f).map { |c| "%%%0.2x" % c })
242 input.push(*(0x21..0x2b).map { |c| "%%%0.2x" % c })
243 input.push(*%w[, - . /])
244 input.push(*('0'..'9'))
245 input.push(*%w[: %3b %3c %3d %3e %3f %40])
246 input.push(*('A'..'Z'))
247 input.push(*%w[%5b \\ %5d %5e _ %60])
248 input.push(*('a'..'z'))
249 input.push(*(0x7b..0xff).map { |c| "%%%0.2x" % c })
251 actual = input.map { |c| @backend.url_unescape c }.join "\n"
253 expected = (0..255).map { |c| c.chr }.join "\n"
254 expected.sub! '+', ' '
256 assert_equal expected, actual