aleksi-rush 0.6.6

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.
Files changed (50) hide show
  1. data/README.rdoc +89 -0
  2. data/Rakefile +59 -0
  3. data/VERSION +1 -0
  4. data/bin/rush +13 -0
  5. data/bin/rushd +7 -0
  6. data/lib/rush.rb +87 -0
  7. data/lib/rush/access.rb +130 -0
  8. data/lib/rush/array_ext.rb +19 -0
  9. data/lib/rush/box.rb +115 -0
  10. data/lib/rush/commands.rb +55 -0
  11. data/lib/rush/config.rb +154 -0
  12. data/lib/rush/dir.rb +160 -0
  13. data/lib/rush/embeddable_shell.rb +26 -0
  14. data/lib/rush/entry.rb +189 -0
  15. data/lib/rush/exceptions.rb +39 -0
  16. data/lib/rush/file.rb +85 -0
  17. data/lib/rush/find_by.rb +39 -0
  18. data/lib/rush/fixnum_ext.rb +18 -0
  19. data/lib/rush/head_tail.rb +11 -0
  20. data/lib/rush/local.rb +398 -0
  21. data/lib/rush/process.rb +59 -0
  22. data/lib/rush/process_set.rb +62 -0
  23. data/lib/rush/remote.rb +158 -0
  24. data/lib/rush/search_results.rb +58 -0
  25. data/lib/rush/server.rb +117 -0
  26. data/lib/rush/shell.rb +187 -0
  27. data/lib/rush/ssh_tunnel.rb +122 -0
  28. data/lib/rush/string_ext.rb +3 -0
  29. data/spec/access_spec.rb +134 -0
  30. data/spec/array_ext_spec.rb +15 -0
  31. data/spec/base.rb +24 -0
  32. data/spec/box_spec.rb +80 -0
  33. data/spec/commands_spec.rb +47 -0
  34. data/spec/config_spec.rb +108 -0
  35. data/spec/dir_spec.rb +164 -0
  36. data/spec/embeddable_shell_spec.rb +17 -0
  37. data/spec/entry_spec.rb +133 -0
  38. data/spec/file_spec.rb +83 -0
  39. data/spec/find_by_spec.rb +58 -0
  40. data/spec/fixnum_ext_spec.rb +19 -0
  41. data/spec/local_spec.rb +364 -0
  42. data/spec/process_set_spec.rb +50 -0
  43. data/spec/process_spec.rb +73 -0
  44. data/spec/remote_spec.rb +140 -0
  45. data/spec/rush_spec.rb +28 -0
  46. data/spec/search_results_spec.rb +44 -0
  47. data/spec/shell_spec.rb +23 -0
  48. data/spec/ssh_tunnel_spec.rb +122 -0
  49. data/spec/string_ext_spec.rb +23 -0
  50. metadata +142 -0
@@ -0,0 +1,133 @@
1
+ require File.dirname(__FILE__) + '/base'
2
+
3
+ describe Rush::Entry do
4
+ before do
5
+ @sandbox_dir = "/tmp/rush_spec.#{Process.pid}/"
6
+ system "rm -rf #{@sandbox_dir}; mkdir -p #{@sandbox_dir}"
7
+
8
+ @filename = "#{@sandbox_dir}/test_file"
9
+ system "touch #{@filename}"
10
+
11
+ @entry = Rush::Entry.new(@filename)
12
+ end
13
+
14
+ after do
15
+ system "rm -rf #{@sandbox_dir}"
16
+ end
17
+
18
+ it "knows its name" do
19
+ @entry.name.should == File.basename(@filename)
20
+ end
21
+
22
+ it "knows its parent dir" do
23
+ @entry.parent.should be_kind_of(Rush::Dir)
24
+ @entry.parent.name.should == File.basename(@sandbox_dir)
25
+ @entry.parent.full_path.should == @sandbox_dir
26
+ end
27
+
28
+ it "cleans its pathname" do
29
+ Rush::Entry.new('/a//b//c').full_path.should == '/a/b/c'
30
+ Rush::Entry.new('/1/2/../3').full_path.should == '/1/3'
31
+ end
32
+
33
+ it "knows its changed_at time" do
34
+ @entry.changed_at.should == File.stat(@filename).ctime
35
+ end
36
+
37
+ it "knows its last_modified time" do
38
+ @entry.last_modified.should == File.stat(@filename).mtime
39
+ end
40
+
41
+ it "knows its last_accessed time" do
42
+ @entry.last_accessed.should == File.stat(@filename).atime
43
+ end
44
+
45
+ it "considers itself equal to other instances with the same full path" do
46
+ Rush::Entry.new('/not/the/same').should_not == @entry
47
+ Rush::Entry.new(@entry.full_path).should == @entry
48
+ end
49
+
50
+ it "can rename itself" do
51
+ new_file = "test2"
52
+
53
+ @entry.rename(new_file)
54
+
55
+ File.exists?(@filename).should be_false
56
+ File.exists?("#{@sandbox_dir}/#{new_file}").should be_true
57
+ end
58
+
59
+ it "rename returns the renamed file" do
60
+ @entry.rename('file2').should == @entry.parent['file2']
61
+ end
62
+
63
+ it "can't rename itself if another file already exists with that name" do
64
+ new_file = "test3"
65
+ system "touch #{@sandbox_dir}/#{new_file}"
66
+
67
+ lambda { @entry.rename(new_file) }.should raise_error(Rush::NameAlreadyExists, /#{new_file}/)
68
+ end
69
+
70
+ it "can't rename itself to something with a slash in it" do
71
+ lambda { @entry.rename('has/slash') }.should raise_error(Rush::NameCannotContainSlash, /slash/)
72
+ end
73
+
74
+ it "can duplicate itself within the directory" do
75
+ @entry.duplicate('newfile').should == Rush::File.new("#{@sandbox_dir}/newfile")
76
+ end
77
+
78
+ it "can move itself to another dir" do
79
+ newdir = "#{@sandbox_dir}/newdir"
80
+ system "mkdir -p #{newdir}"
81
+
82
+ dst = Rush::Dir.new(newdir)
83
+ @entry.move_to(dst)
84
+
85
+ File.exists?(@filename).should be_false
86
+ File.exists?("#{newdir}/#{@entry.name}").should be_true
87
+ end
88
+
89
+ it "can copy itself to another directory" do
90
+ newdir = "#{@sandbox_dir}/newdir"
91
+ system "mkdir -p #{newdir}"
92
+
93
+ dst = Rush::Dir.new(newdir)
94
+ @copied_dir = @entry.copy_to(dst)
95
+
96
+ File.exists?(@filename).should be_true
97
+ File.exists?("#{newdir}/#{@entry.name}").should be_true
98
+
99
+ @copied_dir.full_path.should == "#{@sandbox_dir}newdir/#{@entry.name}"
100
+ end
101
+
102
+ it "considers dotfiles to be hidden" do
103
+ Rush::Entry.new("#{@sandbox_dir}/show").should_not be_hidden
104
+ Rush::Entry.new("#{@sandbox_dir}/.dont_show").should be_hidden
105
+ end
106
+
107
+ it "is considered equal to entries with the same full path and on the same box" do
108
+ same = Rush::Entry.new(@entry.full_path, @entry.box)
109
+ @entry.should == same
110
+ end
111
+
112
+ it "is considered not equal to entries with the same full path on a different box" do
113
+ same = Rush::Entry.new(@entry.full_path, Rush::Box.new('dummy'))
114
+ @entry.should_not == same
115
+ end
116
+
117
+ it "can mimic another entry" do
118
+ copy = Rush::Entry.new('abc', :dummy)
119
+ copy.mimic(@entry)
120
+ copy.path.should == @entry.path
121
+ end
122
+
123
+ it "can update the read access permission" do
124
+ system "chmod 666 #{@filename}"
125
+ @entry.access = { :user_can => :read }
126
+ `ls -l #{@filename}`.should match(/^-r--------/)
127
+ end
128
+
129
+ it "reads the file permissions in the access hash" do
130
+ system "chmod 640 #{@filename}"
131
+ @entry.access.should == { :user_can_read => true, :user_can_write => true, :group_can_read => true }
132
+ end
133
+ end
data/spec/file_spec.rb ADDED
@@ -0,0 +1,83 @@
1
+ require File.dirname(__FILE__) + '/base'
2
+
3
+ describe Rush::File do
4
+ before do
5
+ @sandbox_dir = "/tmp/rush_spec.#{Process.pid}"
6
+ system "rm -rf #{@sandbox_dir}; mkdir -p #{@sandbox_dir}"
7
+
8
+ @filename = "#{@sandbox_dir}/test_file"
9
+ @contents = "1234"
10
+ system "echo #{@contents} > #{@filename}"
11
+ @contents += "\n"
12
+
13
+ @file = Rush::File.new(@filename)
14
+ end
15
+
16
+ after do
17
+ system "rm -rf #{@sandbox_dir}"
18
+ end
19
+
20
+ it "is a child of Rush::Entry" do
21
+ @file.should be_kind_of(Rush::Entry)
22
+ end
23
+
24
+ it "is not a dir" do
25
+ @file.should_not be_dir
26
+ end
27
+
28
+ it "can create itself as a blank file, and return itself" do
29
+ create_me = Rush::File.new("#{@sandbox_dir}/create_me")
30
+ create_me.create.should == create_me
31
+ File.exists?("#{@sandbox_dir}/create_me").should == true
32
+ end
33
+
34
+ it "knows its size in bytes" do
35
+ @file.size.should == @contents.length
36
+ end
37
+
38
+ it "can read its contents" do
39
+ @file.contents.should == @contents
40
+ end
41
+
42
+ it "read is an alias for contents" do
43
+ @file.read.should == @contents
44
+ end
45
+
46
+ it "can write new contents" do
47
+ @file.write('write test')
48
+ @file.contents.should == 'write test'
49
+ end
50
+
51
+ it "can count the number of lines it contains" do
52
+ @file.write("1\n2\n3\n")
53
+ @file.line_count.should == 3
54
+ end
55
+
56
+ it "searches its contents for matching lines" do
57
+ @file.write("a\n1\nb\n2\n")
58
+ @file.search(/\d/).should == %w(1 2)
59
+ end
60
+
61
+ it "search returns nil if no lines match" do
62
+ @file.write("a\nb\nc\n")
63
+ @file.search(/\d/).should be_nil
64
+ end
65
+
66
+ it "find-in-file replace" do
67
+ @file.replace_contents!(/\d/, 'x')
68
+ @file.contents.should == "xxxx\n"
69
+ end
70
+
71
+ it "can destroy itself" do
72
+ @file.destroy
73
+ ::File.exists?(@filename).should be_false
74
+ end
75
+
76
+ it "can fetch contents or blank if doesn't exist" do
77
+ Rush::File.new('/does/not/exist').contents_or_blank.should == ""
78
+ end
79
+
80
+ it "can fetch lines, or empty if doesn't exist" do
81
+ Rush::File.new('/does/not/exist').lines_or_empty.should == []
82
+ end
83
+ end
@@ -0,0 +1,58 @@
1
+ require File.dirname(__FILE__) + '/base'
2
+
3
+ describe Rush::FindBy do
4
+ before do
5
+ class Foo
6
+ attr_accessor :bar
7
+
8
+ def initialize(bar)
9
+ @bar = bar
10
+ end end
11
+
12
+ @one = Foo.new('one')
13
+ @two = Foo.new('two')
14
+ @three = Foo.new('three')
15
+
16
+ @list = [ @one, @two, @three ]
17
+ end
18
+
19
+ it "compare_or_match exact match success" do
20
+ @list.compare_or_match('1', '1').should == true
21
+ end
22
+
23
+ it "compare_or_match exact match failure" do
24
+ @list.compare_or_match('1', '2').should == false
25
+ end
26
+
27
+ it "compare_or_match regexp match success" do
28
+ @list.compare_or_match('123', /2/).should == true
29
+ end
30
+
31
+ it "compare_or_match regexp match failure" do
32
+ @list.compare_or_match('123', /x/).should == false
33
+ end
34
+
35
+ it "find_by_ extact match" do
36
+ @list.find_by_bar('two').should == @two
37
+ end
38
+
39
+ it "find_by_ regexp match" do
40
+ @list.find_by_bar(/.hree/).should == @three
41
+ end
42
+
43
+ it "find_all_by_ exact match" do
44
+ @list.find_all_by_bar('one').should == [ @one ]
45
+ end
46
+
47
+ it "find_all_by_ regexp match" do
48
+ @list.find_all_by_bar(/^...$/).should == [ @one, @two ]
49
+ end
50
+
51
+ it "find_by_ with field not recognized by objects raises no errors" do
52
+ @list.find_by_nothing('x')
53
+ end
54
+
55
+ it "raises NoMethodError for things other than find_by" do
56
+ lambda { @list.does_not_exist }.should raise_error(NoMethodError)
57
+ end
58
+ end
@@ -0,0 +1,19 @@
1
+ require File.dirname(__FILE__) + '/base'
2
+
3
+ describe Fixnum do
4
+ before do
5
+ @num = 2
6
+ end
7
+
8
+ it "counts kb" do
9
+ @num.kb.should == 2*1024
10
+ end
11
+
12
+ it "counts mb" do
13
+ @num.mb.should == 2*1024*1024
14
+ end
15
+
16
+ it "counts gb" do
17
+ @num.gb.should == 2*1024*1024*1024
18
+ end
19
+ end
@@ -0,0 +1,364 @@
1
+ require File.dirname(__FILE__) + '/base'
2
+
3
+ describe Rush::Connection::Local do
4
+ before do
5
+ @sandbox_dir = "/tmp/rush_spec.#{Process.pid}"
6
+ system "rm -rf #{@sandbox_dir}; mkdir -p #{@sandbox_dir}"
7
+
8
+ @con = Rush::Connection::Local.new
9
+ end
10
+
11
+ after do
12
+ system "rm -rf #{@sandbox_dir}"
13
+ end
14
+
15
+ it "receive -> write_file(file, contents)" do
16
+ @con.should_receive(:write_file).with('file', 'contents')
17
+ @con.receive(:action => 'write_file', :full_path => 'file', :payload => 'contents')
18
+ end
19
+
20
+ it "receive -> append_to_file(file, contents)" do
21
+ @con.should_receive(:append_to_file).with('file', 'contents')
22
+ @con.receive(:action => 'append_to_file', :full_path => 'file', :payload => 'contents')
23
+ end
24
+
25
+ it "receive -> file_contents(file)" do
26
+ @con.should_receive(:file_contents).with('file').and_return('the contents')
27
+ @con.receive(:action => 'file_contents', :full_path => 'file').should == 'the contents'
28
+ end
29
+
30
+ it "receive -> destroy(file or dir)" do
31
+ @con.should_receive(:destroy).with('file')
32
+ @con.receive(:action => 'destroy', :full_path => 'file')
33
+ end
34
+
35
+ it "receive -> purge(dir)" do
36
+ @con.should_receive(:purge).with('dir')
37
+ @con.receive(:action => 'purge', :full_path => 'dir')
38
+ end
39
+
40
+ it "receive -> create_dir(path)" do
41
+ @con.should_receive(:create_dir).with('dir')
42
+ @con.receive(:action => 'create_dir', :full_path => 'dir')
43
+ end
44
+
45
+ it "receive -> rename(path, name, new_name)" do
46
+ @con.should_receive(:rename).with('path', 'name', 'new_name')
47
+ @con.receive(:action => 'rename', :path => 'path', :name => 'name', :new_name => 'new_name')
48
+ end
49
+
50
+ it "receive -> copy(src, dst)" do
51
+ @con.should_receive(:copy).with('src', 'dst')
52
+ @con.receive(:action => 'copy', :src => 'src', :dst => 'dst')
53
+ end
54
+
55
+ it "receive -> read_archive(full_path)" do
56
+ @con.should_receive(:read_archive).with('full_path').and_return('archive data')
57
+ @con.receive(:action => 'read_archive', :full_path => 'full_path').should == 'archive data'
58
+ end
59
+
60
+ it "receive -> write_archive(archive, dir)" do
61
+ @con.should_receive(:write_archive).with('archive', 'dir')
62
+ @con.receive(:action => 'write_archive', :dir => 'dir', :payload => 'archive')
63
+ end
64
+
65
+ it "receive -> index(base_path, glob)" do
66
+ @con.should_receive(:index).with('base_path', '*').and_return(%w(1 2))
67
+ @con.receive(:action => 'index', :base_path => 'base_path', :glob => '*').should == "1\n2\n"
68
+ end
69
+
70
+ it "receive -> stat(full_path)" do
71
+ @con.should_receive(:stat).with('full_path').and_return(1 => 2)
72
+ @con.receive(:action => 'stat', :full_path => 'full_path').should == YAML.dump(1 => 2)
73
+ end
74
+
75
+ it "receive -> set_access(full_path, user, group, permissions)" do
76
+ access = mock("access")
77
+ Rush::Access.should_receive(:from_hash).with(:action => 'set_access', :full_path => 'full_path', :user => 'joe').and_return(access)
78
+
79
+ @con.should_receive(:set_access).with('full_path', access)
80
+ @con.receive(:action => 'set_access', :full_path => 'full_path', :user => 'joe')
81
+ end
82
+
83
+ it "receive -> size(full_path)" do
84
+ @con.should_receive(:size).with('full_path').and_return("1024")
85
+ @con.receive(:action => 'size', :full_path => 'full_path').should == "1024"
86
+ end
87
+
88
+ it "receive -> processes" do
89
+ @con.should_receive(:processes).with().and_return([ { :pid => 1 } ])
90
+ @con.receive(:action => 'processes').should == YAML.dump([ { :pid => 1 } ])
91
+ end
92
+
93
+ it "receive -> process_alive" do
94
+ @con.should_receive(:process_alive).with(123).and_return(true)
95
+ @con.receive(:action => 'process_alive', :pid => 123).should == '1'
96
+ end
97
+
98
+ it "receive -> kill_process" do
99
+ @con.should_receive(:kill_process).with(123, :wait => 10).and_return(true)
100
+ @con.receive(:action => 'kill_process', :pid => '123', :payload => YAML.dump(:wait => 10))
101
+ end
102
+
103
+ it "receive -> bash (reset environment)" do
104
+ @con.should_receive(:bash).with('cmd', 'user', false, true).and_return('output')
105
+ @con.receive(:action => 'bash', :payload => 'cmd', :user => 'user', :background => 'false', :reset_environment => 'true').should == 'output'
106
+ end
107
+
108
+ it "receive -> bash (foreground)" do
109
+ @con.should_receive(:bash).with('cmd', 'user', false, false).and_return('output')
110
+ @con.receive(:action => 'bash', :payload => 'cmd', :user => 'user', :background => 'false').should == 'output'
111
+ end
112
+
113
+ it "receive -> bash (background)" do
114
+ @con.should_receive(:bash).with('cmd', 'user', true, false).and_return('output')
115
+ @con.receive(:action => 'bash', :payload => 'cmd', :user => 'user', :background => 'true').should == 'output'
116
+ end
117
+
118
+ it "receive -> unknown action exception" do
119
+ lambda { @con.receive(:action => 'does_not_exist') }.should raise_error(Rush::Connection::Local::UnknownAction)
120
+ end
121
+
122
+ it "write_file writes contents to a file" do
123
+ fname = "#{@sandbox_dir}/a_file"
124
+ data = "some data"
125
+ @con.write_file(fname, data)
126
+ File.read(fname).should == data
127
+ end
128
+
129
+ it "append_to_file appends contents to a file" do
130
+ fname = "#{@sandbox_dir}/a_file"
131
+ system "echo line1 > #{fname}"
132
+ @con.append_to_file(fname, 'line2')
133
+ File.read(fname).should == "line1\nline2"
134
+ end
135
+
136
+ it "file_contents reads a file's contents" do
137
+ fname = "#{@sandbox_dir}/a_file"
138
+ system "echo stuff > #{fname}"
139
+ @con.file_contents(fname).should == "stuff\n"
140
+ end
141
+
142
+ it "file_contents raises DoesNotExist if the file does not exist" do
143
+ fname = "#{@sandbox_dir}/does_not_exist"
144
+ lambda { @con.file_contents(fname) }.should raise_error(Rush::DoesNotExist, fname)
145
+ end
146
+
147
+ it "destroy to destroy a file or dir" do
148
+ fname = "#{@sandbox_dir}/delete_me"
149
+ system "touch #{fname}"
150
+ @con.destroy(fname)
151
+ File.exists?(fname).should be_false
152
+ end
153
+
154
+ it "purge to purge a dir" do
155
+ system "cd #{@sandbox_dir}; touch {1,2}; mkdir 3; touch 3/4"
156
+ @con.purge(@sandbox_dir)
157
+ File.exists?(@sandbox_dir).should be_true
158
+ Dir.glob("#{@sandbox_dir}/*").should == []
159
+ end
160
+
161
+ it "purge kills hidden (dotfile) entries too" do
162
+ system "cd #{@sandbox_dir}; touch .killme"
163
+ @con.purge(@sandbox_dir)
164
+ File.exists?(@sandbox_dir).should be_true
165
+ `cd #{@sandbox_dir}; env LANG=C ls -lA | grep -v total | wc -l`.to_i.should == 0
166
+ end
167
+
168
+ it "create_dir creates a directory" do
169
+ fname = "#{@sandbox_dir}/a/b/c/"
170
+ @con.create_dir(fname)
171
+ File.directory?(fname).should be_true
172
+ end
173
+
174
+ it "rename to rename entries within a dir" do
175
+ system "touch #{@sandbox_dir}/a"
176
+ system "touch #{@sandbox_dir}/b"
177
+ lambda { @con.rename(@sandbox_dir, 'a', 'b', false) }.should raise_error(Rush::NameAlreadyExists, /rename a to b$/)
178
+ @con.rename(@sandbox_dir, 'a', 'b', true)
179
+ File.exists?("#{@sandbox_dir}/a").should be_false
180
+ File.exists?("#{@sandbox_dir}/b").should be_true
181
+ end
182
+
183
+ it "copy to copy an entry to another dir on the same box" do
184
+ system "mkdir #{@sandbox_dir}/subdir"
185
+ system "touch #{@sandbox_dir}/a"
186
+ @con.copy("#{@sandbox_dir}/a", "#{@sandbox_dir}/subdir", true)
187
+ File.exists?("#{@sandbox_dir}/a").should be_true
188
+ File.exists?("#{@sandbox_dir}/subdir/a").should be_true
189
+ end
190
+
191
+ it "copy raises DoesNotExist with source path if it doesn't exist or otherwise can't be accessed" do
192
+ lambda { @con.copy('/does/not/exist', '/tmp', false) }.should raise_error(Rush::DoesNotExist, '/does/not/exist')
193
+ end
194
+
195
+ it "copy raises DoesNotExist with destination path if it can't access the destination" do
196
+ lambda { @con.copy('/tmp', '/does/not/exist', false) }.should raise_error(Rush::DoesNotExist, '/does/not')
197
+ end
198
+
199
+ it "read_archive to pull an archive of a dir into a byte stream" do
200
+ system "touch #{@sandbox_dir}/a"
201
+ @con.read_archive(@sandbox_dir).size.should > 50
202
+ end
203
+
204
+ it "read_archive works for paths with spaces" do
205
+ system "mkdir -p #{@sandbox_dir}/with\\ space; touch #{@sandbox_dir}/with\\ space/a"
206
+ @con.read_archive("#{@sandbox_dir}/with space").size.should > 50
207
+ end
208
+
209
+ it "write_archive to turn a byte stream into a dir" do
210
+ system "cd #{@sandbox_dir}; mkdir -p a; touch a/b; tar cf xfer.tar a; mkdir dst"
211
+ archive = File.read("#{@sandbox_dir}/xfer.tar")
212
+ @con.write_archive(archive, "#{@sandbox_dir}/dst", false)
213
+ File.directory?("#{@sandbox_dir}/dst/a").should be_true
214
+ File.exists?("#{@sandbox_dir}/dst/a/b").should be_true
215
+ end
216
+
217
+ it "write_archive works for paths with spaces" do
218
+ system "cd #{@sandbox_dir}; mkdir -p a; touch a/b; tar cf xfer.tar a; mkdir with\\ space"
219
+ archive = File.read("#{@sandbox_dir}/xfer.tar")
220
+ @con.write_archive(archive, "#{@sandbox_dir}/with space", false)
221
+ File.directory?("#{@sandbox_dir}/with space/a").should be_true
222
+ File.exists?("#{@sandbox_dir}/with space/a/b").should be_true
223
+ end
224
+
225
+ it "index fetches list of all files and dirs in a dir when pattern is empty" do
226
+ system "cd #{@sandbox_dir}; mkdir dir; touch file"
227
+ @con.index(@sandbox_dir, '').should == [ 'dir/', 'file' ]
228
+ end
229
+
230
+ it "index fetches only files with a certain extension with a flat pattern, *.rb" do
231
+ system "cd #{@sandbox_dir}; touch a.rb; touch b.txt"
232
+ @con.index(@sandbox_dir, '*.rb').should == [ 'a.rb' ]
233
+ end
234
+
235
+ it "index raises DoesNotExist when the base path is invalid" do
236
+ lambda { @con.index('/does/not/exist', '*') }.should raise_error(Rush::DoesNotExist, '/does/not/exist')
237
+ end
238
+
239
+ it "stat gives file stats like size and timestamps" do
240
+ @con.stat(@sandbox_dir).should have_key(:ctime)
241
+ @con.stat(@sandbox_dir).should have_key(:size)
242
+ end
243
+
244
+ it "stat fetches the octal permissions" do
245
+ @con.stat(@sandbox_dir)[:mode].should be_kind_of(Fixnum)
246
+ end
247
+
248
+ it "stat raises DoesNotExist if the entry does not exist" do
249
+ fname = "#{@sandbox_dir}/does_not_exist"
250
+ lambda { @con.stat(fname) }.should raise_error(Rush::DoesNotExist, fname)
251
+ end
252
+
253
+ it "set_access invokes the access object" do
254
+ access = mock("access")
255
+ access.should_receive(:apply).with('/some/path')
256
+ @con.set_access('/some/path', access)
257
+ end
258
+
259
+ if !RUBY_PLATFORM.match(/darwin/) # doesn't work on OS X 'cause du switches are different
260
+ it "size gives size of a directory and all its contents recursively" do
261
+ system "mkdir -p #{@sandbox_dir}/a/b/; echo 1234 > #{@sandbox_dir}/a/b/c"
262
+ @con.size(@sandbox_dir).should == (4096*3 + 5)
263
+ end
264
+ end
265
+
266
+ it "parses ps output on os x" do
267
+ @con.parse_ps("21712 501 21711 1236 0 /usr/bin/vi somefile.rb").should == {
268
+ :pid => "21712",
269
+ :uid => "501",
270
+ :parent_pid => 21711,
271
+ :mem => 1236,
272
+ :cpu => 0,
273
+ :command => '/usr/bin/vi',
274
+ :cmdline => '/usr/bin/vi somefile.rb',
275
+ }
276
+ end
277
+
278
+ it "gets the list of processes on os x via the ps command" do
279
+ @con.should_receive(:os_x_raw_ps).and_return <<EOPS
280
+ PID UID PPID RSS CPU COMMAND
281
+ 1 0 1 1111 0 cmd1 args
282
+ 2 501 1 222 1 cmd2
283
+ EOPS
284
+ @con.os_x_processes.should == [
285
+ { :pid => "1", :uid => "0", :parent_pid => 1, :mem => 1111, :cpu => 0, :command => "cmd1", :cmdline => "cmd1 args" },
286
+ { :pid => "2", :uid => "501", :parent_pid => 1, :mem => 222, :cpu => 1, :command => "cmd2", :cmdline => "cmd2" },
287
+ ]
288
+ end
289
+
290
+ it "the current process should be alive" do
291
+ @con.process_alive(Process.pid).should be_true
292
+ end
293
+
294
+ it "a made-up process should not be alive" do
295
+ @con.process_alive(99999).should be_false
296
+ end
297
+
298
+ it "kills a process by pid sending a TERM" do
299
+ @con.stub!(:process_alive).and_return(false)
300
+ ::Process.should_receive(:kill).with('TERM', 123).once
301
+ @con.kill_process(123)
302
+ end
303
+
304
+ it "kills a process by pid sending a KILL signal if TERM doesn't work" do
305
+ @con.stub!(:process_alive).and_return(true)
306
+ ::Process.should_receive(:kill).with('TERM', 123).at_least(:twice)
307
+ ::Process.should_receive(:kill).with('KILL', 123)
308
+ @con.kill_process(123)
309
+ end
310
+
311
+ it "kills a process by pid without sending TERM if :wait is zero" do
312
+ ::Process.should_not_receive(:kill).with('TERM', 123)
313
+ ::Process.should_receive(:kill).with('KILL', 123)
314
+ @con.kill_process(123, :wait => 0)
315
+ end
316
+
317
+ it "does not raise an error if the process is already dead" do
318
+ ::Process.should_receive(:kill).and_raise(Errno::ESRCH)
319
+ lambda { @con.kill_process(123) }.should_not raise_error
320
+ end
321
+
322
+ it "executes a bash command, returning stdout when successful" do
323
+ @con.bash("echo test").should == "test\n"
324
+ end
325
+
326
+ it "executes a bash command, raising an error (with stderr as #stderr and stdout as #stdout) when return value is nonzero" do
327
+ lambda { @con.bash("env LANG=C no_such_bin") }.should raise_error(Rush::BashFailed) do |error|
328
+ (error.stdout.should == '') and (error.stderr.should =~ /(command not found|no such file or directory)/i)
329
+ end
330
+ lambda { @con.bash("echo test && env LANG=C no_such_bin") }.should raise_error(Rush::BashFailed) do |error|
331
+ (error.stdout.should =~ /test/) and (error.stderr.should =~ /(command not found|no such file or directory)/i)
332
+ end
333
+ end
334
+
335
+ it "executes a bash command as another user using sudo" do
336
+ @con.bash("echo test2", ENV['USER']).should == "test2\n"
337
+ end
338
+
339
+ it "executes a bash command in the background, returning the pid" do
340
+ @con.bash("true", nil, true).should > 0
341
+ end
342
+
343
+ it "ensure_tunnel to match with remote connection" do
344
+ @con.ensure_tunnel
345
+ end
346
+
347
+ it "always returns true on alive?" do
348
+ @con.should be_alive
349
+ end
350
+
351
+ it "resolves a unix uid to a user" do
352
+ @con.resolve_unix_uid_to_user(0).should == "root"
353
+ @con.resolve_unix_uid_to_user('0').should == "root"
354
+ end
355
+
356
+ it "returns nil if the unix uid does not exist" do
357
+ @con.resolve_unix_uid_to_user(9999).should be_nil
358
+ end
359
+
360
+ it "iterates through a process list and resolves the unix uid for each" do
361
+ list = [ { :uid => 0, :command => 'pureftpd' }, { :uid => 9999, :command => 'defunk' } ]
362
+ @con.resolve_unix_uids(list).should == [ { :uid => 0, :user => 'root', :command => 'pureftpd' }, { :uid => 9999, :command => 'defunk', :user => nil } ]
363
+ end
364
+ end