rfuse 1.1.2 → 1.2.0.rc202009.69

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,143 +0,0 @@
1
- require 'spec_helper'
2
- require 'pathname'
3
- require 'tempfile'
4
-
5
- describe RFuse do
6
-
7
- let(:dir_stat) { RFuse::Stat.directory(0444) }
8
- let(:file_stat) { RFuse::Stat.file(0444) }
9
- let!(:mockfs) { m = mock("fuse"); m.stub(:getattr).and_return(nil); m }
10
- let(:mountpoint) { tempmount() }
11
-
12
- context "mount options" do
13
- it "should handle -h" do
14
- fuse = RFuse::FuseDelegator.new(mockfs,mountpoint,"-h")
15
- fuse.mounted?.should be_falsey
16
- lambda { fuse.loop }.should raise_error(RFuse::Error)
17
- end
18
-
19
- it "should behave sensibly for bad mountpoint" do
20
- fuse = RFuse::FuseDelegator.new(mockfs,"bad/mount/point")
21
- fuse.mounted?.should be_falsey
22
- lambda { fuse.loop }.should raise_error(RFuse::Error)
23
- end
24
-
25
- it "should behave sensibly for bad options" do
26
- fuse = RFuse::FuseDelegator.new(mockfs,mountpoint,"-eviloption")
27
- fuse.mounted?.should be_falsey
28
- lambda { fuse.loop }.should raise_error(RFuse::Error)
29
- end
30
-
31
- it "should handle a Pathname as a mountpoint" do
32
- fuse = RFuse::FuseDelegator.new(mockfs,Pathname.new(mountpoint))
33
- fuse.mounted?.should be(true)
34
- fuse.unmount()
35
- end
36
- end
37
-
38
- context "#parse_options" do
39
-
40
- it "should detect -h" do
41
- argv = [ "/mountpoint","-h" ]
42
- result = RFuse.parse_options(argv)
43
-
44
- result[:help].should be(true)
45
- result[:mountpoint].should == "/mountpoint"
46
- result[:debug].should be_falsey
47
- end
48
-
49
- it "should detect -h mixed with -o" do
50
- argv = [ "/mountpoint","-h", "-o", "debug" ]
51
- result = RFuse.parse_options(argv)
52
-
53
- result[:help].should be(true)
54
- result[:mountpoint].should == "/mountpoint"
55
- result[:debug].should be(true)
56
- end
57
-
58
- it "should detect debug" do
59
- argv = [ "/mountpoint","-o","debug" ]
60
- result = RFuse.parse_options(argv)
61
-
62
- result[:debug].should be(true)
63
- result[:help].should be_falsey
64
-
65
- argv = [ "/mountpoint","-o","default_permissions,debug" ]
66
- result = RFuse.parse_options(argv)
67
- result[:debug].should be(true)
68
- end
69
-
70
- it "detects debug as -d" do
71
- argv = [ "/mountpoint","-o","someopt","-d" ]
72
- result = RFuse.parse_options(argv)
73
- result[:debug].should be(true)
74
- end
75
-
76
- it "should remove local options" do
77
- argv = [ "/mountpoint","-o","debug,myoption" ]
78
-
79
- result = RFuse.parse_options(argv,:myoption)
80
-
81
- result[:debug].should be(true)
82
- result[:myoption].should be(true)
83
-
84
- argv.should == [ "/mountpoint", "-o", "debug" ]
85
- end
86
-
87
- it "should remove the only local option" do
88
- argv = ["/mountpoint","-o","myoption" ]
89
-
90
- result = RFuse.parse_options(argv,:myoption)
91
-
92
- result[:myoption].should be(true)
93
- argv.should == [ "/mountpoint" ]
94
- end
95
-
96
-
97
- it "parses the value from the only local option" do
98
- argv = [ "adevice", "/mountpoint", "-o","someopt=somevalue"]
99
- result = RFuse.parse_options(argv,:someopt)
100
-
101
- result[:someopt].should == "somevalue"
102
- argv.should == [ "/mountpoint" ]
103
- end
104
-
105
- it "should parse values from options" do
106
- argv = [ "/mountpoint", "-o", "debug,someopt=somevalue" ]
107
- result = RFuse.parse_options(argv)
108
-
109
- result[:someopt].should == "somevalue"
110
- end
111
-
112
- it "should parse values and remove local options" do
113
- argv = [ "/mountpoint", "-o", "debug,someopt=somevalue" ]
114
- result = RFuse.parse_options(argv,:someopt)
115
-
116
- result[:someopt].should == "somevalue"
117
- argv[2].should == "debug"
118
- end
119
-
120
- it "should parse and remove optional device" do
121
-
122
- argv = [ "a device", "/mountpoint" , "-o", "rw,debug,default_permissions" ]
123
- result = RFuse.parse_options(argv)
124
-
125
- result[:device].should == "a device"
126
- result[:mountpoint].should == "/mountpoint"
127
- result[:rw].should be(true)
128
- result[:debug].should be(true)
129
- result[:default_permissions].should be(true)
130
-
131
- argv.should == [ "/mountpoint" , "-o", "rw,debug,default_permissions" ]
132
- end
133
-
134
- context "with '-' in device" do
135
- it "should parse the device correctly" do
136
- argv = [ "a-device", "/mountpoint" , "-o", "rw,debug,default_permissions" ]
137
- result = RFuse.parse_options(argv)
138
-
139
- result[:device].should == "a-device"
140
- end
141
- end
142
- end
143
- end
@@ -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
-
@@ -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
@@ -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
@@ -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