Ruby mogilefs-client 3.4.0
[ruby-mogilefs-client.git] / test / test_backend.rb
blob22592014eae0a52f21dd1e2586f8daedbcf068ed
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 nil, @backend.lasterr
29     assert_equal nil, @backend.lasterrstr
30     assert_equal({}, @backend.dead)
32     @backend = MogileFS::Backend.new :hosts => ['localhost:6001'], :timeout => 1
33     assert_equal 1, @backend.timeout
34   end
36   def test_do_request
37     srv = TCPServer.new("127.0.0.1", 0)
38     port = srv.addr[1]
39     accepted = Thread.new do
40       client = srv.accept
41       client.write("OK 1 you=win\r\n")
42       client
43     end
44     @backend.hosts = [ "127.0.0.1:#{port}" ]
45     assert_equal({'you' => 'win'},
46                  @backend.do_request('go!', { 'fight' => 'team fight!' }))
47     accepted = accepted.value
48     assert_equal "go! fight=team+fight%21\r\n", accepted.readpartial(4096)
49   end
51   def test_automatic_exception
52     assert ! MogileFS::Backend.const_defined?('PebkacError')
53     assert @backend.error('pebkac')
54     assert_equal MogileFS::Error, @backend.error('PebkacError').superclass
55     assert MogileFS::Backend.const_defined?('PebkacError')
57     assert ! MogileFS::Backend.const_defined?('PebKacError')
58     assert @backend.error('peb_kac')
59     assert_equal MogileFS::Error, @backend.error('PebKacError').superclass
60     assert MogileFS::Backend.const_defined?('PebKacError')
62     assert_nothing_raised do
63       MogileFS::Backend::OMFGWTFBBQError
64     end
65     assert_equal MogileFS::Error, MogileFS::Backend::OMFGWTFBBQError.superclass
66     assert_raises(NameError) do
67       MogileFS::Backend::FailFailFail
68     end
69   end
71   def test_make_request
72     assert_equal "go! fight=team+fight%21\r\n",
73                  @backend.make_request('go!', { 'fight' => 'team fight!' })
74   end
76   def test_parse_response
77     assert_equal({'foo' => 'bar', 'baz' => 'hoge'},
78                  @backend.parse_response("OK 1 foo=bar&baz=hoge\r\n"))
80     err = nil
81     begin
82       @backend.parse_response("ERR you totally suck\r\n")
83     rescue MogileFS::Error => err
84       assert_equal 'MogileFS::Backend::YouError', err.class.to_s
85       assert_equal 'totally suck', err.message
86     end
87     assert_equal 'MogileFS::Backend::YouError', err.class.to_s
89     assert_equal 'you', @backend.lasterr
90     assert_equal 'totally suck', @backend.lasterrstr
92     assert_raises MogileFS::InvalidResponseError do
93       @backend.parse_response 'garbage'
94     end
95     assert_raises MogileFS::InvalidResponseError do
96       @backend.parse_response("OK 1 foo=bar&baz=hoge")
97     end
98   end
100   def test_parse_response_newline
101     begin
102       @backend.parse_response("ERR you totally suck\r\n")
103     rescue MogileFS::Error => err
104       assert_equal 'MogileFS::Backend::YouError', err.class.to_s
105       assert_equal 'totally suck', err.message
106     end
108     assert_equal 'you', @backend.lasterr
109     assert_equal 'totally suck', @backend.lasterrstr
110   end
112   def test_readable_eh_not_readable
113     srv = TCPServer.new("127.0.0.1", 0)
114     port = srv.addr[1]
115     @backend = MogileFS::Backend.new(:hosts => [ "127.0.0.1:#{port}" ],
116                                      :timeout => 0.5)
117     begin
118       @backend.do_request 'foo', {}
119     rescue MogileFS::UnreadableSocketError => e
120       assert_match(/127\.0\.0\.1:#{port} never became readable/, e.message)
121     rescue Exception => err
122       flunk "MogileFS::UnreadableSocketError not raised #{err} #{err.backtrace}"
123     else
124       flunk "MogileFS::UnreadableSocketError not raised"
125     end
126   end
128   def test_socket_dead
129     assert_equal({}, @backend.dead)
130     assert_raises(MogileFS::UnreachableBackendError) do
131       @backend.do_request('test', {})
132     end
133     assert_equal(['localhost:1'], @backend.dead.keys)
134   end
136   def test_socket_robust_on_dead_server
137     10.times do
138       t1 = TCPServer.new("127.0.0.1", 0)
139       t2 = TCPServer.new("127.0.0.1", 0)
140       hosts = ["127.0.0.1:#{t1.addr[1]}", "127.0.0.1:#{t2.addr[1]}"]
141       @backend = MogileFS::Backend.new(:hosts => hosts.dup)
142       assert_equal({}, @backend.dead)
143       t1.close
144       thr = Thread.new do
145         client = t2.accept
146         client.write("OK 1 foo=bar\r\n")
147         client
148       end
149       rv = nil
150       assert_nothing_raised do
151         rv = @backend.do_request('test', { "all" => "ALL" })
152       end
153       accepted = thr.value
154       assert_equal "test all=ALL\r\n", accepted.readpartial(666)
155       assert_equal({"foo"=>"bar"}, rv)
156     end
157   end
159   def test_shutdown
160     srv = TCPServer.new('127.0.0.1', 0)
161     port = srv.addr[1]
162     @backend = MogileFS::Backend.new :hosts => [ "127.0.0.1:#{port}" ]
163     assert @backend.socket
164     assert ! @backend.socket.closed?
165     client = srv.accept
166     client.write '1'
167     resp = @backend.socket.read(1)
168     @backend.shutdown
169     assert_equal nil, @backend.instance_variable_get(:@socket)
170     assert_equal 1, resp.to_i
171   end
173   def test_url_decode
174     assert_equal({"\272z" => "\360opy", "f\000" => "\272r"},
175                  @backend.url_decode("%baz=%f0opy&f%00=%bar"))
176     assert_equal({}, @backend.url_decode(''))
177   end
179   def test_url_encode
180     params = [["f\000", "\272r"], ["\272z", "\360opy"]]
181     assert_equal "f%00=%bar&%baz=%f0opy", @backend.url_encode(params)
182   end
184   def test_url_escape # \n for unit_diff
185     actual = (0..255).map { |c| @backend.url_escape c.chr }.join "\n"
187     expected = []
188     expected.push(*(0..0x1f).map { |c| "%%%0.2x" % c })
189     expected << '+'
190     expected.push(*(0x21..0x2b).map { |c| "%%%0.2x" % c })
191     expected.push(*%w[, - . /])
192     expected.push(*('0'..'9'))
193     expected.push(*%w[: %3b %3c %3d %3e %3f %40])
194     expected.push(*('A'..'Z'))
195     expected.push(*%w[%5b \\ %5d %5e _ %60])
196     expected.push(*('a'..'z'))
197     expected.push(*(0x7b..0xff).map { |c| "%%%0.2x" % c })
199     expected = expected.join "\n"
201     assert_equal expected, actual
202   end
204   def test_url_unescape
205     input = []
206     input.push(*(0..0x1f).map { |c| "%%%0.2x" % c })
207     input << '+'
208     input.push(*(0x21..0x2b).map { |c| "%%%0.2x" % c })
209     input.push(*%w[, - . /])
210     input.push(*('0'..'9'))
211     input.push(*%w[: %3b %3c %3d %3e %3f %40])
212     input.push(*('A'..'Z'))
213     input.push(*%w[%5b \\ %5d %5e _ %60])
214     input.push(*('a'..'z'))
215     input.push(*(0x7b..0xff).map { |c| "%%%0.2x" % c })
217     actual = input.map { |c| @backend.url_unescape c }.join "\n"
219     expected = (0..255).map { |c| c.chr }.join "\n"
221     assert_equal expected, actual
222   end
224   def test_fail_timeout
225     o = { :domain => "none", :hosts => %w(0:666 0:6 0:66) }
226     c = MogileFS::MogileFS.new(o)
227     assert_equal 5, c.backend.instance_variable_get(:@fail_timeout)
228     o[:fail_timeout] = 0.666
229     c = MogileFS::MogileFS.new(o)
230     assert_equal 0.666, c.backend.instance_variable_get(:@fail_timeout)
231   end