rfuse 1.1.2 → 1.2.3
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.
- checksums.yaml +5 -13
- data/CHANGES.md +6 -0
- data/README.md +3 -2
- data/ext/rfuse/rfuse.c +2 -2
- data/lib/rfuse/version.rb +1 -1
- metadata +25 -42
- data/.gitignore +0 -5
- data/.travis.yml +0 -20
- data/Gemfile +0 -4
- data/Rakefile +0 -17
- data/ext/.gitignore +0 -2
- data/rfuse.gemspec +0 -31
- data/sample/test-ruby.rb +0 -310
- data/spec/basic_spec.rb +0 -243
- data/spec/fuse_file_info_spec.rb +0 -119
- data/spec/main_spec.rb +0 -161
- data/spec/options_spec.rb +0 -143
- data/spec/ruby_loop_spec.rb +0 -63
- data/spec/run_spec.rb +0 -60
- data/spec/signals_spec.rb +0 -108
- data/spec/spec_helper.rb +0 -109
- data/spec/xattr_spec.rb +0 -49
data/spec/ruby_loop_spec.rb
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
|
|
3
|
-
describe RFuse::Fuse do
|
|
4
|
-
|
|
5
|
-
let(:mockfs) { m = mock("fuse"); m.stub(:getattr).and_return(nil) ; m }
|
|
6
|
-
let(:mountpoint) { tempmount() }
|
|
7
|
-
|
|
8
|
-
context "#loop" do
|
|
9
|
-
it "should exit from another thread and allow multiple loops" do
|
|
10
|
-
|
|
11
|
-
fuse = RFuse::FuseDelegator.new(mockfs,mountpoint)
|
|
12
|
-
t = Thread.new { sleep 0.2; fuse.exit }
|
|
13
|
-
fuse.loop()
|
|
14
|
-
t.join
|
|
15
|
-
t = Thread.new { sleep 0.2; fuse.exit }
|
|
16
|
-
fuse.loop
|
|
17
|
-
t.join
|
|
18
|
-
fuse.unmount
|
|
19
|
-
fuse.mounted?.should be(false)
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
# This will never work!
|
|
24
|
-
#it "should allow threads to operate on the filesystem" do
|
|
25
|
-
#
|
|
26
|
-
# mockfs = mock("fuse")
|
|
27
|
-
# mockfs.stub(:getattr).and_return(nil)
|
|
28
|
-
#
|
|
29
|
-
# fuse = RFuse::FuseDelegator.new(mockfs,"/tmp/rfuse-spec")
|
|
30
|
-
#
|
|
31
|
-
# t = Thread.new { sleep 0.5 ; File.stat("/tmp/rfuse-spec/thread") ; fuse.exit }
|
|
32
|
-
#
|
|
33
|
-
# fuse.loop()
|
|
34
|
-
# fuse.unmount()
|
|
35
|
-
#end
|
|
36
|
-
|
|
37
|
-
it "should allow other threads to be scheduled" do
|
|
38
|
-
|
|
39
|
-
file_stat = RFuse::Stat.file(0444)
|
|
40
|
-
|
|
41
|
-
thread_ran = false
|
|
42
|
-
|
|
43
|
-
mockfs.stub(:getattr).with(anything(),"/before") {
|
|
44
|
-
thread_ran.should be(false)
|
|
45
|
-
file_stat
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
mockfs.stub(:getattr).with(anything(),"/missing") {
|
|
49
|
-
#GC.start()
|
|
50
|
-
thread_ran.should be(true)
|
|
51
|
-
file_stat
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
t = Thread.new() { sleep 0.5 ; thread_ran = true }
|
|
55
|
-
with_fuse(mountpoint,mockfs) do
|
|
56
|
-
File.stat("#{mountpoint}/before");
|
|
57
|
-
sleep 1;
|
|
58
|
-
File.stat("#{mountpoint}/missing");
|
|
59
|
-
end
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
end
|
|
63
|
-
|
data/spec/run_spec.rb
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
|
|
3
|
-
describe RFuse::Fuse do
|
|
4
|
-
context "#run" do
|
|
5
|
-
|
|
6
|
-
let(:file_stat) { RFuse::Stat.file(0444) }
|
|
7
|
-
let(:mountpoint) { tempmount() }
|
|
8
|
-
let(:mockfs) { m = double("fuse"); allow(m).to receive(:getattr) { |ctx,path| puts "#{ctx},#{path}"}; m }
|
|
9
|
-
let(:fuse) { RFuse::FuseDelegator.new(mockfs,mountpoint) }
|
|
10
|
-
|
|
11
|
-
it "runs a mounted filesystem with default traps" do
|
|
12
|
-
|
|
13
|
-
# expect traps to be set
|
|
14
|
-
expect(mockfs).to receive(:sighup) { }
|
|
15
|
-
expect(mockfs).to receive(:getattr).with(anything(),"/run").and_return(file_stat)
|
|
16
|
-
|
|
17
|
-
# Need to call this before we fork..
|
|
18
|
-
expect(fuse.mountpoint).to eq(mountpoint)
|
|
19
|
-
|
|
20
|
-
pid = Process.pid
|
|
21
|
-
|
|
22
|
-
fpid = Kernel.fork do
|
|
23
|
-
File.stat("#{mountpoint}/run")
|
|
24
|
-
Process.kill("HUP",pid)
|
|
25
|
-
sleep(0.1)
|
|
26
|
-
Process.kill("TERM",pid)
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
fuse.run
|
|
30
|
-
|
|
31
|
-
rpid,result = Process.waitpid2(fpid)
|
|
32
|
-
expect(result).to be_success
|
|
33
|
-
|
|
34
|
-
expect(fuse).not_to be_mounted
|
|
35
|
-
expect(Signal.trap("HUP","DEFAULT")).to eq("DEFAULT")
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
it "unmounts the filesystem and resets traps on exception" do
|
|
39
|
-
expect(mockfs).to receive(:getattr).with(anything(),"/run").and_return(file_stat)
|
|
40
|
-
# raising an error in a sighandler will exit the loop..
|
|
41
|
-
expect(mockfs).to receive(:sighup).and_raise("oh noes")
|
|
42
|
-
pid = Process.pid
|
|
43
|
-
# Need to call this before we fork..
|
|
44
|
-
expect(fuse.mountpoint).to eq(mountpoint)
|
|
45
|
-
|
|
46
|
-
fpid = Kernel.fork do
|
|
47
|
-
File.stat("#{mountpoint}/run")
|
|
48
|
-
Process.kill("HUP",pid)
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
expect { fuse.run }.to raise_error
|
|
52
|
-
|
|
53
|
-
pid,result = Process.waitpid2(fpid)
|
|
54
|
-
|
|
55
|
-
expect(fuse).not_to be_mounted
|
|
56
|
-
expect(Signal.trap("HUP","DEFAULT")).to eq("DEFAULT")
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
end
|
|
60
|
-
end
|
data/spec/signals_spec.rb
DELETED
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
|
|
3
|
-
describe RFuse::Fuse do
|
|
4
|
-
|
|
5
|
-
let(:mountpoint) { tempmount() }
|
|
6
|
-
let(:fuse) { RFuse::Fuse.new(mountpoint) }
|
|
7
|
-
|
|
8
|
-
before(:each) do
|
|
9
|
-
# Override traps (note rspec itself traps "INT") with "DEFAULT"
|
|
10
|
-
@traps = ["INT","TERM","HUP","USR1","USR2"].inject({}) { |h,signame| h[signame] = Signal.trap(signame,"DEFAULT"); h }
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
after(:each) do
|
|
14
|
-
fuse.unmount()
|
|
15
|
-
# Restore previously set traps
|
|
16
|
-
@traps.each_pair { |signame,prev_trap| Signal.trap(signame,prev_trap) }
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
context "#trap_signals" do
|
|
20
|
-
|
|
21
|
-
it "returns the list of signals trapped" do
|
|
22
|
-
|
|
23
|
-
allow(fuse).to receive(:sighup)
|
|
24
|
-
|
|
25
|
-
expect(fuse.trap_signals("HUP")).to include("HUP")
|
|
26
|
-
expect(Signal.trap("HUP","DEFAULT")).not_to eq("DEFAULT")
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
it "does not override previously set traps" do
|
|
30
|
-
|
|
31
|
-
allow(fuse).to receive(:sighup)
|
|
32
|
-
|
|
33
|
-
Signal.trap("HUP","HUPCOMMAND")
|
|
34
|
-
|
|
35
|
-
expect(fuse.trap_signals()).not_to include("HUP")
|
|
36
|
-
expect(Signal.trap("HUP","DEFAULT")).to eq("HUPCOMMAND")
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
it "only traps the specified signals" do
|
|
40
|
-
|
|
41
|
-
allow(fuse).to receive(:sighup)
|
|
42
|
-
allow(fuse).to receive(:sigusr2)
|
|
43
|
-
|
|
44
|
-
expect(fuse.trap_signals("HUP")).to include("HUP")
|
|
45
|
-
expect(Signal.trap("HUP","DEFAULT")).not_to eq("DEFAULT")
|
|
46
|
-
expect(Signal.trap("USR2","DEFAULT")).to eq("DEFAULT")
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
it "allows signals to be handled by the filesystem" do
|
|
50
|
-
expect(fuse).to receive(:sighup) { fuse.exit }
|
|
51
|
-
|
|
52
|
-
expect(fuse.trap_signals("HUP")).to include("HUP")
|
|
53
|
-
|
|
54
|
-
pid = Process.pid
|
|
55
|
-
fork_fuse(fuse) { Process.kill("HUP",pid) }
|
|
56
|
-
# Exitted loop, but still mounted - ie not with fusermount -u
|
|
57
|
-
expect(fuse).to be_mounted
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
it "exits on INT by default" do
|
|
61
|
-
pid = Process.pid
|
|
62
|
-
expect(fuse.trap_signals("INT")).to include("INT")
|
|
63
|
-
|
|
64
|
-
fork_fuse(fuse) { Process.kill("INT",pid) }
|
|
65
|
-
expect(fuse).to be_mounted
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
it "exits on TERM by default" do
|
|
69
|
-
pid = Process.pid
|
|
70
|
-
expect(fuse.trap_signals("TERM")).to include("TERM")
|
|
71
|
-
|
|
72
|
-
fork_fuse(fuse) { Process.kill("TERM",pid) }
|
|
73
|
-
expect(fuse).to be_mounted
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
context "with a delegated filesystem" do
|
|
77
|
-
let(:mockfs) { m = mock("fuse"); m.stub(:getattr).and_return(nil); m }
|
|
78
|
-
let(:fuse) { RFuse::FuseDelegator.new(mockfs,mountpoint) }
|
|
79
|
-
|
|
80
|
-
it "enables FuseDelegator debugging on USR1" do
|
|
81
|
-
|
|
82
|
-
pid = Process.pid
|
|
83
|
-
expect(fuse.trap_signals("USR1","INT")).to include("USR1")
|
|
84
|
-
|
|
85
|
-
expect(fuse.debug?).to be(false)
|
|
86
|
-
|
|
87
|
-
fork_fuse(fuse) do
|
|
88
|
-
Process.kill("USR1",pid)
|
|
89
|
-
sleep(0.1)
|
|
90
|
-
Process.kill("INT",pid)
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
expect(fuse.debug?).to be(true)
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
it "allows delegate filesystem to override default sig handler method" do
|
|
97
|
-
expect(mockfs).to receive(:sigint) { fuse.exit }
|
|
98
|
-
|
|
99
|
-
pid = Process.pid
|
|
100
|
-
fuse.trap_signals("INT")
|
|
101
|
-
|
|
102
|
-
fork_fuse(fuse) do
|
|
103
|
-
Process.kill("INT",pid)
|
|
104
|
-
end
|
|
105
|
-
end
|
|
106
|
-
end
|
|
107
|
-
end
|
|
108
|
-
end
|
data/spec/spec_helper.rb
DELETED
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
require 'rfuse'
|
|
2
|
-
require 'tmpdir'
|
|
3
|
-
|
|
4
|
-
class FileModeMatcher
|
|
5
|
-
def initialize(expected)
|
|
6
|
-
@expected = expected
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
def description
|
|
10
|
-
"file mode #{@expected}"
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def ==(actual)
|
|
14
|
-
(actual | RFuse::Stat::S_IFMT) == (@expected | RFuse::Stat::S_IFMT)
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
module DoubleAliases
|
|
19
|
-
def mock(*args, &block)
|
|
20
|
-
double(*args, &block)
|
|
21
|
-
end
|
|
22
|
-
alias stub mock
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
module RFuseHelper
|
|
27
|
-
# Runs the single threaded fuse loop
|
|
28
|
-
# on a pre configured mock fuse filesystem
|
|
29
|
-
# Executes fork block in a separate process
|
|
30
|
-
# that is expected to return success
|
|
31
|
-
def with_fuse(mnt,mockfs,*options,&fork_block)
|
|
32
|
-
|
|
33
|
-
fuse = RFuse::FuseDelegator.new(mockfs,mnt,*options)
|
|
34
|
-
fuse.mounted?.should be(true)
|
|
35
|
-
fork_fuse(fuse) do
|
|
36
|
-
begin
|
|
37
|
-
fork_block.call() if fork_block
|
|
38
|
-
ensure
|
|
39
|
-
fusermount(mnt)
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
fuse.open_files.should be_empty()
|
|
43
|
-
fuse.mounted?.should be(false)
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
def fork_fuse(fuse,&fork_block)
|
|
47
|
-
|
|
48
|
-
fpid = Kernel.fork() { fork_block.call() }
|
|
49
|
-
|
|
50
|
-
fuse.loop
|
|
51
|
-
|
|
52
|
-
pid,result = Process.waitpid2(fpid)
|
|
53
|
-
result.should be_success
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
def fusermount(mnt)
|
|
57
|
-
unless system("fusermount -u #{mnt} >/dev/null 2>&1")
|
|
58
|
-
sleep(0.5)
|
|
59
|
-
system("fusermount -u #{mnt}")
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
def file_mode(mode)
|
|
64
|
-
FileModeMatcher.new(mode)
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
def tempmount()
|
|
68
|
-
Dir.mktmpdir("rfuse-spec")
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
# Generate a set of times with non-zero usec values
|
|
72
|
-
def usec_times(*increments)
|
|
73
|
-
increments.collect { |inc|
|
|
74
|
-
begin
|
|
75
|
-
time = Time.now() + inc
|
|
76
|
-
sleep(0.001)
|
|
77
|
-
end until time.usec != 0
|
|
78
|
-
time
|
|
79
|
-
}
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
RSpec.configure do |config|
|
|
85
|
-
config.expect_with :rspec do |c|
|
|
86
|
-
c.syntax = [:should, :expect]
|
|
87
|
-
end
|
|
88
|
-
config.mock_with :rspec do |c|
|
|
89
|
-
c.syntax = [:should, :expect]
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
config.after(:suite) do
|
|
93
|
-
Dir.glob(Dir.tmpdir + "/rfuse-spec*") do |dir|
|
|
94
|
-
count = 0
|
|
95
|
-
begin
|
|
96
|
-
system("fusermount -u #{dir} >/dev/null 2>&1")
|
|
97
|
-
FileUtils.rmdir(dir)
|
|
98
|
-
rescue Errno::EBUSY
|
|
99
|
-
#puts "Cleaning up #{dir} is busy, retrying..."
|
|
100
|
-
sleep(0.5)
|
|
101
|
-
count = count + 1
|
|
102
|
-
retry unless count > 3
|
|
103
|
-
end
|
|
104
|
-
end
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
config.include RFuseHelper
|
|
108
|
-
config.include DoubleAliases
|
|
109
|
-
end
|
data/spec/xattr_spec.rb
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
require 'ffi-xattr'
|
|
3
|
-
|
|
4
|
-
describe RFuse::Fuse do
|
|
5
|
-
it "should handle extended attributes" do
|
|
6
|
-
mockfs = mock("fuse")
|
|
7
|
-
|
|
8
|
-
file_stat = RFuse::Stat.file(0444,:size => 11)
|
|
9
|
-
|
|
10
|
-
mockfs.stub(:getattr).and_return(file_stat)
|
|
11
|
-
mockfs.stub(:getxattr) { |ctx,path,name|
|
|
12
|
-
case name
|
|
13
|
-
when "user.one"
|
|
14
|
-
"1"
|
|
15
|
-
when "user.two"
|
|
16
|
-
"2"
|
|
17
|
-
when "user.large"
|
|
18
|
-
"x" * 1000
|
|
19
|
-
else
|
|
20
|
-
""
|
|
21
|
-
end
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
mockfs.stub(:listxattr).with(anything(),"/myfile").and_return([ "user.one","user.two","user.large" ])
|
|
25
|
-
mockfs.should_receive(:setxattr).with(anything(),"/myfile","user.three","updated",anything())
|
|
26
|
-
mockfs.should_receive(:removexattr).with(anything(),"/myfile","user.one")
|
|
27
|
-
|
|
28
|
-
mountpoint = tempmount()
|
|
29
|
-
|
|
30
|
-
with_fuse(mountpoint,mockfs) do
|
|
31
|
-
xattr = Xattr.new("#{mountpoint}/myfile")
|
|
32
|
-
xattr.list.should include("user.one")
|
|
33
|
-
xattr.list.should include("user.two")
|
|
34
|
-
xattr.list.size.should == 3
|
|
35
|
-
|
|
36
|
-
xattr['user.one'].should == "1"
|
|
37
|
-
xattr['user.two'].should == "2"
|
|
38
|
-
xattr['user.three']= "updated"
|
|
39
|
-
xattr['xxxxx'].should be_nil
|
|
40
|
-
xattr.remove('user.one')
|
|
41
|
-
# And now with a non-ruby system #TODO. There'd be a way to guard this properly
|
|
42
|
-
if system("getfattr --version")
|
|
43
|
-
system("getfattr -d #{mountpoint}/myfile > /dev/null").should be(true)
|
|
44
|
-
else
|
|
45
|
-
puts "Warning Skipping getfattr test"
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
end
|