Ruby mogilefs-client 3.12.2
[ruby-mogilefs-client.git] / test / test_backend.rb
blob4d41354e22003e79bb3c4a1ebb784dceda41fb66
1 # -*- encoding: binary -*-
2 require 'test/unit'
3 require './test/setup'
5 $TESTING = true
7 class MogileFS::Backend
9   attr_accessor :hosts
10   attr_reader :timeout, :dead
11   attr_writer :lasterr, :lasterrstr, :socket
13 end
15 class TestBackend < Test::Unit::TestCase
17   def setup
18     @backend = MogileFS::Backend.new :hosts => ['localhost:1']
19   end
21   def test_initialize
22     assert_raises ArgumentError do MogileFS::Backend.new end
23     assert_raises ArgumentError do MogileFS::Backend.new :hosts => [] end
24     assert_raises ArgumentError do MogileFS::Backend.new :hosts => [''] end
26     assert_equal ['localhost:1'], @backend.hosts
27     assert_equal 3, @backend.timeout
28     assert_equal 3, @backend.instance_variable_get(:@connect_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
35     assert_equal 1, @backend.instance_variable_get(:@connect_timeout)
36   end
38   def test_do_request
39     srv = TCPServer.new("127.0.0.1", 0)
40     port = srv.addr[1]
41     accepted = Thread.new do
42       client = srv.accept
43       client.write("OK 1 you=win\r\n")
44       client
45     end
46     @backend.hosts = [ "127.0.0.1:#{port}" ]
47     assert_equal({'you' => 'win'},
48                  @backend.do_request('go!', { 'fight' => 'team fight!' }))
49     accepted = accepted.value
50     assert_equal "go! fight=team+fight%21\r\n", accepted.readpartial(4096)
51   end
53   def test_automatic_exception
54     assert ! MogileFS::Backend.const_defined?('PebkacError')
55     assert @backend.error('pebkac')
56     assert_equal MogileFS::Error, @backend.error('PebkacError').superclass
57     assert MogileFS::Backend.const_defined?('PebkacError')
59     assert ! MogileFS::Backend.const_defined?('PebKacError')
60     assert @backend.error('peb_kac')
61     assert_equal MogileFS::Error, @backend.error('PebKacError').superclass
62     assert MogileFS::Backend.const_defined?('PebKacError')
64     assert_equal MogileFS::Error, MogileFS::Backend::OMFGWTFBBQError.superclass
65     assert_raises(NameError) do
66       MogileFS::Backend::FailFailFail
67     end
68   end
70   def test_make_request
71     assert_equal "go! fight=team+fight%21\r\n",
72                  @backend.make_request('go!', { 'fight' => 'team fight!' })
73   end
75   def test_parse_response
76     assert_equal({'foo' => 'bar', 'baz' => 'hoge'},
77                  @backend.parse_response("OK 1 foo=bar&baz=hoge\r\n"))
79     err = nil
80     begin
81       @backend.parse_response("ERR you totally suck\r\n")
82     rescue MogileFS::Error => err
83       assert_equal 'MogileFS::Backend::YouError', err.class.to_s
84       assert_equal 'totally suck', err.message
85     end
86     assert_equal 'MogileFS::Backend::YouError', err.class.to_s
88     assert_equal 'you', @backend.lasterr
89     assert_equal 'totally suck', @backend.lasterrstr
91     assert_raises MogileFS::InvalidResponseError do
92       @backend.parse_response 'garbage'
93     end
94     assert_raises MogileFS::InvalidResponseError do
95       @backend.parse_response("OK 1 foo=bar&baz=hoge")
96     end
97   end
99   def test_parse_response_newline
100     begin
101       @backend.parse_response("ERR you totally suck\r\n")
102     rescue MogileFS::Error => err
103       assert_equal 'MogileFS::Backend::YouError', err.class.to_s
104       assert_equal 'totally suck', err.message
105     end
107     assert_equal 'you', @backend.lasterr
108     assert_equal 'totally suck', @backend.lasterrstr
109   end
111   def test_readable_eh_not_readable
112     srv = TCPServer.new("127.0.0.1", 0)
113     port = srv.addr[1]
114     @backend = MogileFS::Backend.new(:hosts => [ "127.0.0.1:#{port}" ],
115                                      :timeout => 0.5)
116     begin
117       @backend.do_request 'foo', {}
118     rescue MogileFS::UnreadableSocketError => e
119       assert_match(/127\.0\.0\.1:#{port} never became readable/, e.message)
120     rescue Exception => err
121       flunk "MogileFS::UnreadableSocketError not raised #{err} #{err.backtrace}"
122     else
123       flunk "MogileFS::UnreadableSocketError not raised"
124     end
125   end
127   def test_socket_dead
128     assert_equal({}, @backend.dead)
129     assert_raises(MogileFS::UnreachableBackendError) do
130       @backend.do_request('test', {})
131     end
132     assert_equal(['localhost:1'], @backend.dead.keys)
133   end
135   def test_socket_robust_on_dead_server
136     10.times do
137       t1 = TCPServer.new("127.0.0.1", 0)
138       t2 = TCPServer.new("127.0.0.1", 0)
139       hosts = ["127.0.0.1:#{t1.addr[1]}", "127.0.0.1:#{t2.addr[1]}"]
140       @backend = MogileFS::Backend.new(:hosts => hosts.dup)
141       assert_equal({}, @backend.dead)
142       t1.close
143       thr = Thread.new do
144         client = t2.accept
145         client.write("OK 1 foo=bar\r\n")
146         client
147       end
148       rv = @backend.do_request('test', { "all" => "ALL" })
149       accepted = thr.value
150       assert_equal "test all=ALL\r\n", accepted.readpartial(666)
151       assert_equal({"foo"=>"bar"}, rv)
152     end
153   end
155   def test_shutdown
156     srv = TCPServer.new('127.0.0.1', 0)
157     port = srv.addr[1]
158     @backend = MogileFS::Backend.new :hosts => [ "127.0.0.1:#{port}" ]
159     assert @backend.socket
160     assert ! @backend.socket.closed?
161     client = srv.accept
162     client.write '1'
163     resp = @backend.socket.read(1)
164     @backend.shutdown
165     assert_equal nil, @backend.instance_variable_get(:@socket)
166     assert_equal 1, resp.to_i
167   end
169   def test_url_decode
170     assert_equal({"\272z" => "\360opy", "f\000" => "\272r"},
171                  @backend.url_decode("%baz=%f0opy&f%00=%bar"))
172     assert_equal({}, @backend.url_decode(''))
173   end
175   def test_url_encode
176     params = [["f\000", "\272r"], ["\272z", "\360opy"]]
177     assert_equal "f%00=%bar&%baz=%f0opy", @backend.url_encode(params)
178   end
180   def test_url_escape # \n for unit_diff
181     actual = (0..255).map { |c| @backend.url_escape c.chr }.join "\n"
183     expected = []
184     expected.push(*(0..0x1f).map { |c| "%%%0.2x" % c })
185     expected << '+'
186     expected.push(*(0x21..0x2b).map { |c| "%%%0.2x" % c })
187     expected.push(*%w[, - . /])
188     expected.push(*('0'..'9'))
189     expected.push(*%w[: %3b %3c %3d %3e %3f %40])
190     expected.push(*('A'..'Z'))
191     expected.push(*%w[%5b \\ %5d %5e _ %60])
192     expected.push(*('a'..'z'))
193     expected.push(*(0x7b..0xff).map { |c| "%%%0.2x" % c })
195     expected = expected.join "\n"
197     assert_equal expected, actual
198   end
200   def test_url_unescape
201     input = []
202     input.push(*(0..0x1f).map { |c| "%%%0.2x" % c })
203     input << '+'
204     input.push(*(0x21..0x2b).map { |c| "%%%0.2x" % c })
205     input.push(*%w[, - . /])
206     input.push(*('0'..'9'))
207     input.push(*%w[: %3b %3c %3d %3e %3f %40])
208     input.push(*('A'..'Z'))
209     input.push(*%w[%5b \\ %5d %5e _ %60])
210     input.push(*('a'..'z'))
211     input.push(*(0x7b..0xff).map { |c| "%%%0.2x" % c })
213     actual = input.map { |c| @backend.url_unescape c }.join "\n"
215     expected = (0..255).map { |c| c.chr }.join "\n"
217     assert_equal expected, actual
218   end
220   def test_fail_timeout
221     o = { :domain => "none", :hosts => %w(0:666 0:6 0:66) }
222     c = MogileFS::MogileFS.new(o)
223     assert_equal 5, c.backend.instance_variable_get(:@fail_timeout)
224     o[:fail_timeout] = 0.666
225     c = MogileFS::MogileFS.new(o)
226     assert_equal 0.666, c.backend.instance_variable_get(:@fail_timeout)
227   end
229   def test_connect_timeout
230     o = {
231       :domain => "none",
232       :hosts => %w(0:666 0:6 0:66),
233       :connect_timeout => 1
234     }
235     c = MogileFS::MogileFS.new(o)
236     assert_equal 1, c.backend.instance_variable_get(:@connect_timeout)
237     o[:timeout] = 5
238     c = MogileFS::MogileFS.new(o)
239     assert_equal 1, c.backend.instance_variable_get(:@connect_timeout)
240     assert_equal 5, c.backend.instance_variable_get(:@timeout)
241   end