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/.gitignore +2 -0
- data/GNUmakefile +32 -0
- data/History.txt +23 -0
- data/LICENSE.txt +1 -0
- data/Manifest.txt +12 -1
- data/README.txt +22 -13
- data/bin/mog +37 -6
- data/lib/mogilefs.rb +19 -5
- data/lib/mogilefs/admin.rb +27 -34
- data/lib/mogilefs/backend.rb +106 -39
- data/lib/mogilefs/bigfile.rb +153 -0
- data/lib/mogilefs/client.rb +1 -5
- data/lib/mogilefs/httpfile.rb +65 -71
- data/lib/mogilefs/mogilefs.rb +102 -102
- data/lib/mogilefs/mysql.rb +166 -0
- data/lib/mogilefs/network.rb +64 -0
- data/lib/mogilefs/pool.rb +1 -1
- data/lib/mogilefs/util.rb +140 -9
- data/test/.gitignore +2 -0
- data/test/aggregate.rb +13 -0
- data/test/setup.rb +72 -91
- data/test/test_admin.rb +2 -2
- data/test/test_backend.rb +100 -38
- data/test/test_bigfile.rb +48 -0
- data/test/test_client.rb +7 -2
- data/test/test_db_backend.rb +73 -0
- data/test/test_mogilefs.rb +287 -107
- data/test/test_mysql.rb +94 -0
- data/test/test_network.rb +27 -0
- data/test/test_util.rb +59 -0
- metadata +22 -6
- data/lib/mogilefs/nfsfile.rb +0 -81
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
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
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.
|
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
|
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
|
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
|
-
|
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
|
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
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
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
|
-
|
109
|
-
|
110
|
-
|
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
|
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
|
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
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
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
|
-
|
138
|
-
|
139
|
-
|
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
|
-
|
144
|
-
|
145
|
-
|
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
|
-
|
4
|
+
class MogileFS::Backend
|
5
|
+
attr_accessor :timeout, :lasterr, :lasterrstr, :hosts
|
6
|
+
end
|
4
7
|
|
5
|
-
|
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
|
+
|
data/test/test_mogilefs.rb
CHANGED
@@ -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']
|
18
|
+
MogileFS::MogileFS.new :hosts => ['kaa:6001']
|
36
19
|
end
|
37
20
|
end
|
38
21
|
|
39
22
|
def test_get_file_data_http
|
40
|
-
|
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
|
-
|
43
|
-
|
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 =
|
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
|
-
|
65
|
-
|
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 = [
|
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
|
-
|
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
|
-
|
114
|
-
|
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
|
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
|
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
|
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
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
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
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
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
|
-
|
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
|
-
|
282
|
+
received = ''
|
283
|
+
expected = "PUT /path HTTP/1.0\r\nContent-Length: 4\r\n\r\ndata"
|
196
284
|
|
197
|
-
|
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' =>
|
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
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
data
|
211
|
-
EOF
|
300
|
+
assert_equal expected, received
|
301
|
+
ensure
|
302
|
+
TempServer.destroy_all!
|
303
|
+
end
|
212
304
|
|
213
|
-
|
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
|
-
|
216
|
-
|
217
|
-
|
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
|
-
|
220
|
-
|
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
|
-
|
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' =>
|
351
|
+
'path' => "http://127.0.0.1:#{t.port}/path",
|
227
352
|
}
|
228
353
|
|
229
|
-
|
354
|
+
assert_raises MogileFS::HTTPFile::BadResponseError do
|
355
|
+
@client.store_content 'new_key', 'test', 'data'
|
356
|
+
end
|
357
|
+
end
|
230
358
|
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
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
|
-
|
370
|
+
@backend.create_open = {
|
371
|
+
'devid' => '1',
|
372
|
+
'path' => "http://127.0.0.1:#{t.port}/path",
|
373
|
+
}
|
238
374
|
|
239
|
-
|
240
|
-
|
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
|
-
|
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
|
-
|
395
|
+
nr = nr_chunks
|
396
|
+
chunk_size = 1024 * 1024
|
397
|
+
expect_size = nr * chunk_size
|
253
398
|
|
254
|
-
|
255
|
-
|
256
|
-
|
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
|
-
'
|
261
|
-
'
|
262
|
-
'path_1' => '/path',
|
425
|
+
'devid' => '1',
|
426
|
+
'path' => "http://127.0.0.1:#{t.port}/path",
|
263
427
|
}
|
264
428
|
|
265
|
-
@client.
|
429
|
+
@client.store_file('new_key', 'test', to_put.path)
|
430
|
+
assert_equal expect.stat.size, readed
|
266
431
|
|
267
|
-
|
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
|
-
|
270
|
-
|
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
|
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
|
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
|
-
|
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
|
476
|
+
e = assert_raises MogileFS::Backend::NoKeyError do
|
304
477
|
@client.rename 'new_key', 'test'
|
305
478
|
end
|
306
479
|
|
307
|
-
assert_equal '
|
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
|
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
|
|