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 TCPSocket.connections = []
20 TCPSocket.sockets = []
21 @backend = MogileFS::Backend.new :hosts => ['localhost:1']
25 assert_raises ArgumentError do MogileFS::Backend.new end
26 assert_raises ArgumentError do MogileFS::Backend.new :hosts => [] end
27 assert_raises ArgumentError do MogileFS::Backend.new :hosts => [''] end
29 assert_equal ['localhost:1'], @backend.hosts
30 assert_equal 3, @backend.timeout
31 assert_equal nil, @backend.lasterr
32 assert_equal nil, @backend.lasterrstr
33 assert_equal({}, @backend.dead)
35 @backend = MogileFS::Backend.new :hosts => ['localhost:6001'], :timeout => 1
36 assert_equal 1, @backend.timeout
42 def socket.closed?() false end
43 def socket.send(request, flags) return request.length end
44 def @backend.select(*args) return [true] end
45 def socket.gets() return 'OK 1 you=win' end
47 @backend.instance_variable_set '@socket', socket
49 assert_equal({'you' => 'win'},
50 @backend.do_request('go!', { 'fight' => 'team fight!' }))
53 def test_do_request_send_error
56 def socket.closed?() false end
57 def socket.send(request, flags) raise SystemCallError, 'dummy' end
59 @backend.instance_variable_set '@socket', socket
61 assert_raises MogileFS::UnreachableBackendError do
62 @backend.do_request 'go!', { 'fight' => 'team fight!' }
65 assert_equal nil, @backend.instance_variable_get('@socket')
68 def test_automatic_exception
69 assert ! MogileFS::Backend.const_defined?('PebkacError')
70 assert @backend.error('pebkac')
71 assert_equal MogileFS::Error, @backend.error('PebkacError').superclass
72 assert MogileFS::Backend.const_defined?('PebkacError')
74 assert ! MogileFS::Backend.const_defined?('PebKacError')
75 assert @backend.error('peb_kac')
76 assert_equal MogileFS::Error, @backend.error('PebKacError').superclass
77 assert MogileFS::Backend.const_defined?('PebKacError')
80 def test_do_request_truncated
83 def socket.closed?() false end
84 def socket.send(request, flags) return request.length - 1 end
86 @backend.instance_variable_set '@socket', socket
88 assert_raises MogileFS::RequestTruncatedError do
89 @backend.do_request 'go!', { 'fight' => 'team fight!' }
94 assert_equal "go! fight=team+fight%21\r\n",
95 @backend.make_request('go!', { 'fight' => 'team fight!' })
98 def test_parse_response
99 assert_equal({'foo' => 'bar', 'baz' => 'hoge'},
100 @backend.parse_response('OK 1 foo=bar&baz=hoge'))
104 @backend.parse_response('ERR you totally suck')
105 rescue MogileFS::Error => err
106 assert_equal 'MogileFS::Backend::YouError', err.class.to_s
108 assert_equal 'MogileFS::Backend::YouError', err.class.to_s
110 assert_equal 'you', @backend.lasterr
111 assert_equal 'totally suck', @backend.lasterrstr
113 assert_raises MogileFS::InvalidResponseError do
114 @backend.parse_response 'garbage'
118 def test_readable_eh_readable
120 def socket.closed?() false end
121 def @backend.select(*args) return [true] end
122 @backend.instance_variable_set '@socket', socket
124 assert_equal true, @backend.readable?
127 def test_readable_eh_not_readable
128 socket = FakeSocket.new
129 def socket.closed?() false end
130 def @backend.select(r=nil, w=nil, e=nil, t=1)
131 Kernel.sleep(t.to_f + 0.1)
134 @backend.instance_variable_set '@socket', socket
138 rescue MogileFS::UnreadableSocketError => e
139 assert_equal '127.0.0.1:6001 never became readable', e.message
140 rescue Exception => err
141 flunk "MogileFS::UnreadableSocketError not raised #{err} #{err.backtrace}"
143 flunk "MogileFS::UnreadableSocketError not raised"
148 assert_equal({}, @backend.dead)
149 assert_raises MogileFS::UnreachableBackendError do @backend.socket end
150 assert_equal(['localhost:1'], @backend.dead.keys)
153 def test_socket_robust
154 @backend.hosts = ['localhost:6001', 'localhost:6002']
155 def @backend.connect_to(host, port)
156 @first = (defined? @first) ? false : true
157 raise Errno::ECONNREFUSED if @first
160 assert_equal({}, @backend.dead)
162 assert_equal false, @backend.dead.keys.empty?
166 fake_socket = FakeSocket.new
167 @backend.socket = fake_socket
168 assert_equal fake_socket, @backend.socket
170 assert_equal nil, @backend.instance_variable_get(:@socket)
174 assert_equal({"\272z" => "\360opy", "f\000" => "\272r"},
175 @backend.url_decode("%baz=%f0opy&f%00=%bar"))
179 params = [["f\000", "\272r"], ["\272z", "\360opy"]]
180 assert_equal "f%00=%bar&%baz=%f0opy", @backend.url_encode(params)
183 def test_url_escape # \n for unit_diff
184 actual = (0..255).map { |c| @backend.url_escape c.chr }.join "\n"
187 expected.push(*(0..0x1f).map { |c| "%%%0.2x" % c })
189 expected.push(*(0x21..0x2b).map { |c| "%%%0.2x" % c })
190 expected.push(*%w[, - . /])
191 expected.push(*('0'..'9'))
192 expected.push(*%w[: %3b %3c %3d %3e %3f %40])
193 expected.push(*('A'..'Z'))
194 expected.push(*%w[%5b \\ %5d %5e _ %60])
195 expected.push(*('a'..'z'))
196 expected.push(*(0x7b..0xff).map { |c| "%%%0.2x" % c })
198 expected = expected.join "\n"
200 assert_equal expected, actual
203 def test_url_unescape
205 input.push(*(0..0x1f).map { |c| "%%%0.2x" % c })
207 input.push(*(0x21..0x2b).map { |c| "%%%0.2x" % c })
208 input.push(*%w[, - . /])
209 input.push(*('0'..'9'))
210 input.push(*%w[: %3b %3c %3d %3e %3f %40])
211 input.push(*('A'..'Z'))
212 input.push(*%w[%5b \\ %5d %5e _ %60])
213 input.push(*('a'..'z'))
214 input.push(*(0x7b..0xff).map { |c| "%%%0.2x" % c })
216 actual = input.map { |c| @backend.url_unescape c }.join "\n"
218 expected = (0..255).map { |c| c.chr }.join "\n"
219 expected.sub! '+', ' '
221 assert_equal expected, actual