adamwiggins-rush 0.6.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +87 -0
- data/Rakefile +61 -0
- data/VERSION +1 -0
- data/bin/rush +13 -0
- data/bin/rushd +7 -0
- data/lib/rush/access.rb +130 -0
- data/lib/rush/array_ext.rb +19 -0
- data/lib/rush/box.rb +112 -0
- data/lib/rush/commands.rb +55 -0
- data/lib/rush/config.rb +154 -0
- data/lib/rush/dir.rb +160 -0
- data/lib/rush/embeddable_shell.rb +26 -0
- data/lib/rush/entry.rb +185 -0
- data/lib/rush/exceptions.rb +31 -0
- data/lib/rush/file.rb +85 -0
- data/lib/rush/find_by.rb +39 -0
- data/lib/rush/fixnum_ext.rb +18 -0
- data/lib/rush/head_tail.rb +11 -0
- data/lib/rush/local.rb +402 -0
- data/lib/rush/process.rb +59 -0
- data/lib/rush/process_set.rb +62 -0
- data/lib/rush/remote.rb +156 -0
- data/lib/rush/search_results.rb +58 -0
- data/lib/rush/server.rb +117 -0
- data/lib/rush/shell.rb +187 -0
- data/lib/rush/ssh_tunnel.rb +122 -0
- data/lib/rush/string_ext.rb +3 -0
- data/lib/rush.rb +87 -0
- data/spec/access_spec.rb +134 -0
- data/spec/array_ext_spec.rb +15 -0
- data/spec/base.rb +24 -0
- data/spec/box_spec.rb +64 -0
- data/spec/commands_spec.rb +47 -0
- data/spec/config_spec.rb +108 -0
- data/spec/dir_spec.rb +164 -0
- data/spec/embeddable_shell_spec.rb +17 -0
- data/spec/entry_spec.rb +133 -0
- data/spec/file_spec.rb +83 -0
- data/spec/find_by_spec.rb +58 -0
- data/spec/fixnum_ext_spec.rb +19 -0
- data/spec/local_spec.rb +352 -0
- data/spec/process_set_spec.rb +50 -0
- data/spec/process_spec.rb +73 -0
- data/spec/remote_spec.rb +140 -0
- data/spec/rush_spec.rb +28 -0
- data/spec/search_results_spec.rb +44 -0
- data/spec/shell_spec.rb +23 -0
- data/spec/ssh_tunnel_spec.rb +122 -0
- data/spec/string_ext_spec.rb +23 -0
- 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
|
data/spec/local_spec.rb
ADDED
@@ -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
|
data/spec/remote_spec.rb
ADDED
@@ -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
|