adamwiggins-rush 0.6.1

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 +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