qfs 0.0.13

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