win32-process 0.8.3 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,218 +1,218 @@
1
- if RUBY_PLATFORM == 'java'
2
- require 'rubygems'
3
- gem 'ffi'
4
- end
5
-
6
- require 'ffi'
7
-
8
- module Process::Structs
9
- extend FFI::Library
10
-
11
- typedef :ulong, :dword
12
- typedef :uintptr_t, :handle
13
- typedef :short, :word
14
-
15
- private
16
-
17
- # sizeof(LARGE_INTEGER) == 8
18
- class LARGE_INTEGER < FFI::Union
19
- layout(:QuadPart, :long_long)
20
- end
21
-
22
- # sizeof(IO_COUNTERS) == 48
23
- class IO_COUNTERS < FFI::Struct
24
- layout(
25
- :ReadOperationCount, :ulong_long,
26
- :WriteOperationCount, :ulong_long,
27
- :OtherOperationCount, :ulong_long,
28
- :ReadTransferCount, :ulong_long,
29
- :WriteTransferCount, :ulong_long,
30
- :OtherTransferCount, :ulong_long
31
- )
32
- end
33
-
34
- class JOBJECT_BASIC_LIMIT_INFORMATION < FFI::Struct
35
- layout(
36
- :PerProcessUserTimeLimit, LARGE_INTEGER,
37
- :PerJobUserTimeLimit, LARGE_INTEGER,
38
- :LimitFlags, :dword,
39
- :MinimumWorkingSetSize, :size_t,
40
- :MaximumWorkingSetSize, :size_t,
41
- :ActiveProcessLimit, :dword,
42
- :Affinity, :pointer,
43
- :PriorityClass, :dword,
44
- :SchedulingClass, :dword
45
- )
46
- end
47
-
48
- class JOBJECT_EXTENDED_LIMIT_INFORMATION < FFI::Struct
49
- layout(
50
- :BasicLimitInformation, JOBJECT_BASIC_LIMIT_INFORMATION,
51
- :IoInfo, IO_COUNTERS,
52
- :ProcessMemoryLimit, :size_t,
53
- :JobMemoryLimit, :size_t,
54
- :PeakProcessMemoryUsed, :size_t,
55
- :PeakJobMemoryUsed, :size_t
56
- )
57
- end
58
-
59
- class SECURITY_ATTRIBUTES < FFI::Struct
60
- layout(
61
- :nLength, :dword,
62
- :lpSecurityDescriptor, :pointer,
63
- :bInheritHandle, :int
64
- )
65
- end
66
-
67
- # sizeof(STARTUPINFO) == 68
68
- class STARTUPINFO < FFI::Struct
69
- layout(
70
- :cb, :ulong,
71
- :lpReserved, :string,
72
- :lpDesktop, :string,
73
- :lpTitle, :string,
74
- :dwX, :dword,
75
- :dwY, :dword,
76
- :dwXSize, :dword,
77
- :dwYSize, :dword,
78
- :dwXCountChars, :dword,
79
- :dwYCountChars, :dword,
80
- :dwFillAttribute, :dword,
81
- :dwFlags, :dword,
82
- :wShowWindow, :word,
83
- :cbReserved2, :word,
84
- :lpReserved2, :pointer,
85
- :hStdInput, :handle,
86
- :hStdOutput, :handle,
87
- :hStdError, :handle
88
- )
89
- end
90
-
91
- class PROCESS_INFORMATION < FFI::Struct
92
- layout(
93
- :hProcess, :handle,
94
- :hThread, :handle,
95
- :dwProcessId, :ulong,
96
- :dwThreadId, :ulong
97
- )
98
- end
99
-
100
- class OSVERSIONINFO < FFI::Struct
101
- layout(
102
- :dwOSVersionInfoSize, :dword,
103
- :dwMajorVersion, :dword,
104
- :dwMinorVersion, :dword,
105
- :dwBuildNumber, :dword,
106
- :dwPlatformId, :dword,
107
- :szCSDVersion, [:char, 128]
108
- )
109
- end
110
-
111
- class THREADENTRY32 < FFI::Struct
112
- layout(
113
- :dwSize, :dword,
114
- :cntUsage, :dword,
115
- :th32ThreadID, :dword,
116
- :th32OwnerProcessID, :dword,
117
- :tpBasePri, :long,
118
- :tpDeltaPri, :long,
119
- :dwFlags, :dword
120
- )
121
- end
122
-
123
- class HEAPLIST32 < FFI::Struct
124
- layout(
125
- :dwSize, :size_t,
126
- :th32ProcessID, :dword,
127
- :th32HeapID, :uintptr_t,
128
- :dwFlags, :dword
129
- )
130
- end
131
-
132
- class HEAPENTRY32 < FFI::Struct
133
- layout(
134
- :dwSize, :size_t,
135
- :hHandle, :handle,
136
- :dwAddress, :uintptr_t,
137
- :dwBlockSize, :size_t,
138
- :dwFlags, :dword,
139
- :dwLockCount, :dword,
140
- :dwResvd, :dword,
141
- :th32ProcessID, :dword,
142
- :th32HeapID, :uintptr_t
143
- )
144
- end
145
-
146
- class MODULEENTRY32 < FFI::Struct
147
- layout(
148
- :dwSize, :dword,
149
- :th32ModuleID, :dword,
150
- :th32ProcessID, :dword,
151
- :GlblcntUsage, :dword,
152
- :ProccntUsage, :dword,
153
- :modBaseAddr, :pointer,
154
- :modBaseSize, :dword,
155
- :hModule, :handle,
156
- :szModule, [:char, 256],
157
- :szExePath, [:char, 260]
158
- )
159
- end
160
-
161
- class PROCESSENTRY32 < FFI::Struct
162
- layout(
163
- :dwSize, :dword,
164
- :cntUsage, :dword,
165
- :th32ProcessID, :dword,
166
- :th32DefaultHeapID, :uintptr_t,
167
- :th32ModuleID, :dword,
168
- :cntThreads, :dword,
169
- :th32ParentProcessID, :dword,
170
- :pcPriClassBase, :long,
171
- :dwFlags, :dword,
172
- :szExeFile, [:char, 260]
173
- )
174
- end
175
-
176
- # Used by Process.create
177
-
178
- ProcessInfo = Struct.new("ProcessInfo",
179
- :process_handle,
180
- :thread_handle,
181
- :process_id,
182
- :thread_id
183
- )
184
-
185
- # Used by Process.snapshot
186
-
187
- ThreadSnapInfo = Struct.new("ThreadSnapInfo",
188
- :thread_id,
189
- :process_id,
190
- :base_priority
191
- )
192
-
193
- HeapSnapInfo = Struct.new("HeapSnapInfo",
194
- :address,
195
- :block_size,
196
- :flags,
197
- :process_id,
198
- :heap_id
199
- )
200
-
201
- ModuleSnapInfo = Struct.new("ModuleSnapInfo",
202
- :process_id,
203
- :address,
204
- :module_size,
205
- :handle,
206
- :name,
207
- :path
208
- )
209
-
210
- ProcessSnapInfo = Struct.new("ProcessSnapInfo",
211
- :process_id,
212
- :threads,
213
- :parent_process_id,
214
- :priority,
215
- :flags,
216
- :path
217
- )
218
- end
1
+ if RUBY_PLATFORM == 'java'
2
+ require 'rubygems'
3
+ gem 'ffi'
4
+ end
5
+
6
+ require 'ffi'
7
+
8
+ module Process::Structs
9
+ extend FFI::Library
10
+
11
+ typedef :ulong, :dword
12
+ typedef :uintptr_t, :handle
13
+ typedef :short, :word
14
+
15
+ private
16
+
17
+ # sizeof(LARGE_INTEGER) == 8
18
+ class LARGE_INTEGER < FFI::Union
19
+ layout(:QuadPart, :long_long)
20
+ end
21
+
22
+ # sizeof(IO_COUNTERS) == 48
23
+ class IO_COUNTERS < FFI::Struct
24
+ layout(
25
+ :ReadOperationCount, :ulong_long,
26
+ :WriteOperationCount, :ulong_long,
27
+ :OtherOperationCount, :ulong_long,
28
+ :ReadTransferCount, :ulong_long,
29
+ :WriteTransferCount, :ulong_long,
30
+ :OtherTransferCount, :ulong_long
31
+ )
32
+ end
33
+
34
+ class JOBJECT_BASIC_LIMIT_INFORMATION < FFI::Struct
35
+ layout(
36
+ :PerProcessUserTimeLimit, LARGE_INTEGER,
37
+ :PerJobUserTimeLimit, LARGE_INTEGER,
38
+ :LimitFlags, :dword,
39
+ :MinimumWorkingSetSize, :size_t,
40
+ :MaximumWorkingSetSize, :size_t,
41
+ :ActiveProcessLimit, :dword,
42
+ :Affinity, :pointer,
43
+ :PriorityClass, :dword,
44
+ :SchedulingClass, :dword
45
+ )
46
+ end
47
+
48
+ class JOBJECT_EXTENDED_LIMIT_INFORMATION < FFI::Struct
49
+ layout(
50
+ :BasicLimitInformation, JOBJECT_BASIC_LIMIT_INFORMATION,
51
+ :IoInfo, IO_COUNTERS,
52
+ :ProcessMemoryLimit, :size_t,
53
+ :JobMemoryLimit, :size_t,
54
+ :PeakProcessMemoryUsed, :size_t,
55
+ :PeakJobMemoryUsed, :size_t
56
+ )
57
+ end
58
+
59
+ class SECURITY_ATTRIBUTES < FFI::Struct
60
+ layout(
61
+ :nLength, :dword,
62
+ :lpSecurityDescriptor, :pointer,
63
+ :bInheritHandle, :int
64
+ )
65
+ end
66
+
67
+ # sizeof(STARTUPINFO) == 68
68
+ class STARTUPINFO < FFI::Struct
69
+ layout(
70
+ :cb, :ulong,
71
+ :lpReserved, :string,
72
+ :lpDesktop, :string,
73
+ :lpTitle, :string,
74
+ :dwX, :dword,
75
+ :dwY, :dword,
76
+ :dwXSize, :dword,
77
+ :dwYSize, :dword,
78
+ :dwXCountChars, :dword,
79
+ :dwYCountChars, :dword,
80
+ :dwFillAttribute, :dword,
81
+ :dwFlags, :dword,
82
+ :wShowWindow, :word,
83
+ :cbReserved2, :word,
84
+ :lpReserved2, :pointer,
85
+ :hStdInput, :handle,
86
+ :hStdOutput, :handle,
87
+ :hStdError, :handle
88
+ )
89
+ end
90
+
91
+ class PROCESS_INFORMATION < FFI::Struct
92
+ layout(
93
+ :hProcess, :handle,
94
+ :hThread, :handle,
95
+ :dwProcessId, :ulong,
96
+ :dwThreadId, :ulong
97
+ )
98
+ end
99
+
100
+ class OSVERSIONINFO < FFI::Struct
101
+ layout(
102
+ :dwOSVersionInfoSize, :dword,
103
+ :dwMajorVersion, :dword,
104
+ :dwMinorVersion, :dword,
105
+ :dwBuildNumber, :dword,
106
+ :dwPlatformId, :dword,
107
+ :szCSDVersion, [:char, 128]
108
+ )
109
+ end
110
+
111
+ class THREADENTRY32 < FFI::Struct
112
+ layout(
113
+ :dwSize, :dword,
114
+ :cntUsage, :dword,
115
+ :th32ThreadID, :dword,
116
+ :th32OwnerProcessID, :dword,
117
+ :tpBasePri, :long,
118
+ :tpDeltaPri, :long,
119
+ :dwFlags, :dword
120
+ )
121
+ end
122
+
123
+ class HEAPLIST32 < FFI::Struct
124
+ layout(
125
+ :dwSize, :size_t,
126
+ :th32ProcessID, :dword,
127
+ :th32HeapID, :uintptr_t,
128
+ :dwFlags, :dword
129
+ )
130
+ end
131
+
132
+ class HEAPENTRY32 < FFI::Struct
133
+ layout(
134
+ :dwSize, :size_t,
135
+ :hHandle, :handle,
136
+ :dwAddress, :uintptr_t,
137
+ :dwBlockSize, :size_t,
138
+ :dwFlags, :dword,
139
+ :dwLockCount, :dword,
140
+ :dwResvd, :dword,
141
+ :th32ProcessID, :dword,
142
+ :th32HeapID, :uintptr_t
143
+ )
144
+ end
145
+
146
+ class MODULEENTRY32 < FFI::Struct
147
+ layout(
148
+ :dwSize, :dword,
149
+ :th32ModuleID, :dword,
150
+ :th32ProcessID, :dword,
151
+ :GlblcntUsage, :dword,
152
+ :ProccntUsage, :dword,
153
+ :modBaseAddr, :pointer,
154
+ :modBaseSize, :dword,
155
+ :hModule, :handle,
156
+ :szModule, [:char, 256],
157
+ :szExePath, [:char, 260]
158
+ )
159
+ end
160
+
161
+ class PROCESSENTRY32 < FFI::Struct
162
+ layout(
163
+ :dwSize, :dword,
164
+ :cntUsage, :dword,
165
+ :th32ProcessID, :dword,
166
+ :th32DefaultHeapID, :uintptr_t,
167
+ :th32ModuleID, :dword,
168
+ :cntThreads, :dword,
169
+ :th32ParentProcessID, :dword,
170
+ :pcPriClassBase, :long,
171
+ :dwFlags, :dword,
172
+ :szExeFile, [:char, 260]
173
+ )
174
+ end
175
+
176
+ # Used by Process.create
177
+
178
+ ProcessInfo = Struct.new("ProcessInfo",
179
+ :process_handle,
180
+ :thread_handle,
181
+ :process_id,
182
+ :thread_id
183
+ )
184
+
185
+ # Used by Process.snapshot
186
+
187
+ ThreadSnapInfo = Struct.new("ThreadSnapInfo",
188
+ :thread_id,
189
+ :process_id,
190
+ :base_priority
191
+ )
192
+
193
+ HeapSnapInfo = Struct.new("HeapSnapInfo",
194
+ :address,
195
+ :block_size,
196
+ :flags,
197
+ :process_id,
198
+ :heap_id
199
+ )
200
+
201
+ ModuleSnapInfo = Struct.new("ModuleSnapInfo",
202
+ :process_id,
203
+ :address,
204
+ :module_size,
205
+ :handle,
206
+ :name,
207
+ :path
208
+ )
209
+
210
+ ProcessSnapInfo = Struct.new("ProcessSnapInfo",
211
+ :process_id,
212
+ :threads,
213
+ :parent_process_id,
214
+ :priority,
215
+ :flags,
216
+ :path
217
+ )
218
+ end
@@ -1,370 +1,370 @@
1
- ###############################################################################
2
- # test_win32_process.rb
3
- #
4
- # Test suite for the win32-process library. This test suite will start
5
- # at least two instances of Notepad on your system, which will then
6
- # be killed. Requires the sys-proctable library.
7
- #
8
- # I haven't added a lot of test cases for fork/wait because it's difficult
9
- # to run such tests without causing havoc with Test::Unit itself. Ideas
10
- # welcome.
11
- #
12
- # You should run this test case via the 'rake test' task.
13
- ###############################################################################
14
- require 'test-unit'
15
- require 'win32/process'
16
-
17
- class TC_Win32Process < Test::Unit::TestCase
18
- def self.startup
19
- @@pids = []
20
- @@jruby = RUBY_PLATFORM == 'java'
21
- end
22
-
23
- def setup
24
- @priority = Process::BELOW_NORMAL_PRIORITY_CLASS
25
- end
26
-
27
- test "win32-process version is set to the correct value" do
28
- assert_equal('0.8.3', Process::WIN32_PROCESS_VERSION)
29
- end
30
-
31
- test "create basic functionality" do
32
- assert_respond_to(Process, :create)
33
- end
34
-
35
- test "create with common flags works as expected" do
36
- assert_nothing_raised{
37
- @@pids << Process.create(
38
- :app_name => "notepad.exe",
39
- :creation_flags => Process::DETACHED_PROCESS,
40
- :process_inherit => false,
41
- :thread_inherit => true,
42
- :cwd => "C:\\"
43
- ).process_id
44
- }
45
-
46
- assert_nothing_raised{ Process.kill(9, @@pids.pop) }
47
- end
48
-
49
- test "create requires a hash argument" do
50
- assert_raise(TypeError){ Process.create("bogusapp.exe") }
51
- end
52
-
53
- test "create does not accept invalid keys" do
54
- assert_raise(ArgumentError){ Process.create(:bogus => 'test.exe') }
55
- assert_raise_message("invalid key 'bogus'"){
56
- Process.create(:bogus => 'test.exe')
57
- }
58
- end
59
-
60
- test "create does not accept invalid startup_info keys" do
61
- assert_raise(ArgumentError){
62
- Process.create(:startup_info => {:foo => 'test'})
63
- }
64
- assert_raise_message("invalid startup_info key 'foo'"){
65
- Process.create(:startup_info => {:foo => 'test'})
66
- }
67
- end
68
-
69
- test "create raises an error if the executable cannot be found" do
70
- assert_raise(Errno::ENOENT){ Process.create(:app_name => "bogusapp.exe") }
71
- end
72
-
73
- test "create passes local environment when environment is not specified" do
74
- omit_if(@@jruby)
75
- stdout_read, stdout_write = IO.pipe
76
-
77
- ENV['AARDVARK'] = 'B'
78
- assert_nothing_raised {
79
- Process.create(
80
- :app_name => 'cmd.exe /c echo %AARDVARK%',
81
- :creation_flags => Process::DETACHED_PROCESS,
82
- :startup_info => { :stdout => stdout_write }
83
- )
84
- }
85
-
86
- stdout_write.close
87
- assert_equal('B', stdout_read.read.chomp)
88
- end
89
-
90
- test "create does not pass local environment when environment is specified" do
91
- omit_if(@@jruby)
92
- stdout_read, stdout_write = IO.pipe
93
-
94
- ENV['AARDVARK'] = 'B'
95
- assert_nothing_raised {
96
- Process.create(
97
- :app_name => 'cmd.exe /c echo %AARDVARK%',
98
- :creation_flags => Process::DETACHED_PROCESS,
99
- :environment => "",
100
- :startup_info => { :stdout => stdout_write }
101
- )
102
- }
103
-
104
- stdout_write.close
105
- assert_equal('%AARDVARK%', stdout_read.read.chomp)
106
- end
107
-
108
- test "create supports :environment as a string" do
109
- omit_if(@@jruby)
110
- stdout_read, stdout_write = IO.pipe
111
-
112
- assert_nothing_raised {
113
- Process.create(
114
- :app_name => 'cmd.exe /c echo %A% %C%',
115
- :creation_flags => Process::DETACHED_PROCESS,
116
- :environment => "A=B;C=D",
117
- :startup_info => { :stdout => stdout_write }
118
- )
119
- }
120
-
121
- stdout_write.close
122
- assert_equal("B D", stdout_read.read.chomp)
123
- end
124
-
125
- test "create supports :environment as an array" do
126
- omit_if(@@jruby)
127
- stdout_read, stdout_write = IO.pipe
128
-
129
- assert_nothing_raised {
130
- Process.create(
131
- :app_name => 'cmd.exe /c echo %A% %C%',
132
- :creation_flags => Process::DETACHED_PROCESS,
133
- :environment => [ "A=B;X;", "C=;D;Y" ],
134
- :startup_info => { :stdout => stdout_write }
135
- )
136
- }
137
-
138
- stdout_write.close
139
- assert_equal("B;X; ;D;Y", stdout_read.read.chomp)
140
- end
141
-
142
- test "create supports empty :environment string" do
143
- assert_nothing_raised {
144
- Process.create(
145
- :creation_flags => Process::DETACHED_PROCESS,
146
- :app_name => 'cmd.exe',
147
- :environment => ''
148
- )
149
- }
150
- end
151
-
152
- test "create supports empty :environment array" do
153
- assert_nothing_raised {
154
- Process.create(
155
- :creation_flags => Process::DETACHED_PROCESS,
156
- :app_name => 'cmd.exe',
157
- :environment => []
158
- )
159
- }
160
- end
161
-
162
- test "uid basic functionality" do
163
- assert_respond_to(Process, :uid)
164
- assert_kind_of(Fixnum, Process.uid)
165
- end
166
-
167
- test "uid accepts a boolean argument" do
168
- assert_nothing_raised{ Process.uid(true) }
169
- assert_nothing_raised{ Process.uid(true) }
170
- end
171
-
172
- test "uid returns a string if its argument is true" do
173
- assert_kind_of(String, Process.uid(true))
174
- end
175
-
176
- test "uid accepts a maximum of one argument" do
177
- assert_raise(ArgumentError){ Process.uid(true, true) }
178
- end
179
-
180
- test "argument to uid must be a boolean" do
181
- assert_raise(TypeError){ Process.uid('test') }
182
- end
183
-
184
- test "getpriority basic functionality" do
185
- assert_respond_to(Process, :getpriority)
186
- assert_nothing_raised{ Process.getpriority(Process::PRIO_PROCESS, Process.pid) }
187
- assert_kind_of(Fixnum, Process.getpriority(Process::PRIO_PROCESS, Process.pid))
188
- end
189
-
190
- test "getpriority treats an int argument of zero as the current process" do
191
- assert_nothing_raised{ Process.getpriority(0, 0) }
192
- end
193
-
194
- test "getpriority requires both a kind and an int" do
195
- assert_raise(ArgumentError){ Process.getpriority }
196
- assert_raise(ArgumentError){ Process.getpriority(Process::PRIO_PROCESS) }
197
- end
198
-
199
- test "getpriority requires integer arguments" do
200
- assert_raise(TypeError){ Process.getpriority('test', 0) }
201
- assert_raise(TypeError){ Process.getpriority(Process::PRIO_PROCESS, 'test') }
202
- end
203
-
204
- test "setpriority basic functionality" do
205
- assert_respond_to(Process, :setpriority)
206
- assert_nothing_raised{ Process.setpriority(0, Process.pid, @priority) }
207
- assert_equal(@priority, Process.getpriority(0, Process.pid))
208
- end
209
-
210
- test "setpriority returns zero on success" do
211
- assert_equal(0, Process.setpriority(0, Process.pid, @priority))
212
- end
213
-
214
- test "setpriority treats an int argument of zero as the current process" do
215
- assert_equal(0, Process.setpriority(0, 0, @priority))
216
- end
217
-
218
- test "setpriority requires at least three arguments" do
219
- assert_raise(ArgumentError){ Process.setpriority }
220
- assert_raise(ArgumentError){ Process.setpriority(0) }
221
- assert_raise(ArgumentError){ Process.setpriority(0, 0) }
222
- end
223
-
224
- test "arguments to setpriority must be numeric" do
225
- assert_raise(TypeError){ Process.setpriority('test', 0, @priority) }
226
- assert_raise(TypeError){ Process.setpriority(0, 'test', @priority) }
227
- assert_raise(TypeError){ Process.setpriority(0, 0, 'test') }
228
- end
229
-
230
- test "custom creation constants are defined" do
231
- assert_not_nil(Process::CREATE_DEFAULT_ERROR_MODE)
232
- assert_not_nil(Process::CREATE_NEW_CONSOLE)
233
- assert_not_nil(Process::CREATE_NEW_PROCESS_GROUP)
234
- assert_not_nil(Process::CREATE_NO_WINDOW)
235
- assert_not_nil(Process::CREATE_SEPARATE_WOW_VDM)
236
- assert_not_nil(Process::CREATE_SHARED_WOW_VDM)
237
- assert_not_nil(Process::CREATE_SUSPENDED)
238
- assert_not_nil(Process::CREATE_UNICODE_ENVIRONMENT)
239
- assert_not_nil(Process::DEBUG_ONLY_THIS_PROCESS)
240
- assert_not_nil(Process::DEBUG_PROCESS)
241
- assert_not_nil(Process::DETACHED_PROCESS)
242
- end
243
-
244
- test "getrlimit basic functionality" do
245
- assert_respond_to(Process, :getrlimit)
246
- assert_nothing_raised{ Process.getrlimit(Process::RLIMIT_CPU) }
247
- assert_nothing_raised{ Process.getrlimit(Process::RLIMIT_FSIZE) }
248
- end
249
-
250
- test "getrlimit returns an array of two numeric elements" do
251
- assert_kind_of(Array, Process.getrlimit(Process::RLIMIT_CPU))
252
- assert_equal(2, Process.getrlimit(Process::RLIMIT_CPU).length)
253
- assert_kind_of(Integer, Process.getrlimit(Process::RLIMIT_CPU).first)
254
- end
255
-
256
- test "getrlimit can be called multiple times without issue" do
257
- assert_nothing_raised{ Process.getrlimit(Process::RLIMIT_CPU) }
258
- assert_nothing_raised{ Process.getrlimit(Process::RLIMIT_CPU) }
259
- assert_nothing_raised{ Process.getrlimit(Process::RLIMIT_CPU) }
260
- end
261
-
262
- test "getrlimit requires a valid resource value" do
263
- assert_raise(ArgumentError){ Process.getrlimit(9999) }
264
- end
265
-
266
- test "setrlimit basic functionality" do
267
- assert_respond_to(Process, :setrlimit)
268
- assert_nothing_raised{ Process.setrlimit(Process::RLIMIT_CPU, 1000000) }
269
- end
270
-
271
- test "setrlimit returns nil on success" do
272
- assert_nil(Process.setrlimit(Process::RLIMIT_CPU, 1000000))
273
- end
274
-
275
- test "setrlimit sets the resource limit as expected" do
276
- assert_nothing_raised{ Process.setrlimit(Process::RLIMIT_CPU, 1000000) }
277
- assert_equal([1000000, 1000000], Process.getrlimit(Process::RLIMIT_CPU))
278
- end
279
-
280
- test "setrlimit raises an error if the resource value is invalid" do
281
- assert_raise(ArgumentError){ Process.setrlimit(9999, 100) }
282
- end
283
-
284
- test "is_job basic functionality" do
285
- assert_respond_to(Process, :job?)
286
- assert_nothing_raised{ Process.job? }
287
- end
288
-
289
- test "is_job returns a boolean value" do
290
- assert_boolean(Process.job?)
291
- end
292
-
293
- test "is_job does not accept any arguments" do
294
- assert_raise(ArgumentError){ Process.job?(Process.pid) }
295
- end
296
-
297
- test "volume_type is a private method" do
298
- assert_not_respond_to(Process, :volume_type)
299
- end
300
-
301
- test "snapshot method basic functionality" do
302
- assert_respond_to(Process, :snapshot)
303
- assert_nothing_raised{ Process.snapshot }
304
- assert_kind_of(Hash, Process.snapshot)
305
- end
306
-
307
- test "snapshot accepts :thread, :module or :heap arguments" do
308
- assert_nothing_raised{ Process.snapshot(:thread) }
309
- assert_nothing_raised{ Process.snapshot(:module) }
310
- #assert_nothing_raised{ Process.snapshot(:heap) }
311
- assert_nothing_raised{ Process.snapshot(:process) }
312
- end
313
-
314
- test "snapshot raises an error if an invalid argument is passed" do
315
- assert_raise(ArgumentError){ Process.snapshot(:bogus) }
316
- end
317
-
318
- test "ffi functions are private" do
319
- assert_not_respond_to(Process, :CloseHandle)
320
- assert_not_respond_to(Process, :GetCurrentProcess)
321
- assert_not_respond_to(Process, :GetProcessAffinityMask)
322
- assert_not_respond_to(Process, :GetPriorityClass)
323
- assert_not_respond_to(Process, :IsProcessInJob)
324
- assert_not_respond_to(Process, :OpenProcess)
325
- assert_not_respond_to(Process, :SetHandleInformation)
326
- assert_not_respond_to(Process, :SetPriorityClass)
327
- end
328
-
329
- test "get_exitcode basic functionality" do
330
- assert_respond_to(Process, :get_exitcode)
331
- end
332
-
333
- =begin
334
- test "get_exitcode returns the process exit code" do
335
- pid = Process.create(
336
- :app_name => 'cmd /c exit 7',
337
- :creation_flags => Process::DETACHED_PROCESS
338
- ).process_id
339
- 10.times do
340
- sleep(0.1)
341
- break if Process.get_exitcode(pid)
342
- end
343
- assert_equal 7, Process.get_exitcode(pid)
344
- end
345
-
346
- test "get_exitcode returns nil while the process is running" do
347
- stdin_read, stdin_write = IO.pipe
348
- pid = Process.create(
349
- :app_name => 'cmd /c pause',
350
- :creation_flags => Process::DETACHED_PROCESS,
351
- :startup_info => { :stdin => stdin_read }
352
- ).process_id
353
- assert_equal nil, Process.get_exitcode(pid)
354
- stdin_write.write("\n")
355
- 10.times do
356
- sleep(0.1)
357
- break if Process.get_exitcode(pid)
358
- end
359
- assert_equal 1, Process.get_exitcode(pid)
360
- end
361
- =end
362
-
363
- def teardown
364
- @priority = nil
365
- end
366
-
367
- def self.shutdown
368
- @@pids = nil
369
- end
370
- end
1
+ ###############################################################################
2
+ # test_win32_process.rb
3
+ #
4
+ # Test suite for the win32-process library. This test suite will start
5
+ # at least two instances of Notepad on your system, which will then
6
+ # be killed. Requires the sys-proctable library.
7
+ #
8
+ # I haven't added a lot of test cases for fork/wait because it's difficult
9
+ # to run such tests without causing havoc with Test::Unit itself. Ideas
10
+ # welcome.
11
+ #
12
+ # You should run this test case via the 'rake test' task.
13
+ ###############################################################################
14
+ require 'test-unit'
15
+ require 'win32/process'
16
+
17
+ class TC_Win32Process < Test::Unit::TestCase
18
+ def self.startup
19
+ @@pids = []
20
+ @@jruby = RUBY_PLATFORM == 'java'
21
+ end
22
+
23
+ def setup
24
+ @priority = Process::BELOW_NORMAL_PRIORITY_CLASS
25
+ end
26
+
27
+ test "win32-process version is set to the correct value" do
28
+ assert_equal('0.9.0', Process::WIN32_PROCESS_VERSION)
29
+ end
30
+
31
+ test "create basic functionality" do
32
+ assert_respond_to(Process, :create)
33
+ end
34
+
35
+ test "create with common flags works as expected" do
36
+ assert_nothing_raised{
37
+ @@pids << Process.create(
38
+ :app_name => "notepad.exe",
39
+ :creation_flags => Process::DETACHED_PROCESS,
40
+ :process_inherit => false,
41
+ :thread_inherit => true,
42
+ :cwd => "C:\\"
43
+ ).process_id
44
+ }
45
+
46
+ assert_nothing_raised{ Process.kill(9, @@pids.pop) }
47
+ end
48
+
49
+ test "create requires a hash argument" do
50
+ assert_raise(TypeError){ Process.create("bogusapp.exe") }
51
+ end
52
+
53
+ test "create does not accept invalid keys" do
54
+ assert_raise(ArgumentError){ Process.create(:bogus => 'test.exe') }
55
+ assert_raise_message("invalid key 'bogus'"){
56
+ Process.create(:bogus => 'test.exe')
57
+ }
58
+ end
59
+
60
+ test "create does not accept invalid startup_info keys" do
61
+ assert_raise(ArgumentError){
62
+ Process.create(:startup_info => {:foo => 'test'})
63
+ }
64
+ assert_raise_message("invalid startup_info key 'foo'"){
65
+ Process.create(:startup_info => {:foo => 'test'})
66
+ }
67
+ end
68
+
69
+ test "create raises an error if the executable cannot be found" do
70
+ assert_raise(Errno::ENOENT){ Process.create(:app_name => "bogusapp.exe") }
71
+ end
72
+
73
+ test "create passes local environment when environment is not specified" do
74
+ omit_if(@@jruby)
75
+ stdout_read, stdout_write = IO.pipe
76
+
77
+ ENV['AARDVARK'] = 'B'
78
+ assert_nothing_raised {
79
+ Process.create(
80
+ :app_name => 'cmd.exe /c echo %AARDVARK%',
81
+ :creation_flags => Process::DETACHED_PROCESS,
82
+ :startup_info => { :stdout => stdout_write }
83
+ )
84
+ }
85
+
86
+ stdout_write.close
87
+ assert_equal('B', stdout_read.read.chomp)
88
+ end
89
+
90
+ test "create does not pass local environment when environment is specified" do
91
+ omit_if(@@jruby)
92
+ stdout_read, stdout_write = IO.pipe
93
+
94
+ ENV['AARDVARK'] = 'B'
95
+ assert_nothing_raised {
96
+ Process.create(
97
+ :app_name => 'cmd.exe /c echo %AARDVARK%',
98
+ :creation_flags => Process::DETACHED_PROCESS,
99
+ :environment => "",
100
+ :startup_info => { :stdout => stdout_write }
101
+ )
102
+ }
103
+
104
+ stdout_write.close
105
+ assert_equal('%AARDVARK%', stdout_read.read.chomp)
106
+ end
107
+
108
+ test "create supports :environment as a string" do
109
+ omit_if(@@jruby)
110
+ stdout_read, stdout_write = IO.pipe
111
+
112
+ assert_nothing_raised {
113
+ Process.create(
114
+ :app_name => 'cmd.exe /c echo %A% %C%',
115
+ :creation_flags => Process::DETACHED_PROCESS,
116
+ :environment => "A=B;C=D",
117
+ :startup_info => { :stdout => stdout_write }
118
+ )
119
+ }
120
+
121
+ stdout_write.close
122
+ assert_equal("B D", stdout_read.read.chomp)
123
+ end
124
+
125
+ test "create supports :environment as an array" do
126
+ omit_if(@@jruby)
127
+ stdout_read, stdout_write = IO.pipe
128
+
129
+ assert_nothing_raised {
130
+ Process.create(
131
+ :app_name => 'cmd.exe /c echo %A% %C%',
132
+ :creation_flags => Process::DETACHED_PROCESS,
133
+ :environment => [ "A=B;X;", "C=;D;Y" ],
134
+ :startup_info => { :stdout => stdout_write }
135
+ )
136
+ }
137
+
138
+ stdout_write.close
139
+ assert_equal("B;X; ;D;Y", stdout_read.read.chomp)
140
+ end
141
+
142
+ test "create supports empty :environment string" do
143
+ assert_nothing_raised {
144
+ Process.create(
145
+ :creation_flags => Process::DETACHED_PROCESS,
146
+ :app_name => 'cmd.exe',
147
+ :environment => ''
148
+ )
149
+ }
150
+ end
151
+
152
+ test "create supports empty :environment array" do
153
+ assert_nothing_raised {
154
+ Process.create(
155
+ :creation_flags => Process::DETACHED_PROCESS,
156
+ :app_name => 'cmd.exe',
157
+ :environment => []
158
+ )
159
+ }
160
+ end
161
+
162
+ test "uid basic functionality" do
163
+ assert_respond_to(Process, :uid)
164
+ assert_kind_of(Fixnum, Process.uid)
165
+ end
166
+
167
+ test "uid accepts a boolean argument" do
168
+ assert_nothing_raised{ Process.uid(true) }
169
+ assert_nothing_raised{ Process.uid(true) }
170
+ end
171
+
172
+ test "uid returns a string if its argument is true" do
173
+ assert_kind_of(String, Process.uid(true))
174
+ end
175
+
176
+ test "uid accepts a maximum of one argument" do
177
+ assert_raise(ArgumentError){ Process.uid(true, true) }
178
+ end
179
+
180
+ test "argument to uid must be a boolean" do
181
+ assert_raise(TypeError){ Process.uid('test') }
182
+ end
183
+
184
+ test "getpriority basic functionality" do
185
+ assert_respond_to(Process, :getpriority)
186
+ assert_nothing_raised{ Process.getpriority(Process::PRIO_PROCESS, Process.pid) }
187
+ assert_kind_of(Fixnum, Process.getpriority(Process::PRIO_PROCESS, Process.pid))
188
+ end
189
+
190
+ test "getpriority treats an int argument of zero as the current process" do
191
+ assert_nothing_raised{ Process.getpriority(0, 0) }
192
+ end
193
+
194
+ test "getpriority requires both a kind and an int" do
195
+ assert_raise(ArgumentError){ Process.getpriority }
196
+ assert_raise(ArgumentError){ Process.getpriority(Process::PRIO_PROCESS) }
197
+ end
198
+
199
+ test "getpriority requires integer arguments" do
200
+ assert_raise(TypeError){ Process.getpriority('test', 0) }
201
+ assert_raise(TypeError){ Process.getpriority(Process::PRIO_PROCESS, 'test') }
202
+ end
203
+
204
+ test "setpriority basic functionality" do
205
+ assert_respond_to(Process, :setpriority)
206
+ assert_nothing_raised{ Process.setpriority(0, Process.pid, @priority) }
207
+ assert_equal(@priority, Process.getpriority(0, Process.pid))
208
+ end
209
+
210
+ test "setpriority returns zero on success" do
211
+ assert_equal(0, Process.setpriority(0, Process.pid, @priority))
212
+ end
213
+
214
+ test "setpriority treats an int argument of zero as the current process" do
215
+ assert_equal(0, Process.setpriority(0, 0, @priority))
216
+ end
217
+
218
+ test "setpriority requires at least three arguments" do
219
+ assert_raise(ArgumentError){ Process.setpriority }
220
+ assert_raise(ArgumentError){ Process.setpriority(0) }
221
+ assert_raise(ArgumentError){ Process.setpriority(0, 0) }
222
+ end
223
+
224
+ test "arguments to setpriority must be numeric" do
225
+ assert_raise(TypeError){ Process.setpriority('test', 0, @priority) }
226
+ assert_raise(TypeError){ Process.setpriority(0, 'test', @priority) }
227
+ assert_raise(TypeError){ Process.setpriority(0, 0, 'test') }
228
+ end
229
+
230
+ test "custom creation constants are defined" do
231
+ assert_not_nil(Process::CREATE_DEFAULT_ERROR_MODE)
232
+ assert_not_nil(Process::CREATE_NEW_CONSOLE)
233
+ assert_not_nil(Process::CREATE_NEW_PROCESS_GROUP)
234
+ assert_not_nil(Process::CREATE_NO_WINDOW)
235
+ assert_not_nil(Process::CREATE_SEPARATE_WOW_VDM)
236
+ assert_not_nil(Process::CREATE_SHARED_WOW_VDM)
237
+ assert_not_nil(Process::CREATE_SUSPENDED)
238
+ assert_not_nil(Process::CREATE_UNICODE_ENVIRONMENT)
239
+ assert_not_nil(Process::DEBUG_ONLY_THIS_PROCESS)
240
+ assert_not_nil(Process::DEBUG_PROCESS)
241
+ assert_not_nil(Process::DETACHED_PROCESS)
242
+ end
243
+
244
+ test "getrlimit basic functionality" do
245
+ assert_respond_to(Process, :getrlimit)
246
+ assert_nothing_raised{ Process.getrlimit(Process::RLIMIT_CPU) }
247
+ assert_nothing_raised{ Process.getrlimit(Process::RLIMIT_FSIZE) }
248
+ end
249
+
250
+ test "getrlimit returns an array of two numeric elements" do
251
+ assert_kind_of(Array, Process.getrlimit(Process::RLIMIT_CPU))
252
+ assert_equal(2, Process.getrlimit(Process::RLIMIT_CPU).length)
253
+ assert_kind_of(Integer, Process.getrlimit(Process::RLIMIT_CPU).first)
254
+ end
255
+
256
+ test "getrlimit can be called multiple times without issue" do
257
+ assert_nothing_raised{ Process.getrlimit(Process::RLIMIT_CPU) }
258
+ assert_nothing_raised{ Process.getrlimit(Process::RLIMIT_CPU) }
259
+ assert_nothing_raised{ Process.getrlimit(Process::RLIMIT_CPU) }
260
+ end
261
+
262
+ test "getrlimit requires a valid resource value" do
263
+ assert_raise(ArgumentError){ Process.getrlimit(9999) }
264
+ end
265
+
266
+ test "setrlimit basic functionality" do
267
+ assert_respond_to(Process, :setrlimit)
268
+ assert_nothing_raised{ Process.setrlimit(Process::RLIMIT_CPU, 1000000) }
269
+ end
270
+
271
+ test "setrlimit returns nil on success" do
272
+ assert_nil(Process.setrlimit(Process::RLIMIT_CPU, 1000000))
273
+ end
274
+
275
+ test "setrlimit sets the resource limit as expected" do
276
+ assert_nothing_raised{ Process.setrlimit(Process::RLIMIT_CPU, 1000000) }
277
+ assert_equal([1000000, 1000000], Process.getrlimit(Process::RLIMIT_CPU))
278
+ end
279
+
280
+ test "setrlimit raises an error if the resource value is invalid" do
281
+ assert_raise(ArgumentError){ Process.setrlimit(9999, 100) }
282
+ end
283
+
284
+ test "is_job basic functionality" do
285
+ assert_respond_to(Process, :job?)
286
+ assert_nothing_raised{ Process.job? }
287
+ end
288
+
289
+ test "is_job returns a boolean value" do
290
+ assert_boolean(Process.job?)
291
+ end
292
+
293
+ test "is_job does not accept any arguments" do
294
+ assert_raise(ArgumentError){ Process.job?(Process.pid) }
295
+ end
296
+
297
+ test "volume_type is a private method" do
298
+ assert_not_respond_to(Process, :volume_type)
299
+ end
300
+
301
+ test "snapshot method basic functionality" do
302
+ assert_respond_to(Process, :snapshot)
303
+ assert_nothing_raised{ Process.snapshot }
304
+ assert_kind_of(Hash, Process.snapshot)
305
+ end
306
+
307
+ test "snapshot accepts :thread, :module or :heap arguments" do
308
+ assert_nothing_raised{ Process.snapshot(:thread) }
309
+ assert_nothing_raised{ Process.snapshot(:module) }
310
+ #assert_nothing_raised{ Process.snapshot(:heap) }
311
+ assert_nothing_raised{ Process.snapshot(:process) }
312
+ end
313
+
314
+ test "snapshot raises an error if an invalid argument is passed" do
315
+ assert_raise(ArgumentError){ Process.snapshot(:bogus) }
316
+ end
317
+
318
+ test "ffi functions are private" do
319
+ assert_not_respond_to(Process, :CloseHandle)
320
+ assert_not_respond_to(Process, :GetCurrentProcess)
321
+ assert_not_respond_to(Process, :GetProcessAffinityMask)
322
+ assert_not_respond_to(Process, :GetPriorityClass)
323
+ assert_not_respond_to(Process, :IsProcessInJob)
324
+ assert_not_respond_to(Process, :OpenProcess)
325
+ assert_not_respond_to(Process, :SetHandleInformation)
326
+ assert_not_respond_to(Process, :SetPriorityClass)
327
+ end
328
+
329
+ test "get_exitcode basic functionality" do
330
+ assert_respond_to(Process, :get_exitcode)
331
+ end
332
+
333
+ =begin
334
+ test "get_exitcode returns the process exit code" do
335
+ pid = Process.create(
336
+ :app_name => 'cmd /c exit 7',
337
+ :creation_flags => Process::DETACHED_PROCESS
338
+ ).process_id
339
+ 10.times do
340
+ sleep(0.1)
341
+ break if Process.get_exitcode(pid)
342
+ end
343
+ assert_equal 7, Process.get_exitcode(pid)
344
+ end
345
+
346
+ test "get_exitcode returns nil while the process is running" do
347
+ stdin_read, stdin_write = IO.pipe
348
+ pid = Process.create(
349
+ :app_name => 'cmd /c pause',
350
+ :creation_flags => Process::DETACHED_PROCESS,
351
+ :startup_info => { :stdin => stdin_read }
352
+ ).process_id
353
+ assert_equal nil, Process.get_exitcode(pid)
354
+ stdin_write.write("\n")
355
+ 10.times do
356
+ sleep(0.1)
357
+ break if Process.get_exitcode(pid)
358
+ end
359
+ assert_equal 1, Process.get_exitcode(pid)
360
+ end
361
+ =end
362
+
363
+ def teardown
364
+ @priority = nil
365
+ end
366
+
367
+ def self.shutdown
368
+ @@pids = nil
369
+ end
370
+ end