win32-process 0.6.4 → 0.6.5

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/CHANGES CHANGED
@@ -1,3 +1,15 @@
1
+ = 0.6.5 - 27-Dec-2010
2
+ * Fixed getpriority and setpriority so that the underlying process handle is
3
+ always closed. Thanks go to Rafal Michalski for the spot and patch.
4
+ * Updated getpriority and setpriority so that there are no longer any
5
+ default arguments. This now matches the MRI spec.
6
+ * Updated Process.create so that illegal options now raise an ArgumentError
7
+ instead of a Process::Error.
8
+ * Fixed a bug in an error message in the Process.create method where the actual
9
+ error message was getting lost.
10
+ * Refactored the test suite to use test-unit 2.x features, and make tests a
11
+ little more robust in general.
12
+
1
13
  = 0.6.4 - 13-Nov-2010
2
14
  * Altered the wait, wait2, waitpid and waitpid2 methods to match the current
3
15
  MRI interface, i.e. they accept and optional pid and flags, though the
data/README CHANGED
@@ -1,14 +1,14 @@
1
1
  = Description
2
- This package provides the fork, wait, wait2, waitpid, and waitpid2 methods
2
+ This library provides the fork, wait, wait2, waitpid, and waitpid2 methods
3
3
  for MS Windows. In addition, it provides a different implementation of the
4
4
  kill method, a proper implementation of Process.ppid, and decent analogues
5
- of Process.getpriority, Process.setpriority and Process.getrlimit.
5
+ of Process.getpriority, Process.setpriority, Process.getrlimit and
6
+ Process.setrlimit.
6
7
 
7
8
  = Prerequisites
8
- Ruby 1.8.2 or later.
9
- The windows-pr library, 0.8.6 or later.
10
- The sys-proctable library, 0.7.6 or later (test suite only).
11
- The test-unit library, 2.0.3 or later (test suite only).
9
+ * windows-pr
10
+ * sys-proctable (dev only)
11
+ * test-unit 2 (dev only)
12
12
 
13
13
  = Supported Platforms
14
14
  This library is supported on Windows 2000 or later.
@@ -104,7 +104,7 @@
104
104
  Artistic 2.0
105
105
 
106
106
  = Copyright
107
- (C) 2003-2010 Daniel J. Berger
107
+ (C) 2003-2011 Daniel J. Berger
108
108
  All Rights Reserved
109
109
 
110
110
  = Warranty
data/Rakefile CHANGED
@@ -8,7 +8,7 @@ CLEAN.include('**/*.gem', '**/*.rbc')
8
8
 
9
9
  namespace :gem do
10
10
  desc 'Create the win32-process gem'
11
- task :create do
11
+ task :create => [:clean] do
12
12
  spec = eval(IO.read('win32-process.gemspec'))
13
13
  Gem::Builder.new(spec).build
14
14
  end
data/lib/win32/process.rb CHANGED
@@ -21,7 +21,13 @@ module Process
21
21
  undef_method :setpriority, :wait, :wait2, :waitpid, :waitpid2, :uid
22
22
 
23
23
  # The version of the win32-process library
24
- WIN32_PROCESS_VERSION = '0.6.4'
24
+ WIN32_PROCESS_VERSION = '0.6.5'
25
+
26
+ # Defined for interface compatibility, but not used
27
+
28
+ PRIO_PROCESS = 0
29
+ PRIO_PGRP = 1
30
+ PRIO_USER = 2
25
31
 
26
32
  include Windows::Process
27
33
  include Windows::Thread
@@ -307,10 +313,10 @@ module Process
307
313
  end
308
314
 
309
315
  # Retrieves the priority class for the specified process id +int+. Unlike
310
- # the default implementation, lower values do not necessarily correspond to
311
- # higher priority classes.
316
+ # the default implementation, lower return values do not necessarily
317
+ # correspond to higher priority classes.
312
318
  #
313
- # The +kind+ parameter is ignored but present for API compatibility.
319
+ # The +kind+ parameter is ignored but required for API compatibility.
314
320
  # You can only retrieve process information, not process group or user
315
321
  # information, so it is effectively always Process::PRIO_PROCESS.
316
322
  #
@@ -323,8 +329,11 @@ module Process
323
329
  # 16384 - Process::BELOW_NORMAL_PRIORITY_CLASS
324
330
  # 32768 - Process::ABOVE_NORMAL_PRIORITY_CLASS
325
331
  #
326
- def getpriority(kind = Process::PRIO_PROCESS, int = nil)
327
- raise ArgumentError unless int
332
+ def getpriority(kind, int)
333
+ raise TypeError unless kind.is_a?(Integer)
334
+ raise TypeError unless int.is_a?(Integer)
335
+
336
+ int = Process.pid if int == 0 # Match spec
328
337
 
329
338
  handle = OpenProcess(PROCESS_QUERY_INFORMATION, 0 , int)
330
339
 
@@ -332,10 +341,14 @@ module Process
332
341
  raise Error, get_last_error
333
342
  end
334
343
 
335
- priority_class = GetPriorityClass(handle)
344
+ begin
345
+ priority_class = GetPriorityClass(handle)
336
346
 
337
- if priority_class == 0
338
- raise Error, get_last_error
347
+ if priority_class == 0
348
+ raise Error, get_last_error
349
+ end
350
+ ensure
351
+ CloseHandle(handle)
339
352
  end
340
353
 
341
354
  priority_class
@@ -356,9 +369,12 @@ module Process
356
369
  # * Process::BELOW_NORMAL_PRIORITY_CLASS
357
370
  # * Process::ABOVE_NORMAL_PRIORITY_CLASS
358
371
  #
359
- def setpriority(kind = nil, int = nil, int_priority = nil)
360
- raise ArgumentError unless int
361
- raise ArgumentError unless int_priority
372
+ def setpriority(kind, int, int_priority)
373
+ raise TypeError unless kind.is_a?(Integer)
374
+ raise TypeError unless int.is_a?(Integer)
375
+ raise TypeError unless int_priority.is_a?(Integer)
376
+
377
+ int = Process.pid if int == 0 # Match spec
362
378
 
363
379
  handle = OpenProcess(PROCESS_SET_INFORMATION, 0 , int)
364
380
 
@@ -366,8 +382,12 @@ module Process
366
382
  raise Error, get_last_error
367
383
  end
368
384
 
369
- unless SetPriorityClass(handle, int_priority)
370
- raise Error, get_last_error
385
+ begin
386
+ unless SetPriorityClass(handle, int_priority)
387
+ raise Error, get_last_error
388
+ end
389
+ ensure
390
+ CloseHandle(handle)
371
391
  end
372
392
 
373
393
  return 0 # Match the spec
@@ -384,6 +404,8 @@ module Process
384
404
  def uid(sid = false)
385
405
  token = 0.chr * 4
386
406
 
407
+ raise TypeError unless sid.is_a?(TrueClass) || sid.is_a?(FalseClass)
408
+
387
409
  unless OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, token)
388
410
  raise Error, get_last_error
389
411
  end
@@ -710,7 +732,7 @@ module Process
710
732
  args.each{ |key, val|
711
733
  key = key.to_s.downcase
712
734
  unless valid_keys.include?(key)
713
- raise Error, "invalid key '#{key}'"
735
+ raise ArgumentError, "invalid key '#{key}'"
714
736
  end
715
737
  hash[key] = val
716
738
  }
@@ -722,7 +744,7 @@ module Process
722
744
  hash['startup_info'].each{ |key, val|
723
745
  key = key.to_s.downcase
724
746
  unless valid_si_keys.include?(key)
725
- raise Error, "invalid startup_info key '#{key}'"
747
+ raise ArgumentError, "invalid startup_info key '#{key}'"
726
748
  end
727
749
  si_hash[key] = val
728
750
  }
@@ -735,7 +757,7 @@ module Process
735
757
  hash['command_line'] = hash['app_name']
736
758
  hash['app_name'] = nil
737
759
  else
738
- raise Error, 'command_line or app_name must be specified'
760
+ raise ArgumentError, 'command_line or app_name must be specified'
739
761
  end
740
762
  end
741
763
 
@@ -864,7 +886,7 @@ module Process
864
886
  # TODO: Close stdin, stdout and stderr handles in the si_hash unless
865
887
  # they're pointing to one of the standard handles already. [Maybe]
866
888
  unless bool
867
- raise Error, "CreateProcess() failed: ", get_last_error
889
+ raise Error, "CreateProcess() failed: " + get_last_error
868
890
  end
869
891
 
870
892
  # Automatically close the process and thread handles in the
@@ -17,7 +17,6 @@ gem 'test-unit'
17
17
  require 'test/unit'
18
18
  require 'win32/process'
19
19
  require 'sys/proctable'
20
- include Sys
21
20
 
22
21
  class TC_Win32Process < Test::Unit::TestCase
23
22
 
@@ -29,55 +28,66 @@ class TC_Win32Process < Test::Unit::TestCase
29
28
 
30
29
  @@pids = []
31
30
 
32
- ProcTable.ps{ |struct|
31
+ Sys::ProcTable.ps{ |struct|
33
32
  next unless struct.comm =~ /notepad/i
34
33
  @@pids << struct.pid
35
34
  }
36
35
  end
37
36
 
38
37
  def setup
39
- @pid = nil
40
38
  @pri_class = Process::NORMAL_PRIORITY_CLASS
41
39
  end
42
40
 
43
- def test_version
44
- assert_equal('0.6.4', Process::WIN32_PROCESS_VERSION)
41
+ test "win32-process version is set to the correct value" do
42
+ assert_equal('0.6.5', Process::WIN32_PROCESS_VERSION)
45
43
  end
46
44
 
47
- def test_kill
45
+ test "kill basic functionality" do
48
46
  assert_respond_to(Process, :kill)
49
47
  end
50
48
 
51
- def test_kill_expected_errors
49
+ test "kill requires at least one argument" do
52
50
  assert_raises(ArgumentError){ Process.kill }
51
+ end
52
+
53
+ test "kill raises an error if an invalid signal is provided" do
53
54
  assert_raises(Process::Error){ Process.kill('SIGBOGUS') }
55
+ end
56
+
57
+ test "kill raises an error if an invalid process id is provided" do
54
58
  assert_raises(Process::Error){ Process.kill(0, 9999999) }
55
59
  end
56
60
 
57
- def test_kill_signal_0
61
+ test "kill with signal 0 does not kill the process" do
58
62
  pid = @@pids.first
59
63
  assert_nothing_raised{ Process.kill(0, pid) }
64
+ assert_not_nil(Sys::ProcTable.ps(pid))
60
65
  end
61
66
 
62
- def test_kill_signal_1
67
+ test "kill with signal 1 kills the process normally" do
63
68
  pid = @@pids.shift
64
69
  assert_nothing_raised{ Process.kill(1, pid) }
70
+ assert_nil(Sys::ProcTable.ps(pid))
65
71
  end
66
72
 
67
- def test_kill_signal_9
73
+ test "kill with signal 9 kills the process brutally" do
68
74
  pid = @@pids.pop
69
75
  msg = "Could not find pid #{pid}"
70
76
  assert_nothing_raised(msg){ Process.kill(9, pid) }
77
+ assert_nil(Sys::ProcTable.ps(pid))
71
78
  end
72
79
 
73
- def test_fork
80
+ test "fork basic functionality" do
74
81
  assert_respond_to(Process, :fork)
75
82
  end
76
83
 
77
- def test_create
84
+ test "create basic functionality" do
78
85
  assert_respond_to(Process, :create)
86
+ end
87
+
88
+ test "create with common flags works as expected" do
79
89
  assert_nothing_raised{
80
- @pid = Process.create(
90
+ @@pids << Process.create(
81
91
  :app_name => "notepad.exe",
82
92
  :creation_flags => Process::DETACHED_PROCESS,
83
93
  :process_inherit => false,
@@ -86,66 +96,130 @@ class TC_Win32Process < Test::Unit::TestCase
86
96
  ).process_id
87
97
  }
88
98
 
89
- assert_nothing_raised{ Process.kill(1, @pid) }
99
+ assert_nothing_raised{ Process.kill(1, @@pids.pop) }
90
100
  end
91
101
 
92
- def test_create_expected_errors
93
- assert_raises(TypeError){ Process.create("bogusapp.exe") }
94
- assert_raises(Process::Error){ Process.create(:app_name => "bogusapp.exe") }
102
+ test "create requires a hash argument" do
103
+ assert_raise(TypeError){ Process.create("bogusapp.exe") }
104
+ end
105
+
106
+ test "create does not accept invalid keys" do
107
+ assert_raise(ArgumentError){ Process.create(:bogus => 'test.exe') }
108
+ assert_raise_message("invalid key 'bogus'"){
109
+ Process.create(:bogus => 'test.exe')
110
+ }
111
+ end
112
+
113
+ test "create does not accept invalid startup_info keys" do
114
+ assert_raise(ArgumentError){
115
+ Process.create(:startup_info => {:foo => 'test'})
116
+ }
117
+ assert_raise_message("invalid startup_info key 'foo'"){
118
+ Process.create(:startup_info => {:foo => 'test'})
119
+ }
120
+ end
121
+
122
+ test "create raises an error if the executable cannot be found" do
123
+ err = "CreateProcess() failed: The system cannot find the file specified."
124
+ assert_raise(Process::Error){ Process.create(:app_name => "bogusapp.exe") }
125
+ assert_raise_message(err){ Process.create(:app_name => "bogusapp.exe") }
95
126
  end
96
127
 
97
- def test_wait
128
+ test "wait basic functionality" do
98
129
  assert_respond_to(Process, :wait)
99
130
  end
100
131
 
101
- def test_wait2
132
+ test "wait2 basic functionality" do
102
133
  assert_respond_to(Process, :wait2)
103
134
  end
104
135
 
105
- def test_waitpid
136
+ test "waitpid basic functionality" do
106
137
  assert_respond_to(Process, :waitpid)
107
138
  end
108
139
 
109
- def test_waitpid2
140
+ test "waitpid2 basic functionality" do
110
141
  assert_respond_to(Process, :waitpid2)
111
142
  end
112
143
 
113
- def test_ppid
144
+ test "ppid basic functionality" do
114
145
  assert_respond_to(Process, :ppid)
115
- assert_equal(true, Process.ppid > 0)
116
- assert_equal(false, Process.pid == Process.ppid)
146
+ assert_nothing_raised{ Process.ppid }
147
+ end
148
+
149
+ test "ppid returns expected results" do
150
+ assert_kind_of(Integer, Process.ppid)
151
+ assert_true(Process.ppid > 0)
152
+ assert_false(Process.pid == Process.ppid)
117
153
  end
118
154
 
119
- def test_uid
155
+ test "uid basic functionality" do
120
156
  assert_respond_to(Process, :uid)
121
157
  assert_kind_of(Fixnum, Process.uid)
158
+ end
159
+
160
+ test "uid accepts a boolean argument" do
161
+ assert_nothing_raised{ Process.uid(true) }
162
+ assert_nothing_raised{ Process.uid(true) }
163
+ end
164
+
165
+ test "uid returns a string if its argument is true" do
122
166
  assert_kind_of(String, Process.uid(true))
123
167
  end
124
168
 
125
- def test_getpriority
169
+ test "uid accepts a maximum of one argument" do
170
+ assert_raise(ArgumentError){ Process.uid(true, true) }
171
+ end
172
+
173
+ test "argument to uid must be a boolean" do
174
+ assert_raise(TypeError){ Process.uid('test') }
175
+ end
176
+
177
+ test "getpriority basic functionality" do
126
178
  assert_respond_to(Process, :getpriority)
127
- assert_nothing_raised{ Process.getpriority(nil, Process.pid) }
128
- assert_kind_of(Fixnum, Process.getpriority(nil, Process.pid))
179
+ assert_nothing_raised{ Process.getpriority(Process::PRIO_PROCESS, Process.pid) }
180
+ assert_kind_of(Fixnum, Process.getpriority(Process::PRIO_PROCESS, Process.pid))
129
181
  end
130
182
 
131
- def test_getpriority_expected_errors
132
- assert_raise{ Process.getpriority }
133
- assert_raise{ Process.getpriority(nil) }
183
+ test "getpriority treats an int argument of zero as the current process" do
184
+ assert_nothing_raised{ Process.getpriority(0, 0) }
134
185
  end
135
186
 
136
- def test_setpriority
187
+ test "getpriority requires both a kind and an int" do
188
+ assert_raise(ArgumentError){ Process.getpriority }
189
+ assert_raise(ArgumentError){ Process.getpriority(Process::PRIO_PROCESS) }
190
+ end
191
+
192
+ test "getpriority requires integer arguments" do
193
+ assert_raise(TypeError){ Process.getpriority('test', 0) }
194
+ assert_raise(TypeError){ Process.getpriority(Process::PRIO_PROCESS, 'test') }
195
+ end
196
+
197
+ test "setpriority basic functionality" do
137
198
  assert_respond_to(Process, :setpriority)
138
- assert_nothing_raised{ Process.setpriority(nil, Process.pid, @pri_class) }
139
- assert_equal(0, Process.setpriority(nil, Process.pid, @pri_class))
199
+ assert_nothing_raised{ Process.setpriority(0, Process.pid, @pri_class) }
200
+ end
201
+
202
+ test "setpriority returns zero on success" do
203
+ assert_equal(0, Process.setpriority(0, Process.pid, @pri_class))
204
+ end
205
+
206
+ test "setpriority treats an int argument of zero as the current process" do
207
+ assert_equal(0, Process.setpriority(0, 0, @pri_class))
140
208
  end
141
209
 
142
- def test_setpriority_expected_errors
143
- assert_raise{ Process.setpriority }
144
- assert_raise{ Process.setpriority(nil) }
145
- assert_raise{ Process.setpriority(nil, Process.pid) }
210
+ test "setpriority requires at least three arguments" do
211
+ assert_raise(ArgumentError){ Process.setpriority }
212
+ assert_raise(ArgumentError){ Process.setpriority(0) }
213
+ assert_raise(ArgumentError){ Process.setpriority(0, 0) }
146
214
  end
147
-
148
- def test_creation_constants
215
+
216
+ test "arguments to setpriority must be numeric" do
217
+ assert_raise(TypeError){ Process.setpriority('test', 0, @pri_class) }
218
+ assert_raise(TypeError){ Process.setpriority(0, 'test', @pri_class) }
219
+ assert_raise(TypeError){ Process.setpriority(0, 0, 'test') }
220
+ end
221
+
222
+ test "custom creation constants are defined" do
149
223
  assert_not_nil(Process::CREATE_DEFAULT_ERROR_MODE)
150
224
  assert_not_nil(Process::CREATE_NEW_CONSOLE)
151
225
  assert_not_nil(Process::CREATE_NEW_PROCESS_GROUP)
@@ -159,49 +233,64 @@ class TC_Win32Process < Test::Unit::TestCase
159
233
  assert_not_nil(Process::DETACHED_PROCESS)
160
234
  end
161
235
 
162
- def test_getrlimit
236
+ test "getrlimit basic functionality" do
163
237
  assert_respond_to(Process, :getrlimit)
164
238
  assert_nothing_raised{ Process.getrlimit(Process::RLIMIT_CPU) }
239
+ end
240
+
241
+ test "getrlimit returns an array of two numeric elements" do
165
242
  assert_kind_of(Array, Process.getrlimit(Process::RLIMIT_CPU))
166
243
  assert_equal(2, Process.getrlimit(Process::RLIMIT_CPU).length)
244
+ assert_kind_of(Integer, Process.getrlimit(Process::RLIMIT_CPU).first)
167
245
  end
168
246
 
169
- def test_getrlimit_can_be_called_multiple_times
247
+ test "getrlimit can be called multiple times without issue" do
170
248
  assert_nothing_raised{ Process.getrlimit(Process::RLIMIT_CPU) }
171
249
  assert_nothing_raised{ Process.getrlimit(Process::RLIMIT_CPU) }
172
250
  assert_nothing_raised{ Process.getrlimit(Process::RLIMIT_CPU) }
173
251
  end
174
252
 
175
- def test_getrlimit_raises_an_error_if_the_resource_is_invalid
253
+ test "getrlimit requires a valid resource value" do
176
254
  assert_raise(Process::Error){ Process.getrlimit(9999) }
177
255
  end
178
256
 
179
- def test_setrlimit_basic
257
+ test "setrlimit basic functionality" do
180
258
  assert_respond_to(Process, :getrlimit)
181
259
  assert_nothing_raised{ Process.setrlimit(Process::RLIMIT_VMEM, 1024 * 4) }
260
+ end
261
+
262
+ test "setrlimit returns nil on success" do
182
263
  assert_nil(Process.setrlimit(Process::RLIMIT_VMEM, 1024 * 4))
183
264
  end
184
265
 
185
- def test_setrlimit_sets_the_resource_as_expected
266
+ test "setrlimit sets the resource limit as expected" do
186
267
  assert_nothing_raised{ Process.setrlimit(Process::RLIMIT_VMEM, 1024 * 4) }
187
268
  assert_equal([4096, 4096], Process.getrlimit(Process::RLIMIT_VMEM))
188
269
  end
189
270
 
190
- def test_setrlimit_raises_an_error_if_the_resource_is_invalid
271
+ test "setrlimit raises an error if the resource value is invalid" do
191
272
  assert_raise(Process::Error){ Process.setrlimit(9999, 100) }
192
273
  end
193
274
 
194
- def test_is_job
275
+ test "is_job basic functionality" do
195
276
  assert_respond_to(Process, :job?)
196
277
  assert_nothing_raised{ Process.job? }
278
+ end
279
+
280
+ test "is_job returns a boolean value" do
197
281
  assert_boolean(Process.job?)
198
282
  end
283
+
284
+ test "is_job does not accept any arguments" do
285
+ assert_raise(ArgumentError){ Process.job?(Process.pid) }
286
+ end
199
287
 
200
288
  def teardown
201
- @pid = nil
289
+ @pri_class = nil
202
290
  end
203
291
 
204
292
  def self.shutdown
293
+ @@pids.each{ |pid| Process.kill(1, pid) }
205
294
  @@pids = []
206
295
  end
207
296
  end
@@ -2,7 +2,7 @@ require 'rubygems'
2
2
 
3
3
  Gem::Specification.new do |spec|
4
4
  spec.name = 'win32-process'
5
- spec.version = '0.6.4'
5
+ spec.version = '0.6.5'
6
6
  spec.license = 'Artistic 2.0'
7
7
  spec.authors = ['Daniel Berger', 'Park Heesob']
8
8
  spec.email = 'djberg96@gmail.com'
@@ -16,7 +16,7 @@ Gem::Specification.new do |spec|
16
16
  spec.rubyforge_project = 'win32utils'
17
17
  spec.extra_rdoc_files = ['README', 'CHANGES', 'MANIFEST']
18
18
 
19
- spec.add_dependency('windows-pr', '>= 1.1.0')
19
+ spec.add_dependency('windows-pr', '>= 1.1.2')
20
20
  spec.add_development_dependency('test-unit', '>= 2.1.1')
21
21
  spec.add_development_dependency('sys-proctable')
22
22
 
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: win32-process
3
3
  version: !ruby/object:Gem::Version
4
- hash: 15
4
+ hash: 13
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 6
9
- - 4
10
- version: 0.6.4
9
+ - 5
10
+ version: 0.6.5
11
11
  platform: ruby
12
12
  authors:
13
13
  - Daniel Berger
@@ -16,7 +16,7 @@ autorequire:
16
16
  bindir: bin
17
17
  cert_chain: []
18
18
 
19
- date: 2010-11-13 00:00:00 -07:00
19
+ date: 2010-12-27 00:00:00 -07:00
20
20
  default_executable:
21
21
  dependencies:
22
22
  - !ruby/object:Gem::Dependency
@@ -27,12 +27,12 @@ dependencies:
27
27
  requirements:
28
28
  - - ">="
29
29
  - !ruby/object:Gem::Version
30
- hash: 19
30
+ hash: 23
31
31
  segments:
32
32
  - 1
33
33
  - 1
34
- - 0
35
- version: 1.1.0
34
+ - 2
35
+ version: 1.1.2
36
36
  type: :runtime
37
37
  version_requirements: *id001
38
38
  - !ruby/object:Gem::Dependency