-
Notifications
You must be signed in to change notification settings - Fork 0
/
executioner_test.rb
198 lines (160 loc) · 7.45 KB
/
executioner_test.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
require File.expand_path('../test_helper', __FILE__)
class AClassThatUsesSubshells
include Executioner
executable :sh
executable :doesnotexistforsure
executable 'executable-with-dash'
executable :with_path, :path => '/path/to/executable'
executable :with_env, :path => '/path/to/executable', :env => { :foo => 'bar' }
public :execute
end
describe "Executioner, when executing" do
before do
@object = AClassThatUsesSubshells.new
end
it "should open a pipe with the given command" do
Open3.expects(:popen3).with('/the/command')
@object.execute('/the/command')
end
it "should return the output received from stdout" do
stub_popen3 'stdout output', ''
@object.execute('/the/command').should == 'stdout output'
end
it "should return the output received from stderr if they should be reversed" do
stub_popen3 '', 'stderr output'
@object.execute('/the/command', :switch_stdout_and_stderr => true).should == 'stderr output'
end
it "should raise a Executioner::ProcessError if stdout is empty and stderr is not" do
stub_popen3 '', 'stderr output'
lambda { @object.execute('foo') }.should.raise Executioner::ProcessError
end
it "should raise a Executioner::ProcessError if stderr is empty and stdout is not and the streams are reversed" do
stub_popen3 'stdout output', ''
lambda { @object.execute('foo', :switch_stdout_and_stderr => true) }.should.raise Executioner::ProcessError
end
it "should prepend the given env variables" do
Open3.expects(:popen3).with("foo='bar' /the/command")
@object.execute('/the/command', :env => { :foo => :bar })
end
it "should log the command that's going to be executed if a logger is available" do
begin
logger = mock('Logger')
Executioner.logger = logger
logger.expects(:debug).with("Executing: `foo'")
stub_popen3
@object.execute('foo')
ensure
Executioner.logger = nil
end
end
private
def stub_popen3(stdout = '', stderr = '')
Open3.stubs(:popen3).yields(*['stdin', stdout, stderr].map { |s| StringIO.new(s) })
end
end
describe "Executioner, instance methods" do
before do
@object = AClassThatUsesSubshells.new
end
it "should raise a Executioner::ProcessError if a command could not be executed" do
proc = lambda { @object.send(:execute, "/bin/sh -M") }
proc.should.raise Executioner::ProcessError
begin
proc.call
rescue Executioner::ProcessError => error
error.message.should =~ %r%Command: "/bin/sh -M"%
error.message.should =~ %r%Output: "/bin/sh: -M: invalid option%
end
end
it "should be able to switch stdout and stderr, for instance for ffmpeg" do
lambda { @object.send(:execute, "/bin/sh -M", :switch_stdout_and_stderr => true) }.should.not.raise Executioner::ProcessError
end
it "should help concat arguments" do
@object.send(:concat_args, [[:foo, 'foo'], [:bar, 'bar']]).should == "-foo foo -bar bar"
end
it "should queue one command" do
@object.send(:queue, 'ls')
@object.send(:queued_commands).should == 'ls'
end
it "should queue multiple commands" do
@object.send(:queue, 'ls')
@object.send(:queue, 'cat')
@object.send(:queued_commands).should == 'ls && cat'
end
it "should execute queued commands" do
@object.send(:queue, 'ls')
@object.send(:queue, 'ls')
@object.expects(:execute).with(@object.send(:queued_commands), {})
@object.send(:execute_queued)
@object.send(:queued_commands).should == ''
end
end
describe "Executioner, class methods" do
before do
@object = AClassThatUsesSubshells.new
end
it "should define an instance method for the specified binary that's needed" do
AClassThatUsesSubshells.instance_methods.should.include 'sh'
end
it "should define an instance method which calls #execute with the correct path to the executable" do
@object.expects(:execute).with('/bin/sh with some args', { :switch_stdout_and_stderr => false })
@object.sh 'with some args'
end
it "should define an instance method for an executable with dashes replaced by underscores" do
@object.should.respond_to :executable_with_dash
end
it "should be possible to switch stdin and stderr" do
AClassThatUsesSubshells.class_eval { executable(:sh, { :switch_stdout_and_stderr => true }) }
@object.expects(:execute).with('/bin/sh with some args', { :switch_stdout_and_stderr => true })
@object.sh 'with some args'
end
it "should be possible to use the queue by default" do
AClassThatUsesSubshells.class_eval { executable(:sh, { :use_queue => true }) }
@object.expects(:execute).with('/bin/sh arg1 && /bin/sh arg2', {})
@object.sh 'arg1'
@object.sh 'arg2'
@object.execute_queued
end
it "should be possible to specify the path to the executable" do
@object.expects(:execute).with { |command, options| command == "/path/to/executable arg1" }
@object.with_path 'arg1'
end
it "should be possible to specify the env that's to be prepended to the command" do
@object.expects(:execute).with { |command, options| options[:env] == { :foo => 'bar' } }
@object.with_env 'arg1'
end
it "should merge options onto the default options" do
@object.expects(:execute).with { |command, options| options[:env] == { :foo => 'foo' } }
@object.with_env 'arg1', :env => { :foo => 'foo' }
end
it "should be possible to find an executable" do
File.stubs(:exist?).with(File.expand_path('~/bin/sh')).returns(false)
File.stubs(:exist?).with('/bin/sh').returns(true)
Executioner::ClassMethods.find_executable('sh').should == '/bin/sh'
end
it "should be possible to find an executable advancing from a given path" do
File.stubs(:exist?).with('/usr/bin/sh').returns(true)
Executioner::ClassMethods.find_executable('sh', '/bin').should == '/usr/bin/sh'
end
it "should yield all found executables, but use the one for which the proc returns a truthful value" do
File.stubs(:exist?).with(File.expand_path('~/bin/with_selection_proc')).returns(true)
File.stubs(:exist?).with('/bin/with_selection_proc').returns(true)
File.stubs(:exist?).with('/usr/bin/with_selection_proc').returns(true)
File.stubs(:exist?).with('/usr/local/bin/with_selection_proc').returns(true)
File.stubs(:exist?).with('/opt/homebrew/bin/with_selection_proc').returns(true)
File.stubs(:exist?).with('/opt/local/bin/with_selection_proc').returns(true)
AClassThatUsesSubshells.executable(:with_selection_proc, :select_if => lambda { |executable| nil })
lambda { @object.with_selection_proc('foo') }.should.raise Executioner::ExecutableNotFoundError
AClassThatUsesSubshells.executable(:with_selection_proc, :select_if => lambda { |executable| executable == '/usr/bin/with_selection_proc' })
@object.expects(:execute).with("/usr/bin/with_selection_proc foo", {:switch_stdout_and_stderr => false})
@object.with_selection_proc('foo')
AClassThatUsesSubshells.executable(:with_selection_proc, :select_if => lambda { |executable| executable == '/opt/local/bin/with_selection_proc' })
@object.expects(:execute).with("/opt/local/bin/with_selection_proc foo", {:switch_stdout_and_stderr => false})
@object.with_selection_proc('foo')
end
it "should define an instance method which raises a Executioner::ExecutableNotFoundError error if the executable could not be found" do
lambda {
@object.doesnotexistforsure 'right?'
}.should.raise Executioner::ExecutableNotFoundError
end
end