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