scmd 2.2.0 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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