rush2 0.7.0

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 (52) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +13 -0
  3. data/Gemfile.lock +86 -0
  4. data/README.rdoc +125 -0
  5. data/Rakefile +57 -0
  6. data/VERSION +1 -0
  7. data/bin/rush +13 -0
  8. data/bin/rushd +7 -0
  9. data/lib/rush.rb +91 -0
  10. data/lib/rush/access.rb +121 -0
  11. data/lib/rush/array_ext.rb +19 -0
  12. data/lib/rush/box.rb +124 -0
  13. data/lib/rush/commands.rb +76 -0
  14. data/lib/rush/config.rb +147 -0
  15. data/lib/rush/dir.rb +166 -0
  16. data/lib/rush/embeddable_shell.rb +26 -0
  17. data/lib/rush/entry.rb +229 -0
  18. data/lib/rush/exceptions.rb +32 -0
  19. data/lib/rush/file.rb +94 -0
  20. data/lib/rush/find_by.rb +39 -0
  21. data/lib/rush/fixnum_ext.rb +18 -0
  22. data/lib/rush/head_tail.rb +11 -0
  23. data/lib/rush/local.rb +377 -0
  24. data/lib/rush/process.rb +59 -0
  25. data/lib/rush/process_set.rb +62 -0
  26. data/lib/rush/remote.rb +33 -0
  27. data/lib/rush/search_results.rb +71 -0
  28. data/lib/rush/shell.rb +111 -0
  29. data/lib/rush/shell/completion.rb +110 -0
  30. data/lib/rush/string_ext.rb +16 -0
  31. data/spec/access_spec.rb +134 -0
  32. data/spec/array_ext_spec.rb +15 -0
  33. data/spec/base.rb +22 -0
  34. data/spec/box_spec.rb +76 -0
  35. data/spec/commands_spec.rb +47 -0
  36. data/spec/config_spec.rb +108 -0
  37. data/spec/dir_spec.rb +163 -0
  38. data/spec/embeddable_shell_spec.rb +17 -0
  39. data/spec/entry_spec.rb +133 -0
  40. data/spec/file_spec.rb +83 -0
  41. data/spec/find_by_spec.rb +58 -0
  42. data/spec/fixnum_ext_spec.rb +19 -0
  43. data/spec/local_spec.rb +365 -0
  44. data/spec/process_set_spec.rb +50 -0
  45. data/spec/process_spec.rb +73 -0
  46. data/spec/remote_spec.rb +140 -0
  47. data/spec/rush_spec.rb +28 -0
  48. data/spec/search_results_spec.rb +44 -0
  49. data/spec/shell_spec.rb +35 -0
  50. data/spec/ssh_tunnel_spec.rb +122 -0
  51. data/spec/string_ext_spec.rb +23 -0
  52. metadata +209 -0
@@ -0,0 +1,133 @@
1
+ require_relative '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
@@ -0,0 +1,83 @@
1
+ require_relative '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_relative '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_relative '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,365 @@
1
+ require_relative '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 = double("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 -> chown(full_path, user, group, options)" do
89
+ options = { noop: true }
90
+ @con.should_receive(:chown).with('full_path', 'username', 'groupname', options )
91
+ @con.receive(:action => 'chown', :full_path => 'full_path', user: 'username', group: 'groupname', options: options)
92
+ end
93
+
94
+ it "receive -> processes" do
95
+ @con.should_receive(:processes).with().and_return([ { :pid => 1 } ])
96
+ @con.receive(:action => 'processes').should == YAML.dump([ { :pid => 1 } ])
97
+ end
98
+
99
+ it "receive -> process_alive" do
100
+ @con.should_receive(:process_alive).with(123).and_return(true)
101
+ @con.receive(:action => 'process_alive', :pid => 123).should == '1'
102
+ end
103
+
104
+ it "receive -> kill_process" do
105
+ @con.should_receive(:kill_process).with(123, :wait => 10).and_return(true)
106
+ @con.receive(:action => 'kill_process', :pid => '123', :payload => YAML.dump(:wait => 10))
107
+ end
108
+
109
+ it "receive -> bash (reset environment)" do
110
+ @con.should_receive(:bash).with('cmd', 'user', false, true).and_return('output')
111
+ @con.receive(:action => 'bash', :payload => 'cmd', :user => 'user', :background => 'false', :reset_environment => 'true').should == 'output'
112
+ end
113
+
114
+ it "receive -> bash (foreground)" do
115
+ @con.should_receive(:bash).with('cmd', 'user', false, false).and_return('output')
116
+ @con.receive(:action => 'bash', :payload => 'cmd', :user => 'user', :background => 'false').should == 'output'
117
+ end
118
+
119
+ it "receive -> bash (background)" do
120
+ @con.should_receive(:bash).with('cmd', 'user', true, false).and_return('output')
121
+ @con.receive(:action => 'bash', :payload => 'cmd', :user => 'user', :background => 'true').should == 'output'
122
+ end
123
+
124
+ it "receive -> unknown action exception" do
125
+ lambda { @con.receive(:action => 'does_not_exist') }.should raise_error(Rush::Connection::Local::UnknownAction)
126
+ end
127
+
128
+ it "write_file writes contents to a file" do
129
+ fname = "#{@sandbox_dir}/a_file"
130
+ data = "some data"
131
+ @con.write_file(fname, data)
132
+ File.read(fname).should == data
133
+ end
134
+
135
+ it "append_to_file appends contents to a file" do
136
+ fname = "#{@sandbox_dir}/a_file"
137
+ system "echo line1 > #{fname}"
138
+ @con.append_to_file(fname, 'line2')
139
+ File.read(fname).should == "line1\nline2"
140
+ end
141
+
142
+ it "file_contents reads a file's contents" do
143
+ fname = "#{@sandbox_dir}/a_file"
144
+ system "echo stuff > #{fname}"
145
+ @con.file_contents(fname).should == "stuff\n"
146
+ end
147
+
148
+ it "file_contents raises DoesNotExist if the file does not exist" do
149
+ fname = "#{@sandbox_dir}/does_not_exist"
150
+ lambda { @con.file_contents(fname) }.should raise_error(Rush::DoesNotExist, fname)
151
+ end
152
+
153
+ it "destroy to destroy a file or dir" do
154
+ fname = "#{@sandbox_dir}/delete_me"
155
+ system "touch #{fname}"
156
+ @con.destroy(fname)
157
+ File.exists?(fname).should be_false
158
+ end
159
+
160
+ it "purge to purge a dir" do
161
+ system "cd #{@sandbox_dir}; touch {1,2}; mkdir 3; touch 3/4"
162
+ @con.purge(@sandbox_dir)
163
+ File.exists?(@sandbox_dir).should be_true
164
+ Dir.glob("#{@sandbox_dir}/*").should == []
165
+ end
166
+
167
+ it "purge kills hidden (dotfile) entries too" do
168
+ system "cd #{@sandbox_dir}; touch .killme"
169
+ @con.purge(@sandbox_dir)
170
+ File.exists?(@sandbox_dir).should be_true
171
+ `cd #{@sandbox_dir}; ls -lA | grep -v total | wc -l`.to_i.should == 0
172
+ end
173
+
174
+ it "create_dir creates a directory" do
175
+ fname = "#{@sandbox_dir}/a/b/c/"
176
+ @con.create_dir(fname)
177
+ File.directory?(fname).should be_true
178
+ end
179
+
180
+ it "rename to rename entries within a dir" do
181
+ system "touch #{@sandbox_dir}/a"
182
+ @con.rename(@sandbox_dir, 'a', 'b')
183
+ File.exists?("#{@sandbox_dir}/a").should be_false
184
+ File.exists?("#{@sandbox_dir}/b").should be_true
185
+ end
186
+
187
+ it "copy to copy an entry to another dir on the same box" do
188
+ system "mkdir #{@sandbox_dir}/subdir"
189
+ system "touch #{@sandbox_dir}/a"
190
+ @con.copy("#{@sandbox_dir}/a", "#{@sandbox_dir}/subdir")
191
+ File.exists?("#{@sandbox_dir}/a").should be_true
192
+ File.exists?("#{@sandbox_dir}/subdir/a").should be_true
193
+ end
194
+
195
+ it "copy raises DoesNotExist with source path if it doesn't exist or otherwise can't be accessed" do
196
+ lambda { @con.copy('/does/not/exist', '/tmp') }.should raise_error(Rush::DoesNotExist, '/does/not/exist')
197
+ end
198
+
199
+ it "copy raises DoesNotExist with destination path if it can't access the destination" do
200
+ lambda { @con.copy('/tmp', '/does/not/exist') }.should raise_error(Rush::DoesNotExist, '/does/not')
201
+ end
202
+
203
+ it "read_archive to pull an archive of a dir into a byte stream" do
204
+ system "touch #{@sandbox_dir}/a"
205
+ @con.read_archive(@sandbox_dir).size.should > 50
206
+ end
207
+
208
+ it "read_archive works for paths with spaces" do
209
+ system "mkdir -p #{@sandbox_dir}/with\\ space; touch #{@sandbox_dir}/with\\ space/a"
210
+ @con.read_archive("#{@sandbox_dir}/with space").size.should > 50
211
+ end
212
+
213
+ it "write_archive to turn a byte stream into a dir" do
214
+ system "cd #{@sandbox_dir}; mkdir -p a; touch a/b; tar cf xfer.tar a; mkdir dst"
215
+ archive = File.read("#{@sandbox_dir}/xfer.tar")
216
+ @con.write_archive(archive, "#{@sandbox_dir}/dst")
217
+ File.directory?("#{@sandbox_dir}/dst/a").should be_true
218
+ File.exists?("#{@sandbox_dir}/dst/a/b").should be_true
219
+ end
220
+
221
+ it "write_archive works for paths with spaces" do
222
+ system "cd #{@sandbox_dir}; mkdir -p a; touch a/b; tar cf xfer.tar a; mkdir with\\ space"
223
+ archive = File.read("#{@sandbox_dir}/xfer.tar")
224
+ @con.write_archive(archive, "#{@sandbox_dir}/with space")
225
+ File.directory?("#{@sandbox_dir}/with space/a").should be_true
226
+ File.exists?("#{@sandbox_dir}/with space/a/b").should be_true
227
+ end
228
+
229
+ it "index fetches list of all files and dirs in a dir when pattern is empty" do
230
+ system "cd #{@sandbox_dir}; mkdir dir; touch file"
231
+ @con.index(@sandbox_dir, '').should == [ 'dir/', 'file' ]
232
+ end
233
+
234
+ it "index fetches only files with a certain extension with a flat pattern, *.rb" do
235
+ system "cd #{@sandbox_dir}; touch a.rb; touch b.txt"
236
+ @con.index(@sandbox_dir, '*.rb').should == [ 'a.rb' ]
237
+ end
238
+
239
+ it "index raises DoesNotExist when the base path is invalid" do
240
+ lambda { @con.index('/does/not/exist', '*') }.should raise_error(Rush::DoesNotExist, '/does/not/exist')
241
+ end
242
+
243
+ it "stat gives file stats like size and timestamps" do
244
+ @con.stat(@sandbox_dir).should have_key(:ctime)
245
+ @con.stat(@sandbox_dir).should have_key(:size)
246
+ end
247
+
248
+ it "stat fetches the octal permissions" do
249
+ @con.stat(@sandbox_dir)[:mode].should be_kind_of(Fixnum)
250
+ end
251
+
252
+ it "stat raises DoesNotExist if the entry does not exist" do
253
+ fname = "#{@sandbox_dir}/does_not_exist"
254
+ lambda { @con.stat(fname) }.should raise_error(Rush::DoesNotExist, fname)
255
+ end
256
+
257
+ it "set_access invokes the access object" do
258
+ access = double("access")
259
+ access.should_receive(:apply).with('/some/path')
260
+ @con.set_access('/some/path', access)
261
+ end
262
+
263
+ it "chown should change the ownership of a file"
264
+
265
+ if !RUBY_PLATFORM.match(/darwin/) # doesn't work on OS X 'cause du switches are different
266
+ it "size gives size of a directory and all its contents recursively" do
267
+ system "mkdir -p #{@sandbox_dir}/a/b/; echo 1234 > #{@sandbox_dir}/a/b/c"
268
+ @con.size(@sandbox_dir).should == (4096*3 + 5)
269
+ end
270
+ end
271
+
272
+ it "parses ps output on os x" do
273
+ @con.parse_ps("21712 501 21711 1236 0 /usr/bin/vi somefile.rb").should == {
274
+ :pid => "21712",
275
+ :uid => "501",
276
+ :parent_pid => 21711,
277
+ :mem => 1236,
278
+ :cpu => 0,
279
+ :command => '/usr/bin/vi',
280
+ :cmdline => '/usr/bin/vi somefile.rb',
281
+ }
282
+ end
283
+
284
+ it "gets the list of processes on os x via the ps command" do
285
+ @con.should_receive(:os_x_raw_ps).and_return <<EOPS
286
+ PID UID PPID RSS CPU COMMAND
287
+ 1 0 1 1111 0 cmd1 args
288
+ 2 501 1 222 1 cmd2
289
+ EOPS
290
+ @con.os_x_processes.should == [
291
+ { :pid => "1", :uid => "0", :parent_pid => 1, :mem => 1111, :cpu => 0, :command => "cmd1", :cmdline => "cmd1 args" },
292
+ { :pid => "2", :uid => "501", :parent_pid => 1, :mem => 222, :cpu => 1, :command => "cmd2", :cmdline => "cmd2" },
293
+ ]
294
+ end
295
+
296
+ it "the current process should be alive" do
297
+ @con.process_alive(Process.pid).should be_true
298
+ end
299
+
300
+ it "a made-up process should not be alive" do
301
+ @con.process_alive(99999).should be_false
302
+ end
303
+
304
+ it "kills a process by pid sending a TERM" do
305
+ @con.stub(:process_alive).and_return(false)
306
+ ::Process.should_receive(:kill).with('TERM', 123).once
307
+ @con.kill_process(123)
308
+ end
309
+
310
+ it "kills a process by pid sending a KILL signal if TERM doesn't work" do
311
+ @con.stub(:process_alive).and_return(true)
312
+ ::Process.should_receive(:kill).with('TERM', 123).at_least(:twice)
313
+ ::Process.should_receive(:kill).with('KILL', 123)
314
+ @con.kill_process(123)
315
+ end
316
+
317
+ it "kills a process by pid without sending TERM if :wait is zero" do
318
+ ::Process.should_not_receive(:kill).with('TERM', 123)
319
+ ::Process.should_receive(:kill).with('KILL', 123)
320
+ @con.kill_process(123, :wait => 0)
321
+ end
322
+
323
+ it "does not raise an error if the process is already dead" do
324
+ ::Process.should_receive(:kill).and_raise(Errno::ESRCH)
325
+ lambda { @con.kill_process(123) }.should_not raise_error
326
+ end
327
+
328
+ it "executes a bash command, returning stdout when successful" do
329
+ @con.bash("echo test").should == "test\n"
330
+ end
331
+
332
+ it "executes a bash command, raising and error (with stderr as the message) when return value is nonzero" do
333
+ lambda { @con.bash("no_such_bin") }.should raise_error(Rush::BashFailed, /command not found/)
334
+ end
335
+
336
+ it "executes a bash command as another user using sudo" do
337
+ @con.bash("echo test2", ENV['USER']).should == "test2\n"
338
+ end
339
+
340
+ it "executes a bash command in the background, returning the pid" do
341
+ @con.bash("true", nil, true).should > 0
342
+ end
343
+
344
+ it "ensure_tunnel to match with remote connection" do
345
+ @con.ensure_tunnel
346
+ end
347
+
348
+ it "always returns true on alive?" do
349
+ @con.should be_alive
350
+ end
351
+
352
+ it "resolves a unix uid to a user" do
353
+ @con.resolve_unix_uid_to_user(0).should == "root"
354
+ @con.resolve_unix_uid_to_user('0').should == "root"
355
+ end
356
+
357
+ it "returns nil if the unix uid does not exist" do
358
+ @con.resolve_unix_uid_to_user(9999).should be_nil
359
+ end
360
+
361
+ it "iterates through a process list and resolves the unix uid for each" do
362
+ list = [ { :uid => 0, :command => 'pureftpd' }, { :uid => 9999, :command => 'defunk' } ]
363
+ @con.resolve_unix_uids(list).should == [ { :uid => 0, :user => 'root', :command => 'pureftpd' }, { :uid => 9999, :command => 'defunk', :user => nil } ]
364
+ end
365
+ end