mogilefs-client 1.3.1 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/test/test_admin.rb CHANGED
@@ -19,7 +19,7 @@ class TestMogileFS__Admin < TestMogileFS
19
19
  "host1_status"=>"alive",
20
20
  "host1_altmask"=>""}
21
21
  actual = @client.clean 'hosts', 'host', res
22
-
22
+
23
23
  expected = [{"status"=>"alive",
24
24
  "http_get_port"=>"",
25
25
  "http_port"=>"",
@@ -119,7 +119,7 @@ class TestMogileFS__Admin < TestMogileFS
119
119
  'file' => [{ 'files' => '2', 'class' => 'normal', 'domain' => 'test' }]
120
120
  }
121
121
 
122
- assert_equal
122
+ assert_equal
123
123
  end
124
124
 
125
125
  def test_get_stats_fids
data/test/test_backend.rb CHANGED
@@ -16,8 +16,6 @@ end
16
16
  class TestBackend < Test::Unit::TestCase
17
17
 
18
18
  def setup
19
- TCPSocket.connections = []
20
- TCPSocket.sockets = []
21
19
  @backend = MogileFS::Backend.new :hosts => ['localhost:1']
22
20
  end
23
21
 
@@ -37,17 +35,21 @@ class TestBackend < Test::Unit::TestCase
37
35
  end
38
36
 
39
37
  def test_do_request
40
- socket_request = ''
41
- socket = Object.new
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
38
+ received = ''
39
+ tmp = TempServer.new(Proc.new do |serv, port|
40
+ client, client_addr = serv.accept
41
+ client.sync = true
42
+ received = client.recv 4096
43
+ client.send "OK 1 you=win\r\n", 0
44
+ end)
46
45
 
47
- @backend.instance_variable_set '@socket', socket
46
+ @backend.hosts = "127.0.0.1:#{tmp.port}"
48
47
 
49
48
  assert_equal({'you' => 'win'},
50
49
  @backend.do_request('go!', { 'fight' => 'team fight!' }))
50
+ assert_equal "go! fight=team+fight%21\r\n", received
51
+ ensure
52
+ TempServer.destroy_all!
51
53
  end
52
54
 
53
55
  def test_do_request_send_error
@@ -58,13 +60,25 @@ class TestBackend < Test::Unit::TestCase
58
60
 
59
61
  @backend.instance_variable_set '@socket', socket
60
62
 
61
- assert_raises RuntimeError do
63
+ assert_raises MogileFS::UnreachableBackendError do
62
64
  @backend.do_request 'go!', { 'fight' => 'team fight!' }
63
65
  end
64
66
 
65
67
  assert_equal nil, @backend.instance_variable_get('@socket')
66
68
  end
67
69
 
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')
75
+
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')
80
+ end
81
+
68
82
  def test_do_request_truncated
69
83
  socket_request = ''
70
84
  socket = Object.new
@@ -73,7 +87,7 @@ class TestBackend < Test::Unit::TestCase
73
87
 
74
88
  @backend.instance_variable_set '@socket', socket
75
89
 
76
- assert_raises RuntimeError do
90
+ assert_raises MogileFS::RequestTruncatedError do
77
91
  @backend.do_request 'go!', { 'fight' => 'team fight!' }
78
92
  end
79
93
  end
@@ -86,70 +100,118 @@ class TestBackend < Test::Unit::TestCase
86
100
  def test_parse_response
87
101
  assert_equal({'foo' => 'bar', 'baz' => 'hoge'},
88
102
  @backend.parse_response('OK 1 foo=bar&baz=hoge'))
89
- assert_equal nil, @backend.parse_response('ERR you totally suck')
103
+
104
+ err = nil
105
+ begin
106
+ @backend.parse_response('ERR you totally suck')
107
+ rescue MogileFS::Error => err
108
+ assert_equal 'MogileFS::Backend::YouError', err.class.to_s
109
+ end
110
+ assert_equal 'MogileFS::Backend::YouError', err.class.to_s
111
+
90
112
  assert_equal 'you', @backend.lasterr
91
113
  assert_equal 'totally suck', @backend.lasterrstr
92
114
 
93
- assert_raises RuntimeError do
115
+ assert_raises MogileFS::InvalidResponseError do
94
116
  @backend.parse_response 'garbage'
95
117
  end
96
118
  end
97
119
 
98
120
  def test_readable_eh_readable
99
- socket = Object.new
100
- def socket.closed?() false end
101
- def @backend.select(*args) return [true] end
102
- @backend.instance_variable_set '@socket', socket
103
-
121
+ accept_nr = 0
122
+ tmp = TempServer.new(Proc.new do |serv, port|
123
+ client, client_addr = serv.accept
124
+ client.sync = true
125
+ accept_nr += 1
126
+ client.send('.', 0)
127
+ sleep
128
+ end)
129
+
130
+ @backend = MogileFS::Backend.new :hosts => [ "127.0.0.1:#{tmp.port}" ]
104
131
  assert_equal true, @backend.readable?
132
+ assert_equal 1, accept_nr
133
+ ensure
134
+ TempServer.destroy_all!
105
135
  end
106
136
 
107
137
  def test_readable_eh_not_readable
108
- socket = FakeSocket.new
109
- def socket.closed?() false end
110
- def @backend.select(*args) return [] end
111
- @backend.instance_variable_set '@socket', socket
112
-
138
+ tmp = TempServer.new(Proc.new { |a,b| sleep })
139
+ @backend = MogileFS::Backend.new(:hosts => [ "127.0.0.1:#{tmp.port}" ],
140
+ :timeout => 0.5)
113
141
  begin
114
142
  @backend.readable?
115
143
  rescue MogileFS::UnreadableSocketError => e
116
- assert_equal '127.0.0.1:6001 never became readable', e.message
117
- rescue Exception
118
- flunk "MogileFS::UnreadableSocketError not raised"
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}"
119
147
  else
120
148
  flunk "MogileFS::UnreadableSocketError not raised"
149
+ ensure
150
+ TempServer.destroy_all!
121
151
  end
122
152
  end
123
153
 
124
154
  def test_socket
125
155
  assert_equal({}, @backend.dead)
126
- assert_raises RuntimeError do @backend.socket end
156
+ assert_raises MogileFS::UnreachableBackendError do @backend.socket end
127
157
  assert_equal(['localhost:1'], @backend.dead.keys)
128
158
  end
129
159
 
130
160
  def test_socket_robust
131
- @backend.hosts = ['localhost:6001', 'localhost:6002']
132
- def @backend.connect_to(host, port)
133
- @first = (defined? @first) ? false : true
134
- raise Errno::ECONNREFUSED if @first
161
+ bad_accept_nr = accept_nr = 0
162
+ queue = Queue.new
163
+ bad = Proc.new { |serv,port| sleep; bad_accept_nr += 1 }
164
+ good = Proc.new do |serv,port|
165
+ client, client_addr = serv.accept
166
+ client.sync = true
167
+ accept_nr += 1
168
+ client.send '.', 0
169
+ client.flush
170
+ queue.push true
171
+ sleep
135
172
  end
136
-
137
- assert_equal({}, @backend.dead)
138
- @backend.socket
139
- assert_equal false, @backend.dead.keys.empty?
173
+ nr = 10
174
+
175
+ nr.times do
176
+ begin
177
+ t1 = TempServer.new(bad)
178
+ t2 = TempServer.new(good)
179
+ hosts = ["0:#{t1.port}", "0:#{t2.port}"]
180
+ @backend = MogileFS::Backend.new(:hosts => hosts)
181
+ assert_equal({}, @backend.dead)
182
+ t1.destroy!
183
+ @backend.socket
184
+ wait = queue.pop
185
+ ensure
186
+ TempServer.destroy_all!
187
+ end
188
+ end # nr.times
189
+ assert_equal 0, bad_accept_nr
190
+ assert_equal nr, accept_nr
140
191
  end
141
192
 
142
193
  def test_shutdown
143
- fake_socket = FakeSocket.new
144
- @backend.socket = fake_socket
145
- assert_equal fake_socket, @backend.socket
194
+ accept_nr = 0
195
+ tmp = TempServer.new(Proc.new do |serv,port|
196
+ client, client_addr = serv.accept
197
+ accept_nr += 1
198
+ sleep
199
+ end)
200
+ @backend = MogileFS::Backend.new :hosts => [ "127.0.0.1:#{tmp.port}" ]
201
+ assert @backend.socket
202
+ assert ! @backend.socket.closed?
146
203
  @backend.shutdown
147
204
  assert_equal nil, @backend.instance_variable_get(:@socket)
205
+ assert_equal 1, accept_nr
206
+
207
+ ensure
208
+ TempServer.destroy_all!
148
209
  end
149
210
 
150
211
  def test_url_decode
151
212
  assert_equal({"\272z" => "\360opy", "f\000" => "\272r"},
152
213
  @backend.url_decode("%baz=%f0opy&f%00=%bar"))
214
+ assert_equal({}, @backend.url_decode(''))
153
215
  end
154
216
 
155
217
  def test_url_encode
@@ -0,0 +1,48 @@
1
+ require 'test/setup'
2
+ require 'mogilefs/bigfile'
3
+
4
+ class TestMogileFS__Bigfile < TestMogileFS
5
+ include MogileFS::Bigfile
6
+
7
+ def setup
8
+ @klass = MogileFS::MogileFS
9
+ super
10
+ end
11
+
12
+ def test_parser
13
+ expect = {:type=>"file",
14
+ :des=>"no description",
15
+ :chunks=>2,
16
+ :parts=>
17
+ [nil,
18
+ {:md5=>"d3b4d15c294b24d9f853e26095dfe3d0",
19
+ :paths=>
20
+ ["http://foo1:7500/dev2/0/000/144/0000144411.fid",
21
+ "http://foo2:7500/dev1/0/000/144/0000144411.fid"],
22
+ :bytes=>12},
23
+ {:md5=>"d3b4d15c294b24d9f853e26095dfe3d0",
24
+ :paths=>
25
+ ["http://foo4:7500/dev2/0/000/144/0000144411.fid",
26
+ "http://foo3:7500/dev1/0/000/144/0000144411.fid"],
27
+ :bytes=>6}],
28
+ :size=>18,
29
+ :filename=>"foo.tar",
30
+ :compressed=>false}
31
+
32
+ s = <<EOS
33
+ des no description
34
+ type file
35
+ compressed 0
36
+ filename foo.tar
37
+ chunks 2
38
+ size 18
39
+
40
+ part 1 bytes=12 md5=d3b4d15c294b24d9f853e26095dfe3d0 paths: http://foo1:7500/dev2/0/000/144/0000144411.fid, http://foo2:7500/dev1/0/000/144/0000144411.fid
41
+ part 2 bytes=6 md5=d3b4d15c294b24d9f853e26095dfe3d0 paths: http://foo4:7500/dev2/0/000/144/0000144411.fid, http://foo3:7500/dev1/0/000/144/0000144411.fid
42
+ EOS
43
+ i = parse_info(s)
44
+ assert_equal expect, i
45
+ end
46
+
47
+ end
48
+
data/test/test_client.rb CHANGED
@@ -1,8 +1,13 @@
1
1
  require 'test/unit'
2
+ require 'mogilefs'
2
3
 
3
- $TESTING = true
4
+ class MogileFS::Backend
5
+ attr_accessor :timeout, :lasterr, :lasterrstr, :hosts
6
+ end
4
7
 
5
- require 'mogilefs'
8
+ class MogileFS::Client
9
+ attr_accessor :hosts
10
+ end
6
11
 
7
12
  class TestClient < Test::Unit::TestCase
8
13
 
@@ -0,0 +1,73 @@
1
+ require 'test/setup'
2
+ require 'mogilefs/mysql'
3
+
4
+ class TestMogileFS__DbBackend < Test::Unit::TestCase
5
+ def setup
6
+ @my = FakeMysql.new
7
+ @mgmy = MogileFS::Mysql.new(:mysql => @my)
8
+ @mg = MogileFS::MogileFS.new(:db_backend => @mgmy, :domain => 'test')
9
+ end
10
+
11
+ def test_initialize
12
+ assert_equal 'test', @mg.domain
13
+ assert @mg.readonly?
14
+ end
15
+
16
+ def test_list_keys_block
17
+ expect_full = [ [ 'foo', 123, 2 ], [ 'bar', 456, 1 ] ]
18
+ expect_keys = [ [ 'foo', 'bar' ], 'bar' ]
19
+ @my.expect << expect_full
20
+ full = []
21
+ keys = @mg.list_keys('test') do |dkey,length,devcount|
22
+ full << [ dkey, length, devcount ]
23
+ end
24
+ assert_equal expect_keys, keys
25
+ assert_equal expect_full, full
26
+ end
27
+
28
+ def test_list_keys
29
+ expect_full = [ [ 'foo', 123, 2 ], [ 'bar', 456, 1 ] ]
30
+ expect_keys = [ [ 'foo', 'bar' ], 'bar' ]
31
+ @my.expect << expect_full
32
+ keys = @mg.list_keys('test')
33
+ assert_equal expect_keys, keys
34
+ end
35
+
36
+ def test_size
37
+ @my.expect << [ [ '123' ] ]
38
+ assert_equal 123, @mg.size('foo')
39
+
40
+ @my.expect << [ [ '456' ] ]
41
+ assert_equal 456, @mg.size('foo')
42
+ end
43
+
44
+ def test_store_file_readonly
45
+ assert_raises(MogileFS::ReadOnlyError) do
46
+ @mg.store_file 'new_key', 'test', '/dev/null'
47
+ end
48
+ end
49
+
50
+ def test_store_content_readonly
51
+ assert_raises(MogileFS::ReadOnlyError) do
52
+ @mg.store_content 'new_key', 'test', 'data'
53
+ end
54
+ end
55
+
56
+ def test_new_file_readonly
57
+ assert_raises(MogileFS::ReadOnlyError) { @mg.new_file 'new_key', 'test' }
58
+ end
59
+
60
+ def test_rename_readonly
61
+ assert_raises(MogileFS::ReadOnlyError) { @mg.rename 'a', 'b' }
62
+ end
63
+
64
+ def test_delete_readonly
65
+ assert_raises(MogileFS::ReadOnlyError) { @mg.delete 'no_such_key' }
66
+ end
67
+
68
+ def test_sleep
69
+ assert_nothing_raised { assert_equal({}, @mg.sleep(1)) }
70
+ end
71
+
72
+ end
73
+
@@ -3,24 +3,8 @@ require 'stringio'
3
3
  require 'tempfile'
4
4
  require 'fileutils'
5
5
 
6
- class URI::HTTP
7
-
8
- class << self
9
- attr_accessor :read_data
10
- attr_accessor :open_data
11
- end
12
-
13
- def read
14
- self.class.read_data.shift
15
- end
16
-
17
- def open(&block)
18
- yield self.class.open_data
19
- end
20
-
21
- end
22
-
23
6
  class TestMogileFS__MogileFS < TestMogileFS
7
+ include MogileFS::Util
24
8
 
25
9
  def setup
26
10
  @klass = MogileFS::MogileFS
@@ -29,27 +13,76 @@ class TestMogileFS__MogileFS < TestMogileFS
29
13
 
30
14
  def test_initialize
31
15
  assert_equal 'test', @client.domain
32
- assert_equal @root, @client.root
33
16
 
34
17
  assert_raises ArgumentError do
35
- MogileFS::MogileFS.new :hosts => ['kaa:6001'], :root => '/mogilefs/test'
18
+ MogileFS::MogileFS.new :hosts => ['kaa:6001']
36
19
  end
37
20
  end
38
21
 
39
22
  def test_get_file_data_http
40
- URI::HTTP.read_data = %w[data!]
23
+ accept_nr = 0
24
+ svr = Proc.new do |serv, port|
25
+ client, client_addr = serv.accept
26
+ client.sync = true
27
+ readed = client.recv(4096, 0)
28
+ assert(readed =~ \
29
+ %r{\AGET /dev[12]/0/000/000/0000000062\.fid HTTP/1.[01]\r\n\r\n\Z})
30
+ client.send("HTTP/1.0 200 OK\r\nContent-Length: 5\r\n\r\ndata!", 0)
31
+ accept_nr += 1
32
+ client.close
33
+ end
34
+ t1 = TempServer.new(svr)
35
+ t2 = TempServer.new(svr)
36
+ path1 = "http://127.0.0.1:#{t1.port}/dev1/0/000/000/0000000062.fid"
37
+ path2 = "http://127.0.0.1:#{t2.port}/dev2/0/000/000/0000000062.fid"
41
38
 
42
- path1 = 'http://rur-1/dev1/0/000/000/0000000062.fid'
43
- path2 = 'http://rur-2/dev2/0/000/000/0000000062.fid'
39
+ @backend.get_paths = { 'paths' => 2, 'path1' => path1, 'path2' => path2 }
40
+
41
+ assert_equal 'data!', @client.get_file_data('key')
42
+ assert_equal 1, accept_nr
43
+ ensure
44
+ TempServer.destroy_all!
45
+ end
44
46
 
47
+ def test_get_file_data_http_not_found_failover
48
+ accept_nr = 0
49
+ svr1 = Proc.new do |serv, port|
50
+ client, client_addr = serv.accept
51
+ client.sync = true
52
+ readed = client.recv(4096, 0)
53
+ assert(readed =~ \
54
+ %r{\AGET /dev1/0/000/000/0000000062\.fid HTTP/1.[01]\r\n\r\n\Z})
55
+ client.send("HTTP/1.0 404 Not Found\r\n\r\ndata!", 0)
56
+ accept_nr += 1
57
+ client.close
58
+ end
59
+
60
+ svr2 = Proc.new do |serv, port|
61
+ client, client_addr = serv.accept
62
+ client.sync = true
63
+ readed = client.recv(4096, 0)
64
+ assert(readed =~ \
65
+ %r{\AGET /dev2/0/000/000/0000000062\.fid HTTP/1.[01]\r\n\r\n\Z})
66
+ client.send("HTTP/1.0 200 OK\r\nContent-Length: 5\r\n\r\ndata!", 0)
67
+ accept_nr += 1
68
+ client.close
69
+ end
70
+
71
+ t1 = TempServer.new(svr1)
72
+ t2 = TempServer.new(svr2)
73
+ path1 = "http://127.0.0.1:#{t1.port}/dev1/0/000/000/0000000062.fid"
74
+ path2 = "http://127.0.0.1:#{t2.port}/dev2/0/000/000/0000000062.fid"
45
75
  @backend.get_paths = { 'paths' => 2, 'path1' => path1, 'path2' => path2 }
46
76
 
47
77
  assert_equal 'data!', @client.get_file_data('key')
78
+ assert_equal 2, accept_nr
79
+ ensure
80
+ TempServer.destroy_all!
48
81
  end
49
82
 
50
83
  def test_get_file_data_http_block
51
84
  tmpfp = Tempfile.new('test_mogilefs.open_data')
52
- nr = 100 # tested with 1000
85
+ nr = nr_chunks
53
86
  chunk_size = 1024 * 1024
54
87
  expect_size = nr * chunk_size
55
88
  header = "HTTP/1.0 200 OK\r\n" \
@@ -58,18 +91,29 @@ class TestMogileFS__MogileFS < TestMogileFS
58
91
  nr.times { assert_equal chunk_size, tmpfp.syswrite(' ' * chunk_size) }
59
92
  assert_equal expect_size + header.size, File.size(tmpfp.path)
60
93
  tmpfp.sysseek(0)
61
- socket = FakeSocket.new(tmpfp)
62
- TCPSocket.sockets << socket
63
94
 
64
- path1 = 'http://rur-1/dev1/0/000/000/0000000062.fid'
65
- path2 = 'http://rur-2/dev2/0/000/000/0000000062.fid'
95
+ accept_nr = 0
96
+ svr = Proc.new do |serv, port|
97
+ client, client_addr = serv.accept
98
+ client.sync = true
99
+ accept_nr += 1
100
+ readed = client.recv(4096, 0)
101
+ assert(readed =~ \
102
+ %r{\AGET /dev[12]/0/000/000/0000000062\.fid HTTP/1.[01]\r\n\r\n\Z})
103
+ sysrwloop(tmpfp, client)
104
+ client.close
105
+ end
106
+ t1 = TempServer.new(svr)
107
+ t2 = TempServer.new(svr)
108
+ path1 = "http://127.0.0.1:#{t1.port}/dev1/0/000/000/0000000062.fid"
109
+ path2 = "http://127.0.0.1:#{t2.port}/dev2/0/000/000/0000000062.fid"
66
110
 
67
111
  @backend.get_paths = { 'paths' => 2, 'path1' => path1, 'path2' => path2 }
68
112
 
69
113
  data = Tempfile.new('test_mogilefs.dest_data')
114
+ read_nr = nr = 0
70
115
  @client.get_file_data('key') do |fp|
71
116
  buf = ''
72
- read_nr = nr = 0
73
117
  loop do
74
118
  begin
75
119
  fp.sysread(16384, buf)
@@ -80,17 +124,18 @@ class TestMogileFS__MogileFS < TestMogileFS
80
124
  break
81
125
  end
82
126
  end
83
- assert_equal expect_size, nr, "size mismatch"
84
127
  end
128
+ assert_equal expect_size, nr, "size mismatch"
129
+ assert_equal 1, accept_nr
85
130
  end
86
131
 
87
132
  def test_get_paths
88
- path1 = 'rur-1/dev1/0/000/000/0000000062.fid'
89
- path2 = 'rur-2/dev2/0/000/000/0000000062.fid'
133
+ path1 = 'http://rur-1/dev1/0/000/000/0000000062.fid'
134
+ path2 = 'http://rur-2/dev2/0/000/000/0000000062.fid'
90
135
 
91
136
  @backend.get_paths = { 'paths' => 2, 'path1' => path1, 'path2' => path2 }
92
137
 
93
- expected = ["#{@root}/#{path1}", "#{@root}/#{path2}"]
138
+ expected = [ path1, path2 ]
94
139
 
95
140
  assert_equal expected, @client.get_paths('key').sort
96
141
  end
@@ -98,7 +143,9 @@ class TestMogileFS__MogileFS < TestMogileFS
98
143
  def test_get_paths_unknown_key
99
144
  @backend.get_paths = ['unknown_key', '']
100
145
 
101
- assert_equal nil, @client.get_paths('key')
146
+ assert_raises MogileFS::Backend::UnknownKeyError do
147
+ assert_equal nil, @client.get_paths('key')
148
+ end
102
149
  end
103
150
 
104
151
  def test_delete_existing
@@ -110,14 +157,14 @@ class TestMogileFS__MogileFS < TestMogileFS
110
157
 
111
158
  def test_delete_nonexisting
112
159
  @backend.delete = 'unknown_key', ''
113
- assert_nothing_raised do
114
- assert_equal nil, @client.delete('no_such_key')
160
+ assert_raises MogileFS::Backend::UnknownKeyError do
161
+ @client.delete('no_such_key')
115
162
  end
116
163
  end
117
164
 
118
165
  def test_delete_readonly
119
166
  @client.readonly = true
120
- assert_raises RuntimeError do
167
+ assert_raises MogileFS::ReadOnlyError do
121
168
  @client.delete 'no_such_key'
122
169
  end
123
170
  end
@@ -145,99 +192,188 @@ class TestMogileFS__MogileFS < TestMogileFS
145
192
  assert_equal 'new_key_2', next_after
146
193
  end
147
194
 
195
+ def test_list_keys_block
196
+ @backend.list_keys = { 'key_count' => 2, 'next_after' => 'new_key_2',
197
+ 'key_1' => 'new_key_1', 'key_2' => 'new_key_2' }
198
+ http_resp = "HTTP/1.0 200 OK\r\nContent-Length: %u\r\n"
199
+ srv = Proc.new do |serv, port, size|
200
+ client, client_addr = serv.accept
201
+ client.sync = true
202
+ readed = client.readpartial(4096)
203
+ assert %r{\AHEAD } =~ readed
204
+ client.send(http_resp % size, 0)
205
+ client.close
206
+ end
207
+ t1 = TempServer.new(Proc.new { |serv, port| srv.call(serv, port, 5) })
208
+ t2 = TempServer.new(Proc.new { |serv, port| srv.call(serv, port, 5) })
209
+ t3 = TempServer.new(Proc.new { |serv, port| srv.call(serv, port, 10) })
210
+ @backend.get_paths = { 'paths' => 2,
211
+ 'path1' => "http://127.0.0.1:#{t1.port}/",
212
+ 'path2' => "http://127.0.0.1:#{t2.port}/" }
213
+ @backend.get_paths = { 'paths' => 1,
214
+ 'path1' => "http://127.0.0.1:#{t3.port}/" }
215
+
216
+ res = []
217
+ keys, next_after = @client.list_keys('new') do |key,length,devcount|
218
+ res << [ key, length, devcount ]
219
+ end
220
+
221
+ expect_res = [ [ 'new_key_1', 5, 2 ], [ 'new_key_2', 10, 1 ] ]
222
+ assert_equal expect_res, res
223
+ assert_equal ['new_key_1', 'new_key_2'], keys.sort
224
+ assert_equal 'new_key_2', next_after
225
+ ensure
226
+ TempServer.destroy_all!
227
+ end
228
+
148
229
  def test_new_file_http
149
230
  @client.readonly = true
150
- assert_raises RuntimeError do
231
+ assert_raises MogileFS::ReadOnlyError do
151
232
  @client.new_file 'new_key', 'test'
152
233
  end
153
234
  end
154
235
 
155
236
  def test_new_file_readonly
156
237
  @client.readonly = true
157
- assert_raises RuntimeError do
238
+ assert_raises MogileFS::ReadOnlyError do
158
239
  @client.new_file 'new_key', 'test'
159
240
  end
160
241
  end
161
242
 
162
243
  def test_size_http
163
- socket = FakeSocket.new <<-EOF
164
- HTTP/1.0 200 OK\r
165
- Content-Length: 5\r
166
- EOF
167
-
168
- TCPSocket.sockets << socket
169
-
170
- path = 'http://example.com/path'
171
-
244
+ accept_nr = 0
245
+ t = TempServer.new(Proc.new do |serv,port|
246
+ client, client_addr = serv.accept
247
+ client.sync = true
248
+ readed = client.recv(4096, 0) rescue nil
249
+ assert_equal "HEAD /path HTTP/1.0\r\n\r\n", readed
250
+ client.send("HTTP/1.0 200 OK\r\nContent-Length: 5\r\n\r\n", 0)
251
+ accept_nr += 1
252
+ client.close
253
+ end)
254
+
255
+ path = "http://127.0.0.1:#{t.port}/path"
172
256
  @backend.get_paths = { 'paths' => 1, 'path1' => path }
173
257
 
174
258
  assert_equal 5, @client.size('key')
175
-
176
- socket.write_s.rewind
177
-
178
- assert_equal "HEAD /path HTTP/1.1\r\n", socket.write_s.gets
179
-
180
- assert_equal ['example.com', 80], TCPSocket.connections.shift
181
- assert_empty TCPSocket.connections
259
+ assert_equal 1, accept_nr
182
260
  end
183
261
 
184
- def test_size_nfs
185
- path = File.join @root, 'path'
186
-
187
- File.open path, 'w' do |fp| fp.write 'data!' end
188
-
189
- @backend.get_paths = { 'paths' => 1, 'path1' => 'path' }
262
+ def test_bad_size_http
263
+ accept_nr = 0
264
+ t = TempServer.new(Proc.new do |serv,port|
265
+ client, client_addr = serv.accept
266
+ client.sync = true
267
+ readed = client.recv(4096, 0) rescue nil
268
+ assert_equal "HEAD /path HTTP/1.0\r\n\r\n", readed
269
+ client.send("HTTP/1.0 404 Not Found\r\nContent-Length: 5\r\n\r\n", 0)
270
+ accept_nr += 1
271
+ client.close
272
+ end)
273
+
274
+ path = "http://127.0.0.1:#{t.port}/path"
275
+ @backend.get_paths = { 'paths' => 1, 'path1' => path }
190
276
 
191
- assert_equal 5, @client.size('key')
277
+ assert_nil @client.size('key')
278
+ assert_equal 1, accept_nr
192
279
  end
193
280
 
194
281
  def test_store_content_http
195
- socket = FakeSocket.new 'HTTP/1.0 200 OK'
282
+ received = ''
283
+ expected = "PUT /path HTTP/1.0\r\nContent-Length: 4\r\n\r\ndata"
196
284
 
197
- TCPSocket.sockets << socket
285
+ t = TempServer.new(Proc.new do |serv, accept|
286
+ client, client_addr = serv.accept
287
+ client.sync = true
288
+ received = client.recv(4096, 0)
289
+ client.send("HTTP/1.0 200 OK\r\n\r\n", 0)
290
+ client.close
291
+ end)
198
292
 
199
293
  @backend.create_open = {
200
294
  'devid' => '1',
201
- 'path' => 'http://example.com/path',
295
+ 'path' => "http://127.0.0.1:#{t.port}/path",
202
296
  }
203
297
 
204
298
  @client.store_content 'new_key', 'test', 'data'
205
299
 
206
- expected = <<-EOF.chomp
207
- PUT /path HTTP/1.0\r
208
- Content-Length: 4\r
209
- \r
210
- data
211
- EOF
300
+ assert_equal expected, received
301
+ ensure
302
+ TempServer.destroy_all!
303
+ end
212
304
 
213
- assert_equal expected, socket.write_s.string
305
+ def test_store_content_multi_dest_failover
306
+ received1 = received2 = nil
307
+ expected = "PUT /path HTTP/1.0\r\nContent-Length: 4\r\n\r\ndata"
308
+
309
+ t1 = TempServer.new(Proc.new do |serv, accept|
310
+ client, client_addr = serv.accept
311
+ client.sync = true
312
+ received1 = client.recv(4096, 0)
313
+ client.send("HTTP/1.0 500 Internal Server Error\r\n\r\n", 0)
314
+ client.close
315
+ end)
316
+
317
+ t2 = TempServer.new(Proc.new do |serv, accept|
318
+ client, client_addr = serv.accept
319
+ client.sync = true
320
+ received2 = client.recv(4096, 0)
321
+ client.send("HTTP/1.0 200 OK\r\n\r\n", 0)
322
+ client.close
323
+ end)
214
324
 
215
- assert_equal ['example.com', 80], TCPSocket.connections.shift
216
- assert_empty TCPSocket.connections
217
- end
325
+ @backend.create_open = {
326
+ 'dev_count' => '2',
327
+ 'devid_1' => '1',
328
+ 'path_1' => "http://127.0.0.1:#{t1.port}/path",
329
+ 'devid_2' => '2',
330
+ 'path_2' => "http://127.0.0.1:#{t2.port}/path",
331
+ }
218
332
 
219
- def test_store_content_http_empty
220
- socket = FakeSocket.new 'HTTP/1.0 200 OK'
333
+ @client.store_content 'new_key', 'test', 'data'
334
+ assert_equal expected, received1
335
+ assert_equal expected, received2
336
+ ensure
337
+ TempServer.destroy_all!
338
+ end
221
339
 
222
- TCPSocket.sockets << socket
340
+ def test_store_content_http_fail
341
+ t = TempServer.new(Proc.new do |serv, accept|
342
+ client, client_addr = serv.accept
343
+ client.sync = true
344
+ client.recv(4096, 0)
345
+ client.send("HTTP/1.0 500 Internal Server Error\r\n\r\n", 0)
346
+ client.close
347
+ end)
223
348
 
224
349
  @backend.create_open = {
225
350
  'devid' => '1',
226
- 'path' => 'http://example.com/path',
351
+ 'path' => "http://127.0.0.1:#{t.port}/path",
227
352
  }
228
353
 
229
- @client.store_content 'new_key', 'test', ''
354
+ assert_raises MogileFS::HTTPFile::BadResponseError do
355
+ @client.store_content 'new_key', 'test', 'data'
356
+ end
357
+ end
230
358
 
231
- expected = <<-EOF
232
- PUT /path HTTP/1.0\r
233
- Content-Length: 0\r
234
- \r
235
- EOF
359
+ def test_store_content_http_empty
360
+ received = ''
361
+ expected = "PUT /path HTTP/1.0\r\nContent-Length: 0\r\n\r\n"
362
+ t = TempServer.new(Proc.new do |serv, accept|
363
+ client, client_addr = serv.accept
364
+ client.sync = true
365
+ received = client.recv(4096, 0)
366
+ client.send("HTTP/1.0 200 OK\r\n\r\n", 0)
367
+ client.close
368
+ end)
236
369
 
237
- assert_equal expected, socket.write_s.string
370
+ @backend.create_open = {
371
+ 'devid' => '1',
372
+ 'path' => "http://127.0.0.1:#{t.port}/path",
373
+ }
238
374
 
239
- assert_equal ['example.com', 80], TCPSocket.connections.shift
240
- assert_empty TCPSocket.connections
375
+ @client.store_content 'new_key', 'test', ''
376
+ assert_equal expected, received
241
377
  end
242
378
 
243
379
  def test_store_content_nfs
@@ -246,41 +382,76 @@ Content-Length: 0\r
246
382
  'devid_1' => '1',
247
383
  'path_1' => '/path',
248
384
  }
385
+ assert_raises MogileFS::UnsupportedPathError do
386
+ @client.store_content 'new_key', 'test', 'data'
387
+ end
388
+ end
249
389
 
250
- @client.store_content 'new_key', 'test', 'data'
390
+ def test_new_file_http_large
391
+ expect = Tempfile.new('test_mogilefs.expect')
392
+ to_put = Tempfile.new('test_mogilefs.to_put')
393
+ received = Tempfile.new('test_mogilefs.received')
251
394
 
252
- dest_file = File.join(@root, 'path')
395
+ nr = nr_chunks
396
+ chunk_size = 1024 * 1024
397
+ expect_size = nr * chunk_size
253
398
 
254
- assert File.exist?(dest_file)
255
- assert_equal 'data', File.read(dest_file)
256
- end
399
+ header = "PUT /path HTTP/1.0\r\n" \
400
+ "Content-Length: #{expect_size}\r\n\r\n"
401
+ assert_equal header.size, expect.syswrite(header)
402
+ nr.times do
403
+ assert_equal chunk_size, expect.syswrite(' ' * chunk_size)
404
+ assert_equal chunk_size, to_put.syswrite(' ' * chunk_size)
405
+ end
406
+ assert_equal expect_size + header.size, expect.stat.size
407
+ assert_equal expect_size, to_put.stat.size
408
+
409
+ readed = 0
410
+ t = TempServer.new(Proc.new do |serv, accept|
411
+ client, client_addr = serv.accept
412
+ client.sync = true
413
+ loop do
414
+ buf = client.readpartial(8192) or break
415
+ break if buf.length == 0
416
+ assert_equal buf.length, received.syswrite(buf)
417
+ readed += buf.length
418
+ break if readed >= expect.stat.size
419
+ end
420
+ client.send("HTTP/1.0 200 OK\r\n\r\n", 0)
421
+ client.close
422
+ end)
257
423
 
258
- def test_store_content_nfs_empty
259
424
  @backend.create_open = {
260
- 'dev_count' => '1',
261
- 'devid_1' => '1',
262
- 'path_1' => '/path',
425
+ 'devid' => '1',
426
+ 'path' => "http://127.0.0.1:#{t.port}/path",
263
427
  }
264
428
 
265
- @client.store_content 'new_key', 'test', ''
429
+ @client.store_file('new_key', 'test', to_put.path)
430
+ assert_equal expect.stat.size, readed
266
431
 
267
- dest_file = File.join(@root, 'path')
432
+ ENV['PATH'].split(/:/).each do |path|
433
+ cmp_bin = "#{path}/cmp"
434
+ File.executable?(cmp_bin) or next
435
+ # puts "running #{cmp_bin} #{expect.path} #{received.path}"
436
+ assert( system(cmp_bin, expect.path, received.path) )
437
+ break
438
+ end
268
439
 
269
- assert File.exist?(dest_file)
270
- assert_equal '', File.read(dest_file)
440
+ ensure
441
+ TempServer.destroy_all!
271
442
  end
272
443
 
273
444
  def test_store_content_readonly
274
445
  @client.readonly = true
275
446
 
276
- assert_raises RuntimeError do
447
+ assert_raises MogileFS::ReadOnlyError do
277
448
  @client.store_content 'new_key', 'test', nil
278
449
  end
279
450
  end
280
451
 
281
452
  def test_store_file_readonly
282
453
  @client.readonly = true
283
- assert_raises RuntimeError do
454
+ assert_raises MogileFS::ReadOnlyError do
284
455
  @client.store_file 'new_key', 'test', nil
285
456
  end
286
457
  end
@@ -294,23 +465,25 @@ Content-Length: 0\r
294
465
  def test_rename_nonexisting
295
466
  @backend.rename = 'unknown_key', ''
296
467
 
297
- assert_nil @client.rename('from_key', 'to_key')
468
+ assert_raises MogileFS::Backend::UnknownKeyError do
469
+ @client.rename('from_key', 'to_key')
470
+ end
298
471
  end
299
472
 
300
473
  def test_rename_no_key
301
- @backend.rename = 'no_key', ''
474
+ @backend.rename = 'no_key', 'no_key'
302
475
 
303
- e = assert_raises RuntimeError do
476
+ e = assert_raises MogileFS::Backend::NoKeyError do
304
477
  @client.rename 'new_key', 'test'
305
478
  end
306
479
 
307
- assert_equal 'unable to rename new_key to test: no_key', e.message
480
+ assert_equal 'no_key', e.message
308
481
  end
309
482
 
310
483
  def test_rename_readonly
311
484
  @client.readonly = true
312
485
 
313
- e = assert_raises RuntimeError do
486
+ e = assert_raises MogileFS::ReadOnlyError do
314
487
  @client.rename 'new_key', 'test'
315
488
  end
316
489
 
@@ -324,5 +497,12 @@ Content-Length: 0\r
324
497
  end
325
498
  end
326
499
 
500
+ private
501
+
502
+ # tested with 1000, though it takes a while
503
+ def nr_chunks
504
+ ENV['NR_CHUNKS'] ? ENV['NR_CHUNKS'].to_i : 10
505
+ end
506
+
327
507
  end
328
508