adamwiggins-rush 0.6.1

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 +87 -0
  2. data/Rakefile +61 -0
  3. data/VERSION +1 -0
  4. data/bin/rush +13 -0
  5. data/bin/rushd +7 -0
  6. data/lib/rush/access.rb +130 -0
  7. data/lib/rush/array_ext.rb +19 -0
  8. data/lib/rush/box.rb +112 -0
  9. data/lib/rush/commands.rb +55 -0
  10. data/lib/rush/config.rb +154 -0
  11. data/lib/rush/dir.rb +160 -0
  12. data/lib/rush/embeddable_shell.rb +26 -0
  13. data/lib/rush/entry.rb +185 -0
  14. data/lib/rush/exceptions.rb +31 -0
  15. data/lib/rush/file.rb +85 -0
  16. data/lib/rush/find_by.rb +39 -0
  17. data/lib/rush/fixnum_ext.rb +18 -0
  18. data/lib/rush/head_tail.rb +11 -0
  19. data/lib/rush/local.rb +402 -0
  20. data/lib/rush/process.rb +59 -0
  21. data/lib/rush/process_set.rb +62 -0
  22. data/lib/rush/remote.rb +156 -0
  23. data/lib/rush/search_results.rb +58 -0
  24. data/lib/rush/server.rb +117 -0
  25. data/lib/rush/shell.rb +187 -0
  26. data/lib/rush/ssh_tunnel.rb +122 -0
  27. data/lib/rush/string_ext.rb +3 -0
  28. data/lib/rush.rb +87 -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 +64 -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 +352 -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 +141 -0
@@ -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,352 @@
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 (foreground)" do
104
+ @con.should_receive(:bash).with('cmd', 'user', false).and_return('output')
105
+ @con.receive(:action => 'bash', :payload => 'cmd', :user => 'user', :background => 'false').should == 'output'
106
+ end
107
+
108
+ it "receive -> bash (background)" do
109
+ @con.should_receive(:bash).with('cmd', 'user', true).and_return('output')
110
+ @con.receive(:action => 'bash', :payload => 'cmd', :user => 'user', :background => 'true').should == 'output'
111
+ end
112
+
113
+ it "receive -> unknown action exception" do
114
+ lambda { @con.receive(:action => 'does_not_exist') }.should raise_error(Rush::Connection::Local::UnknownAction)
115
+ end
116
+
117
+ it "write_file writes contents to a file" do
118
+ fname = "#{@sandbox_dir}/a_file"
119
+ data = "some data"
120
+ @con.write_file(fname, data)
121
+ File.read(fname).should == data
122
+ end
123
+
124
+ it "append_to_file appends contents to a file" do
125
+ fname = "#{@sandbox_dir}/a_file"
126
+ system "echo line1 > #{fname}"
127
+ @con.append_to_file(fname, 'line2')
128
+ File.read(fname).should == "line1\nline2"
129
+ end
130
+
131
+ it "file_contents reads a file's contents" do
132
+ fname = "#{@sandbox_dir}/a_file"
133
+ system "echo stuff > #{fname}"
134
+ @con.file_contents(fname).should == "stuff\n"
135
+ end
136
+
137
+ it "file_contents raises DoesNotExist if the file does not exist" do
138
+ fname = "#{@sandbox_dir}/does_not_exist"
139
+ lambda { @con.file_contents(fname) }.should raise_error(Rush::DoesNotExist, fname)
140
+ end
141
+
142
+ it "destroy to destroy a file or dir" do
143
+ fname = "#{@sandbox_dir}/delete_me"
144
+ system "touch #{fname}"
145
+ @con.destroy(fname)
146
+ File.exists?(fname).should be_false
147
+ end
148
+
149
+ it "purge to purge a dir" do
150
+ system "cd #{@sandbox_dir}; touch {1,2}; mkdir 3; touch 3/4"
151
+ @con.purge(@sandbox_dir)
152
+ File.exists?(@sandbox_dir).should be_true
153
+ Dir.glob("#{@sandbox_dir}/*").should == []
154
+ end
155
+
156
+ it "purge kills hidden (dotfile) entries too" do
157
+ system "cd #{@sandbox_dir}; touch .killme"
158
+ @con.purge(@sandbox_dir)
159
+ File.exists?(@sandbox_dir).should be_true
160
+ `cd #{@sandbox_dir}; ls -lA | grep -v total | wc -l`.to_i.should == 0
161
+ end
162
+
163
+ it "create_dir creates a directory" do
164
+ fname = "#{@sandbox_dir}/a/b/c/"
165
+ @con.create_dir(fname)
166
+ File.directory?(fname).should be_true
167
+ end
168
+
169
+ it "rename to rename entries within a dir" do
170
+ system "touch #{@sandbox_dir}/a"
171
+ @con.rename(@sandbox_dir, 'a', 'b')
172
+ File.exists?("#{@sandbox_dir}/a").should be_false
173
+ File.exists?("#{@sandbox_dir}/b").should be_true
174
+ end
175
+
176
+ it "copy to copy an entry to another dir on the same box" do
177
+ system "mkdir #{@sandbox_dir}/subdir"
178
+ system "touch #{@sandbox_dir}/a"
179
+ @con.copy("#{@sandbox_dir}/a", "#{@sandbox_dir}/subdir")
180
+ File.exists?("#{@sandbox_dir}/a").should be_true
181
+ File.exists?("#{@sandbox_dir}/subdir/a").should be_true
182
+ end
183
+
184
+ it "copy raises DoesNotExist with source path if it doesn't exist or otherwise can't be accessed" do
185
+ lambda { @con.copy('/does/not/exist', '/tmp') }.should raise_error(Rush::DoesNotExist, '/does/not/exist')
186
+ end
187
+
188
+ it "copy raises DoesNotExist with destination path if it can't access the destination" do
189
+ lambda { @con.copy('/tmp', '/does/not/exist') }.should raise_error(Rush::DoesNotExist, '/does/not')
190
+ end
191
+
192
+ it "read_archive to pull an archive of a dir into a byte stream" do
193
+ system "touch #{@sandbox_dir}/a"
194
+ @con.read_archive(@sandbox_dir).size.should > 50
195
+ end
196
+
197
+ it "read_archive works for paths with spaces" do
198
+ system "mkdir -p #{@sandbox_dir}/with\\ space; touch #{@sandbox_dir}/with\\ space/a"
199
+ @con.read_archive("#{@sandbox_dir}/with space").size.should > 50
200
+ end
201
+
202
+ it "write_archive to turn a byte stream into a dir" do
203
+ system "cd #{@sandbox_dir}; mkdir -p a; touch a/b; tar cf xfer.tar a; mkdir dst"
204
+ archive = File.read("#{@sandbox_dir}/xfer.tar")
205
+ @con.write_archive(archive, "#{@sandbox_dir}/dst")
206
+ File.directory?("#{@sandbox_dir}/dst/a").should be_true
207
+ File.exists?("#{@sandbox_dir}/dst/a/b").should be_true
208
+ end
209
+
210
+ it "write_archive works for paths with spaces" do
211
+ system "cd #{@sandbox_dir}; mkdir -p a; touch a/b; tar cf xfer.tar a; mkdir with\\ space"
212
+ archive = File.read("#{@sandbox_dir}/xfer.tar")
213
+ @con.write_archive(archive, "#{@sandbox_dir}/with space")
214
+ File.directory?("#{@sandbox_dir}/with space/a").should be_true
215
+ File.exists?("#{@sandbox_dir}/with space/a/b").should be_true
216
+ end
217
+
218
+ it "index fetches list of all files and dirs in a dir when pattern is empty" do
219
+ system "cd #{@sandbox_dir}; mkdir dir; touch file"
220
+ @con.index(@sandbox_dir, '').should == [ 'dir/', 'file' ]
221
+ end
222
+
223
+ it "index fetches only files with a certain extension with a flat pattern, *.rb" do
224
+ system "cd #{@sandbox_dir}; touch a.rb; touch b.txt"
225
+ @con.index(@sandbox_dir, '*.rb').should == [ 'a.rb' ]
226
+ end
227
+
228
+ it "index raises DoesNotExist when the base path is invalid" do
229
+ lambda { @con.index('/does/not/exist', '*') }.should raise_error(Rush::DoesNotExist, '/does/not/exist')
230
+ end
231
+
232
+ it "stat gives file stats like size and timestamps" do
233
+ @con.stat(@sandbox_dir).should have_key(:ctime)
234
+ @con.stat(@sandbox_dir).should have_key(:size)
235
+ end
236
+
237
+ it "stat fetches the octal permissions" do
238
+ @con.stat(@sandbox_dir)[:mode].should be_kind_of(Fixnum)
239
+ end
240
+
241
+ it "stat raises DoesNotExist if the entry does not exist" do
242
+ fname = "#{@sandbox_dir}/does_not_exist"
243
+ lambda { @con.stat(fname) }.should raise_error(Rush::DoesNotExist, fname)
244
+ end
245
+
246
+ it "set_access invokes the access object" do
247
+ access = mock("access")
248
+ access.should_receive(:apply).with('/some/path')
249
+ @con.set_access('/some/path', access)
250
+ end
251
+
252
+ if !RUBY_PLATFORM.match(/darwin/) # doesn't work on OS X 'cause du switches are different
253
+ it "size gives size of a directory and all its contents recursively" do
254
+ system "mkdir -p #{@sandbox_dir}/a/b/; echo 1234 > #{@sandbox_dir}/a/b/c"
255
+ @con.size(@sandbox_dir).should == (4096*3 + 5)
256
+ end
257
+ end
258
+
259
+ it "parses ps output on os x" do
260
+ @con.parse_ps("21712 501 21711 1236 0 /usr/bin/vi somefile.rb").should == {
261
+ :pid => "21712",
262
+ :uid => "501",
263
+ :parent_pid => 21711,
264
+ :mem => 1236,
265
+ :cpu => 0,
266
+ :command => '/usr/bin/vi',
267
+ :cmdline => '/usr/bin/vi somefile.rb',
268
+ }
269
+ end
270
+
271
+ it "gets the list of processes on os x via the ps command" do
272
+ @con.should_receive(:os_x_raw_ps).and_return <<EOPS
273
+ PID UID PPID RSS CPU COMMAND
274
+ 1 0 1 1111 0 cmd1 args
275
+ 2 501 1 222 1 cmd2
276
+ EOPS
277
+ @con.os_x_processes.should == [
278
+ { :pid => "1", :uid => "0", :parent_pid => 1, :mem => 1111, :cpu => 0, :command => "cmd1", :cmdline => "cmd1 args" },
279
+ { :pid => "2", :uid => "501", :parent_pid => 1, :mem => 222, :cpu => 1, :command => "cmd2", :cmdline => "cmd2" },
280
+ ]
281
+ end
282
+
283
+ it "the current process should be alive" do
284
+ @con.process_alive(Process.pid).should be_true
285
+ end
286
+
287
+ it "a made-up process should not be alive" do
288
+ @con.process_alive(99999).should be_false
289
+ end
290
+
291
+ it "kills a process by pid sending a TERM" do
292
+ @con.stub!(:process_alive).and_return(false)
293
+ ::Process.should_receive(:kill).with('TERM', 123).once
294
+ @con.kill_process(123)
295
+ end
296
+
297
+ it "kills a process by pid sending a KILL signal if TERM doesn't work" do
298
+ @con.stub!(:process_alive).and_return(true)
299
+ ::Process.should_receive(:kill).with('TERM', 123).at_least(:twice)
300
+ ::Process.should_receive(:kill).with('KILL', 123)
301
+ @con.kill_process(123)
302
+ end
303
+
304
+ it "kills a process by pid without sending TERM if :wait is zero" do
305
+ ::Process.should_not_receive(:kill).with('TERM', 123)
306
+ ::Process.should_receive(:kill).with('KILL', 123)
307
+ @con.kill_process(123, :wait => 0)
308
+ end
309
+
310
+ it "does not raise an error if the process is already dead" do
311
+ ::Process.should_receive(:kill).and_raise(Errno::ESRCH)
312
+ lambda { @con.kill_process(123) }.should_not raise_error
313
+ end
314
+
315
+ it "executes a bash command, returning stdout when successful" do
316
+ @con.bash("echo test").should == "test\n"
317
+ end
318
+
319
+ it "executes a bash command, raising and error (with stderr as the message) when return value is nonzero" do
320
+ lambda { @con.bash("no_such_bin") }.should raise_error(Rush::BashFailed, /command not found/)
321
+ end
322
+
323
+ it "executes a bash command as another user using sudo" do
324
+ @con.bash("echo test2", ENV['USER']).should == "test2\n"
325
+ end
326
+
327
+ it "executes a bash command in the background, returning the pid" do
328
+ @con.bash("true", nil, true).should > 0
329
+ end
330
+
331
+ it "ensure_tunnel to match with remote connection" do
332
+ @con.ensure_tunnel
333
+ end
334
+
335
+ it "always returns true on alive?" do
336
+ @con.should be_alive
337
+ end
338
+
339
+ it "resolves a unix uid to a user" do
340
+ @con.resolve_unix_uid_to_user(0).should == "root"
341
+ @con.resolve_unix_uid_to_user('0').should == "root"
342
+ end
343
+
344
+ it "returns nil if the unix uid does not exist" do
345
+ @con.resolve_unix_uid_to_user(9999).should be_nil
346
+ end
347
+
348
+ it "iterates through a process list and resolves the unix uid for each" do
349
+ list = [ { :uid => 0, :command => 'pureftpd' }, { :uid => 9999, :command => 'defunk' } ]
350
+ @con.resolve_unix_uids(list).should == [ { :uid => 0, :user => 'root', :command => 'pureftpd' }, { :uid => 9999, :command => 'defunk', :user => nil } ]
351
+ end
352
+ end
@@ -0,0 +1,50 @@
1
+ require File.dirname(__FILE__) + '/base'
2
+
3
+ describe Rush::ProcessSet do
4
+ before do
5
+ @process = mock('process')
6
+ @set = Rush::ProcessSet.new([ @process ])
7
+ end
8
+
9
+ it "is Enumerable" do
10
+ @set.select { |s| s == @process }.should == [ @process ]
11
+ end
12
+
13
+ it "defines size" do
14
+ @set.size.should == 1
15
+ end
16
+
17
+ it "defines first" do
18
+ @set.first.should == @process
19
+ end
20
+
21
+ it "is equal to sets with the same contents" do
22
+ @set.should == Rush::ProcessSet.new([ @process ])
23
+ end
24
+
25
+ it "is equal to arrays with the same contents" do
26
+ @set.should == [ @process ]
27
+ end
28
+
29
+ it "kills all processes in the set" do
30
+ @process.should_receive(:kill)
31
+ @set.kill
32
+ end
33
+
34
+ it "checks the alive? state of all processes in the set" do
35
+ @process.should_receive(:alive?).and_return(true)
36
+ @set.alive?.should == [ true ]
37
+ end
38
+
39
+ it "filters the set from a conditions hash and returns the filtered set" do
40
+ @process.stub!(:pid).and_return(123)
41
+ @set.filter(:pid => 123).first.should == @process
42
+ @set.filter(:pid => 456).size.should == 0
43
+ end
44
+
45
+ it "filters with regexps if provided in the conditions" do
46
+ @process.stub!(:command).and_return('foobaz')
47
+ @set.filter(:command => /baz/).first.should == @process
48
+ @set.filter(:command => /blerg/).size.should == 0
49
+ end
50
+ end
@@ -0,0 +1,73 @@
1
+ require File.dirname(__FILE__) + '/base'
2
+
3
+ describe Rush::Process do
4
+ before do
5
+ @pid = fork do
6
+ sleep 999
7
+ end
8
+ @process = Rush::Process.all.detect { |p| p.pid == @pid }
9
+ end
10
+
11
+ after do
12
+ system "kill -9 #{@pid}"
13
+ end
14
+
15
+ if !RUBY_PLATFORM.match(/darwin/) # OS x reports pids weird
16
+ it "knows all its child processes" do
17
+ parent = Rush::Process.all.detect { |p| p.pid == Process.pid }
18
+ parent.children.should == [ @process ]
19
+ end
20
+ end
21
+
22
+ it "gets the list of all processes" do
23
+ list = Rush::Process.all
24
+ list.size.should > 5
25
+ list.first.should be_kind_of(Rush::Process)
26
+ end
27
+
28
+ it "knows the pid" do
29
+ @process.pid.should == @pid
30
+ end
31
+
32
+ it "knows the uid" do
33
+ @process.uid.should == ::Process.uid
34
+ end
35
+
36
+ it "knows the executed binary" do
37
+ @process.command.should match(/ruby/)
38
+ end
39
+
40
+ it "knows the command line" do
41
+ @process.cmdline.should match(/process_spec.rb/)
42
+ end
43
+
44
+ it "knows the memory used" do
45
+ @process.mem.should > 0
46
+ end
47
+
48
+ it "knows the cpu used" do
49
+ @process.cpu.should >= 0
50
+ end
51
+
52
+ it "knows the parent process pid" do
53
+ @process.parent_pid.should == Process.pid
54
+ end
55
+
56
+ it "knows the parent process" do
57
+ this = Rush::Box.new.processes.select { |p| p.pid == Process.pid }.first
58
+ @process.parent.should == this
59
+ end
60
+
61
+ it "can kill itself" do
62
+ process = Rush.bash("sleep 30", :background => true)
63
+ process.alive?.should be_true
64
+ process.kill
65
+ sleep 0.1
66
+ process.alive?.should be_false
67
+ end
68
+
69
+ it "if box and pid are the same, process is equal" do
70
+ other = Rush::Process.new({ :pid => @process.pid }, @process.box)
71
+ @process.should == other
72
+ end
73
+ end
@@ -0,0 +1,140 @@
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::Remote.new('spec.example.com')
9
+ end
10
+
11
+ after do
12
+ system "rm -rf #{@sandbox_dir}"
13
+ end
14
+
15
+ it "transmits write_file" do
16
+ @con.should_receive(:transmit).with(:action => 'write_file', :full_path => 'file', :payload => 'contents')
17
+ @con.write_file('file', 'contents')
18
+ end
19
+
20
+ it "transmits append_to_file" do
21
+ @con.should_receive(:transmit).with(:action => 'append_to_file', :full_path => 'file', :payload => 'contents')
22
+ @con.append_to_file('file', 'contents')
23
+ end
24
+
25
+ it "transmits file_contents" do
26
+ @con.should_receive(:transmit).with(:action => 'file_contents', :full_path => 'file').and_return('contents')
27
+ @con.file_contents('file').should == 'contents'
28
+ end
29
+
30
+ it "transmits destroy" do
31
+ @con.should_receive(:transmit).with(:action => 'destroy', :full_path => 'file')
32
+ @con.destroy('file')
33
+ end
34
+
35
+ it "transmits purge" do
36
+ @con.should_receive(:transmit).with(:action => 'purge', :full_path => 'dir')
37
+ @con.purge('dir')
38
+ end
39
+
40
+ it "transmits create_dir" do
41
+ @con.should_receive(:transmit).with(:action => 'create_dir', :full_path => 'file')
42
+ @con.create_dir('file')
43
+ end
44
+
45
+ it "transmits rename" do
46
+ @con.should_receive(:transmit).with(:action => 'rename', :path => 'path', :name => 'name', :new_name => 'new_name')
47
+ @con.rename('path', 'name', 'new_name')
48
+ end
49
+
50
+ it "transmits copy" do
51
+ @con.should_receive(:transmit).with(:action => 'copy', :src => 'src', :dst => 'dst')
52
+ @con.copy('src', 'dst')
53
+ end
54
+
55
+ it "transmits read_archive" do
56
+ @con.should_receive(:transmit).with(:action => 'read_archive', :full_path => 'full_path').and_return('archive data')
57
+ @con.read_archive('full_path').should == 'archive data'
58
+ end
59
+
60
+ it "transmits write_archive" do
61
+ @con.should_receive(:transmit).with(:action => 'write_archive', :dir => 'dir', :payload => 'archive')
62
+ @con.write_archive('archive', 'dir')
63
+ end
64
+
65
+ it "transmits index" do
66
+ @con.should_receive(:transmit).with(:action => 'index', :base_path => 'base_path', :glob => '*').and_return("1\n2\n")
67
+ @con.index('base_path', '*').should == %w(1 2)
68
+ end
69
+
70
+ it "transmits stat" do
71
+ @con.should_receive(:transmit).with(:action => 'stat', :full_path => 'full_path').and_return(YAML.dump(1 => 2))
72
+ @con.stat('full_path').should == { 1 => 2 }
73
+ end
74
+
75
+ it "transmits set_access" do
76
+ @con.should_receive(:transmit).with(:action => 'set_access', :full_path => 'full_path', :user => 'joe', :user_read => 1)
77
+ @con.set_access('full_path', :user => 'joe', :user_read => 1)
78
+ end
79
+
80
+ it "transmits size" do
81
+ @con.should_receive(:transmit).with(:action => 'size', :full_path => 'full_path').and_return("123")
82
+ @con.size('full_path').should == 123
83
+ end
84
+
85
+ it "transmits processes" do
86
+ @con.should_receive(:transmit).with(:action => 'processes').and_return(YAML.dump([ { :pid => 1 } ]))
87
+ @con.processes.should == [ { :pid => 1 } ]
88
+ end
89
+
90
+ it "transmits process_alive" do
91
+ @con.should_receive(:transmit).with(:action => 'process_alive', :pid => 123).and_return(true)
92
+ @con.process_alive(123).should == true
93
+ end
94
+
95
+ it "transmits kill_process" do
96
+ @con.should_receive(:transmit).with(:action => 'kill_process', :pid => 123, :payload => YAML.dump(:wait => 10))
97
+ @con.kill_process(123, :wait => 10)
98
+ end
99
+
100
+ it "transmits bash" do
101
+ @con.should_receive(:transmit).with(:action => 'bash', :payload => 'cmd', :user => 'user', :background => 'bg').and_return('output')
102
+ @con.bash('cmd', 'user', 'bg').should == 'output'
103
+ end
104
+
105
+ it "an http result code of 401 raises NotAuthorized" do
106
+ lambda { @con.process_result("401", "") }.should raise_error(Rush::NotAuthorized)
107
+ end
108
+
109
+ it "an http result code of 400 raises the exception passed in the result body" do
110
+ @con.stub!(:parse_exception).and_return(Rush::DoesNotExist, "message")
111
+ lambda { @con.process_result("400", "") }.should raise_error(Rush::DoesNotExist)
112
+ end
113
+
114
+ it "an http result code of 501 (or anything other than the other defined codes) raises FailedTransmit" do
115
+ lambda { @con.process_result("501", "") }.should raise_error(Rush::FailedTransmit)
116
+ end
117
+
118
+ it "parse_exception takes the class from the first line and the message from the second" do
119
+ @con.parse_exception("Rush::DoesNotExist\nthe message\n").should == [ Rush::DoesNotExist, "the message" ]
120
+ end
121
+
122
+ it "parse_exception rejects unrecognized exceptions" do
123
+ lambda { @con.parse_exception("NotARushException\n") }.should raise_error
124
+ end
125
+
126
+ it "passes through ensure_tunnel" do
127
+ @con.tunnel.should_receive(:ensure_tunnel)
128
+ @con.ensure_tunnel
129
+ end
130
+
131
+ it "is alive if the box is responding to commands" do
132
+ @con.should_receive(:index).and_return(:dummy)
133
+ @con.should be_alive
134
+ end
135
+
136
+ it "not alive if an attempted command throws an exception" do
137
+ @con.should_receive(:index).and_raise(RuntimeError)
138
+ @con.should_not be_alive
139
+ end
140
+ end