aleksi-rush 0.6.6

Sign up to get free protection for your applications and to get access to all the features.
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