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/.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
|
|