mogilefs-client 1.3.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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