mogilefs-client 2.0.0 → 2.0.1
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/.gitignore +2 -0
- data/History.txt +6 -0
- data/README.txt +1 -1
- data/bin/mog +1 -0
- data/lib/mogilefs.rb +1 -1
- data/lib/mogilefs/backend.rb +8 -3
- data/lib/mogilefs/httpfile.rb +13 -2
- data/lib/mogilefs/mogilefs.rb +6 -2
- data/lib/mogilefs/network.rb +72 -32
- data/lib/mogilefs/pool.rb +2 -0
- data/lib/mogilefs/util.rb +10 -0
- data/test/setup.rb +15 -9
- data/test/test_backend.rb +38 -25
- data/test/test_mogilefs.rb +84 -31
- data/test/test_network.rb +28 -0
- data/test/test_util.rb +10 -10
- metadata +3 -3
data/.gitignore
CHANGED
data/History.txt
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
= 2.0.1
|
2
|
+
* verify_uris method made more robust
|
3
|
+
* preliminary Ruby 1.9 compatibility, tests still need some work
|
4
|
+
* allow store_content to be used with a streamable object of known length
|
5
|
+
* add setup.rb for non-RubyGems users
|
6
|
+
|
1
7
|
= 2.0.0
|
2
8
|
|
3
9
|
* use a set of standard exceptions based on MogileFS::Error,
|
data/README.txt
CHANGED
@@ -60,7 +60,7 @@ Then install the gem:
|
|
60
60
|
|
61
61
|
# Store the contents of 'image.jpeg' into the key 'my_image' with a class of
|
62
62
|
# 'image' using an open IO.
|
63
|
-
File.open 'image.jpeg' do |fp|
|
63
|
+
File.open 'image.jpeg', 'rb' do |fp|
|
64
64
|
mg.store_file 'my_image', 'image', fp
|
65
65
|
end
|
66
66
|
|
data/bin/mog
CHANGED
data/lib/mogilefs.rb
CHANGED
data/lib/mogilefs/backend.rb
CHANGED
@@ -274,9 +274,14 @@ class MogileFS::Backend
|
|
274
274
|
|
275
275
|
##
|
276
276
|
# Escapes naughty URL characters.
|
277
|
-
|
278
|
-
|
279
|
-
|
277
|
+
if ''.respond_to?(:ord) # Ruby 1.9
|
278
|
+
def url_escape(str)
|
279
|
+
str.gsub(/([^\w\,\-.\/\\\: ])/) { "%%%02x" % $1.ord }.tr(' ', '+')
|
280
|
+
end
|
281
|
+
else # Ruby 1.8
|
282
|
+
def url_escape(str)
|
283
|
+
str.gsub(/([^\w\,\-.\/\\\: ])/) { "%%%02x" % $1[0] }.tr(' ', '+')
|
284
|
+
end
|
280
285
|
end
|
281
286
|
|
282
287
|
##
|
data/lib/mogilefs/httpfile.rb
CHANGED
@@ -44,12 +44,15 @@ class MogileFS::HTTPFile < StringIO
|
|
44
44
|
|
45
45
|
attr_accessor :big_io
|
46
46
|
|
47
|
+
attr_accessor :streaming_io
|
48
|
+
|
47
49
|
##
|
48
50
|
# Works like File.open. Use MogileFS::MogileFS#new_file instead of this
|
49
51
|
# method.
|
50
52
|
|
51
53
|
def self.open(*args)
|
52
54
|
fp = new(*args)
|
55
|
+
fp.set_encoding(Encoding::BINARY) if fp.respond_to?(:set_encoding)
|
53
56
|
|
54
57
|
return fp unless block_given?
|
55
58
|
|
@@ -72,6 +75,7 @@ class MogileFS::HTTPFile < StringIO
|
|
72
75
|
@klass = klass
|
73
76
|
@key = key
|
74
77
|
@big_io = nil
|
78
|
+
@streaming_io = nil
|
75
79
|
|
76
80
|
@dests = dests
|
77
81
|
@tried = {}
|
@@ -87,9 +91,16 @@ class MogileFS::HTTPFile < StringIO
|
|
87
91
|
sock = Socket.mogilefs_new(uri.host, uri.port)
|
88
92
|
sock.mogilefs_tcp_cork = true
|
89
93
|
|
90
|
-
if @
|
94
|
+
if @streaming_io
|
95
|
+
file_size = @streaming_io.length
|
96
|
+
syswrite_full(sock, "PUT #{uri.request_uri} HTTP/1.0\r\n" \
|
97
|
+
"Content-Length: #{file_size}\r\n\r\n")
|
98
|
+
@streaming_io.call(Proc.new do |data_to_write|
|
99
|
+
syswrite_full(sock, data_to_write)
|
100
|
+
end)
|
101
|
+
elsif @big_io
|
91
102
|
# Don't try to run out of memory
|
92
|
-
File.open(@big_io) do |fp|
|
103
|
+
File.open(@big_io, "rb") do |fp|
|
93
104
|
file_size = fp.stat.size
|
94
105
|
fp.sync = true
|
95
106
|
syswrite_full(sock, "PUT #{uri.request_uri} HTTP/1.0\r\n" \
|
data/lib/mogilefs/mogilefs.rb
CHANGED
@@ -148,7 +148,7 @@ class MogileFS::MogileFS < MogileFS::Client
|
|
148
148
|
mfp.big_io = file
|
149
149
|
return
|
150
150
|
else
|
151
|
-
return File.open(file) { |fp| sysrwloop(fp, mfp) }
|
151
|
+
return File.open(file, "rb") { |fp| sysrwloop(fp, mfp) }
|
152
152
|
end
|
153
153
|
end
|
154
154
|
end
|
@@ -161,7 +161,11 @@ class MogileFS::MogileFS < MogileFS::Client
|
|
161
161
|
raise MogileFS::ReadOnlyError if readonly?
|
162
162
|
|
163
163
|
new_file key, klass do |mfp|
|
164
|
-
|
164
|
+
if content.is_a?(MogileFS::Util::StoreContent)
|
165
|
+
mfp.streaming_io = content
|
166
|
+
else
|
167
|
+
mfp << content
|
168
|
+
end
|
165
169
|
end
|
166
170
|
|
167
171
|
content.length
|
data/lib/mogilefs/network.rb
CHANGED
@@ -7,8 +7,6 @@ module MogileFS::Network
|
|
7
7
|
# with the expected HTTP code within the timeout period (in seconds).
|
8
8
|
def verify_uris(uris = [], expect = '200', timeout = 2.00)
|
9
9
|
uri_socks = {}
|
10
|
-
ok_uris = []
|
11
|
-
sockets = []
|
12
10
|
|
13
11
|
# first, we asynchronously connect to all of them
|
14
12
|
uris.each do |uri|
|
@@ -18,47 +16,89 @@ module MogileFS::Network
|
|
18
16
|
|
19
17
|
# wait for at least one of them to finish connecting and send
|
20
18
|
# HTTP requests to the connected ones
|
21
|
-
|
22
|
-
t0 = Time.now
|
23
|
-
r = IO.select(nil, uri_socks.keys, nil, timeout > 0 ? timeout : 0)
|
24
|
-
timeout -= (Time.now - t0)
|
25
|
-
break unless r && r[1]
|
26
|
-
r[1].each do |sock|
|
27
|
-
begin
|
28
|
-
# we don't about short/interrupted writes here, if the following
|
29
|
-
# request fails or blocks then the server is flat-out hopeless
|
30
|
-
sock.syswrite "HEAD #{uri_socks[sock].request_uri} HTTP/1.0\r\n\r\n"
|
31
|
-
sockets << sock
|
32
|
-
rescue
|
33
|
-
sock.close rescue nil
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end until sockets[0] || timeout < 0
|
19
|
+
sockets, timeout = get_writable_set(uri_socks, timeout)
|
37
20
|
|
38
21
|
# Await a response from the sockets we had written to, we only need one
|
39
22
|
# valid response, but we'll take more if they return simultaneously
|
40
|
-
|
23
|
+
sockets[0] ? get_readable_uris(sockets, uri_socks, expect, timeout) : []
|
24
|
+
|
25
|
+
ensure
|
26
|
+
uri_socks.keys.each { |sock| sock.close rescue nil }
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
include MogileFS::Util
|
31
|
+
|
32
|
+
# returns an array of writeable Sockets and leftover from timeout
|
33
|
+
def get_writable_set(uri_socks, timeout)
|
34
|
+
sockets = []
|
41
35
|
begin
|
42
36
|
t0 = Time.now
|
43
|
-
r =
|
37
|
+
r = begin
|
38
|
+
IO.select(nil, uri_socks.keys, nil, timeout > 0 ? timeout : 0)
|
39
|
+
rescue
|
40
|
+
# get rid of bad descriptors
|
41
|
+
uri_socks.delete_if do |sock, uri|
|
42
|
+
begin
|
43
|
+
sock.recv_nonblock(1)
|
44
|
+
false # should never get here for HTTP, really...
|
45
|
+
rescue Errno::EAGAIN, Errno::EINTR
|
46
|
+
false
|
47
|
+
rescue
|
48
|
+
sock.close rescue nil
|
49
|
+
true
|
50
|
+
end
|
51
|
+
end
|
52
|
+
timeout -= (Time.now - t0)
|
53
|
+
retry if timeout >= 0
|
54
|
+
end
|
55
|
+
|
56
|
+
break unless r && r[1]
|
57
|
+
|
58
|
+
r[1].each do |sock|
|
59
|
+
begin
|
60
|
+
# we don't about short/interrupted writes here, if the following
|
61
|
+
# request fails or blocks then the server is flat-out hopeless
|
62
|
+
sock.syswrite "HEAD #{uri_socks[sock].request_uri} HTTP/1.0\r\n\r\n"
|
63
|
+
sockets << sock
|
64
|
+
rescue
|
65
|
+
sock.close rescue nil
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
44
69
|
timeout -= (Time.now - t0)
|
45
|
-
|
46
|
-
|
47
|
-
|
70
|
+
end until (sockets[0] || timeout < 0)
|
71
|
+
|
72
|
+
[ sockets, timeout ]
|
73
|
+
end
|
74
|
+
|
75
|
+
# returns an array of URIs from uri_socks that are good
|
76
|
+
def get_readable_uris(sockets, uri_socks, expect, timeout)
|
77
|
+
ok_uris = []
|
78
|
+
|
79
|
+
begin
|
80
|
+
t0 = Time.now
|
81
|
+
r = IO.select(sockets, nil, nil, timeout > 0 ? timeout : 0) rescue nil
|
82
|
+
|
83
|
+
(r && r[0] ? r[0] : sockets).each do |sock|
|
84
|
+
buf = begin
|
85
|
+
sock.recv_nonblock(128, Socket::MSG_PEEK)
|
86
|
+
rescue Errno::EAGAIN, Errno::EINTR
|
87
|
+
next
|
88
|
+
rescue
|
89
|
+
sockets.delete(sock) # socket went bad
|
90
|
+
next
|
91
|
+
end
|
92
|
+
|
48
93
|
if buf && /\AHTTP\/[\d\.]+ #{expect} / =~ buf
|
49
94
|
ok_uris << uri_socks.delete(sock)
|
50
95
|
sock.close rescue nil
|
51
96
|
end
|
52
97
|
end
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
ok_uris
|
57
|
-
ensure
|
58
|
-
uri_socks.keys.each { |sock| sock.close rescue nil }
|
59
|
-
end
|
98
|
+
timeout -= (Time.now - t0)
|
99
|
+
end until ok_uris[0] || timeout < 0
|
60
100
|
|
61
|
-
|
62
|
-
|
101
|
+
ok_uris
|
102
|
+
end
|
63
103
|
|
64
104
|
end # module MogileFS::Network
|
data/lib/mogilefs/pool.rb
CHANGED
data/lib/mogilefs/util.rb
CHANGED
@@ -67,6 +67,16 @@ module MogileFS::Util
|
|
67
67
|
# should never get here
|
68
68
|
end
|
69
69
|
|
70
|
+
class StoreContent < Proc
|
71
|
+
def initialize(total_size, &writer_proc)
|
72
|
+
@total_size = total_size
|
73
|
+
super(&writer_proc)
|
74
|
+
end
|
75
|
+
def length
|
76
|
+
@total_size
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
70
80
|
end
|
71
81
|
|
72
82
|
require 'timeout'
|
data/test/setup.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
1
|
STDIN.sync = STDOUT.sync = STDERR.sync = true
|
2
2
|
require 'test/unit'
|
3
|
-
|
3
|
+
require 'tempfile'
|
4
4
|
require 'fileutils'
|
5
5
|
require 'tmpdir'
|
6
6
|
require 'stringio'
|
7
7
|
|
8
|
+
trap('CHLD') { Process.waitpid(-1, Process::WNOHANG) rescue nil }
|
9
|
+
|
8
10
|
$TESTING = true
|
9
11
|
|
10
12
|
require 'mogilefs'
|
@@ -52,37 +54,41 @@ end
|
|
52
54
|
|
53
55
|
require 'socket'
|
54
56
|
class TempServer
|
55
|
-
attr_reader :port
|
57
|
+
attr_reader :port, :pid
|
56
58
|
|
57
59
|
def self.destroy_all!
|
58
60
|
ObjectSpace.each_object(TempServer) { |t| t.destroy! }
|
59
61
|
end
|
60
62
|
|
61
|
-
|
62
|
-
|
63
|
+
at_exit { TempServer.destroy_all! }
|
64
|
+
|
65
|
+
def initialize(server_proc, port = nil)
|
66
|
+
@pid = @sock = nil
|
67
|
+
@port = port
|
63
68
|
retries = 0
|
64
69
|
begin
|
65
|
-
@port
|
70
|
+
@port ||= 1024 + rand(32768 - 1024)
|
66
71
|
@sock = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
|
67
|
-
@sock.bind(Socket.pack_sockaddr_in(@port, '127.0.0.1'))
|
72
|
+
@sock.bind(Socket.pack_sockaddr_in(@port.to_i, '127.0.0.1'))
|
68
73
|
@sock.listen(5)
|
69
74
|
rescue Errno::EADDRINUSE, Errno::EACCES
|
70
75
|
@sock.close rescue nil
|
71
76
|
retry if (retries += 1) < 10
|
72
77
|
end
|
73
|
-
@
|
78
|
+
@pid = fork { server_proc.call(@sock, @port) }
|
79
|
+
@sock.close rescue nil
|
74
80
|
end
|
75
81
|
|
76
82
|
def destroy!
|
77
83
|
@sock.close rescue nil
|
78
|
-
|
84
|
+
Process.kill('KILL', @pid) rescue nil
|
79
85
|
end
|
80
86
|
|
81
87
|
end
|
82
88
|
|
83
89
|
class TestMogileFS < Test::Unit::TestCase
|
84
90
|
|
85
|
-
undef_method :default_test
|
91
|
+
undef_method :default_test if method_defined?(:default_test)
|
86
92
|
|
87
93
|
def setup
|
88
94
|
@client = @klass.new :hosts => ['kaa:6001'], :domain => 'test'
|
data/test/test_backend.rb
CHANGED
@@ -35,19 +35,20 @@ class TestBackend < Test::Unit::TestCase
|
|
35
35
|
end
|
36
36
|
|
37
37
|
def test_do_request
|
38
|
-
received = ''
|
38
|
+
received = Tempfile.new('received')
|
39
39
|
tmp = TempServer.new(Proc.new do |serv, port|
|
40
40
|
client, client_addr = serv.accept
|
41
41
|
client.sync = true
|
42
|
-
received
|
42
|
+
received.syswrite(client.recv(4096))
|
43
43
|
client.send "OK 1 you=win\r\n", 0
|
44
44
|
end)
|
45
45
|
|
46
|
-
@backend.hosts = "127.0.0.1:#{tmp.port}"
|
46
|
+
@backend.hosts = [ "127.0.0.1:#{tmp.port}" ]
|
47
47
|
|
48
48
|
assert_equal({'you' => 'win'},
|
49
49
|
@backend.do_request('go!', { 'fight' => 'team fight!' }))
|
50
|
-
|
50
|
+
received.sysseek(0)
|
51
|
+
assert_equal "go! fight=team+fight%21\r\n", received.sysread(4096)
|
51
52
|
ensure
|
52
53
|
TempServer.destroy_all!
|
53
54
|
end
|
@@ -118,24 +119,24 @@ class TestBackend < Test::Unit::TestCase
|
|
118
119
|
end
|
119
120
|
|
120
121
|
def test_readable_eh_readable
|
121
|
-
|
122
|
+
accept = Tempfile.new('accept')
|
122
123
|
tmp = TempServer.new(Proc.new do |serv, port|
|
123
124
|
client, client_addr = serv.accept
|
124
125
|
client.sync = true
|
125
|
-
|
126
|
+
accept.syswrite('.')
|
126
127
|
client.send('.', 0)
|
127
128
|
sleep
|
128
129
|
end)
|
129
130
|
|
130
131
|
@backend = MogileFS::Backend.new :hosts => [ "127.0.0.1:#{tmp.port}" ]
|
131
132
|
assert_equal true, @backend.readable?
|
132
|
-
assert_equal 1,
|
133
|
+
assert_equal 1, accept.stat.size
|
133
134
|
ensure
|
134
135
|
TempServer.destroy_all!
|
135
136
|
end
|
136
137
|
|
137
138
|
def test_readable_eh_not_readable
|
138
|
-
tmp = TempServer.new(Proc.new { |
|
139
|
+
tmp = TempServer.new(Proc.new { |serv,port| serv.accept; sleep })
|
139
140
|
@backend = MogileFS::Backend.new(:hosts => [ "127.0.0.1:#{tmp.port}" ],
|
140
141
|
:timeout => 0.5)
|
141
142
|
begin
|
@@ -158,36 +159,45 @@ class TestBackend < Test::Unit::TestCase
|
|
158
159
|
end
|
159
160
|
|
160
161
|
def test_socket_robust
|
161
|
-
|
162
|
-
|
163
|
-
bad = Proc.new
|
162
|
+
bad_accept = Tempfile.new('bad_accept')
|
163
|
+
accept = Tempfile.new('accept')
|
164
|
+
bad = Proc.new do |serv,port|
|
165
|
+
client, client_addr = serv.accept
|
166
|
+
bad_accept.syswrite('!')
|
167
|
+
end
|
164
168
|
good = Proc.new do |serv,port|
|
165
169
|
client, client_addr = serv.accept
|
166
|
-
|
167
|
-
|
168
|
-
client.
|
169
|
-
client.flush
|
170
|
-
queue.push true
|
170
|
+
accept.syswrite('.')
|
171
|
+
client.syswrite('.')
|
172
|
+
client.close
|
171
173
|
sleep
|
172
174
|
end
|
173
175
|
nr = 10
|
174
176
|
|
175
177
|
nr.times do
|
176
178
|
begin
|
177
|
-
t1 = TempServer.new(bad)
|
179
|
+
t1 = TempServer.new(bad, ENV['TEST_DEAD_PORT'])
|
178
180
|
t2 = TempServer.new(good)
|
179
|
-
hosts = ["0:#{t1.port}", "0:#{t2.port}"]
|
180
|
-
@backend = MogileFS::Backend.new(:hosts => hosts)
|
181
|
+
hosts = ["127.0.0.1:#{t1.port}", "127.0.0.1:#{t2.port}"]
|
182
|
+
@backend = MogileFS::Backend.new(:hosts => hosts.dup)
|
181
183
|
assert_equal({}, @backend.dead)
|
184
|
+
old_chld_handler = trap('CHLD', 'DEFAULT')
|
182
185
|
t1.destroy!
|
183
|
-
|
184
|
-
|
186
|
+
Process.waitpid(t1.pid)
|
187
|
+
trap('CHLD', old_chld_handler)
|
188
|
+
sock = @backend.socket
|
189
|
+
assert_equal Socket, sock.class
|
190
|
+
port = Socket.unpack_sockaddr_in(sock.getpeername).first
|
191
|
+
# p [ 'ports', "port=#{port}", "t1=#{t1.port}", "t2=#{t2.port}" ]
|
192
|
+
assert_equal t2.port, port
|
193
|
+
IO.select([sock])
|
194
|
+
assert_equal '.', sock.sysread(1)
|
185
195
|
ensure
|
186
196
|
TempServer.destroy_all!
|
187
197
|
end
|
188
198
|
end # nr.times
|
189
|
-
assert_equal 0,
|
190
|
-
assert_equal nr,
|
199
|
+
assert_equal 0, bad_accept.stat.size
|
200
|
+
assert_equal nr, accept.stat.size
|
191
201
|
end
|
192
202
|
|
193
203
|
def test_shutdown
|
@@ -195,15 +205,18 @@ class TestBackend < Test::Unit::TestCase
|
|
195
205
|
tmp = TempServer.new(Proc.new do |serv,port|
|
196
206
|
client, client_addr = serv.accept
|
197
207
|
accept_nr += 1
|
208
|
+
r = IO.select([client], [client])
|
209
|
+
client.syswrite(accept_nr.to_s)
|
198
210
|
sleep
|
199
211
|
end)
|
200
212
|
@backend = MogileFS::Backend.new :hosts => [ "127.0.0.1:#{tmp.port}" ]
|
201
213
|
assert @backend.socket
|
202
214
|
assert ! @backend.socket.closed?
|
215
|
+
IO.select([@backend.socket])
|
216
|
+
resp = @backend.socket.sysread(4096)
|
203
217
|
@backend.shutdown
|
204
218
|
assert_equal nil, @backend.instance_variable_get(:@socket)
|
205
|
-
assert_equal 1,
|
206
|
-
|
219
|
+
assert_equal 1, resp.to_i
|
207
220
|
ensure
|
208
221
|
TempServer.destroy_all!
|
209
222
|
end
|
data/test/test_mogilefs.rb
CHANGED
@@ -20,15 +20,16 @@ class TestMogileFS__MogileFS < TestMogileFS
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def test_get_file_data_http
|
23
|
-
|
23
|
+
tmp = Tempfile.new('accept')
|
24
|
+
accept = File.open(tmp.path, "ab")
|
24
25
|
svr = Proc.new do |serv, port|
|
25
26
|
client, client_addr = serv.accept
|
26
27
|
client.sync = true
|
27
28
|
readed = client.recv(4096, 0)
|
28
29
|
assert(readed =~ \
|
29
30
|
%r{\AGET /dev[12]/0/000/000/0000000062\.fid HTTP/1.[01]\r\n\r\n\Z})
|
31
|
+
accept.syswrite('.')
|
30
32
|
client.send("HTTP/1.0 200 OK\r\nContent-Length: 5\r\n\r\ndata!", 0)
|
31
|
-
accept_nr += 1
|
32
33
|
client.close
|
33
34
|
end
|
34
35
|
t1 = TempServer.new(svr)
|
@@ -39,13 +40,14 @@ class TestMogileFS__MogileFS < TestMogileFS
|
|
39
40
|
@backend.get_paths = { 'paths' => 2, 'path1' => path1, 'path2' => path2 }
|
40
41
|
|
41
42
|
assert_equal 'data!', @client.get_file_data('key')
|
42
|
-
assert_equal 1,
|
43
|
+
assert_equal 1, accept.stat.size
|
43
44
|
ensure
|
44
45
|
TempServer.destroy_all!
|
45
46
|
end
|
46
47
|
|
47
48
|
def test_get_file_data_http_not_found_failover
|
48
|
-
|
49
|
+
tmp = Tempfile.new('accept')
|
50
|
+
accept = File.open(tmp.path, 'ab')
|
49
51
|
svr1 = Proc.new do |serv, port|
|
50
52
|
client, client_addr = serv.accept
|
51
53
|
client.sync = true
|
@@ -53,7 +55,7 @@ class TestMogileFS__MogileFS < TestMogileFS
|
|
53
55
|
assert(readed =~ \
|
54
56
|
%r{\AGET /dev1/0/000/000/0000000062\.fid HTTP/1.[01]\r\n\r\n\Z})
|
55
57
|
client.send("HTTP/1.0 404 Not Found\r\n\r\ndata!", 0)
|
56
|
-
|
58
|
+
accept.syswrite('.')
|
57
59
|
client.close
|
58
60
|
end
|
59
61
|
|
@@ -64,7 +66,7 @@ class TestMogileFS__MogileFS < TestMogileFS
|
|
64
66
|
assert(readed =~ \
|
65
67
|
%r{\AGET /dev2/0/000/000/0000000062\.fid HTTP/1.[01]\r\n\r\n\Z})
|
66
68
|
client.send("HTTP/1.0 200 OK\r\nContent-Length: 5\r\n\r\ndata!", 0)
|
67
|
-
|
69
|
+
accept.syswrite('.')
|
68
70
|
client.close
|
69
71
|
end
|
70
72
|
|
@@ -75,7 +77,7 @@ class TestMogileFS__MogileFS < TestMogileFS
|
|
75
77
|
@backend.get_paths = { 'paths' => 2, 'path1' => path1, 'path2' => path2 }
|
76
78
|
|
77
79
|
assert_equal 'data!', @client.get_file_data('key')
|
78
|
-
assert_equal 2,
|
80
|
+
assert_equal 2, accept.stat.size
|
79
81
|
ensure
|
80
82
|
TempServer.destroy_all!
|
81
83
|
end
|
@@ -92,16 +94,17 @@ class TestMogileFS__MogileFS < TestMogileFS
|
|
92
94
|
assert_equal expect_size + header.size, File.size(tmpfp.path)
|
93
95
|
tmpfp.sysseek(0)
|
94
96
|
|
95
|
-
|
97
|
+
accept = Tempfile.new('accept')
|
96
98
|
svr = Proc.new do |serv, port|
|
97
99
|
client, client_addr = serv.accept
|
98
100
|
client.sync = true
|
99
|
-
|
101
|
+
accept.syswrite('.')
|
100
102
|
readed = client.recv(4096, 0)
|
101
103
|
assert(readed =~ \
|
102
104
|
%r{\AGET /dev[12]/0/000/000/0000000062\.fid HTTP/1.[01]\r\n\r\n\Z})
|
103
105
|
sysrwloop(tmpfp, client)
|
104
106
|
client.close
|
107
|
+
exit 0
|
105
108
|
end
|
106
109
|
t1 = TempServer.new(svr)
|
107
110
|
t2 = TempServer.new(svr)
|
@@ -120,13 +123,15 @@ class TestMogileFS__MogileFS < TestMogileFS
|
|
120
123
|
read_nr = buf.size
|
121
124
|
nr += read_nr
|
122
125
|
assert_equal read_nr, data.syswrite(buf), "partial write"
|
126
|
+
rescue Errno::EAGAIN
|
127
|
+
retry
|
123
128
|
rescue EOFError
|
124
129
|
break
|
125
130
|
end
|
126
131
|
end
|
127
132
|
end
|
128
133
|
assert_equal expect_size, nr, "size mismatch"
|
129
|
-
assert_equal 1,
|
134
|
+
assert_equal 1, accept.stat.size
|
130
135
|
end
|
131
136
|
|
132
137
|
def test_get_paths
|
@@ -241,14 +246,14 @@ class TestMogileFS__MogileFS < TestMogileFS
|
|
241
246
|
end
|
242
247
|
|
243
248
|
def test_size_http
|
244
|
-
|
249
|
+
accept = Tempfile.new('accept')
|
245
250
|
t = TempServer.new(Proc.new do |serv,port|
|
246
251
|
client, client_addr = serv.accept
|
247
252
|
client.sync = true
|
248
253
|
readed = client.recv(4096, 0) rescue nil
|
254
|
+
accept.syswrite('.')
|
249
255
|
assert_equal "HEAD /path HTTP/1.0\r\n\r\n", readed
|
250
256
|
client.send("HTTP/1.0 200 OK\r\nContent-Length: 5\r\n\r\n", 0)
|
251
|
-
accept_nr += 1
|
252
257
|
client.close
|
253
258
|
end)
|
254
259
|
|
@@ -256,18 +261,18 @@ class TestMogileFS__MogileFS < TestMogileFS
|
|
256
261
|
@backend.get_paths = { 'paths' => 1, 'path1' => path }
|
257
262
|
|
258
263
|
assert_equal 5, @client.size('key')
|
259
|
-
assert_equal 1,
|
264
|
+
assert_equal 1, accept.stat.size
|
260
265
|
end
|
261
266
|
|
262
267
|
def test_bad_size_http
|
263
|
-
|
268
|
+
tmp = Tempfile.new('accept')
|
264
269
|
t = TempServer.new(Proc.new do |serv,port|
|
265
270
|
client, client_addr = serv.accept
|
266
271
|
client.sync = true
|
267
272
|
readed = client.recv(4096, 0) rescue nil
|
268
273
|
assert_equal "HEAD /path HTTP/1.0\r\n\r\n", readed
|
269
274
|
client.send("HTTP/1.0 404 Not Found\r\nContent-Length: 5\r\n\r\n", 0)
|
270
|
-
|
275
|
+
tmp.syswrite('.')
|
271
276
|
client.close
|
272
277
|
end)
|
273
278
|
|
@@ -275,17 +280,17 @@ class TestMogileFS__MogileFS < TestMogileFS
|
|
275
280
|
@backend.get_paths = { 'paths' => 1, 'path1' => path }
|
276
281
|
|
277
282
|
assert_nil @client.size('key')
|
278
|
-
assert_equal 1,
|
283
|
+
assert_equal 1, tmp.stat.size
|
279
284
|
end
|
280
285
|
|
281
286
|
def test_store_content_http
|
282
|
-
received = ''
|
287
|
+
received = Tempfile.new('recieved')
|
283
288
|
expected = "PUT /path HTTP/1.0\r\nContent-Length: 4\r\n\r\ndata"
|
284
289
|
|
285
290
|
t = TempServer.new(Proc.new do |serv, accept|
|
286
291
|
client, client_addr = serv.accept
|
287
292
|
client.sync = true
|
288
|
-
received
|
293
|
+
received.syswrite(client.recv(4096, 0))
|
289
294
|
client.send("HTTP/1.0 200 OK\r\n\r\n", 0)
|
290
295
|
client.close
|
291
296
|
end)
|
@@ -297,19 +302,61 @@ class TestMogileFS__MogileFS < TestMogileFS
|
|
297
302
|
|
298
303
|
@client.store_content 'new_key', 'test', 'data'
|
299
304
|
|
300
|
-
|
305
|
+
received.sysseek(0)
|
306
|
+
assert_equal expected, received.sysread(4096)
|
307
|
+
ensure
|
308
|
+
TempServer.destroy_all!
|
309
|
+
end
|
310
|
+
|
311
|
+
|
312
|
+
def test_store_content_with_writer_callback
|
313
|
+
received = Tempfile.new('recieved')
|
314
|
+
expected = "PUT /path HTTP/1.0\r\nContent-Length: 40\r\n\r\n"
|
315
|
+
10.times do
|
316
|
+
expected += "data"
|
317
|
+
end
|
318
|
+
t = TempServer.new(Proc.new do |serv, accept|
|
319
|
+
client, client_addr = serv.accept
|
320
|
+
client.sync = true
|
321
|
+
nr = 0
|
322
|
+
loop do
|
323
|
+
buf = client.readpartial(8192) or break
|
324
|
+
break if buf.length == 0
|
325
|
+
assert_equal buf.length, received.syswrite(buf)
|
326
|
+
nr += buf.length
|
327
|
+
break if nr >= expected.size
|
328
|
+
end
|
329
|
+
client.send("HTTP/1.0 200 OK\r\n\r\n", 0)
|
330
|
+
client.close
|
331
|
+
end)
|
332
|
+
|
333
|
+
@backend.create_open = {
|
334
|
+
'devid' => '1',
|
335
|
+
'path' => "http://127.0.0.1:#{t.port}/path",
|
336
|
+
}
|
337
|
+
|
338
|
+
cbk = MogileFS::Util::StoreContent.new(40) do |write_callback|
|
339
|
+
10.times do
|
340
|
+
write_callback.call("data")
|
341
|
+
end
|
342
|
+
end
|
343
|
+
@client.store_content('new_key', 'test', cbk)
|
344
|
+
|
345
|
+
received.sysseek(0)
|
346
|
+
assert_equal expected, received.sysread(4096)
|
301
347
|
ensure
|
302
348
|
TempServer.destroy_all!
|
303
349
|
end
|
304
350
|
|
305
351
|
def test_store_content_multi_dest_failover
|
306
|
-
received1 =
|
352
|
+
received1 = Tempfile.new('received')
|
353
|
+
received2 = Tempfile.new('received')
|
307
354
|
expected = "PUT /path HTTP/1.0\r\nContent-Length: 4\r\n\r\ndata"
|
308
355
|
|
309
356
|
t1 = TempServer.new(Proc.new do |serv, accept|
|
310
357
|
client, client_addr = serv.accept
|
311
358
|
client.sync = true
|
312
|
-
received1
|
359
|
+
received1.syswrite(client.recv(4096, 0))
|
313
360
|
client.send("HTTP/1.0 500 Internal Server Error\r\n\r\n", 0)
|
314
361
|
client.close
|
315
362
|
end)
|
@@ -317,7 +364,7 @@ class TestMogileFS__MogileFS < TestMogileFS
|
|
317
364
|
t2 = TempServer.new(Proc.new do |serv, accept|
|
318
365
|
client, client_addr = serv.accept
|
319
366
|
client.sync = true
|
320
|
-
received2
|
367
|
+
received2.syswrite(client.recv(4096, 0))
|
321
368
|
client.send("HTTP/1.0 200 OK\r\n\r\n", 0)
|
322
369
|
client.close
|
323
370
|
end)
|
@@ -331,8 +378,10 @@ class TestMogileFS__MogileFS < TestMogileFS
|
|
331
378
|
}
|
332
379
|
|
333
380
|
@client.store_content 'new_key', 'test', 'data'
|
334
|
-
|
335
|
-
|
381
|
+
received1.sysseek(0)
|
382
|
+
received2.sysseek(0)
|
383
|
+
assert_equal expected, received1.sysread(4096)
|
384
|
+
assert_equal expected, received2.sysread(4096)
|
336
385
|
ensure
|
337
386
|
TempServer.destroy_all!
|
338
387
|
end
|
@@ -357,12 +406,12 @@ class TestMogileFS__MogileFS < TestMogileFS
|
|
357
406
|
end
|
358
407
|
|
359
408
|
def test_store_content_http_empty
|
360
|
-
received = ''
|
409
|
+
received = Tempfile.new('received')
|
361
410
|
expected = "PUT /path HTTP/1.0\r\nContent-Length: 0\r\n\r\n"
|
362
411
|
t = TempServer.new(Proc.new do |serv, accept|
|
363
412
|
client, client_addr = serv.accept
|
364
413
|
client.sync = true
|
365
|
-
received
|
414
|
+
received.syswrite(client.recv(4096, 0))
|
366
415
|
client.send("HTTP/1.0 200 OK\r\n\r\n", 0)
|
367
416
|
client.close
|
368
417
|
end)
|
@@ -373,7 +422,8 @@ class TestMogileFS__MogileFS < TestMogileFS
|
|
373
422
|
}
|
374
423
|
|
375
424
|
@client.store_content 'new_key', 'test', ''
|
376
|
-
|
425
|
+
received.sysseek(0)
|
426
|
+
assert_equal expected, received.sysread(4096)
|
377
427
|
end
|
378
428
|
|
379
429
|
def test_store_content_nfs
|
@@ -406,17 +456,19 @@ class TestMogileFS__MogileFS < TestMogileFS
|
|
406
456
|
assert_equal expect_size + header.size, expect.stat.size
|
407
457
|
assert_equal expect_size, to_put.stat.size
|
408
458
|
|
409
|
-
readed =
|
459
|
+
readed = Tempfile.new('readed')
|
410
460
|
t = TempServer.new(Proc.new do |serv, accept|
|
411
461
|
client, client_addr = serv.accept
|
412
462
|
client.sync = true
|
463
|
+
nr = 0
|
413
464
|
loop do
|
414
465
|
buf = client.readpartial(8192) or break
|
415
466
|
break if buf.length == 0
|
416
467
|
assert_equal buf.length, received.syswrite(buf)
|
417
|
-
|
418
|
-
break if
|
468
|
+
nr += buf.length
|
469
|
+
break if nr >= expect.stat.size
|
419
470
|
end
|
471
|
+
readed.syswrite("#{nr}")
|
420
472
|
client.send("HTTP/1.0 200 OK\r\n\r\n", 0)
|
421
473
|
client.close
|
422
474
|
end)
|
@@ -427,7 +479,8 @@ class TestMogileFS__MogileFS < TestMogileFS
|
|
427
479
|
}
|
428
480
|
|
429
481
|
@client.store_file('new_key', 'test', to_put.path)
|
430
|
-
|
482
|
+
readed.sysseek(0)
|
483
|
+
assert_equal expect.stat.size, readed.sysread(4096).to_i
|
431
484
|
|
432
485
|
ENV['PATH'].split(/:/).each do |path|
|
433
486
|
cmp_bin = "#{path}/cmp"
|
data/test/test_network.rb
CHANGED
@@ -24,4 +24,32 @@ class TestNetwork < Test::Unit::TestCase
|
|
24
24
|
TempServer.destroy_all!
|
25
25
|
end
|
26
26
|
|
27
|
+
def test_verify_non_existent
|
28
|
+
good = TempServer.new(Proc.new do |serv,port|
|
29
|
+
client,client_addr = serv.accept
|
30
|
+
client.readpartial(4096)
|
31
|
+
client.syswrite("HTTP/1.0 200 OK\r\nContent-Length: 0\r\n\r\n")
|
32
|
+
end)
|
33
|
+
bad = TempServer.new(Proc.new { |serv,port| serv.close })
|
34
|
+
|
35
|
+
good_uri = URI.parse("http://127.0.0.1:#{good.port}/")
|
36
|
+
bad_uri = URI.parse("http://127.0.0.1:#{bad.port}/")
|
37
|
+
ok = verify_uris([ good_uri, bad_uri ])
|
38
|
+
assert_equal [ good_uri ], ok
|
39
|
+
ensure
|
40
|
+
TempServer.destroy_all!
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_verify_all_bad
|
44
|
+
good = TempServer.new(Proc.new { |serv,port| serv.close })
|
45
|
+
bad = TempServer.new(Proc.new { |serv,port| serv.close })
|
46
|
+
|
47
|
+
good_uri = URI.parse("http://127.0.0.1:#{good.port}/")
|
48
|
+
bad_uri = URI.parse("http://127.0.0.1:#{bad.port}/")
|
49
|
+
ok = verify_uris([ good_uri, bad_uri ], '200', 1.0)
|
50
|
+
assert ok.empty?, "nothing returned"
|
51
|
+
ensure
|
52
|
+
TempServer.destroy_all!
|
53
|
+
end
|
54
|
+
|
27
55
|
end
|
data/test/test_util.rb
CHANGED
@@ -1,24 +1,23 @@
|
|
1
1
|
require 'test/setup'
|
2
|
-
require 'tempfile'
|
3
2
|
|
4
3
|
class TestMogileFS__Util < Test::Unit::TestCase
|
5
4
|
include MogileFS::Util
|
6
5
|
|
7
6
|
def test_mogilefs_write
|
8
|
-
|
7
|
+
rd, wr = IO.pipe
|
9
8
|
|
10
9
|
svr = Proc.new do |serv, port|
|
11
10
|
client, client_addr = serv.accept
|
12
11
|
client.sync = true
|
13
|
-
|
12
|
+
nr = 0
|
14
13
|
loop do
|
15
14
|
begin
|
16
|
-
|
15
|
+
nr += client.readpartial(16384).length
|
17
16
|
rescue EOFError
|
18
17
|
break
|
19
18
|
end
|
20
19
|
end
|
21
|
-
|
20
|
+
wr.syswrite("#{nr}\n")
|
22
21
|
client.close rescue nil
|
23
22
|
end
|
24
23
|
t = TempServer.new(svr)
|
@@ -32,14 +31,13 @@ class TestMogileFS__Util < Test::Unit::TestCase
|
|
32
31
|
|
33
32
|
syswrite_full(s, big_string)
|
34
33
|
s.close rescue nil
|
35
|
-
|
36
|
-
|
37
|
-
|
34
|
+
IO.select([rd])
|
35
|
+
assert_equal((sent + big_string.length), rd.sysread(4096).to_i)
|
36
|
+
ensure
|
37
|
+
t.destroy!
|
38
38
|
end
|
39
39
|
|
40
40
|
def test_write_timeout
|
41
|
-
done = Queue.new
|
42
|
-
|
43
41
|
svr = Proc.new do |serv, port|
|
44
42
|
client, client_addr = serv.accept
|
45
43
|
client.sync = true
|
@@ -54,6 +52,8 @@ class TestMogileFS__Util < Test::Unit::TestCase
|
|
54
52
|
|
55
53
|
assert_raises(MogileFS::Timeout) { syswrite_full(s, big_string, 0.1) }
|
56
54
|
s.close rescue nil
|
55
|
+
ensure
|
56
|
+
t.destroy!
|
57
57
|
end
|
58
58
|
|
59
59
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mogilefs-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Eric Wong
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2009-02-
|
13
|
+
date: 2009-02-25 00:00:00 -08:00
|
14
14
|
default_executable:
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
@@ -31,7 +31,7 @@ dependencies:
|
|
31
31
|
requirements:
|
32
32
|
- - ">="
|
33
33
|
- !ruby/object:Gem::Version
|
34
|
-
version: 1.8.
|
34
|
+
version: 1.8.3
|
35
35
|
version:
|
36
36
|
description: git://git.bogomips.org/mogilefs-client.git
|
37
37
|
email: normalperson@yhbt.net
|