scmd 2.2.0 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/scmd/command.rb CHANGED
@@ -86,10 +86,10 @@ module Scmd
86
86
  end
87
87
  end
88
88
 
89
- def kill
89
+ def kill(sig = nil)
90
90
  return if !running?
91
91
 
92
- send_kill
92
+ send_kill(sig)
93
93
  wait # indefinitely until cmd is killed
94
94
  end
95
95
 
@@ -146,13 +146,13 @@ module Scmd
146
146
  send_signal 'TERM'
147
147
  end
148
148
 
149
- def send_kill
150
- send_signal 'KILL'
149
+ def send_kill(sig = nil)
150
+ send_signal(sig || 'KILL')
151
151
  end
152
152
 
153
153
  def send_signal(sig)
154
154
  return if !running?
155
- ::Process.kill sig, @child_process.pid
155
+ @child_process.send_signal(sig)
156
156
  end
157
157
 
158
158
  def stringify_hash(hash)
@@ -201,6 +201,10 @@ module Scmd
201
201
  end
202
202
  end
203
203
 
204
+ def send_signal(sig)
205
+ process_kill(sig, self.pid)
206
+ end
207
+
204
208
  def flush_stdout; @stdout.read; end
205
209
  def flush_stderr; @stderr.read; end
206
210
 
@@ -218,6 +222,19 @@ module Scmd
218
222
  io.read_nonblock(size)
219
223
  end
220
224
 
225
+ def process_kill(sig, pid)
226
+ child_pids(pid).each{ |p| process_kill(sig, p) }
227
+ ::Process.kill(sig, pid)
228
+ end
229
+
230
+ def child_pids(pid)
231
+ Command.new("#{pgrep} -P #{pid}").run.stdout.split("\n").map(&:to_i)
232
+ end
233
+
234
+ def pgrep
235
+ @pgrep ||= Command.new('which pgrep').run.stdout.strip
236
+ end
237
+
221
238
  end
222
239
 
223
240
  end
data/lib/scmd/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Scmd
2
- VERSION = "2.2.0"
2
+ VERSION = "2.3.0"
3
3
  end
@@ -0,0 +1,173 @@
1
+ require "assert"
2
+ require 'scmd/command'
3
+
4
+ class Scmd::Command
5
+
6
+ class SystemTests < Assert::Context
7
+ desc "Scmd::Command"
8
+ setup do
9
+ @success_cmd = Scmd::Command.new("echo hi")
10
+ @failure_cmd = Scmd::Command.new("cd /path/that/does/not/exist")
11
+ end
12
+
13
+ should "run the command and set appropriate result data" do
14
+ @success_cmd.run
15
+
16
+ assert_not_nil @success_cmd.pid
17
+ assert_equal 0, @success_cmd.exitstatus
18
+ assert @success_cmd.success?
19
+ assert_equal "hi\n", @success_cmd.stdout
20
+ assert_equal '', @success_cmd.stderr
21
+
22
+ @failure_cmd.run
23
+
24
+ assert_not_nil @failure_cmd.pid
25
+ assert_not_equal 0, @failure_cmd.exitstatus
26
+ assert_not @failure_cmd.success?
27
+ assert_equal '', @failure_cmd.stdout
28
+ assert_not_equal '', @failure_cmd.stderr
29
+ end
30
+
31
+ should "raise an exception with proper backtrace on `run!`" do
32
+ err = begin;
33
+ @failure_cmd.run!
34
+ rescue Exception => err
35
+ err
36
+ end
37
+
38
+ assert_kind_of Scmd::RunError, err
39
+ assert_includes 'No such file or directory', err.message
40
+ assert_includes 'test/system/command_tests.rb:', err.backtrace.first
41
+ end
42
+
43
+ should "return itself on `run`, `run!`" do
44
+ assert_equal @success_cmd, @success_cmd.run
45
+ assert_equal @success_cmd, @success_cmd.run!
46
+ assert_equal @failure_cmd, @failure_cmd.run
47
+ end
48
+
49
+ should "start and be running until `wait` is called and the cmd exits" do
50
+ cmd = Scmd::Command.new("sleep .1")
51
+ assert_not cmd.running?
52
+
53
+ cmd.start
54
+ assert cmd.running?
55
+ assert_not_nil cmd.pid
56
+
57
+ cmd.wait
58
+ assert_not cmd.running?
59
+ end
60
+
61
+ end
62
+
63
+ class InputTests < SystemTests
64
+ desc "that takes input on stdin"
65
+ setup do
66
+ @cmd = Scmd::Command.new("sh")
67
+ end
68
+ subject { @cmd }
69
+
70
+ should "run the command given a single line of input" do
71
+ subject.run "echo hi"
72
+
73
+ assert @cmd.success?
74
+ assert_equal "hi\n", @cmd.stdout
75
+ end
76
+
77
+ should "run the command given multiple lines of input" do
78
+ subject.run ["echo hi", "echo err 1>&2"]
79
+
80
+ assert @cmd.success?
81
+ assert_equal "hi\n", @cmd.stdout
82
+ assert_equal "err\n", @cmd.stderr
83
+ end
84
+
85
+ end
86
+
87
+ class LongRunningTests < SystemTests
88
+ desc "that is long running"
89
+ setup do
90
+ @long_cmd = Scmd::Command.new("sleep .3 && echo hi")
91
+ end
92
+
93
+ should "not timeout if wait timeout is longer than cmd time" do
94
+ assert_nothing_raised do
95
+ @long_cmd.start
96
+ @long_cmd.wait(1)
97
+ end
98
+ assert @long_cmd.success?
99
+ assert_equal "hi\n", @long_cmd.stdout
100
+ end
101
+
102
+ should "timeout if wait timeout is shorter than cmd time" do
103
+ assert_raises(Scmd::TimeoutError) do
104
+ @long_cmd.start
105
+ @long_cmd.wait(0.1)
106
+ end
107
+ assert_not @long_cmd.success?
108
+ assert_empty @long_cmd.stdout
109
+ end
110
+
111
+ should "be stoppable" do
112
+ @long_cmd.start
113
+ @long_cmd.stop
114
+
115
+ assert_not @long_cmd.running?
116
+ end
117
+
118
+ should "be killable" do
119
+ @long_cmd.start
120
+ @long_cmd.kill
121
+
122
+ assert_not @long_cmd.running?
123
+ end
124
+
125
+ should "be killable with a non-default signal" do
126
+ @long_cmd.start
127
+ @long_cmd.kill('INT')
128
+
129
+ assert_not @long_cmd.running?
130
+ end
131
+
132
+ end
133
+
134
+ class BufferDeadlockTests < SystemTests
135
+ desc "when capturing data from an output buffer"
136
+ setup do
137
+ @small_path = File.join(ROOT_PATH, 'test/support/smaller-than-64k.txt')
138
+ @small_data = File.read(@small_path)
139
+ @small_cmd = Scmd::Command.new("cat #{@small_path}")
140
+
141
+ @big_path = File.join(ROOT_PATH, 'test/support/bigger-than-64k.txt')
142
+ @big_data = File.read(@big_path)
143
+ @big_cmd = Scmd::Command.new("cat #{@big_path}")
144
+ end
145
+
146
+ should "not deadlock, just stream the data from the buffer" do
147
+ @small_cmd.start
148
+ assert_nothing_raised{ @small_cmd.wait(1) }
149
+ assert_equal @small_data, @small_cmd.stdout
150
+
151
+ @big_cmd.start
152
+ assert_nothing_raised{ @big_cmd.wait(1) }
153
+ assert_equal @big_data, @big_cmd.stdout
154
+ end
155
+
156
+ end
157
+
158
+ class WithEnvVarTests < SystemTests
159
+ desc "with environment variables"
160
+ setup do
161
+ @cmd = Scmd::Command.new("echo $SCMD_TEST_VAR", {
162
+ 'SCMD_TEST_VAR' => 'test'
163
+ })
164
+ end
165
+
166
+ should "use them when running the command" do
167
+ @cmd.run
168
+ assert_equal "test\n", @cmd.stdout
169
+ end
170
+
171
+ end
172
+
173
+ end
@@ -6,10 +6,9 @@ class Scmd::Command
6
6
  class UnitTests < Assert::Context
7
7
  desc "Scmd::Command"
8
8
  setup do
9
- @success_cmd = Scmd::Command.new("echo hi")
10
- @failure_cmd = Scmd::Command.new("cd /path/that/does/not/exist")
9
+ @cmd = Scmd::Command.new("echo hi")
11
10
  end
12
- subject { @success_cmd }
11
+ subject { @cmd }
13
12
 
14
13
  should have_readers :cmd_str, :env
15
14
  should have_readers :pid, :exitstatus, :stdout, :stderr
@@ -41,52 +40,9 @@ class Scmd::Command
41
40
  assert_equal '', subject.stderr
42
41
  end
43
42
 
44
- should "run the command and set appropriate result data" do
45
- @success_cmd.run
46
-
47
- assert_not_nil @success_cmd.pid
48
- assert_equal 0, @success_cmd.exitstatus
49
- assert @success_cmd.success?
50
- assert_equal "hi\n", @success_cmd.stdout
51
- assert_equal '', @success_cmd.stderr
52
-
53
- @failure_cmd.run
54
-
55
- assert_not_nil @failure_cmd.pid
56
- assert_not_equal 0, @failure_cmd.exitstatus
57
- assert_not @failure_cmd.success?
58
- assert_equal '', @failure_cmd.stdout
59
- assert_not_equal '', @failure_cmd.stderr
60
- end
61
-
62
- should "raise an exception with proper backtrace on `run!`" do
63
- err = begin;
64
- @failure_cmd.run!
65
- rescue Exception => err
66
- err
67
- end
68
-
69
- assert_kind_of Scmd::RunError, err
70
- assert_includes 'No such file or directory', err.message
71
- assert_includes 'test/unit/command_tests.rb:', err.backtrace.first
72
- end
73
-
74
- should "return itself on `run`, `run!`" do
75
- assert_equal @success_cmd, @success_cmd.run
76
- assert_equal @success_cmd, @success_cmd.run!
77
- assert_equal @failure_cmd, @failure_cmd.run
78
- end
79
-
80
- should "start and be running until `wait` is called and the cmd exits" do
81
- cmd = Scmd::Command.new("sleep .1")
82
- assert_not cmd.running?
83
-
84
- cmd.start
85
- assert cmd.running?
86
- assert_not_nil cmd.pid
87
-
88
- cmd.wait
89
- assert_not cmd.running?
43
+ should "default its state" do
44
+ assert_false subject.running?
45
+ assert_false subject.success?
90
46
  end
91
47
 
92
48
  should "do nothing and return when told to wait but not running" do
@@ -115,107 +71,4 @@ class Scmd::Command
115
71
 
116
72
  end
117
73
 
118
- class InputTests < UnitTests
119
- desc "that takes input on stdin"
120
- setup do
121
- @cmd = Scmd::Command.new("sh")
122
- end
123
- subject { @cmd }
124
-
125
- should "run the command given a single line of input" do
126
- subject.run "echo hi"
127
-
128
- assert @cmd.success?
129
- assert_equal "hi\n", @cmd.stdout
130
- end
131
-
132
- should "run the command given multiple lines of input" do
133
- subject.run ["echo hi", "echo err 1>&2"]
134
-
135
- assert @cmd.success?
136
- assert_equal "hi\n", @cmd.stdout
137
- assert_equal "err\n", @cmd.stderr
138
- end
139
-
140
- end
141
-
142
- class LongRunningTests < UnitTests
143
- desc "that is long running"
144
- setup do
145
- @long_cmd = Scmd::Command.new("sleep .3 && echo hi")
146
- end
147
-
148
- should "not timeout if wait timeout is longer than cmd time" do
149
- assert_nothing_raised do
150
- @long_cmd.start
151
- @long_cmd.wait(1)
152
- end
153
- assert @long_cmd.success?
154
- assert_equal "hi\n", @long_cmd.stdout
155
- end
156
-
157
- should "timeout if wait timeout is shorter than cmd time" do
158
- assert_raises(Scmd::TimeoutError) do
159
- @long_cmd.start
160
- @long_cmd.wait(0.1)
161
- end
162
- assert_not @long_cmd.success?
163
- assert_empty @long_cmd.stdout
164
- end
165
-
166
- should "be stoppable" do
167
- @long_cmd.start
168
- @long_cmd.stop
169
-
170
- assert_not @long_cmd.running?
171
- end
172
-
173
- should "be killable" do
174
- @long_cmd.start
175
- @long_cmd.kill
176
-
177
- assert_not @long_cmd.running?
178
- end
179
-
180
- end
181
-
182
- class BufferDeadlockTests < UnitTests
183
- desc "when capturing data from an output buffer"
184
- setup do
185
- @small_path = File.join(ROOT_PATH, 'test/support/smaller-than-64k.txt')
186
- @small_data = File.read(@small_path)
187
- @small_cmd = Scmd::Command.new("cat #{@small_path}")
188
-
189
- @big_path = File.join(ROOT_PATH, 'test/support/bigger-than-64k.txt')
190
- @big_data = File.read(@big_path)
191
- @big_cmd = Scmd::Command.new("cat #{@big_path}")
192
- end
193
-
194
- should "not deadlock, just stream the data from the buffer" do
195
- @small_cmd.start
196
- assert_nothing_raised{ @small_cmd.wait(1) }
197
- assert_equal @small_data, @small_cmd.stdout
198
-
199
- @big_cmd.start
200
- assert_nothing_raised{ @big_cmd.wait(1) }
201
- assert_equal @big_data, @big_cmd.stdout
202
- end
203
-
204
- end
205
-
206
- class WithEnvVarTests < UnitTests
207
- desc "with environment variables"
208
- setup do
209
- @cmd = Scmd::Command.new("echo $SCMD_TEST_VAR", {
210
- 'SCMD_TEST_VAR' => 'test'
211
- })
212
- end
213
-
214
- should "use them when running the command" do
215
- @cmd.run
216
- assert_equal "test\n", @cmd.stdout
217
- end
218
-
219
- end
220
-
221
74
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: scmd
3
3
  version: !ruby/object:Gem::Version
4
- hash: 7
4
+ hash: 3
5
5
  prerelease:
6
6
  segments:
7
7
  - 2
8
- - 2
8
+ - 3
9
9
  - 0
10
- version: 2.2.0
10
+ version: 2.3.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Kelly Redding
@@ -16,7 +16,7 @@ autorequire:
16
16
  bindir: bin
17
17
  cert_chain: []
18
18
 
19
- date: 2014-06-13 00:00:00 Z
19
+ date: 2014-07-31 00:00:00 Z
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
22
22
  requirement: &id001 !ruby/object:Gem::Requirement
@@ -29,9 +29,9 @@ dependencies:
29
29
  - 2
30
30
  - 3
31
31
  version: "2.3"
32
- version_requirements: *id001
33
32
  type: :development
34
33
  name: assert
34
+ version_requirements: *id001
35
35
  prerelease: false
36
36
  - !ruby/object:Gem::Dependency
37
37
  requirement: &id002 !ruby/object:Gem::Requirement
@@ -43,9 +43,9 @@ dependencies:
43
43
  segments:
44
44
  - 0
45
45
  version: "0"
46
- version_requirements: *id002
47
46
  type: :runtime
48
47
  name: posix-spawn
48
+ version_requirements: *id002
49
49
  prerelease: false
50
50
  description: Build and run system commands.
51
51
  email:
@@ -74,6 +74,7 @@ files:
74
74
  - test/helper.rb
75
75
  - test/support/bigger-than-64k.txt
76
76
  - test/support/smaller-than-64k.txt
77
+ - test/system/command_tests.rb
77
78
  - test/unit/command_tests.rb
78
79
  - test/unit/scmd_tests.rb
79
80
  - tmp/.gitkeep
@@ -106,7 +107,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
106
107
  requirements: []
107
108
 
108
109
  rubyforge_project:
109
- rubygems_version: 1.8.29
110
+ rubygems_version: 1.8.25
110
111
  signing_key:
111
112
  specification_version: 3
112
113
  summary: Build and run system commands.
@@ -114,5 +115,6 @@ test_files:
114
115
  - test/helper.rb
115
116
  - test/support/bigger-than-64k.txt
116
117
  - test/support/smaller-than-64k.txt
118
+ - test/system/command_tests.rb
117
119
  - test/unit/command_tests.rb
118
120
  - test/unit/scmd_tests.rb