win32-process 0.6.4 → 0.6.5

Sign up to get free protection for your applications and to get access to all the features.
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