necktie 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. data/bin/necktie +1 -1
  2. data/lib/necktie/rush.rb +11 -0
  3. data/lib/necktie/services.rb +31 -11
  4. data/lib/necktie.rb +10 -6
  5. data/necktie.gemspec +2 -2
  6. data/rush/README.rdoc +87 -0
  7. data/rush/Rakefile +60 -0
  8. data/rush/VERSION +1 -0
  9. data/rush/bin/rush +13 -0
  10. data/rush/bin/rushd +7 -0
  11. data/rush/lib/rush/access.rb +130 -0
  12. data/rush/lib/rush/array_ext.rb +19 -0
  13. data/rush/lib/rush/box.rb +112 -0
  14. data/rush/lib/rush/commands.rb +55 -0
  15. data/rush/lib/rush/config.rb +154 -0
  16. data/rush/lib/rush/dir.rb +160 -0
  17. data/rush/lib/rush/embeddable_shell.rb +26 -0
  18. data/rush/lib/rush/entry.rb +185 -0
  19. data/rush/lib/rush/exceptions.rb +31 -0
  20. data/rush/lib/rush/file.rb +85 -0
  21. data/rush/lib/rush/find_by.rb +39 -0
  22. data/rush/lib/rush/fixnum_ext.rb +18 -0
  23. data/rush/lib/rush/head_tail.rb +11 -0
  24. data/rush/lib/rush/local.rb +402 -0
  25. data/rush/lib/rush/process.rb +59 -0
  26. data/rush/lib/rush/process_set.rb +62 -0
  27. data/rush/lib/rush/remote.rb +156 -0
  28. data/rush/lib/rush/search_results.rb +58 -0
  29. data/rush/lib/rush/server.rb +117 -0
  30. data/rush/lib/rush/shell.rb +187 -0
  31. data/rush/lib/rush/ssh_tunnel.rb +122 -0
  32. data/rush/lib/rush/string_ext.rb +3 -0
  33. data/rush/lib/rush.rb +87 -0
  34. data/rush/rush.gemspec +113 -0
  35. data/rush/spec/access_spec.rb +134 -0
  36. data/rush/spec/array_ext_spec.rb +15 -0
  37. data/rush/spec/base.rb +24 -0
  38. data/rush/spec/box_spec.rb +64 -0
  39. data/rush/spec/commands_spec.rb +47 -0
  40. data/rush/spec/config_spec.rb +108 -0
  41. data/rush/spec/dir_spec.rb +164 -0
  42. data/rush/spec/embeddable_shell_spec.rb +17 -0
  43. data/rush/spec/entry_spec.rb +133 -0
  44. data/rush/spec/file_spec.rb +83 -0
  45. data/rush/spec/find_by_spec.rb +58 -0
  46. data/rush/spec/fixnum_ext_spec.rb +19 -0
  47. data/rush/spec/local_spec.rb +352 -0
  48. data/rush/spec/process_set_spec.rb +50 -0
  49. data/rush/spec/process_spec.rb +73 -0
  50. data/rush/spec/remote_spec.rb +140 -0
  51. data/rush/spec/rush_spec.rb +28 -0
  52. data/rush/spec/search_results_spec.rb +44 -0
  53. data/rush/spec/shell_spec.rb +23 -0
  54. data/rush/spec/ssh_tunnel_spec.rb +122 -0
  55. data/rush/spec/string_ext_spec.rb +23 -0
  56. metadata +53 -3
  57. data/lib/necktie/files.rb +0 -14
@@ -0,0 +1,133 @@
1
+ require File.dirname(__FILE__) + '/base'
2
+
3
+ describe Rush::Entry do
4
+ before do
5
+ @sandbox_dir = "/tmp/rush_spec.#{Process.pid}/"
6
+ system "rm -rf #{@sandbox_dir}; mkdir -p #{@sandbox_dir}"
7
+
8
+ @filename = "#{@sandbox_dir}/test_file"
9
+ system "touch #{@filename}"
10
+
11
+ @entry = Rush::Entry.new(@filename)
12
+ end
13
+
14
+ after do
15
+ system "rm -rf #{@sandbox_dir}"
16
+ end
17
+
18
+ it "knows its name" do
19
+ @entry.name.should == File.basename(@filename)
20
+ end
21
+
22
+ it "knows its parent dir" do
23
+ @entry.parent.should be_kind_of(Rush::Dir)
24
+ @entry.parent.name.should == File.basename(@sandbox_dir)
25
+ @entry.parent.full_path.should == @sandbox_dir
26
+ end
27
+
28
+ it "cleans its pathname" do
29
+ Rush::Entry.new('/a//b//c').full_path.should == '/a/b/c'
30
+ Rush::Entry.new('/1/2/../3').full_path.should == '/1/3'
31
+ end
32
+
33
+ it "knows its changed_at time" do
34
+ @entry.changed_at.should == File.stat(@filename).ctime
35
+ end
36
+
37
+ it "knows its last_modified time" do
38
+ @entry.last_modified.should == File.stat(@filename).mtime
39
+ end
40
+
41
+ it "knows its last_accessed time" do
42
+ @entry.last_accessed.should == File.stat(@filename).atime
43
+ end
44
+
45
+ it "considers itself equal to other instances with the same full path" do
46
+ Rush::Entry.new('/not/the/same').should_not == @entry
47
+ Rush::Entry.new(@entry.full_path).should == @entry
48
+ end
49
+
50
+ it "can rename itself" do
51
+ new_file = "test2"
52
+
53
+ @entry.rename(new_file)
54
+
55
+ File.exists?(@filename).should be_false
56
+ File.exists?("#{@sandbox_dir}/#{new_file}").should be_true
57
+ end
58
+
59
+ it "rename returns the renamed file" do
60
+ @entry.rename('file2').should == @entry.parent['file2']
61
+ end
62
+
63
+ it "can't rename itself if another file already exists with that name" do
64
+ new_file = "test3"
65
+ system "touch #{@sandbox_dir}/#{new_file}"
66
+
67
+ lambda { @entry.rename(new_file) }.should raise_error(Rush::NameAlreadyExists, /#{new_file}/)
68
+ end
69
+
70
+ it "can't rename itself to something with a slash in it" do
71
+ lambda { @entry.rename('has/slash') }.should raise_error(Rush::NameCannotContainSlash, /slash/)
72
+ end
73
+
74
+ it "can duplicate itself within the directory" do
75
+ @entry.duplicate('newfile').should == Rush::File.new("#{@sandbox_dir}/newfile")
76
+ end
77
+
78
+ it "can move itself to another dir" do
79
+ newdir = "#{@sandbox_dir}/newdir"
80
+ system "mkdir -p #{newdir}"
81
+
82
+ dst = Rush::Dir.new(newdir)
83
+ @entry.move_to(dst)
84
+
85
+ File.exists?(@filename).should be_false
86
+ File.exists?("#{newdir}/#{@entry.name}").should be_true
87
+ end
88
+
89
+ it "can copy itself to another directory" do
90
+ newdir = "#{@sandbox_dir}/newdir"
91
+ system "mkdir -p #{newdir}"
92
+
93
+ dst = Rush::Dir.new(newdir)
94
+ @copied_dir = @entry.copy_to(dst)
95
+
96
+ File.exists?(@filename).should be_true
97
+ File.exists?("#{newdir}/#{@entry.name}").should be_true
98
+
99
+ @copied_dir.full_path.should == "#{@sandbox_dir}newdir/#{@entry.name}"
100
+ end
101
+
102
+ it "considers dotfiles to be hidden" do
103
+ Rush::Entry.new("#{@sandbox_dir}/show").should_not be_hidden
104
+ Rush::Entry.new("#{@sandbox_dir}/.dont_show").should be_hidden
105
+ end
106
+
107
+ it "is considered equal to entries with the same full path and on the same box" do
108
+ same = Rush::Entry.new(@entry.full_path, @entry.box)
109
+ @entry.should == same
110
+ end
111
+
112
+ it "is considered not equal to entries with the same full path on a different box" do
113
+ same = Rush::Entry.new(@entry.full_path, Rush::Box.new('dummy'))
114
+ @entry.should_not == same
115
+ end
116
+
117
+ it "can mimic another entry" do
118
+ copy = Rush::Entry.new('abc', :dummy)
119
+ copy.mimic(@entry)
120
+ copy.path.should == @entry.path
121
+ end
122
+
123
+ it "can update the read access permission" do
124
+ system "chmod 666 #{@filename}"
125
+ @entry.access = { :user_can => :read }
126
+ `ls -l #{@filename}`.should match(/^-r--------/)
127
+ end
128
+
129
+ it "reads the file permissions in the access hash" do
130
+ system "chmod 640 #{@filename}"
131
+ @entry.access.should == { :user_can_read => true, :user_can_write => true, :group_can_read => true }
132
+ end
133
+ end
@@ -0,0 +1,83 @@
1
+ require File.dirname(__FILE__) + '/base'
2
+
3
+ describe Rush::File do
4
+ before do
5
+ @sandbox_dir = "/tmp/rush_spec.#{Process.pid}"
6
+ system "rm -rf #{@sandbox_dir}; mkdir -p #{@sandbox_dir}"
7
+
8
+ @filename = "#{@sandbox_dir}/test_file"
9
+ @contents = "1234"
10
+ system "echo #{@contents} > #{@filename}"
11
+ @contents += "\n"
12
+
13
+ @file = Rush::File.new(@filename)
14
+ end
15
+
16
+ after do
17
+ system "rm -rf #{@sandbox_dir}"
18
+ end
19
+
20
+ it "is a child of Rush::Entry" do
21
+ @file.should be_kind_of(Rush::Entry)
22
+ end
23
+
24
+ it "is not a dir" do
25
+ @file.should_not be_dir
26
+ end
27
+
28
+ it "can create itself as a blank file, and return itself" do
29
+ create_me = Rush::File.new("#{@sandbox_dir}/create_me")
30
+ create_me.create.should == create_me
31
+ File.exists?("#{@sandbox_dir}/create_me").should == true
32
+ end
33
+
34
+ it "knows its size in bytes" do
35
+ @file.size.should == @contents.length
36
+ end
37
+
38
+ it "can read its contents" do
39
+ @file.contents.should == @contents
40
+ end
41
+
42
+ it "read is an alias for contents" do
43
+ @file.read.should == @contents
44
+ end
45
+
46
+ it "can write new contents" do
47
+ @file.write('write test')
48
+ @file.contents.should == 'write test'
49
+ end
50
+
51
+ it "can count the number of lines it contains" do
52
+ @file.write("1\n2\n3\n")
53
+ @file.line_count.should == 3
54
+ end
55
+
56
+ it "searches its contents for matching lines" do
57
+ @file.write("a\n1\nb\n2\n")
58
+ @file.search(/\d/).should == %w(1 2)
59
+ end
60
+
61
+ it "search returns nil if no lines match" do
62
+ @file.write("a\nb\nc\n")
63
+ @file.search(/\d/).should be_nil
64
+ end
65
+
66
+ it "find-in-file replace" do
67
+ @file.replace_contents!(/\d/, 'x')
68
+ @file.contents.should == "xxxx\n"
69
+ end
70
+
71
+ it "can destroy itself" do
72
+ @file.destroy
73
+ ::File.exists?(@filename).should be_false
74
+ end
75
+
76
+ it "can fetch contents or blank if doesn't exist" do
77
+ Rush::File.new('/does/not/exist').contents_or_blank.should == ""
78
+ end
79
+
80
+ it "can fetch lines, or empty if doesn't exist" do
81
+ Rush::File.new('/does/not/exist').lines_or_empty.should == []
82
+ end
83
+ end
@@ -0,0 +1,58 @@
1
+ require File.dirname(__FILE__) + '/base'
2
+
3
+ describe Rush::FindBy do
4
+ before do
5
+ class Foo
6
+ attr_accessor :bar
7
+
8
+ def initialize(bar)
9
+ @bar = bar
10
+ end end
11
+
12
+ @one = Foo.new('one')
13
+ @two = Foo.new('two')
14
+ @three = Foo.new('three')
15
+
16
+ @list = [ @one, @two, @three ]
17
+ end
18
+
19
+ it "compare_or_match exact match success" do
20
+ @list.compare_or_match('1', '1').should == true
21
+ end
22
+
23
+ it "compare_or_match exact match failure" do
24
+ @list.compare_or_match('1', '2').should == false
25
+ end
26
+
27
+ it "compare_or_match regexp match success" do
28
+ @list.compare_or_match('123', /2/).should == true
29
+ end
30
+
31
+ it "compare_or_match regexp match failure" do
32
+ @list.compare_or_match('123', /x/).should == false
33
+ end
34
+
35
+ it "find_by_ extact match" do
36
+ @list.find_by_bar('two').should == @two
37
+ end
38
+
39
+ it "find_by_ regexp match" do
40
+ @list.find_by_bar(/.hree/).should == @three
41
+ end
42
+
43
+ it "find_all_by_ exact match" do
44
+ @list.find_all_by_bar('one').should == [ @one ]
45
+ end
46
+
47
+ it "find_all_by_ regexp match" do
48
+ @list.find_all_by_bar(/^...$/).should == [ @one, @two ]
49
+ end
50
+
51
+ it "find_by_ with field not recognized by objects raises no errors" do
52
+ @list.find_by_nothing('x')
53
+ end
54
+
55
+ it "raises NoMethodError for things other than find_by" do
56
+ lambda { @list.does_not_exist }.should raise_error(NoMethodError)
57
+ end
58
+ end
@@ -0,0 +1,19 @@
1
+ require File.dirname(__FILE__) + '/base'
2
+
3
+ describe Fixnum do
4
+ before do
5
+ @num = 2
6
+ end
7
+
8
+ it "counts kb" do
9
+ @num.kb.should == 2*1024
10
+ end
11
+
12
+ it "counts mb" do
13
+ @num.mb.should == 2*1024*1024
14
+ end
15
+
16
+ it "counts gb" do
17
+ @num.gb.should == 2*1024*1024*1024
18
+ end
19
+ end
@@ -0,0 +1,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