rfusefs 1.0.2 → 1.0.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.
@@ -10,8 +10,8 @@ describe "a mounted FuseFS" do
10
10
 
11
11
  it "should get mounted and unmounted callbacks" do
12
12
  mock_fs = FuseFS::FuseDir.new()
13
- mock_fs.should_receive(:mounted)
14
- mock_fs.should_receive(:unmounted)
13
+ expect(mock_fs).to receive(:mounted)
14
+ expect(mock_fs).to receive(:unmounted)
15
15
 
16
16
  t = Thread.new { sleep 0.5 ; puts "exiting" ; FuseFS.exit }
17
17
  FuseFS.start(mock_fs,mountpoint)
@@ -72,41 +72,41 @@ describe FuseFS::PathMapperFS do
72
72
  context "fusefs api" do
73
73
 
74
74
  it "maps files and directories" do
75
- pathmap_fs.directory?("/").should be_true
76
- pathmap_fs.directory?("/textfiles").should be_true
77
- pathmap_fs.directory?("/pictures/201103").should be_true
78
- pathmap_fs.file?("/textfiles/hello").should be_true
79
- pathmap_fs.directory?("/textfiles/hello").should be_false
80
- pathmap_fs.file?("/artist/album/mysong.mp3").should be_true
81
- pathmap_fs.directory?("/artist/album/mysong.mp3").should be_false
82
- pathmap_fs.file?("/some/unknown/path").should be_false
83
- pathmap_fs.directory?("/some/unknown/path").should be_false
75
+ expect(pathmap_fs.directory?("/")).to be_truthy
76
+ expect(pathmap_fs.directory?("/textfiles")).to be_truthy
77
+ expect(pathmap_fs.directory?("/pictures/201103")).to be_truthy
78
+ expect(pathmap_fs.file?("/textfiles/hello")).to be_truthy
79
+ expect(pathmap_fs.directory?("/textfiles/hello")).to be_falsey
80
+ expect(pathmap_fs.file?("/artist/album/mysong.mp3")).to be_truthy
81
+ expect(pathmap_fs.directory?("/artist/album/mysong.mp3")).to be_falsey
82
+ expect(pathmap_fs.file?("/some/unknown/path")).to be_falsey
83
+ expect(pathmap_fs.directory?("/some/unknown/path")).to be_falsey
84
84
  end
85
85
 
86
86
  it "lists the mapped contents of directories" do
87
- pathmap_fs.contents("/").should =~ [ "textfiles","artist","pictures" ]
88
- pathmap_fs.contents("/artist").should =~ [ "album" ]
89
- pathmap_fs.contents("/textfiles").should =~ [ "hello" ]
87
+ expect(pathmap_fs.contents("/")).to match_array([ "textfiles","artist","pictures" ])
88
+ expect(pathmap_fs.contents("/artist")).to match_array([ "album" ])
89
+ expect(pathmap_fs.contents("/textfiles")).to match_array([ "hello" ])
90
90
  end
91
91
 
92
92
  it "reports the size of a file" do
93
- pathmap_fs.size("/textfiles/hello").should == 16
93
+ expect(pathmap_fs.size("/textfiles/hello")).to eq(16)
94
94
  end
95
95
 
96
96
  it "reads the contents of a file" do
97
- pathmap_fs.read_file("/textfiles/hello").should == "/textfiles/hello"
97
+ expect(pathmap_fs.read_file("/textfiles/hello")).to eq("/textfiles/hello")
98
98
  end
99
99
 
100
100
  it "does not allow writes" do
101
- pathmap_fs.can_write?("/textfiles/hello").should be_false
101
+ expect(pathmap_fs.can_write?("/textfiles/hello")).to be_falsey
102
102
  end
103
103
 
104
104
  it "reports the atime,mtime and ctime of the mapped file" do
105
105
  atime,mtime,ctime = pathmap_fs.times("/pictures/201103/apicture.jpg")
106
106
  picture = tmpdir + "apicture.jpeg"
107
- atime.should == picture.atime()
108
- mtime.should == picture.mtime()
109
- ctime.should == picture.ctime()
107
+ expect(atime).to eq(picture.atime())
108
+ expect(mtime).to eq(picture.mtime())
109
+ expect(ctime).to eq(picture.ctime())
110
110
  end
111
111
 
112
112
  context "with extended attributes" do
@@ -130,62 +130,62 @@ describe FuseFS::PathMapperFS do
130
130
  end
131
131
 
132
132
  it "should list extended attributes" do
133
- pm_file_xattr.keys.should include("user.file_attr")
134
- pm_file_xattr.keys.should include("user.add_attr")
135
- pm_file_xattr.keys.size.should == 2
133
+ expect(pm_file_xattr.keys).to include("user.file_attr")
134
+ expect(pm_file_xattr.keys).to include("user.add_attr")
135
+ expect(pm_file_xattr.keys.size).to eq(2)
136
136
  end
137
137
 
138
138
  it "should read extended attributes from underlying file" do
139
- pm_file_xattr["user.file_attr"].should == "fileValue"
139
+ expect(pm_file_xattr["user.file_attr"]).to eq("fileValue")
140
140
  end
141
141
 
142
142
  it "should read additional attributes" do
143
143
  # make sure additional attributes are not on the real file
144
- hello_xattr.list.should_not include("user.add_attr")
144
+ expect(hello_xattr.list).not_to include("user.add_attr")
145
145
 
146
- pm_file_xattr["user.add_attr"].should == "addValue"
146
+ expect(pm_file_xattr["user.add_attr"]).to eq("addValue")
147
147
  end
148
148
 
149
149
  it "should write extended attributes to the underlying file" do
150
150
  pm_file_xattr["user.file_attr"] = "written"
151
- hello_xattr["user.file_attr"].should == "written"
151
+ expect(hello_xattr["user.file_attr"]).to eq("written")
152
152
  end
153
153
 
154
154
  it "should remove extended attributes from the underlying file" do
155
155
  pm_file_xattr.delete("user.file_attr")
156
- hello_xattr.list.should_not include("user.file_attr")
156
+ expect(hello_xattr.list).not_to include("user.file_attr")
157
157
  end
158
158
 
159
159
  it "raise EACCES when writing to additional attributes" do
160
- lambda {pm_file_xattr["user.add_attr"] = "newValue"}.should raise_error(Errno::EACCES)
160
+ expect {pm_file_xattr["user.add_attr"] = "newValue"}.to raise_error(Errno::EACCES)
161
161
  end
162
162
 
163
163
  it "raise EACCES when removing additional attributes" do
164
- lambda {pm_file_xattr.delete("user.add_attr")}.should raise_error(Errno::EACCES)
164
+ expect {pm_file_xattr.delete("user.add_attr")}.to raise_error(Errno::EACCES)
165
165
  end
166
166
 
167
167
  it "should list additional attributes from virtual directories" do
168
- pm_dir_xattr.keys.should include("user.dir_attr")
169
- pm_dir_xattr.keys.size.should == 1
168
+ expect(pm_dir_xattr.keys).to include("user.dir_attr")
169
+ expect(pm_dir_xattr.keys.size).to eq(1)
170
170
  end
171
171
 
172
172
  it "should read additional attributes from virtual directories" do
173
- pm_dir_xattr["user.dir_attr"].should == "dirValue"
173
+ expect(pm_dir_xattr["user.dir_attr"]).to eq("dirValue")
174
174
 
175
175
  end
176
176
 
177
177
  it "should raise EACCES when writing additional attributes on virtual directories" do
178
- lambda {pm_dir_xattr["user.dir_attr"] = "newValue"}.should raise_error(Errno::EACCES)
178
+ expect {pm_dir_xattr["user.dir_attr"] = "newValue"}.to raise_error(Errno::EACCES)
179
179
  end
180
180
 
181
181
  it "should raise EACCES when deleting additional attributes on virtual directories" do
182
- lambda {pm_dir_xattr.delete("user.dir_attr")}.should raise_error(Errno::EACCES)
182
+ expect {pm_dir_xattr.delete("user.dir_attr")}.to raise_error(Errno::EACCES)
183
183
  end
184
184
 
185
185
  it "should accept xattr as option to #map_file" do
186
186
  fixture.pathmap("mapped_xattr.txt","/textfiles/mapped_xattr","content",
187
187
  :xattr => { "user.xattr" => "map_file" })
188
- pathmap_fs.xattr("/textfiles/mapped_xattr")["user.xattr"].should == "map_file"
188
+ expect(pathmap_fs.xattr("/textfiles/mapped_xattr")["user.xattr"]).to eq("map_file")
189
189
  end
190
190
  end
191
191
 
@@ -193,10 +193,10 @@ describe FuseFS::PathMapperFS do
193
193
 
194
194
  it "reports accumulated stats about mapped files" do
195
195
  used_space, used_nodes, max_space, max_nodes = pathmap_fs.statistics("/pictures/201103/apicture.jpg")
196
- used_space.should == 69
197
- used_nodes.should == 9
198
- max_space.should be_nil
199
- max_nodes.should be_nil
196
+ expect(used_space).to eq(69)
197
+ expect(used_nodes).to eq(9)
198
+ expect(max_space).to be_nil
199
+ expect(max_nodes).to be_nil
200
200
  end
201
201
  end
202
202
 
@@ -208,20 +208,20 @@ describe FuseFS::PathMapperFS do
208
208
 
209
209
  it "updates the contents of the real file" do
210
210
  hello_path = tmpdir + "hello.txt"
211
- hello_path.read.should == "updated content"
211
+ expect(hello_path.read).to eq("updated content")
212
212
  end
213
213
 
214
214
  it "updates the contents of the mapped file" do
215
- pathmap_fs.read_file("textfiles/hello").should == "updated content"
215
+ expect(pathmap_fs.read_file("textfiles/hello")).to eq("updated content")
216
216
  end
217
217
 
218
218
  it "changes the reported file size" do
219
- pathmap_fs.size("textfiles/hello").should == 15
219
+ expect(pathmap_fs.size("textfiles/hello")).to eq(15)
220
220
  end
221
221
 
222
222
  it "changes the filesystem statistics" do
223
223
  used_space, used_nodes, max_space, max_nodes = pathmap_fs.statistics("/pictures/201103/apicture.jpg")
224
- used_space.should == 68
224
+ expect(used_space).to eq(68)
225
225
  end
226
226
  end
227
227
 
@@ -233,12 +233,12 @@ describe FuseFS::PathMapperFS do
233
233
  end
234
234
 
235
235
  it "maps files and directories" do
236
- (mountpoint + "textfiles").directory?.should be_true
237
- (mountpoint + "textfiles/hello").file?.should be_true
236
+ expect((mountpoint + "textfiles").directory?).to be_truthy
237
+ expect((mountpoint + "textfiles/hello").file?).to be_truthy
238
238
  end
239
239
 
240
240
  it "lists the mapped contents of directories" do
241
- (mountpoint + "textfiles").entries.should =~ pathnames(".","..","hello")
241
+ expect((mountpoint + "textfiles").entries).to match_array(pathnames(".","..","hello"))
242
242
  end
243
243
 
244
244
  it "represents the stat information of the underlying files" do
@@ -246,15 +246,15 @@ describe FuseFS::PathMapperFS do
246
246
  realpath=(tmpdir + "hello.txt")
247
247
  mappedstat = hellopath.stat
248
248
  realstat = realpath.stat
249
- mappedstat.size.should == realstat.size
250
- mappedstat.atime.should == realstat.atime
251
- mappedstat.mtime.should == realstat.mtime
252
- mappedstat.ctime.should == realstat.ctime
249
+ expect(mappedstat.size).to eq(realstat.size)
250
+ expect(mappedstat.atime).to eq(realstat.atime)
251
+ expect(mappedstat.mtime).to eq(realstat.mtime)
252
+ expect(mappedstat.ctime).to eq(realstat.ctime)
253
253
  end
254
254
 
255
255
  it "reads the files" do
256
256
  hellopath= mountpoint + "textfiles/hello"
257
- hellopath.read.should == "/textfiles/hello"
257
+ expect(hellopath.read).to eq("/textfiles/hello")
258
258
  end
259
259
 
260
260
  it "writes the files" do
@@ -263,8 +263,8 @@ describe FuseFS::PathMapperFS do
263
263
  hellopath.open("w") do |f|
264
264
  f.print "updated content"
265
265
  end
266
- hellopath.read.should == "updated content"
267
- real_path.read.should == "updated content"
266
+ expect(hellopath.read).to eq("updated content")
267
+ expect(real_path.read).to eq("updated content")
268
268
  end
269
269
 
270
270
  context "extended attributes" do
@@ -288,52 +288,52 @@ describe FuseFS::PathMapperFS do
288
288
  end
289
289
 
290
290
  it "should list extended attributes" do
291
- file_xattr.list.should include("user.file_attr")
292
- file_xattr.list.should include("user.add_attr")
293
- file_xattr.list.size.should == 2
291
+ expect(file_xattr.list).to include("user.file_attr")
292
+ expect(file_xattr.list).to include("user.add_attr")
293
+ expect(file_xattr.list.size).to eq(2)
294
294
  end
295
295
 
296
296
  it "should read extended attributes from underlying file" do
297
- file_xattr["user.file_attr"].should == "fileValue"
297
+ expect(file_xattr["user.file_attr"]).to eq("fileValue")
298
298
  end
299
299
 
300
300
  it "should read additional attributes" do
301
- file_xattr["user.add_attr"].should == "addValue"
301
+ expect(file_xattr["user.add_attr"]).to eq("addValue")
302
302
  end
303
303
 
304
304
  it "should write extended attributes to the underlying file" do
305
305
  file_xattr["user.file_attr"] = "written"
306
- hello_xattr["user.file_attr"].should == "written"
306
+ expect(hello_xattr["user.file_attr"]).to eq("written")
307
307
  end
308
308
 
309
309
  it "should remove extended attributes from the underlying file" do
310
310
  file_xattr.remove("user.file_attr")
311
- hello_xattr.list.should_not include("user.file_attr")
311
+ expect(hello_xattr.list).not_to include("user.file_attr")
312
312
  end
313
313
 
314
314
  it "raise EACCES when writing to additional attributes" do
315
- lambda {file_xattr["user.add_attr"] = "newValue"}.should raise_error(Errno::EACCES)
315
+ expect {file_xattr["user.add_attr"] = "newValue"}.to raise_error(Errno::EACCES)
316
316
  end
317
317
 
318
318
  it "raise EACCES when removing additional attributes" do
319
- lambda {file_xattr.remove("user.add_attr")}.should raise_error(Errno::EACCES)
319
+ expect {file_xattr.remove("user.add_attr")}.to raise_error(Errno::EACCES)
320
320
  end
321
321
 
322
322
  it "should list additional attributes from virtual directories" do
323
- dir_xattr.list.should include("user.dir_attr")
324
- dir_xattr.list.size.should == 1
323
+ expect(dir_xattr.list).to include("user.dir_attr")
324
+ expect(dir_xattr.list.size).to eq(1)
325
325
  end
326
326
 
327
327
  it "should read additional attributes from virtual directories" do
328
- dir_xattr["user.dir_attr"].should == "dirValue"
328
+ expect(dir_xattr["user.dir_attr"]).to eq("dirValue")
329
329
  end
330
330
 
331
331
  it "should raise EACCES when writing additional attributes on virtual directories" do
332
- lambda {dir_xattr["user.dir_attr"] = "newValue"}.should raise_error(Errno::EACCES)
332
+ expect {dir_xattr["user.dir_attr"] = "newValue"}.to raise_error(Errno::EACCES)
333
333
  end
334
334
 
335
335
  it "should raise EACCES when deleting additional attributes on virtual directories" do
336
- lambda {dir_xattr.remove("user.dir_attr")}.should raise_error(Errno::EACCES)
336
+ expect {dir_xattr.remove("user.dir_attr")}.to raise_error(Errno::EACCES)
337
337
  end
338
338
 
339
339
  end
@@ -346,25 +346,25 @@ describe FuseFS::PathMapperFS do
346
346
  it "reports stats for files" do
347
347
  statfs = Sys::Filesystem.stat(mountpoint.to_path)
348
348
  # These are fixed
349
- statfs.block_size.should == 1024
350
- statfs.fragment_size.should == 1024
349
+ expect(statfs.block_size).to eq(1024)
350
+ expect(statfs.fragment_size).to eq(1024)
351
351
 
352
352
  # These are dependant on the tests above creating files/directories
353
- statfs.files.should == 10
353
+ expect(statfs.files).to eq(10)
354
354
  statfs.files_available == 10
355
355
 
356
356
  # assume test are less than 1 block, so dependant on bigfile above
357
- statfs.blocks.should == 2
358
- statfs.blocks_available.should == 0
359
- statfs.blocks_free.should == 0
357
+ expect(statfs.blocks).to eq(2)
358
+ expect(statfs.blocks_available).to eq(0)
359
+ expect(statfs.blocks_free).to eq(0)
360
360
  end
361
361
 
362
362
  it "reports stats for files after writing" do
363
363
 
364
364
  (mountpoint + "textfiles/bigfile").open("w") { |f| f.print("y" * 4096) }
365
365
  statfs = Sys::Filesystem.stat(mountpoint.to_path)
366
- statfs.files.should == 10
367
- statfs.blocks.should == 4
366
+ expect(statfs.files).to eq(10)
367
+ expect(statfs.blocks).to eq(4)
368
368
 
369
369
  end
370
370
 
@@ -382,12 +382,12 @@ describe FuseFS::PathMapperFS do
382
382
  hello_path = (mountpoint + "textfiles/hello")
383
383
  hello_path.open do |f|
384
384
  f.seek(2)
385
- f.read(3).should == "ext"
385
+ expect(f.read(3)).to eq("ext")
386
386
  end
387
387
 
388
388
  hello_path.sysopen do |f|
389
389
  f.sysseek(1)
390
- f.sysread(3).should == "tex"
390
+ expect(f.sysread(3)).to eq("tex")
391
391
  end
392
392
  end
393
393
 
@@ -398,10 +398,10 @@ describe FuseFS::PathMapperFS do
398
398
  f.sysseek(2)
399
399
  f.syswrite("zzz")
400
400
  f.sysseek(0)
401
- f.sysread(6).should == "/tzzzf"
401
+ expect(f.sysread(6)).to eq("/tzzzf")
402
402
  end
403
403
 
404
- real_path.read.should == "/tzzzfiles/hello"
404
+ expect(real_path.read).to eq("/tzzzfiles/hello")
405
405
  end
406
406
 
407
407
  it "reports filesystem statistics after raw write" do
@@ -411,7 +411,7 @@ describe FuseFS::PathMapperFS do
411
411
  end
412
412
 
413
413
  statfs = Sys::Filesystem.stat(mountpoint.to_path)
414
- statfs.blocks.should == 2
414
+ expect(statfs.blocks).to eq(2)
415
415
  end
416
416
  end
417
417
  end
@@ -1,497 +1,505 @@
1
- require 'spec_helper'
2
-
3
- describe FuseFS do
4
-
5
- TEST_FILE = "/aPath/aFile"
6
- TEST_DIR = "/aPath"
7
- ROOT_PATH = "/"
8
- Struct.new("FuseFileInfo",:flags,:fh)
9
-
10
- describe "an empty FuseFS object" do
11
- before(:each) do
12
- @fuse = FuseFS::RFuseFS.new(Object.new())
13
- end
14
-
15
- it "should return an appropriate Stat for the root directory" do
16
- stat = @fuse.getattr(nil,ROOT_PATH)
17
- stat.should respond_to(:dev)
18
- (stat.mode & RFuse::Stat::S_IFDIR).should_not == 0
19
- (stat.mode & RFuse::Stat::S_IFREG).should == 0
20
- permissions(stat.mode).should == 0555
21
- end
22
-
23
- it "should have an empty root directory" do
24
- filler = mock("entries_filler")
25
- filler.should_receive(:push).with(".",nil,0)
26
- filler.should_receive(:push).with("..",nil,0)
27
- @fuse.readdir(nil,"/",filler,nil,nil)
28
- end
29
-
30
- it "should raise ENOENT for other paths" do
31
- lambda { @fuse.getattr(nil,"/somepath") }.should raise_error(Errno::ENOENT)
32
- end
33
-
34
- it "should not allow new files or directories" do
35
- lambda { @fuse.mknod(nil,"/afile",0100644,0,0) }.should raise_error(Errno::EACCES)
36
- lambda { @fuse.mkdir(nil,"/adir",0040555) }.should raise_error(Errno::EACCES)
37
- end
38
- end
39
-
40
- describe "a FuseFS filesystem" do
41
- before(:each) do
42
- @mock_fuse = FuseFS::FuseDir.new()
43
- @fuse = FuseFS::RFuseFS.new(@mock_fuse)
44
- end
45
-
46
- describe :readdir do
47
- before(:each) do
48
- @mock_fuse.should_receive(:contents).with("/apath").and_return(["afile"])
49
- end
50
-
51
- it "should add . and .. to the results of :contents when listing a directory" do
52
- filler = mock("entries_filler")
53
- filler.should_receive(:push).with(".",nil,0)
54
- filler.should_receive(:push).with("..",nil,0)
55
- filler.should_receive(:push).with("afile",nil,0)
56
- @fuse.readdir(nil,"/apath",filler,nil,nil)
57
- end
58
-
59
- end
60
-
61
- describe :getattr do
62
-
63
- #Root directory is special (ish) so we need to run these specs twice.
64
- [ROOT_PATH,TEST_DIR].each do |dir|
65
-
66
- context "of a directory #{ dir }" do
67
-
68
- before(:each) do
69
- @mock_fuse.stub!(:file?).and_return(false)
70
- @mock_fuse.should_receive(:directory?).with(dir).at_most(:once).and_return(true)
71
- @checkfile = (dir == "/" ? "" : dir ) + FuseFS::RFuseFS::CHECK_FILE
72
- end
73
-
74
- it "should return a Stat like object representing a directory" do
75
- @mock_fuse.should_receive(:can_write?).with(@checkfile).at_most(:once).and_return(false)
76
- @mock_fuse.should_receive(:can_mkdir?).with(@checkfile).at_most(:once).and_return(false)
77
- stat = @fuse.getattr(nil,dir)
78
- #Apparently find relies on nlink accurately listing the number of files/directories or nlink being 1
79
- stat.nlink.should == 1
80
- filetype(stat.mode).should == RFuse::Stat::S_IFDIR
81
- permissions(stat.mode).should == 0555
82
- end
83
-
84
-
85
- it "should return writable mode if can_mkdir?" do
86
- @mock_fuse.should_receive(:can_mkdir?).with(@checkfile).at_most(:once).and_return(true)
87
-
88
- stat = @fuse.getattr(nil,dir)
89
- permissions(stat.mode).should == 0777
90
- end
91
-
92
- it "should return writable mode if can_write?" do
93
- @mock_fuse.should_receive(:can_write?).with(@checkfile).at_most(:once).and_return(true)
94
-
95
- stat = @fuse.getattr(nil,dir)
96
- permissions(stat.mode).should == 0777
97
-
98
- end
99
-
100
- it "should return times in the result if available" do
101
- @mock_fuse.should_receive(:times).with(dir).and_return([10,20,30])
102
- stat = @fuse.getattr(nil,dir)
103
- stat.atime.should == 10
104
- stat.mtime.should == 20
105
- stat.ctime.should == 30
106
- end
107
- end
108
- end
109
-
110
- describe "a file" do
111
-
112
- before(:each) do
113
- @file="/aPath/aFile"
114
- @mock_fuse.stub!(:directory?).and_return(false)
115
- @mock_fuse.should_receive(:file?).with(@file).at_most(:once).and_return(true)
116
- end
117
-
118
-
119
- it "should return a Stat like object representing a file" do
120
- stat = @fuse.getattr(nil,@file)
121
- (stat.mode & RFuse::Stat::S_IFDIR).should == 0
122
- (stat.mode & RFuse::Stat::S_IFREG).should_not == 0
123
- permissions(stat.mode).should == 0444
124
- end
125
-
126
- it "should indicate executable mode if executable?" do
127
- @mock_fuse.should_receive(:executable?).with(@file).and_return(true)
128
- stat = @fuse.getattr(nil,@file)
129
- permissions(stat.mode).should == 0555
130
- end
131
-
132
- it "should indicate writable mode if can_write?" do
133
- @mock_fuse.should_receive(:can_write?).with(@file).and_return(true)
134
- stat = @fuse.getattr(nil,@file)
135
- permissions(stat.mode).should == 0666
136
- end
137
-
138
- it "should by 777 mode if can_write? and exectuable?" do
139
- @mock_fuse.should_receive(:can_write?).with(@file).and_return(true)
140
- @mock_fuse.should_receive(:executable?).with(@file).and_return(true)
141
- stat = @fuse.getattr(nil,@file)
142
- permissions(stat.mode).should == 0777
143
- end
144
-
145
- it "should include size in the result if available" do
146
- @mock_fuse.should_receive(:size).with(@file).and_return(234)
147
- stat = @fuse.getattr(nil,@file)
148
- stat.size.should == 234
149
- end
150
-
151
- it "should include times in the result if available" do
152
- @mock_fuse.should_receive(:times).with(@file).and_return([22,33,44])
153
- stat = @fuse.getattr(nil,@file)
154
- stat.atime.should == 22
155
- stat.mtime.should == 33
156
- stat.ctime.should == 44
157
- end
158
- end
159
-
160
- it "should raise ENOENT for a path that does not exist" do
161
- @mock_fuse.should_receive(:file?).with(TEST_FILE).and_return(false)
162
- @mock_fuse.should_receive(:directory?).with(TEST_FILE).and_return(false)
163
- lambda{stat = @fuse.getattr(nil,TEST_FILE) }.should raise_error(Errno::ENOENT)
164
- end
165
- end
166
-
167
- context "creating files and directories" do
168
-
169
- it ":mknod should raise EACCES unless :can_write?" do
170
- @mock_fuse.stub!(:file?).with(TEST_FILE).and_return(false)
171
- @mock_fuse.stub!(:directory?).with(TEST_FILE).and_return(false)
172
- @mock_fuse.should_receive(:can_write?).with(TEST_FILE).and_return(false)
173
- lambda{@fuse.mknod(nil,TEST_FILE,0100644,0,0)}.should raise_error(Errno::EACCES)
174
- end
175
-
176
- it ":mkdir should raise EACCES unless :can_mkdir?" do
177
- @mock_fuse.stub!(:file?).with(TEST_FILE).and_return(false)
178
- @mock_fuse.stub!(:directory?).with(TEST_FILE).and_return(false)
179
- @mock_fuse.should_receive(:can_mkdir?).with(TEST_FILE).and_return(false)
180
- lambda{@fuse.mkdir(nil,TEST_FILE,004555)}.should raise_error(Errno::EACCES)
181
- end
182
-
183
- it ":mknod should raise EACCES unless mode requests a regular file" do
184
- @mock_fuse.stub!(:file?).with(TEST_FILE).and_return(false)
185
- @mock_fuse.stub!(:directory?).with(TEST_FILE).and_return(false)
186
- @mock_fuse.stub!(:can_write?).with(TEST_FILE).and_return(true)
187
- lambda{@fuse.mknod(nil,TEST_FILE,RFuse::Stat::S_IFLNK | 0644,0,0)}.should raise_error(Errno::EACCES)
188
- end
189
-
190
- it ":mknod should result in getattr returning a Stat like object representing an empty file" do
191
- @mock_fuse.stub!(:file?).with(TEST_FILE).and_return(false)
192
- @mock_fuse.stub!(:directory?).with(TEST_FILE).and_return(false)
193
- @mock_fuse.stub!(:can_write?).with(TEST_FILE).and_return(true)
194
- @fuse.mknod(nil,TEST_FILE,RFuse::Stat::S_IFREG | 0644,0,0)
195
-
196
- stat = @fuse.getattr(nil,TEST_FILE)
197
- filetype(stat.mode).should == RFuse::Stat::S_IFREG
198
- stat.size.should == 0
199
- end
200
-
201
- it "should create zero length files" do
202
- ffi = Struct::FuseFileInfo.new()
203
- ffi.flags = Fcntl::O_WRONLY
204
- @mock_fuse.stub!(:file?).with(TEST_FILE).and_return(false)
205
- @mock_fuse.stub!(:directory?).with(TEST_FILE).and_return(false)
206
- @mock_fuse.stub!(:can_write?).with(TEST_FILE).and_return(true)
207
- @mock_fuse.should_receive(:write_to).once.with(TEST_FILE,"")
208
- @fuse.mknod(nil,TEST_FILE,RFuse::Stat::S_IFREG | 0644,0,0)
209
- @fuse.open(nil,TEST_FILE,ffi)
210
- @fuse.flush(nil,TEST_FILE,ffi)
211
- @fuse.release(nil,TEST_FILE,ffi)
212
- end
213
-
214
- it ":mkdir should not raise error if can_mkdir?" do
215
- @mock_fuse.should_receive(:can_mkdir?).with(TEST_FILE).and_return(true)
216
- @fuse.mkdir(nil,TEST_FILE,004555)
217
- end
218
-
219
- end
220
-
221
- context "reading files" do
222
- it "should read the contents of a file" do
223
- ffi = Struct::FuseFileInfo.new()
224
- ffi.flags = Fcntl::O_RDONLY
225
- @mock_fuse.stub!(:file?).with(TEST_FILE).and_return(true)
226
- @mock_fuse.stub!(:read_file).with(TEST_FILE).and_return("Hello World\n")
227
- @fuse.open(nil,TEST_FILE,ffi)
228
- #to me fuse is backwards -- size, offset!
229
- @fuse.read(nil,TEST_FILE,5,0,ffi).should == "Hello"
230
- @fuse.read(nil,TEST_FILE,4,6,ffi).should == "Worl"
231
- @fuse.read(nil,TEST_FILE,10,8,ffi).should == "rld\n"
232
- @fuse.flush(nil,TEST_FILE,ffi)
233
- @fuse.release(nil,TEST_FILE,ffi)
234
- end
235
- end
236
-
237
- context "writing files" do
238
- it "should overwrite a file opened WR_ONLY" do
239
- ffi = Struct::FuseFileInfo.new()
240
- ffi.flags = Fcntl::O_WRONLY
241
- @mock_fuse.stub!(:can_write?).with(TEST_FILE).and_return(true)
242
- @mock_fuse.stub!(:read_file).with(TEST_FILE).and_return("I'm writing a file\n")
243
- @mock_fuse.should_receive(:write_to).once().with(TEST_FILE,"My new contents\n")
244
- @fuse.open(nil,TEST_FILE,ffi)
245
- @fuse.ftruncate(nil,TEST_FILE,0,ffi)
246
- @fuse.write(nil,TEST_FILE,"My new c",0,ffi)
247
- @fuse.write(nil,TEST_FILE,"ontents\n",8,ffi)
248
- @fuse.flush(nil,TEST_FILE,ffi)
249
- #that's right flush can be called more than once.
250
- @fuse.flush(nil,TEST_FILE,ffi)
251
- #but then we can write some more and flush again
252
- @fuse.release(nil,TEST_FILE,ffi)
253
- end
254
-
255
- it "should append to a file opened WR_ONLY | APPEND" do
256
- ffi = Struct::FuseFileInfo.new()
257
- ffi.flags = Fcntl::O_WRONLY | Fcntl::O_APPEND
258
- @mock_fuse.stub!(:can_write?).with(TEST_FILE).and_return(true)
259
- @mock_fuse.stub!(:read_file).with(TEST_FILE).and_return("I'm writing a file\n")
260
- @mock_fuse.should_receive(:write_to).once().with(TEST_FILE,"I'm writing a file\nMy new contents\n")
261
- @fuse.open(nil,TEST_FILE,ffi)
262
- @fuse.write(nil,TEST_FILE,"My new c",0,ffi)
263
- @fuse.write(nil,TEST_FILE,"ontents\n",8,ffi)
264
- @fuse.flush(nil,TEST_FILE,ffi)
265
- #that's right flush can be called more than once. But we should only write-to the first time
266
- @fuse.flush(nil,TEST_FILE,ffi)
267
- @fuse.release(nil,TEST_FILE,ffi)
268
-
269
- end
270
-
271
- it "should do sensible things for files opened RDWR"
272
-
273
- it "should pass on buffered data when requested (fsync)"
274
-
275
- end
276
-
277
- context "raw reading" do
278
-
279
- it "should call the raw_read/raw_close if raw_open returns true" do
280
- ffi = Struct::FuseFileInfo.new()
281
- ffi.flags = Fcntl::O_RDONLY
282
- @mock_fuse.stub!(:can_write?).with(TEST_FILE).and_return(true)
283
- @mock_fuse.should_receive(:raw_open).with(TEST_FILE,"r",true).and_return("raw")
284
- @mock_fuse.should_receive(:raw_read).with(TEST_FILE,5,0,"raw").and_return("12345")
285
- @mock_fuse.should_receive(:raw_read).with(TEST_FILE,5,5,"raw").and_return("67890")
286
- @mock_fuse.should_receive(:raw_close).with(TEST_FILE,"raw")
287
- @fuse.open(nil,TEST_FILE,ffi)
288
- @fuse.read(nil,TEST_FILE,0,5,ffi).should == "12345"
289
- @fuse.read(nil,TEST_FILE,5,5,ffi).should == "67890"
290
- @fuse.flush(nil,TEST_FILE,ffi)
291
- @fuse.release(nil,TEST_FILE,ffi)
292
- end
293
-
294
- end
295
-
296
- context "raw writing" do
297
- it "should call other raw_* methods if raw_open returns true" do
298
- ffi = Struct::FuseFileInfo.new()
299
- ffi.flags = Fcntl::O_WRONLY
300
- raw = Object.new()
301
- @mock_fuse.stub!(:can_write?).with(TEST_FILE).and_return(true)
302
- @mock_fuse.should_receive(:raw_open).with(TEST_FILE,"w",true).and_return(raw)
303
- @mock_fuse.should_receive(:raw_truncate).with(TEST_FILE,0,raw)
304
- @mock_fuse.should_receive(:raw_write).with(TEST_FILE,0,5,"12345",raw).once().and_return(5)
305
- @mock_fuse.should_receive(:raw_write).with(TEST_FILE,5,5,"67890",raw).once().and_return(5)
306
- @mock_fuse.should_receive(:raw_sync).with(TEST_FILE, false, raw)
307
- @mock_fuse.should_receive(:raw_close).with(TEST_FILE,raw)
308
- @fuse.open(nil,TEST_FILE,ffi)
309
- @fuse.ftruncate(nil,TEST_FILE,0,ffi)
310
- @fuse.write(nil,TEST_FILE,"12345",0,ffi).should == 5
311
- @fuse.fsync(nil,TEST_FILE,0,ffi)
312
- @fuse.write(nil,TEST_FILE,"67890",5,ffi).should == 5
313
- @fuse.flush(nil,TEST_FILE,ffi)
314
- @fuse.release(nil,TEST_FILE,ffi)
315
- end
316
-
317
- it "should clean up created files" do
318
- ffi = Struct::FuseFileInfo.new()
319
- ffi.flags = Fcntl::O_WRONLY
320
- raw = Object.new()
321
- @mock_fuse.stub!(:directory?).and_return(false)
322
- @mock_fuse.stub!(:file?).with(TEST_FILE).and_return(false,true)
323
- @mock_fuse.stub!(:can_write?).with(TEST_FILE).and_return(true)
324
- @mock_fuse.should_receive(:raw_open).with(TEST_FILE,"w",true).and_return(raw)
325
- @mock_fuse.should_receive(:raw_close).with(TEST_FILE,raw)
326
- @mock_fuse.should_receive(:size).with(TEST_FILE).and_return(25)
327
-
328
- lambda { @fuse.getattr(nil,TEST_FILE) }.should raise_error(Errno::ENOENT)
329
- @fuse.mknod(nil,TEST_FILE,RFuse::Stat::S_IFREG | 0644,0,0)
330
- @fuse.open(nil,TEST_FILE,ffi)
331
- @fuse.flush(nil,TEST_FILE,ffi)
332
- @fuse.release(nil,TEST_FILE,ffi)
333
- stat = @fuse.getattr(nil,TEST_FILE)
334
- stat.size = 25
335
- end
336
-
337
- it "should pass 'wa' to raw_open if fuse sends WRONLY | APPEND" do
338
- ffi = Struct::FuseFileInfo.new()
339
- ffi.flags = Fcntl::O_WRONLY | Fcntl::O_APPEND
340
- raw = Object.new()
341
- @mock_fuse.stub!(:can_write?).with(TEST_FILE).and_return(true)
342
- @mock_fuse.should_receive(:raw_open).with(TEST_FILE,"wa",true).and_return(raw)
343
- @fuse.open(nil,TEST_FILE,ffi)
344
- end
345
- end
346
-
347
- context "deleting files" do
348
- it "should raise EACCES unless :can_delete?" do
349
- @mock_fuse.should_receive(:can_delete?).with(TEST_FILE).and_return(false)
350
- lambda {@fuse.unlink(nil,TEST_FILE)}.should raise_error(Errno::EACCES)
351
- end
352
-
353
- it "should :delete without error if :can_delete?" do
354
- @mock_fuse.stub!(:can_delete?).with(TEST_FILE).and_return(true)
355
- @mock_fuse.should_receive(:delete).with(TEST_FILE)
356
- @fuse.unlink(nil,TEST_FILE)
357
- end
358
-
359
- it "should remove entries created with mknod that have never been opened" do
360
- @mock_fuse.stub!(:file?).with(TEST_FILE).and_return(false)
361
- @mock_fuse.stub!(:directory?).with(TEST_FILE).and_return(false)
362
- @mock_fuse.stub!(:can_delete?).with(TEST_FILE).and_return(true)
363
- @mock_fuse.stub!(:can_write?).with(TEST_FILE).and_return(true)
364
- @fuse.mknod(nil,TEST_FILE,RFuse::Stat::S_IFREG | 0644,0,0)
365
-
366
- @fuse.unlink(nil,TEST_FILE)
367
- lambda {@fuse.getattr(nil,TEST_FILE)}.should raise_error(Errno::ENOENT)
368
- end
369
- end
370
-
371
- context "deleting directories" do
372
- it "should raise EACCES unless :can_rmdir?" do
373
- @mock_fuse.should_receive(:can_rmdir?).with(TEST_DIR).and_return(false)
374
- lambda{@fuse.rmdir(nil,TEST_DIR)}.should raise_error(Errno::EACCES)
375
- end
376
-
377
- it "should :rmdir without error if :can_rmdir?" do
378
- @mock_fuse.stub!(:can_rmdir?).with(TEST_DIR).and_return(true)
379
- @fuse.rmdir(nil,TEST_DIR)
380
- end
381
- end
382
-
383
- context "touching files" do
384
- it "should call :touch in response to utime" do
385
- @mock_fuse.should_receive(:touch).with(TEST_FILE,220)
386
- @fuse.utime(nil,TEST_FILE,100,220)
387
- end
388
- end
389
-
390
- context "renaming files" do
391
- before(:each) do
392
- @oldfile = "/aPath/oldFile"
393
- @newfile = "/aNewFile"
394
- @mock_fuse.stub!(:file?).with(@oldfile).and_return(true)
395
- @mock_fuse.stub!(:directory?).with(@oldfile).and_return(false)
396
- end
397
- it "should raise EACCES unless :can_write? the new file" do
398
- @mock_fuse.stub!(:can_delete?).with(@oldfile).and_return(true)
399
- @mock_fuse.should_receive(:can_write?).with(@newfile).and_return(false)
400
- lambda {@fuse.rename(nil,@oldfile,@newfile)}.should raise_error(Errno::EACCES)
401
- end
402
-
403
- it "should raise EACCES unless :can_delete the old file" do
404
- @mock_fuse.stub!(:can_write?).with(@newfile).and_return(true)
405
- @mock_fuse.should_receive(:can_delete?).with(@oldfile).and_return(false)
406
- lambda {@fuse.rename(nil,@oldfile,@newfile)}.should raise_error(Errno::EACCES)
407
- end
408
-
409
- it "should copy and delete files" do
410
- @mock_fuse.stub!(:can_write?).with(@newfile).and_return(true)
411
- @mock_fuse.stub!(:can_delete?).with(@oldfile).and_return(true)
412
- @mock_fuse.should_receive(:read_file).with(@oldfile).and_return("some contents\n")
413
- @mock_fuse.should_receive(:write_to).with(@newfile,"some contents\n")
414
- @mock_fuse.should_receive(:delete).with(@oldfile)
415
- @fuse.rename(nil,@oldfile,@newfile)
416
- end
417
-
418
- it "should not copy and delete files if fs responds_to? :rename" do
419
- @mock_fuse.should_receive(:rename).with(@oldfile,@newfile).and_return(true)
420
- @fuse.rename(nil,@oldfile,@newfile)
421
- end
422
-
423
- it "should raise EACCES if moving a directory and rename not supported" do
424
- @mock_fuse.stub!(:file?).with(@oldfile).and_return(false)
425
- @mock_fuse.stub!(:directory?).with(@oldfile).and_return(true)
426
- @mock_fuse.stub!(:can_write?).with(@newfile).and_return(true)
427
- @mock_fuse.stub!(:can_delete?).with(@oldfile).and_return(true)
428
- lambda{@fuse.rename(nil,@oldfile,@newfile)}.should raise_error(Errno::EACCES)
429
- end
430
-
431
- end
432
- context "extended attributes" do
433
-
434
- let(:xattr) { mock(:xattr) }
435
- before(:each) { @mock_fuse.stub!(:xattr).with(TEST_FILE).and_return(xattr) }
436
-
437
- it "should list attributes via #keys on result of #xattr" do
438
- xattr.should_receive(:keys).and_return(["one","two"])
439
- @fuse.listxattr(nil,TEST_FILE).should == [ "one","two" ]
440
- end
441
-
442
- it "should get attributes via #xattr.[]" do
443
- xattr.should_receive(:[]).with("user.one").and_return("one")
444
-
445
- @fuse.getxattr(nil,TEST_FILE,"user.one").should == "one"
446
- end
447
-
448
- it "should set attributes via #xattr.[]=" do
449
- xattr.should_receive(:[]=).with("user.two","two")
450
-
451
- @fuse.setxattr(nil,TEST_FILE,"user.two","two",0)
452
- end
453
-
454
- it "should remove attributes via #xattr.delete" do
455
- xattr.should_receive(:delete).with("user.three")
456
-
457
- @fuse.removexattr(nil,TEST_FILE,"user.three")
458
- end
459
-
460
- it "should raise ENODATA when #xattr.[] returns nil" do
461
-
462
- xattr.should_receive(:[]).with("user.xxxx").and_return(nil)
463
- lambda{@fuse.getxattr(nil,TEST_FILE,"user.xxxx") }.should raise_error(Errno::ENODATA)
464
- end
465
- end
466
-
467
- context "#statfs" do
468
- # used space, used files, total_space, total_files
469
- let(:stats) { [ 1000 * 1024, 5, 1200 * 1024, 12 ] }
470
- it "should convert simple array into StatVfs" do
471
-
472
- @mock_fuse.should_receive(:statistics).with(TEST_FILE).and_return(stats)
473
-
474
- result = @fuse.statfs(nil,TEST_FILE)
475
- result.should be_kind_of(RFuse::StatVfs)
476
- result.f_bsize.should == 1024
477
- result.f_blocks.should == 1200
478
- result.f_bavail.should == 200
479
- result.f_files.should == 12
480
- result.f_ffree.should == 7
481
- end
482
-
483
- it "passes on raw statistics" do
484
- statvfs = Object.new()
485
- @mock_fuse.should_receive(:statistics).with(TEST_FILE).and_return(statvfs)
486
-
487
- @fuse.statfs(nil,TEST_FILE).should equal(statvfs)
488
- end
489
-
490
- end
491
- end
492
-
493
- describe "a FuseFS filesystem with gid/uid specific behaviour" do
494
- it "should provide context uid and gid for all API methods"
495
- end
496
-
497
- end
1
+ require 'spec_helper'
2
+
3
+ describe FuseFS do
4
+
5
+ TEST_FILE = "/aPath/aFile"
6
+ TEST_DIR = "/aPath"
7
+ ROOT_PATH = "/"
8
+ Struct.new("FuseFileInfo",:flags,:fh)
9
+
10
+ describe "an empty Root object" do
11
+ before(:each) do
12
+ @fuse = FuseFS::Fuse::Root.new(Object.new())
13
+ end
14
+
15
+ it "should return an appropriate Stat for the root directory" do
16
+ stat = @fuse.getattr(nil,ROOT_PATH)
17
+ expect(stat).to respond_to(:dev)
18
+ expect(stat.mode & RFuse::Stat::S_IFDIR).not_to eq(0)
19
+ expect(stat.mode & RFuse::Stat::S_IFREG).to eq(0)
20
+ expect(permissions(stat.mode)).to eq(0555)
21
+ end
22
+
23
+ it "should have an empty root directory" do
24
+ filler = double("entries_filler")
25
+ expect(filler).to receive(:push).with(".",nil,0)
26
+ expect(filler).to receive(:push).with("..",nil,0)
27
+ @fuse.readdir(nil,"/",filler,nil,nil)
28
+ end
29
+
30
+ it "should raise ENOENT for other paths" do
31
+ expect { @fuse.getattr(nil,"/somepath") }.to raise_error(Errno::ENOENT)
32
+ end
33
+
34
+ it "should not allow new files or directories" do
35
+ expect { @fuse.mknod(nil,"/afile",0100644,0,0) }.to raise_error(Errno::EACCES)
36
+ expect { @fuse.mkdir(nil,"/adir",0040555) }.to raise_error(Errno::EACCES)
37
+ end
38
+ end
39
+
40
+ describe "a FuseFS filesystem" do
41
+ before(:each) do
42
+ @mock_fuse = FuseFS::FuseDir.new()
43
+ @fuse = FuseFS::Fuse::Root.new(@mock_fuse)
44
+ end
45
+
46
+ context("handling signals") do
47
+ it "should pass on signals" do
48
+ expect(@mock_fuse).to receive(:sighup) { }
49
+ fuse = FuseFS::Fuse::Root.new(@mock_fuse)
50
+ fuse.sighup
51
+ end
52
+ end
53
+
54
+ describe :readdir do
55
+ before(:each) do
56
+ expect(@mock_fuse).to receive(:contents).with("/apath").and_return(["afile"])
57
+ end
58
+
59
+ it "should add . and .. to the results of :contents when listing a directory" do
60
+ filler = double("entries_filler")
61
+ expect(filler).to receive(:push).with(".",nil,0)
62
+ expect(filler).to receive(:push).with("..",nil,0)
63
+ expect(filler).to receive(:push).with("afile",nil,0)
64
+ @fuse.readdir(nil,"/apath",filler,nil,nil)
65
+ end
66
+
67
+ end
68
+
69
+ describe :getattr do
70
+
71
+ #Root directory is special (ish) so we need to run these specs twice.
72
+ [ROOT_PATH,TEST_DIR].each do |dir|
73
+
74
+ context "of a directory #{ dir }" do
75
+
76
+ before(:each) do
77
+ allow(@mock_fuse).to receive(:file?).and_return(false)
78
+ expect(@mock_fuse).to receive(:directory?).with(dir).at_most(:once).and_return(true)
79
+ @checkfile = (dir == "/" ? "" : dir ) + FuseFS::Fuse::Root::CHECK_FILE
80
+ end
81
+
82
+ it "should return a Stat like object representing a directory" do
83
+ expect(@mock_fuse).to receive(:can_write?).with(@checkfile).at_most(:once).and_return(false)
84
+ expect(@mock_fuse).to receive(:can_mkdir?).with(@checkfile).at_most(:once).and_return(false)
85
+ stat = @fuse.getattr(nil,dir)
86
+ #Apparently find relies on nlink accurately listing the number of files/directories or nlink being 1
87
+ expect(stat.nlink).to eq(1)
88
+ expect(filetype(stat.mode)).to eq(RFuse::Stat::S_IFDIR)
89
+ expect(permissions(stat.mode)).to eq(0555)
90
+ end
91
+
92
+
93
+ it "should return writable mode if can_mkdir?" do
94
+ expect(@mock_fuse).to receive(:can_mkdir?).with(@checkfile).at_most(:once).and_return(true)
95
+
96
+ stat = @fuse.getattr(nil,dir)
97
+ expect(permissions(stat.mode)).to eq(0777)
98
+ end
99
+
100
+ it "should return writable mode if can_write?" do
101
+ expect(@mock_fuse).to receive(:can_write?).with(@checkfile).at_most(:once).and_return(true)
102
+
103
+ stat = @fuse.getattr(nil,dir)
104
+ expect(permissions(stat.mode)).to eq(0777)
105
+
106
+ end
107
+
108
+ it "should return times in the result if available" do
109
+ expect(@mock_fuse).to receive(:times).with(dir).and_return([10,20,30])
110
+ stat = @fuse.getattr(nil,dir)
111
+ expect(stat.atime).to eq(10)
112
+ expect(stat.mtime).to eq(20)
113
+ expect(stat.ctime).to eq(30)
114
+ end
115
+ end
116
+ end
117
+
118
+ describe "a file" do
119
+
120
+ before(:each) do
121
+ @file="/aPath/aFile"
122
+ allow(@mock_fuse).to receive(:directory?).and_return(false)
123
+ expect(@mock_fuse).to receive(:file?).with(@file).at_most(:once).and_return(true)
124
+ end
125
+
126
+
127
+ it "should return a Stat like object representing a file" do
128
+ stat = @fuse.getattr(nil,@file)
129
+ expect(stat.mode & RFuse::Stat::S_IFDIR).to eq(0)
130
+ expect(stat.mode & RFuse::Stat::S_IFREG).not_to eq(0)
131
+ expect(permissions(stat.mode)).to eq(0444)
132
+ end
133
+
134
+ it "should indicate executable mode if executable?" do
135
+ expect(@mock_fuse).to receive(:executable?).with(@file).and_return(true)
136
+ stat = @fuse.getattr(nil,@file)
137
+ expect(permissions(stat.mode)).to eq(0555)
138
+ end
139
+
140
+ it "should indicate writable mode if can_write?" do
141
+ expect(@mock_fuse).to receive(:can_write?).with(@file).and_return(true)
142
+ stat = @fuse.getattr(nil,@file)
143
+ expect(permissions(stat.mode)).to eq(0666)
144
+ end
145
+
146
+ it "should by 777 mode if can_write? and exectuable?" do
147
+ expect(@mock_fuse).to receive(:can_write?).with(@file).and_return(true)
148
+ expect(@mock_fuse).to receive(:executable?).with(@file).and_return(true)
149
+ stat = @fuse.getattr(nil,@file)
150
+ expect(permissions(stat.mode)).to eq(0777)
151
+ end
152
+
153
+ it "should include size in the result if available" do
154
+ expect(@mock_fuse).to receive(:size).with(@file).and_return(234)
155
+ stat = @fuse.getattr(nil,@file)
156
+ expect(stat.size).to eq(234)
157
+ end
158
+
159
+ it "should include times in the result if available" do
160
+ expect(@mock_fuse).to receive(:times).with(@file).and_return([22,33,44])
161
+ stat = @fuse.getattr(nil,@file)
162
+ expect(stat.atime).to eq(22)
163
+ expect(stat.mtime).to eq(33)
164
+ expect(stat.ctime).to eq(44)
165
+ end
166
+ end
167
+
168
+ it "should raise ENOENT for a path that does not exist" do
169
+ expect(@mock_fuse).to receive(:file?).with(TEST_FILE).and_return(false)
170
+ expect(@mock_fuse).to receive(:directory?).with(TEST_FILE).and_return(false)
171
+ expect{stat = @fuse.getattr(nil,TEST_FILE) }.to raise_error(Errno::ENOENT)
172
+ end
173
+ end
174
+
175
+ context "creating files and directories" do
176
+
177
+ it ":mknod should raise EACCES unless :can_write?" do
178
+ allow(@mock_fuse).to receive(:file?).with(TEST_FILE).and_return(false)
179
+ allow(@mock_fuse).to receive(:directory?).with(TEST_FILE).and_return(false)
180
+ expect(@mock_fuse).to receive(:can_write?).with(TEST_FILE).and_return(false)
181
+ expect{@fuse.mknod(nil,TEST_FILE,0100644,0,0)}.to raise_error(Errno::EACCES)
182
+ end
183
+
184
+ it ":mkdir should raise EACCES unless :can_mkdir?" do
185
+ allow(@mock_fuse).to receive(:file?).with(TEST_FILE).and_return(false)
186
+ allow(@mock_fuse).to receive(:directory?).with(TEST_FILE).and_return(false)
187
+ expect(@mock_fuse).to receive(:can_mkdir?).with(TEST_FILE).and_return(false)
188
+ expect{@fuse.mkdir(nil,TEST_FILE,004555)}.to raise_error(Errno::EACCES)
189
+ end
190
+
191
+ it ":mknod should raise EACCES unless mode requests a regular file" do
192
+ allow(@mock_fuse).to receive(:file?).with(TEST_FILE).and_return(false)
193
+ allow(@mock_fuse).to receive(:directory?).with(TEST_FILE).and_return(false)
194
+ allow(@mock_fuse).to receive(:can_write?).with(TEST_FILE).and_return(true)
195
+ expect{@fuse.mknod(nil,TEST_FILE,RFuse::Stat::S_IFLNK | 0644,0,0)}.to raise_error(Errno::EACCES)
196
+ end
197
+
198
+ it ":mknod should result in getattr returning a Stat like object representing an empty file" do
199
+ allow(@mock_fuse).to receive(:file?).with(TEST_FILE).and_return(false)
200
+ allow(@mock_fuse).to receive(:directory?).with(TEST_FILE).and_return(false)
201
+ allow(@mock_fuse).to receive(:can_write?).with(TEST_FILE).and_return(true)
202
+ @fuse.mknod(nil,TEST_FILE,RFuse::Stat::S_IFREG | 0644,0,0)
203
+
204
+ stat = @fuse.getattr(nil,TEST_FILE)
205
+ expect(filetype(stat.mode)).to eq(RFuse::Stat::S_IFREG)
206
+ expect(stat.size).to eq(0)
207
+ end
208
+
209
+ it "should create zero length files" do
210
+ ffi = Struct::FuseFileInfo.new()
211
+ ffi.flags = Fcntl::O_WRONLY
212
+ allow(@mock_fuse).to receive(:file?).with(TEST_FILE).and_return(false)
213
+ allow(@mock_fuse).to receive(:directory?).with(TEST_FILE).and_return(false)
214
+ allow(@mock_fuse).to receive(:can_write?).with(TEST_FILE).and_return(true)
215
+ expect(@mock_fuse).to receive(:write_to).once.with(TEST_FILE,"")
216
+ @fuse.mknod(nil,TEST_FILE,RFuse::Stat::S_IFREG | 0644,0,0)
217
+ @fuse.open(nil,TEST_FILE,ffi)
218
+ @fuse.flush(nil,TEST_FILE,ffi)
219
+ @fuse.release(nil,TEST_FILE,ffi)
220
+ end
221
+
222
+ it ":mkdir should not raise error if can_mkdir?" do
223
+ expect(@mock_fuse).to receive(:can_mkdir?).with(TEST_FILE).and_return(true)
224
+ @fuse.mkdir(nil,TEST_FILE,004555)
225
+ end
226
+
227
+ end
228
+
229
+ context "reading files" do
230
+ it "should read the contents of a file" do
231
+ ffi = Struct::FuseFileInfo.new()
232
+ ffi.flags = Fcntl::O_RDONLY
233
+ allow(@mock_fuse).to receive(:file?).with(TEST_FILE).and_return(true)
234
+ allow(@mock_fuse).to receive(:read_file).with(TEST_FILE).and_return("Hello World\n")
235
+ @fuse.open(nil,TEST_FILE,ffi)
236
+ #to me fuse is backwards -- size, offset!
237
+ expect(@fuse.read(nil,TEST_FILE,5,0,ffi)).to eq("Hello")
238
+ expect(@fuse.read(nil,TEST_FILE,4,6,ffi)).to eq("Worl")
239
+ expect(@fuse.read(nil,TEST_FILE,10,8,ffi)).to eq("rld\n")
240
+ @fuse.flush(nil,TEST_FILE,ffi)
241
+ @fuse.release(nil,TEST_FILE,ffi)
242
+ end
243
+ end
244
+
245
+ context "writing files" do
246
+ it "should overwrite a file opened WR_ONLY" do
247
+ ffi = Struct::FuseFileInfo.new()
248
+ ffi.flags = Fcntl::O_WRONLY
249
+ allow(@mock_fuse).to receive(:can_write?).with(TEST_FILE).and_return(true)
250
+ allow(@mock_fuse).to receive(:read_file).with(TEST_FILE).and_return("I'm writing a file\n")
251
+ expect(@mock_fuse).to receive(:write_to).once().with(TEST_FILE,"My new contents\n")
252
+ @fuse.open(nil,TEST_FILE,ffi)
253
+ @fuse.ftruncate(nil,TEST_FILE,0,ffi)
254
+ @fuse.write(nil,TEST_FILE,"My new c",0,ffi)
255
+ @fuse.write(nil,TEST_FILE,"ontents\n",8,ffi)
256
+ @fuse.flush(nil,TEST_FILE,ffi)
257
+ #that's right flush can be called more than once.
258
+ @fuse.flush(nil,TEST_FILE,ffi)
259
+ #but then we can write some more and flush again
260
+ @fuse.release(nil,TEST_FILE,ffi)
261
+ end
262
+
263
+ it "should append to a file opened WR_ONLY | APPEND" do
264
+ ffi = Struct::FuseFileInfo.new()
265
+ ffi.flags = Fcntl::O_WRONLY | Fcntl::O_APPEND
266
+ allow(@mock_fuse).to receive(:can_write?).with(TEST_FILE).and_return(true)
267
+ allow(@mock_fuse).to receive(:read_file).with(TEST_FILE).and_return("I'm writing a file\n")
268
+ expect(@mock_fuse).to receive(:write_to).once().with(TEST_FILE,"I'm writing a file\nMy new contents\n")
269
+ @fuse.open(nil,TEST_FILE,ffi)
270
+ @fuse.write(nil,TEST_FILE,"My new c",0,ffi)
271
+ @fuse.write(nil,TEST_FILE,"ontents\n",8,ffi)
272
+ @fuse.flush(nil,TEST_FILE,ffi)
273
+ #that's right flush can be called more than once. But we should only write-to the first time
274
+ @fuse.flush(nil,TEST_FILE,ffi)
275
+ @fuse.release(nil,TEST_FILE,ffi)
276
+
277
+ end
278
+
279
+ it "should do sensible things for files opened RDWR"
280
+
281
+ it "should pass on buffered data when requested (fsync)"
282
+
283
+ end
284
+
285
+ context "raw reading" do
286
+
287
+ it "should call the raw_read/raw_close if raw_open returns true" do
288
+ ffi = Struct::FuseFileInfo.new()
289
+ ffi.flags = Fcntl::O_RDONLY
290
+ allow(@mock_fuse).to receive(:can_write?).with(TEST_FILE).and_return(true)
291
+ expect(@mock_fuse).to receive(:raw_open).with(TEST_FILE,"r",true).and_return("raw")
292
+ expect(@mock_fuse).to receive(:raw_read).with(TEST_FILE,5,0,"raw").and_return("12345")
293
+ expect(@mock_fuse).to receive(:raw_read).with(TEST_FILE,5,5,"raw").and_return("67890")
294
+ expect(@mock_fuse).to receive(:raw_close).with(TEST_FILE,"raw")
295
+ @fuse.open(nil,TEST_FILE,ffi)
296
+ expect(@fuse.read(nil,TEST_FILE,0,5,ffi)).to eq("12345")
297
+ expect(@fuse.read(nil,TEST_FILE,5,5,ffi)).to eq("67890")
298
+ @fuse.flush(nil,TEST_FILE,ffi)
299
+ @fuse.release(nil,TEST_FILE,ffi)
300
+ end
301
+
302
+ end
303
+
304
+ context "raw writing" do
305
+ it "should call other raw_* methods if raw_open returns true" do
306
+ ffi = Struct::FuseFileInfo.new()
307
+ ffi.flags = Fcntl::O_WRONLY
308
+ raw = Object.new()
309
+ allow(@mock_fuse).to receive(:can_write?).with(TEST_FILE).and_return(true)
310
+ expect(@mock_fuse).to receive(:raw_open).with(TEST_FILE,"w",true).and_return(raw)
311
+ expect(@mock_fuse).to receive(:raw_truncate).with(TEST_FILE,0,raw)
312
+ expect(@mock_fuse).to receive(:raw_write).with(TEST_FILE,0,5,"12345",raw).once().and_return(5)
313
+ expect(@mock_fuse).to receive(:raw_write).with(TEST_FILE,5,5,"67890",raw).once().and_return(5)
314
+ expect(@mock_fuse).to receive(:raw_sync).with(TEST_FILE, false, raw)
315
+ expect(@mock_fuse).to receive(:raw_close).with(TEST_FILE,raw)
316
+ @fuse.open(nil,TEST_FILE,ffi)
317
+ @fuse.ftruncate(nil,TEST_FILE,0,ffi)
318
+ expect(@fuse.write(nil,TEST_FILE,"12345",0,ffi)).to eq(5)
319
+ @fuse.fsync(nil,TEST_FILE,0,ffi)
320
+ expect(@fuse.write(nil,TEST_FILE,"67890",5,ffi)).to eq(5)
321
+ @fuse.flush(nil,TEST_FILE,ffi)
322
+ @fuse.release(nil,TEST_FILE,ffi)
323
+ end
324
+
325
+ it "should clean up created files" do
326
+ ffi = Struct::FuseFileInfo.new()
327
+ ffi.flags = Fcntl::O_WRONLY
328
+ raw = Object.new()
329
+ allow(@mock_fuse).to receive(:directory?).and_return(false)
330
+ allow(@mock_fuse).to receive(:file?).with(TEST_FILE).and_return(false,true)
331
+ allow(@mock_fuse).to receive(:can_write?).with(TEST_FILE).and_return(true)
332
+ expect(@mock_fuse).to receive(:raw_open).with(TEST_FILE,"w",true).and_return(raw)
333
+ expect(@mock_fuse).to receive(:raw_close).with(TEST_FILE,raw)
334
+ expect(@mock_fuse).to receive(:size).with(TEST_FILE).and_return(25)
335
+
336
+ expect { @fuse.getattr(nil,TEST_FILE) }.to raise_error(Errno::ENOENT)
337
+ @fuse.mknod(nil,TEST_FILE,RFuse::Stat::S_IFREG | 0644,0,0)
338
+ @fuse.open(nil,TEST_FILE,ffi)
339
+ @fuse.flush(nil,TEST_FILE,ffi)
340
+ @fuse.release(nil,TEST_FILE,ffi)
341
+ stat = @fuse.getattr(nil,TEST_FILE)
342
+ stat.size = 25
343
+ end
344
+
345
+ it "should pass 'wa' to raw_open if fuse sends WRONLY | APPEND" do
346
+ ffi = Struct::FuseFileInfo.new()
347
+ ffi.flags = Fcntl::O_WRONLY | Fcntl::O_APPEND
348
+ raw = Object.new()
349
+ allow(@mock_fuse).to receive(:can_write?).with(TEST_FILE).and_return(true)
350
+ expect(@mock_fuse).to receive(:raw_open).with(TEST_FILE,"wa",true).and_return(raw)
351
+ @fuse.open(nil,TEST_FILE,ffi)
352
+ end
353
+ end
354
+
355
+ context "deleting files" do
356
+ it "should raise EACCES unless :can_delete?" do
357
+ expect(@mock_fuse).to receive(:can_delete?).with(TEST_FILE).and_return(false)
358
+ expect {@fuse.unlink(nil,TEST_FILE)}.to raise_error(Errno::EACCES)
359
+ end
360
+
361
+ it "should :delete without error if :can_delete?" do
362
+ allow(@mock_fuse).to receive(:can_delete?).with(TEST_FILE).and_return(true)
363
+ expect(@mock_fuse).to receive(:delete).with(TEST_FILE)
364
+ @fuse.unlink(nil,TEST_FILE)
365
+ end
366
+
367
+ it "should remove entries created with mknod that have never been opened" do
368
+ allow(@mock_fuse).to receive(:file?).with(TEST_FILE).and_return(false)
369
+ allow(@mock_fuse).to receive(:directory?).with(TEST_FILE).and_return(false)
370
+ allow(@mock_fuse).to receive(:can_delete?).with(TEST_FILE).and_return(true)
371
+ allow(@mock_fuse).to receive(:can_write?).with(TEST_FILE).and_return(true)
372
+ @fuse.mknod(nil,TEST_FILE,RFuse::Stat::S_IFREG | 0644,0,0)
373
+
374
+ @fuse.unlink(nil,TEST_FILE)
375
+ expect {@fuse.getattr(nil,TEST_FILE)}.to raise_error(Errno::ENOENT)
376
+ end
377
+ end
378
+
379
+ context "deleting directories" do
380
+ it "should raise EACCES unless :can_rmdir?" do
381
+ expect(@mock_fuse).to receive(:can_rmdir?).with(TEST_DIR).and_return(false)
382
+ expect{@fuse.rmdir(nil,TEST_DIR)}.to raise_error(Errno::EACCES)
383
+ end
384
+
385
+ it "should :rmdir without error if :can_rmdir?" do
386
+ allow(@mock_fuse).to receive(:can_rmdir?).with(TEST_DIR).and_return(true)
387
+ @fuse.rmdir(nil,TEST_DIR)
388
+ end
389
+ end
390
+
391
+ context "touching files" do
392
+ it "should call :touch in response to utime" do
393
+ expect(@mock_fuse).to receive(:touch).with(TEST_FILE,220)
394
+ @fuse.utime(nil,TEST_FILE,100,220)
395
+ end
396
+ end
397
+
398
+ context "renaming files" do
399
+ before(:each) do
400
+ @oldfile = "/aPath/oldFile"
401
+ @newfile = "/aNewFile"
402
+ allow(@mock_fuse).to receive(:file?).with(@oldfile).and_return(true)
403
+ allow(@mock_fuse).to receive(:directory?).with(@oldfile).and_return(false)
404
+ end
405
+ it "should raise EACCES unless :can_write? the new file" do
406
+ allow(@mock_fuse).to receive(:can_delete?).with(@oldfile).and_return(true)
407
+ expect(@mock_fuse).to receive(:can_write?).with(@newfile).and_return(false)
408
+ expect {@fuse.rename(nil,@oldfile,@newfile)}.to raise_error(Errno::EACCES)
409
+ end
410
+
411
+ it "should raise EACCES unless :can_delete the old file" do
412
+ allow(@mock_fuse).to receive(:can_write?).with(@newfile).and_return(true)
413
+ expect(@mock_fuse).to receive(:can_delete?).with(@oldfile).and_return(false)
414
+ expect {@fuse.rename(nil,@oldfile,@newfile)}.to raise_error(Errno::EACCES)
415
+ end
416
+
417
+ it "should copy and delete files" do
418
+ allow(@mock_fuse).to receive(:can_write?).with(@newfile).and_return(true)
419
+ allow(@mock_fuse).to receive(:can_delete?).with(@oldfile).and_return(true)
420
+ expect(@mock_fuse).to receive(:read_file).with(@oldfile).and_return("some contents\n")
421
+ expect(@mock_fuse).to receive(:write_to).with(@newfile,"some contents\n")
422
+ expect(@mock_fuse).to receive(:delete).with(@oldfile)
423
+ @fuse.rename(nil,@oldfile,@newfile)
424
+ end
425
+
426
+ it "should not copy and delete files if fs responds_to? :rename" do
427
+ expect(@mock_fuse).to receive(:rename).with(@oldfile,@newfile).and_return(true)
428
+ @fuse.rename(nil,@oldfile,@newfile)
429
+ end
430
+
431
+ it "should raise EACCES if moving a directory and rename not supported" do
432
+ allow(@mock_fuse).to receive(:file?).with(@oldfile).and_return(false)
433
+ allow(@mock_fuse).to receive(:directory?).with(@oldfile).and_return(true)
434
+ allow(@mock_fuse).to receive(:can_write?).with(@newfile).and_return(true)
435
+ allow(@mock_fuse).to receive(:can_delete?).with(@oldfile).and_return(true)
436
+ expect{@fuse.rename(nil,@oldfile,@newfile)}.to raise_error(Errno::EACCES)
437
+ end
438
+
439
+ end
440
+ context "extended attributes" do
441
+
442
+ let(:xattr) { double(:xattr) }
443
+ before(:each) { allow(@mock_fuse).to receive(:xattr).with(TEST_FILE).and_return(xattr) }
444
+
445
+ it "should list attributes via #keys on result of #xattr" do
446
+ expect(xattr).to receive(:keys).and_return(["one","two"])
447
+ expect(@fuse.listxattr(nil,TEST_FILE)).to eq([ "one","two" ])
448
+ end
449
+
450
+ it "should get attributes via #xattr.[]" do
451
+ expect(xattr).to receive(:[]).with("user.one").and_return("one")
452
+
453
+ expect(@fuse.getxattr(nil,TEST_FILE,"user.one")).to eq("one")
454
+ end
455
+
456
+ it "should set attributes via #xattr.[]=" do
457
+ expect(xattr).to receive(:[]=).with("user.two","two")
458
+
459
+ @fuse.setxattr(nil,TEST_FILE,"user.two","two",0)
460
+ end
461
+
462
+ it "should remove attributes via #xattr.delete" do
463
+ expect(xattr).to receive(:delete).with("user.three")
464
+
465
+ @fuse.removexattr(nil,TEST_FILE,"user.three")
466
+ end
467
+
468
+ it "should raise ENODATA when #xattr.[] returns nil" do
469
+
470
+ expect(xattr).to receive(:[]).with("user.xxxx").and_return(nil)
471
+ expect{@fuse.getxattr(nil,TEST_FILE,"user.xxxx") }.to raise_error(Errno::ENODATA)
472
+ end
473
+ end
474
+
475
+ context "#statfs" do
476
+ # used space, used files, total_space, total_files
477
+ let(:stats) { [ 1000 * 1024, 5, 1200 * 1024, 12 ] }
478
+ it "should convert simple array into StatVfs" do
479
+
480
+ expect(@mock_fuse).to receive(:statistics).with(TEST_FILE).and_return(stats)
481
+
482
+ result = @fuse.statfs(nil,TEST_FILE)
483
+ expect(result).to be_kind_of(RFuse::StatVfs)
484
+ expect(result.f_bsize).to eq(1024)
485
+ expect(result.f_blocks).to eq(1200)
486
+ expect(result.f_bavail).to eq(200)
487
+ expect(result.f_files).to eq(12)
488
+ expect(result.f_ffree).to eq(7)
489
+ end
490
+
491
+ it "passes on raw statistics" do
492
+ statvfs = Object.new()
493
+ expect(@mock_fuse).to receive(:statistics).with(TEST_FILE).and_return(statvfs)
494
+
495
+ expect(@fuse.statfs(nil,TEST_FILE)).to equal(statvfs)
496
+ end
497
+
498
+ end
499
+ end
500
+
501
+ describe "a FuseFS filesystem with gid/uid specific behaviour" do
502
+ it "should provide context uid and gid for all API methods"
503
+ end
504
+
505
+ end