qfs 0.0.13

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,3 @@
1
+ module Qfs
2
+ VERSION = '0.0.13'
3
+ end
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'qfs/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'qfs'
8
+ spec.version = Qfs::VERSION
9
+ spec.authors = ['Eric Culp', 'Noah Goldman']
10
+ spec.email = ['ruby-qfs@quantcast.com']
11
+ spec.summary = 'Bindings for QFS'
12
+ spec.description = 'Client bindings for Quantcast File System, a distributed filesystem.'
13
+ spec.homepage = ''
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ['lib']
20
+ spec.extensions << 'ext/qfs/extconf.rb'
21
+ spec.platform = Gem::Platform::RUBY
22
+
23
+ spec.add_dependency 'ffi', '~> 1.9'
24
+
25
+ spec.add_development_dependency 'bundler', '~> 1.7'
26
+ spec.add_development_dependency 'rake', '~> 10.0'
27
+ spec.add_development_dependency 'rake-compiler', '~> 0.9'
28
+ spec.add_development_dependency 'minitest', '~> 5.5'
29
+ end
@@ -0,0 +1,393 @@
1
+ require 'test_helper'
2
+ require 'minitest/autorun'
3
+ require 'qfs'
4
+
5
+ class TestQfs < Minitest::Test
6
+ BASE_TEST_PATH = ENV['QFS_TEST_PATH'] || '/ruby-qfs'
7
+ TEST_HOST = ENV['QFS_TEST_HOST'] || 'localhost'
8
+ TEST_PORT = (ENV['QFS_TEST_PORT'] || 10000).to_i
9
+
10
+ def initialize(name = nil)
11
+ @test_name = name
12
+ super(name) unless name.nil?
13
+ end
14
+
15
+ def clear_test_files
16
+ if @client.exists?(@file)
17
+ @client.remove(@file) if @client.file?(@file)
18
+ @client.rm_rf(@file) if @client.directory?(@file)
19
+ end
20
+ end
21
+
22
+ def setup
23
+ @client = Qfs::Client.new TEST_HOST, TEST_PORT
24
+ @client.mkdir_p(BASE_TEST_PATH, 0777) if !@client.exists?(BASE_TEST_PATH)
25
+ @file = get_test_path(@test_name)
26
+ clear_test_files
27
+ end
28
+
29
+ def teardown
30
+ clear_test_files
31
+ @client.release
32
+ end
33
+
34
+ def get_test_path(p)
35
+ File.join(BASE_TEST_PATH, p)
36
+ end
37
+
38
+ def random_data(len = 20)
39
+ (0...len).map { (65 + rand(26)).chr }.join
40
+ end
41
+
42
+ def stat(path)
43
+ Qfs::Client.with_client(TEST_HOST, TEST_PORT) { |c| c.stat(path) }
44
+ end
45
+
46
+ def test_open
47
+ data = random_data
48
+ @client.open(@file, 'w') do |f|
49
+ f.write(data)
50
+ end
51
+ @client.open(@file, 'r') do |f|
52
+ assert_equal(data, f.read(data.length))
53
+ end
54
+ end
55
+
56
+ def test_tell
57
+ data = random_data
58
+ @client.open(@file, 'w') do |f|
59
+ f.write(data)
60
+ assert_equal(data.length, f.tell())
61
+ end
62
+ @client.open(@file, 'w') do |f|
63
+ assert_equal(0, f.tell())
64
+ end
65
+ end
66
+
67
+ def test_remove
68
+ @client.open(@file, 'w') do |f|
69
+ f.write('');
70
+ end
71
+ res = @client.remove(@file)
72
+ assert !@client.exists?(@file)
73
+ assert_equal(1, res)
74
+
75
+ assert_raises(Qfs::Error) { @client.remove(@file) }
76
+ end
77
+
78
+ def test_exists
79
+ @client.open(@file, 'w') do |f|
80
+ f.write('')
81
+ end
82
+ assert @client.exists?(@file)
83
+
84
+ @client.remove(@file)
85
+ assert !@client.exists?(@file)
86
+ end
87
+
88
+ def test_mkdir_rmdir
89
+ assert @client.mkdir(@file)
90
+ assert @client.exists?(@file)
91
+
92
+ assert_raises(Qfs::Error) { @client.mkdir(@file) }
93
+ assert @client.rmdir(@file)
94
+ assert !@client.exists?(@file)
95
+
96
+ assert_raises(Errno::ENOENT) { @client.rmdir(@file) }
97
+ assert_equal(0, @client.rmdir(@file, true))
98
+ end
99
+
100
+ def test_mkdirp_rmdirs
101
+ # Stock local development servers have odd permission
102
+ # settings that seem to be causing "qfs_mkdirs" to fail
103
+ # on creating multiple levels of folder.
104
+ #file = File.join(@file, 'test', 'a', 'long' 'path')
105
+ file = File.join(@file)
106
+ assert @client.mkdir_p(file, 777)
107
+ assert @client.exists?(file)
108
+
109
+ assert @client.rmdirs(file)
110
+ assert !@client.exists(file)
111
+ end
112
+
113
+ def test_directory
114
+ @client.mkdir(@file)
115
+ assert @client.directory?(@file)
116
+ @client.rmdir(@file)
117
+
118
+ @client.open(@file, 'w') { |f| f.write('') }
119
+ assert !@client.directory?(@file)
120
+ @client.remove(@file)
121
+
122
+ assert !@client.directory?(@file)
123
+ end
124
+
125
+ def test_client_stat
126
+ data = random_data(rand(1000))
127
+ @client.open(@file, 'w') do |f|
128
+ f.write(data)
129
+ end
130
+
131
+ res = @client.stat(@file)
132
+
133
+ assert_equal(data.length, res.size)
134
+ assert_equal(File.basename(@file), res.filename)
135
+
136
+ assert_raises(Qfs::Error) { @client.stat('not a real file') }
137
+ end
138
+
139
+ def test_file_stat
140
+ data = random_data(rand(1000))
141
+ @client.open(@file, 'w') do |f|
142
+ f.write(data)
143
+ end
144
+
145
+ @client.open(@file, 'r') do |f|
146
+ res = f.stat
147
+ assert_equal(data.length, res.size)
148
+ assert_equal(File.basename(@file), res.filename)
149
+ end
150
+ end
151
+
152
+ def test_read_all
153
+ data = random_data(rand(1000))
154
+ @client.open(@file, 'w') { |f| f.write(data) }
155
+ @client.open(@file, 'r') do |f|
156
+ len = rand(data.length)
157
+ assert_equal(data[0..(len-1)], f.read(len))
158
+ end
159
+ @client.open(@file, 'r') do |f|
160
+ assert_equal(data, f.read)
161
+ end
162
+ end
163
+
164
+ def test_read_client
165
+ data = random_data(rand(1000))
166
+ len = rand(data.length)
167
+ @client.open(@file, 'w') { |f| f.write(data) }
168
+ assert_equal(data[0...len], @client.read(@file, len))
169
+ assert_equal(data, @client.read(@file))
170
+ end
171
+
172
+ def test_open_no_block
173
+ data = random_data
174
+ f = @client.open(@file, 'w')
175
+ f.write(data)
176
+ f.close
177
+
178
+ f = @client.open(@file, 'r')
179
+ assert_equal(data, f.read())
180
+ f.close
181
+ end
182
+
183
+ def test_chmod
184
+ @client.open(@file, 'w') { |f| f.write('test') }
185
+
186
+ run_chmod = proc do |mode|
187
+ @client.chmod(@file, mode)
188
+ Qfs::Client.with_client(TEST_HOST, TEST_PORT) do |c|
189
+ assert_equal(mode, c.stat(@file).mode)
190
+ end
191
+ end
192
+
193
+ run_chmod.call(0654)
194
+ run_chmod.call(0643)
195
+ run_chmod.call(0777)
196
+ end
197
+
198
+ def test_chmod_file
199
+ @client.write(@file, '')
200
+
201
+ run_chmod = proc do |mode|
202
+ @client.open(@file, 'r') { |f| f.chmod(mode) }
203
+ Qfs::Client.with_client(TEST_HOST, TEST_PORT) do |c|
204
+ assert_equal(mode, c.stat(@file).mode)
205
+ end
206
+ end
207
+
208
+ run_chmod.call(0654)
209
+ run_chmod.call(0643)
210
+ run_chmod.call(0777)
211
+ end
212
+
213
+ def test_chmod_recursive
214
+ @client.mkdir(@file, 0777)
215
+ testfile = File.join(@file, 'testfile')
216
+ @client.write(testfile, '')
217
+
218
+ run_chmod = proc do |mode|
219
+ @client.chmod(@file, mode, recursive: true)
220
+ assert_equal(mode, @client.stat(@file).mode)
221
+ assert_equal(mode, @client.stat(testfile).mode)
222
+ end
223
+
224
+ run_chmod.call(0777)
225
+ run_chmod.call(0766)
226
+ run_chmod.call(0755)
227
+
228
+ @client.remove(testfile)
229
+ end
230
+
231
+ def test_readdir
232
+ @client.mkdir(@file, 0777)
233
+ files = [0..5].map do
234
+ name = random_data(10)
235
+ @client.write(File.join(@file, name), 'test')
236
+ name
237
+ end
238
+
239
+ @client.readdir(@file) { |f| assert_includes(files, f.filename) }
240
+
241
+ attrs = @client.readdir(@file)
242
+ attrs.each { |f| assert_includes(files, f.filename) }
243
+
244
+ assert_raises(Qfs::Error) { @client.readdir('not a real path') }
245
+ end
246
+
247
+ def test_client_read_write
248
+ [0..5].each do
249
+ data = random_data
250
+ @client.write(@file, data)
251
+ assert_equal(data, @client.read(@file))
252
+ end
253
+ end
254
+
255
+ def test_rm_rf
256
+ @client.mkdir(@file, 0777)
257
+ data = random_data
258
+ data.length.times do |i|
259
+ args = [@file].concat(data.chars.to_a[0..i])
260
+ path = File.send(:join, args)
261
+ @client.mkdir(path, 0777)
262
+ @client.write(File.join(path, 'file'), data)
263
+ end
264
+
265
+ @client.rm_rf(@file)
266
+ assert !@client.exists?(@file)
267
+ end
268
+
269
+ def test_attr_to_s
270
+ assert_attr = proc do |mode, str|
271
+ @client.write(@file, '')
272
+ @client.chmod(@file, mode)
273
+ assert_includes(stat(@file).to_s, str)
274
+ end
275
+
276
+ assert_attr.call(0777, '-rwxrwxrwx')
277
+ assert_attr.call(0644, '-rw-r--r--')
278
+ assert_attr.call(0473, '-r--rwx-wx')
279
+ end
280
+
281
+ def test_client_move
282
+ newpath = get_test_path('new_test_file')
283
+ @client.write(@file, '')
284
+
285
+ assert !@client.exists(newpath)
286
+ @client.move(@file, newpath)
287
+
288
+ assert !@client.exists(@file)
289
+ assert @client.exists(newpath)
290
+
291
+ @client.remove(newpath)
292
+ end
293
+
294
+ def test_client_cd
295
+ @client.mkdir(@file)
296
+ @client.cd(@file)
297
+
298
+ assert_equal(@file, @client.cwd)
299
+
300
+ @client.cd('../')
301
+ assert_equal(BASE_TEST_PATH, @client.cwd)
302
+ end
303
+
304
+ def test_client_cd_fail
305
+ assert_raises(Qfs::Error) { @client.cd('/fake/directory') }
306
+ end
307
+
308
+ def test_client_setwd
309
+ @client.mkdir(@file)
310
+ @client.setwd(@file)
311
+
312
+ assert_equal(@file, @client.cwd)
313
+
314
+ @client.setwd('../')
315
+ assert_equal(BASE_TEST_PATH, @client.cwd)
316
+ end
317
+
318
+ def test_mkdir_permissions
319
+ [0755, 0755, 0600].each do |mode|
320
+ @client.mkdir_p(@file, mode)
321
+ Qfs::Client.with_client(TEST_HOST, TEST_PORT) do |c|
322
+ assert_equal(mode, c.stat(@file).mode)
323
+ end
324
+ @client.rmdir(@file)
325
+ end
326
+ end
327
+
328
+ def test_client_cwd
329
+ test_cwd = lambda do |path|
330
+ @client.mkdir_p(path, 0777)
331
+ @client.cd(path)
332
+ assert_equal(path, @client.cwd)
333
+ end
334
+
335
+ test_cwd.call(@file)
336
+ # This should still work for a very long path (>5kb). Since qfs has a max
337
+ # filename length of 255 characters, multiple directories must be created
338
+ files = ['a' * 255] * 7
339
+ subdir = files.reduce(@file) { |sum, x| File.join(sum, x) }
340
+ test_cwd.call(subdir)
341
+
342
+ # A ridiculously long path (>10kb) should fail
343
+ files = files * 4
344
+ subdir = files.reduce(@file) { |sum, x| File.join(sum, x) }
345
+ assert_raises(Errno::ENAMETOOLONG) { test_cwd.call(subdir) }
346
+ end
347
+
348
+ # It should be possible to change the properties of a file and see stat
349
+ # return a different result
350
+ def test_stat_modifications
351
+ @client.write(@file, '')
352
+
353
+ [0745, 0600, 0443].each do |mode|
354
+ @client.chmod(@file, mode)
355
+ assert_equal mode, @client.stat(@file, refresh: true).mode
356
+ end
357
+ end
358
+
359
+ def test_seek
360
+ data = random_data
361
+ @client.write(@file, data)
362
+
363
+ @client.open(@file, 'r') do |f|
364
+ assert_equal 0, f.tell
365
+
366
+ # now seek into the file
367
+ f.seek(1, IO::SEEK_SET)
368
+ assert_equal 1, f.tell
369
+
370
+ # Seek a little farther
371
+ f.seek(5)
372
+ assert_equal 6, f.tell
373
+
374
+ # Seek to the end
375
+ f.seek(0, IO::SEEK_END)
376
+ assert_equal data.length, f.tell
377
+ end
378
+ end
379
+
380
+ def test_open_append
381
+ data = random_data
382
+ @client.write(@file, data)
383
+
384
+ data2 = random_data
385
+ @client.open(@file, 'a') do |f|
386
+ f.write(data2)
387
+ end
388
+
389
+ res = @client.read(@file)
390
+
391
+ assert_equal(data + data2, @client.read(@file))
392
+ end
393
+ end
@@ -0,0 +1,2 @@
1
+ require 'simplecov'
2
+ SimpleCov.start
metadata ADDED
@@ -0,0 +1,149 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: qfs
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.13
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Eric Culp
9
+ - Noah Goldman
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2016-12-19 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: ffi
17
+ requirement: !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ~>
21
+ - !ruby/object:Gem::Version
22
+ version: '1.9'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ~>
29
+ - !ruby/object:Gem::Version
30
+ version: '1.9'
31
+ - !ruby/object:Gem::Dependency
32
+ name: bundler
33
+ requirement: !ruby/object:Gem::Requirement
34
+ none: false
35
+ requirements:
36
+ - - ~>
37
+ - !ruby/object:Gem::Version
38
+ version: '1.7'
39
+ type: :development
40
+ prerelease: false
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ~>
45
+ - !ruby/object:Gem::Version
46
+ version: '1.7'
47
+ - !ruby/object:Gem::Dependency
48
+ name: rake
49
+ requirement: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ~>
61
+ - !ruby/object:Gem::Version
62
+ version: '10.0'
63
+ - !ruby/object:Gem::Dependency
64
+ name: rake-compiler
65
+ requirement: !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ~>
69
+ - !ruby/object:Gem::Version
70
+ version: '0.9'
71
+ type: :development
72
+ prerelease: false
73
+ version_requirements: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ~>
77
+ - !ruby/object:Gem::Version
78
+ version: '0.9'
79
+ - !ruby/object:Gem::Dependency
80
+ name: minitest
81
+ requirement: !ruby/object:Gem::Requirement
82
+ none: false
83
+ requirements:
84
+ - - ~>
85
+ - !ruby/object:Gem::Version
86
+ version: '5.5'
87
+ type: :development
88
+ prerelease: false
89
+ version_requirements: !ruby/object:Gem::Requirement
90
+ none: false
91
+ requirements:
92
+ - - ~>
93
+ - !ruby/object:Gem::Version
94
+ version: '5.5'
95
+ description: Client bindings for Quantcast File System, a distributed filesystem.
96
+ email:
97
+ - ruby-qfs@quantcast.com
98
+ executables: []
99
+ extensions:
100
+ - ext/qfs/extconf.rb
101
+ extra_rdoc_files: []
102
+ files:
103
+ - .gitignore
104
+ - Gemfile
105
+ - LICENSE.txt
106
+ - README.md
107
+ - Rakefile
108
+ - ext/qfs/attr.c
109
+ - ext/qfs/attr.h
110
+ - ext/qfs/extconf.rb
111
+ - ext/qfs/file.c
112
+ - ext/qfs/file.h
113
+ - ext/qfs/qfs.c
114
+ - ext/qfs/qfs.h
115
+ - ext/qfs/qfs_ext.version
116
+ - ext/qfs/util.h
117
+ - lib/qfs.rb
118
+ - lib/qfs/version.rb
119
+ - qfs.gemspec
120
+ - test/qfs_test.rb
121
+ - test/test_helper.rb
122
+ homepage: ''
123
+ licenses:
124
+ - MIT
125
+ post_install_message:
126
+ rdoc_options: []
127
+ require_paths:
128
+ - lib
129
+ required_ruby_version: !ruby/object:Gem::Requirement
130
+ none: false
131
+ requirements:
132
+ - - ! '>='
133
+ - !ruby/object:Gem::Version
134
+ version: '0'
135
+ required_rubygems_version: !ruby/object:Gem::Requirement
136
+ none: false
137
+ requirements:
138
+ - - ! '>='
139
+ - !ruby/object:Gem::Version
140
+ version: '0'
141
+ requirements: []
142
+ rubyforge_project:
143
+ rubygems_version: 1.8.23.2
144
+ signing_key:
145
+ specification_version: 3
146
+ summary: Bindings for QFS
147
+ test_files:
148
+ - test/qfs_test.rb
149
+ - test/test_helper.rb