PageRenderTime 60ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/projects/jruby-1.7.3/test/externals/ruby1.9/ruby/test_process.rb

https://gitlab.com/essere.lab.public/qualitas.class-corpus
Ruby | 1333 lines | 1190 code | 129 blank | 14 comment | 48 complexity | 6dabc9ebb396a86d021c1ee0b499f181 MD5 | raw file
  1. require 'test/unit'
  2. require 'tmpdir'
  3. require 'pathname'
  4. require 'timeout'
  5. require_relative 'envutil'
  6. require 'rbconfig'
  7. class TestProcess < Test::Unit::TestCase
  8. RUBY = EnvUtil.rubybin
  9. def setup
  10. Process.waitall
  11. end
  12. def teardown
  13. Process.waitall
  14. end
  15. def windows?
  16. return /mswin|mingw|bccwin/ =~ RUBY_PLATFORM
  17. end
  18. def write_file(filename, content)
  19. File.open(filename, "w") {|f|
  20. f << content
  21. }
  22. end
  23. def with_tmpchdir
  24. Dir.mktmpdir {|d|
  25. d = Pathname.new(d).realpath.to_s
  26. Dir.chdir(d) {
  27. yield d
  28. }
  29. }
  30. end
  31. def run_in_child(str) # should be called in a temporary directory
  32. write_file("test-script", str)
  33. Process.wait spawn(RUBY, "test-script")
  34. $?
  35. end
  36. def test_rlimit_availability
  37. begin
  38. Process.getrlimit(nil)
  39. rescue NotImplementedError
  40. assert_raise(NotImplementedError) { Process.setrlimit }
  41. rescue TypeError
  42. assert_raise(ArgumentError) { Process.setrlimit }
  43. end
  44. end
  45. def rlimit_exist?
  46. Process.getrlimit(nil)
  47. rescue NotImplementedError
  48. return false
  49. rescue TypeError
  50. return true
  51. end
  52. def test_rlimit_nofile
  53. return unless rlimit_exist?
  54. with_tmpchdir {
  55. write_file 's', <<-"End"
  56. # if limit=0, this test freeze pn OpenBSD
  57. limit = /openbsd/ =~ RUBY_PLATFORM ? 1 : 0
  58. result = 1
  59. begin
  60. Process.setrlimit(Process::RLIMIT_NOFILE, limit)
  61. rescue Errno::EINVAL
  62. result = 0
  63. end
  64. if result == 1
  65. begin
  66. IO.pipe
  67. rescue Errno::EMFILE
  68. result = 0
  69. end
  70. end
  71. exit result
  72. End
  73. pid = spawn RUBY, "s"
  74. Process.wait pid
  75. assert_equal(0, $?.to_i, "#{$?}")
  76. }
  77. end
  78. def test_rlimit_name
  79. return unless rlimit_exist?
  80. [
  81. :AS, "AS",
  82. :CORE, "CORE",
  83. :CPU, "CPU",
  84. :DATA, "DATA",
  85. :FSIZE, "FSIZE",
  86. :MEMLOCK, "MEMLOCK",
  87. :MSGQUEUE, "MSGQUEUE",
  88. :NICE, "NICE",
  89. :NOFILE, "NOFILE",
  90. :NPROC, "NPROC",
  91. :RSS, "RSS",
  92. :RTPRIO, "RTPRIO",
  93. :RTTIME, "RTTIME",
  94. :SBSIZE, "SBSIZE",
  95. :SIGPENDING, "SIGPENDING",
  96. :STACK, "STACK",
  97. ].each {|name|
  98. if Process.const_defined? "RLIMIT_#{name}"
  99. assert_nothing_raised { Process.getrlimit(name) }
  100. else
  101. assert_raise(ArgumentError) { Process.getrlimit(name) }
  102. end
  103. }
  104. assert_raise(ArgumentError) { Process.getrlimit(:FOO) }
  105. assert_raise(ArgumentError) { Process.getrlimit("FOO") }
  106. end
  107. def test_rlimit_value
  108. return unless rlimit_exist?
  109. assert_raise(ArgumentError) { Process.setrlimit(:CORE, :FOO) }
  110. with_tmpchdir do
  111. s = run_in_child(<<-'End')
  112. cur, max = Process.getrlimit(:NOFILE)
  113. Process.setrlimit(:NOFILE, [max-10, cur].min)
  114. begin
  115. Process.setrlimit(:NOFILE, :INFINITY)
  116. rescue Errno::EPERM
  117. exit false
  118. end
  119. End
  120. assert_not_equal(0, s.exitstatus)
  121. s = run_in_child(<<-'End')
  122. cur, max = Process.getrlimit(:NOFILE)
  123. Process.setrlimit(:NOFILE, [max-10, cur].min)
  124. begin
  125. Process.setrlimit(:NOFILE, "INFINITY")
  126. rescue Errno::EPERM
  127. exit false
  128. end
  129. End
  130. assert_not_equal(0, s.exitstatus)
  131. end
  132. end
  133. TRUECOMMAND = [RUBY, '-e', '']
  134. def test_execopts_opts
  135. assert_nothing_raised {
  136. Process.wait Process.spawn(*TRUECOMMAND, {})
  137. }
  138. assert_raise(ArgumentError) {
  139. Process.wait Process.spawn(*TRUECOMMAND, :foo => 100)
  140. }
  141. assert_raise(ArgumentError) {
  142. Process.wait Process.spawn(*TRUECOMMAND, Process => 100)
  143. }
  144. end
  145. def test_execopts_pgroup
  146. skip "system(:pgroup) is not supported" if windows?
  147. assert_nothing_raised { system(*TRUECOMMAND, :pgroup=>false) }
  148. io = IO.popen([RUBY, "-e", "print Process.getpgrp"])
  149. assert_equal(Process.getpgrp.to_s, io.read)
  150. io.close
  151. io = IO.popen([RUBY, "-e", "print Process.getpgrp", :pgroup=>true])
  152. assert_equal(io.pid.to_s, io.read)
  153. io.close
  154. assert_raise(ArgumentError) { system(*TRUECOMMAND, :pgroup=>-1) }
  155. assert_raise(Errno::EPERM) { Process.wait spawn(*TRUECOMMAND, :pgroup=>2) }
  156. io1 = IO.popen([RUBY, "-e", "print Process.getpgrp", :pgroup=>true])
  157. io2 = IO.popen([RUBY, "-e", "print Process.getpgrp", :pgroup=>io1.pid])
  158. assert_equal(io1.pid.to_s, io1.read)
  159. assert_equal(io1.pid.to_s, io2.read)
  160. Process.wait io1.pid
  161. Process.wait io2.pid
  162. io1.close
  163. io2.close
  164. end
  165. def test_execopts_rlimit
  166. return unless rlimit_exist?
  167. assert_raise(ArgumentError) { system(*TRUECOMMAND, :rlimit_foo=>0) }
  168. assert_raise(ArgumentError) { system(*TRUECOMMAND, :rlimit_NOFILE=>0) }
  169. assert_raise(ArgumentError) { system(*TRUECOMMAND, :rlimit_nofile=>[]) }
  170. assert_raise(ArgumentError) { system(*TRUECOMMAND, :rlimit_nofile=>[1,2,3]) }
  171. max = Process.getrlimit(:CORE).last
  172. n = max
  173. IO.popen([RUBY, "-e",
  174. "p Process.getrlimit(:CORE)", :rlimit_core=>n]) {|io|
  175. assert_equal("[#{n}, #{n}]\n", io.read)
  176. }
  177. n = 0
  178. IO.popen([RUBY, "-e",
  179. "p Process.getrlimit(:CORE)", :rlimit_core=>n]) {|io|
  180. assert_equal("[#{n}, #{n}]\n", io.read)
  181. }
  182. n = max
  183. IO.popen([RUBY, "-e",
  184. "p Process.getrlimit(:CORE)", :rlimit_core=>[n]]) {|io|
  185. assert_equal("[#{n}, #{n}]", io.read.chomp)
  186. }
  187. m, n = 0, max
  188. IO.popen([RUBY, "-e",
  189. "p Process.getrlimit(:CORE)", :rlimit_core=>[m,n]]) {|io|
  190. assert_equal("[#{m}, #{n}]", io.read.chomp)
  191. }
  192. m, n = 0, 0
  193. IO.popen([RUBY, "-e",
  194. "p Process.getrlimit(:CORE)", :rlimit_core=>[m,n]]) {|io|
  195. assert_equal("[#{m}, #{n}]", io.read.chomp)
  196. }
  197. n = max
  198. IO.popen([RUBY, "-e",
  199. "p Process.getrlimit(:CORE), Process.getrlimit(:CPU)",
  200. :rlimit_core=>n, :rlimit_cpu=>3600]) {|io|
  201. assert_equal("[#{n}, #{n}]\n[3600, 3600]", io.read.chomp)
  202. }
  203. end
  204. MANDATORY_ENVS = %w[RUBYLIB]
  205. case RbConfig::CONFIG['target_os']
  206. when /linux/
  207. MANDATORY_ENVS << 'LD_PRELOAD'
  208. when /mswin|mingw/
  209. MANDATORY_ENVS.concat(%w[HOME USER TMPDIR])
  210. end
  211. if e = RbConfig::CONFIG['LIBPATHENV']
  212. MANDATORY_ENVS << e
  213. end
  214. PREENVARG = ['-e', "%w[#{MANDATORY_ENVS.join(' ')}].each{|e|ENV.delete(e)}"]
  215. ENVARG = ['-e', 'ENV.each {|k,v| puts "#{k}=#{v}" }']
  216. ENVCOMMAND = [RUBY].concat(PREENVARG).concat(ENVARG)
  217. def test_execopts_env
  218. assert_raise(ArgumentError) {
  219. system({"F=O"=>"BAR"}, *TRUECOMMAND)
  220. }
  221. with_tmpchdir {|d|
  222. prog = "#{d}/notexist"
  223. e = assert_raise(Errno::ENOENT) {
  224. Process.wait Process.spawn({"FOO"=>"BAR"}, prog)
  225. }
  226. assert_equal(prog, e.message.sub(/.* - /, ''))
  227. e = assert_raise(Errno::ENOENT) {
  228. Process.wait Process.spawn({"FOO"=>"BAR"}, [prog, "blar"])
  229. }
  230. assert_equal(prog, e.message.sub(/.* - /, ''))
  231. }
  232. h = {}
  233. cmd = [h, RUBY]
  234. (ENV.keys + MANDATORY_ENVS).each do |k|
  235. case k
  236. when /\APATH\z/i
  237. when *MANDATORY_ENVS
  238. cmd << '-e' << "ENV.delete('#{k}')"
  239. else
  240. h[k] = nil
  241. end
  242. end
  243. cmd << '-e' << 'puts ENV.keys.map{|e|e.upcase}'
  244. IO.popen(cmd) {|io|
  245. assert_equal("PATH\n", io.read)
  246. }
  247. IO.popen([{"FOO"=>"BAR"}, *ENVCOMMAND]) {|io|
  248. assert_match(/^FOO=BAR$/, io.read)
  249. }
  250. with_tmpchdir {|d|
  251. system({"fofo"=>"haha"}, *ENVCOMMAND, STDOUT=>"out")
  252. assert_match(/^fofo=haha$/, File.read("out").chomp)
  253. }
  254. old = ENV["hmm"]
  255. begin
  256. ENV["hmm"] = "fufu"
  257. IO.popen(ENVCOMMAND) {|io| assert_match(/^hmm=fufu$/, io.read) }
  258. IO.popen([{"hmm"=>""}, *ENVCOMMAND]) {|io| assert_match(/^hmm=$/, io.read) }
  259. IO.popen([{"hmm"=>nil}, *ENVCOMMAND]) {|io| assert_not_match(/^hmm=/, io.read) }
  260. ENV["hmm"] = ""
  261. IO.popen(ENVCOMMAND) {|io| assert_match(/^hmm=$/, io.read) }
  262. IO.popen([{"hmm"=>""}, *ENVCOMMAND]) {|io| assert_match(/^hmm=$/, io.read) }
  263. IO.popen([{"hmm"=>nil}, *ENVCOMMAND]) {|io| assert_not_match(/^hmm=/, io.read) }
  264. ENV["hmm"] = nil
  265. IO.popen(ENVCOMMAND) {|io| assert_not_match(/^hmm=/, io.read) }
  266. IO.popen([{"hmm"=>""}, *ENVCOMMAND]) {|io| assert_match(/^hmm=$/, io.read) }
  267. IO.popen([{"hmm"=>nil}, *ENVCOMMAND]) {|io| assert_not_match(/^hmm=/, io.read) }
  268. ensure
  269. ENV["hmm"] = old
  270. end
  271. end
  272. def test_execopts_unsetenv_others
  273. h = {}
  274. MANDATORY_ENVS.each {|k| e = ENV[k] and h[k] = e}
  275. IO.popen([h, *ENVCOMMAND, :unsetenv_others=>true]) {|io|
  276. assert_equal("", io.read)
  277. }
  278. IO.popen([h.merge("A"=>"B"), *ENVCOMMAND, :unsetenv_others=>true]) {|io|
  279. assert_equal("A=B\n", io.read)
  280. }
  281. end
  282. PWD = [RUBY, '-e', 'puts Dir.pwd']
  283. def test_execopts_chdir
  284. with_tmpchdir {|d|
  285. IO.popen([*PWD, :chdir => d]) {|io|
  286. assert_equal(d, io.read.chomp)
  287. }
  288. assert_raise(Errno::ENOENT) {
  289. Process.wait Process.spawn(*PWD, :chdir => "d/notexist")
  290. }
  291. }
  292. end
  293. UMASK = [RUBY, '-e', 'printf "%04o\n", File.umask']
  294. def test_execopts_umask
  295. skip "umask is not supported" if windows?
  296. IO.popen([*UMASK, :umask => 0]) {|io|
  297. assert_equal("0000", io.read.chomp)
  298. }
  299. IO.popen([*UMASK, :umask => 0777]) {|io|
  300. assert_equal("0777", io.read.chomp)
  301. }
  302. end
  303. def with_pipe
  304. begin
  305. r, w = IO.pipe
  306. yield r, w
  307. ensure
  308. r.close unless r.closed?
  309. w.close unless w.closed?
  310. end
  311. end
  312. def with_pipes(n)
  313. ary = []
  314. begin
  315. n.times {
  316. ary << IO.pipe
  317. }
  318. yield ary
  319. ensure
  320. ary.each {|r, w|
  321. r.close unless r.closed?
  322. w.close unless w.closed?
  323. }
  324. end
  325. end
  326. ECHO = lambda {|arg| [RUBY, '-e', "puts #{arg.dump}; STDOUT.flush"] }
  327. SORT = [RUBY, '-e', "puts ARGF.readlines.sort"]
  328. CAT = [RUBY, '-e', "IO.copy_stream STDIN, STDOUT"]
  329. def test_execopts_redirect
  330. with_tmpchdir {|d|
  331. Process.wait Process.spawn(*ECHO["a"], STDOUT=>["out", File::WRONLY|File::CREAT|File::TRUNC, 0644])
  332. assert_equal("a", File.read("out").chomp)
  333. if windows?
  334. # currently telling to child the file modes is not supported.
  335. open("out", "a") {|f| f.write "0\n"}
  336. else
  337. Process.wait Process.spawn(*ECHO["0"], STDOUT=>["out", File::WRONLY|File::CREAT|File::APPEND, 0644])
  338. assert_equal("a\n0\n", File.read("out"))
  339. end
  340. Process.wait Process.spawn(*SORT, STDIN=>["out", File::RDONLY, 0644],
  341. STDOUT=>["out2", File::WRONLY|File::CREAT|File::TRUNC, 0644])
  342. assert_equal("0\na\n", File.read("out2"))
  343. Process.wait Process.spawn(*ECHO["b"], [STDOUT, STDERR]=>["out", File::WRONLY|File::CREAT|File::TRUNC, 0644])
  344. assert_equal("b", File.read("out").chomp)
  345. # problem occur with valgrind
  346. #Process.wait Process.spawn(*ECHO["a"], STDOUT=>:close, STDERR=>["out", File::WRONLY|File::CREAT|File::TRUNC, 0644])
  347. #p File.read("out")
  348. #assert(!File.read("out").empty?) # error message such as "-e:1:in `flush': Bad file descriptor (Errno::EBADF)"
  349. Process.wait Process.spawn(*ECHO["c"], STDERR=>STDOUT, STDOUT=>["out", File::WRONLY|File::CREAT|File::TRUNC, 0644])
  350. assert_equal("c", File.read("out").chomp)
  351. File.open("out", "w") {|f|
  352. Process.wait Process.spawn(*ECHO["d"], STDOUT=>f)
  353. assert_equal("d", File.read("out").chomp)
  354. }
  355. opts = {STDOUT=>["out", File::WRONLY|File::CREAT|File::TRUNC, 0644]}
  356. opts.merge(3=>STDOUT, 4=>STDOUT, 5=>STDOUT, 6=>STDOUT, 7=>STDOUT) unless windows?
  357. Process.wait Process.spawn(*ECHO["e"], opts)
  358. assert_equal("e", File.read("out").chomp)
  359. opts = {STDOUT=>["out", File::WRONLY|File::CREAT|File::TRUNC, 0644]}
  360. opts.merge(3=>0, 4=>:in, 5=>STDIN, 6=>1, 7=>:out, 8=>STDOUT, 9=>2, 10=>:err, 11=>STDERR) unless windows?
  361. Process.wait Process.spawn(*ECHO["ee"], opts)
  362. assert_equal("ee", File.read("out").chomp)
  363. unless windows?
  364. # passing non-stdio fds is not supported on Windows
  365. File.open("out", "w") {|f|
  366. h = {STDOUT=>f, f=>STDOUT}
  367. 3.upto(30) {|i| h[i] = STDOUT if f.fileno != i }
  368. Process.wait Process.spawn(*ECHO["f"], h)
  369. assert_equal("f", File.read("out").chomp)
  370. }
  371. end
  372. assert_raise(ArgumentError) {
  373. Process.wait Process.spawn(*ECHO["f"], 1=>Process)
  374. }
  375. assert_raise(ArgumentError) {
  376. Process.wait Process.spawn(*ECHO["f"], [Process]=>1)
  377. }
  378. assert_raise(ArgumentError) {
  379. Process.wait Process.spawn(*ECHO["f"], [1, STDOUT]=>2)
  380. }
  381. assert_raise(ArgumentError) {
  382. Process.wait Process.spawn(*ECHO["f"], -1=>2)
  383. }
  384. Process.wait Process.spawn(*ECHO["hhh\nggg\n"], STDOUT=>"out")
  385. assert_equal("hhh\nggg\n", File.read("out"))
  386. Process.wait Process.spawn(*SORT, STDIN=>"out", STDOUT=>"out2")
  387. assert_equal("ggg\nhhh\n", File.read("out2"))
  388. unless windows?
  389. # passing non-stdio fds is not supported on Windows
  390. assert_raise(Errno::ENOENT) {
  391. Process.wait Process.spawn("non-existing-command", (3..60).to_a=>["err", File::WRONLY|File::CREAT])
  392. }
  393. assert_equal("", File.read("err"))
  394. end
  395. system(*ECHO["bb\naa\n"], STDOUT=>["out", "w"])
  396. assert_equal("bb\naa\n", File.read("out"))
  397. system(*SORT, STDIN=>["out"], STDOUT=>"out2")
  398. assert_equal("aa\nbb\n", File.read("out2"))
  399. with_pipe {|r1, w1|
  400. with_pipe {|r2, w2|
  401. opts = {STDIN=>r1, STDOUT=>w2}
  402. opts.merge(w1=>:close, r2=>:close) unless windows?
  403. pid = spawn(*SORT, opts)
  404. r1.close
  405. w2.close
  406. w1.puts "c"
  407. w1.puts "a"
  408. w1.puts "b"
  409. w1.close
  410. assert_equal("a\nb\nc\n", r2.read)
  411. r2.close
  412. Process.wait(pid)
  413. }
  414. }
  415. unless windows?
  416. # passing non-stdio fds is not supported on Windows
  417. with_pipes(5) {|pipes|
  418. ios = pipes.flatten
  419. h = {}
  420. ios.length.times {|i| h[ios[i]] = ios[(i-1)%ios.length] }
  421. h2 = h.invert
  422. rios = pipes.map {|r, w| r }
  423. wios = pipes.map {|r, w| w }
  424. child_wfds = wios.map {|w| h2[w].fileno }
  425. pid = spawn(RUBY, "-e",
  426. "[#{child_wfds.join(',')}].each {|fd| IO.new(fd, 'w').puts fd }", h)
  427. pipes.each {|r, w|
  428. assert_equal("#{h2[w].fileno}\n", r.gets)
  429. }
  430. Process.wait pid;
  431. }
  432. with_pipes(5) {|pipes|
  433. ios = pipes.flatten
  434. h = {}
  435. ios.length.times {|i| h[ios[i]] = ios[(i+1)%ios.length] }
  436. h2 = h.invert
  437. rios = pipes.map {|r, w| r }
  438. wios = pipes.map {|r, w| w }
  439. child_wfds = wios.map {|w| h2[w].fileno }
  440. pid = spawn(RUBY, "-e",
  441. "[#{child_wfds.join(',')}].each {|fd| IO.new(fd, 'w').puts fd }", h)
  442. pipes.each {|r, w|
  443. assert_equal("#{h2[w].fileno}\n", r.gets)
  444. }
  445. Process.wait pid
  446. }
  447. closed_fd = nil
  448. with_pipes(5) {|pipes|
  449. io = pipes.last.last
  450. closed_fd = io.fileno
  451. }
  452. assert_raise(Errno::EBADF) { Process.wait spawn(*TRUECOMMAND, closed_fd=>closed_fd) }
  453. with_pipe {|r, w|
  454. if w.respond_to?(:"close_on_exec=")
  455. w.close_on_exec = true
  456. pid = spawn(RUBY, "-e", "IO.new(#{w.fileno}, 'w').print 'a'", w=>w)
  457. w.close
  458. assert_equal("a", r.read)
  459. Process.wait pid
  460. end
  461. }
  462. end
  463. system(*ECHO["funya"], :out=>"out")
  464. assert_equal("funya\n", File.read("out"))
  465. system(RUBY, '-e', 'STDOUT.reopen(STDERR); puts "henya"', :err=>"out")
  466. assert_equal("henya\n", File.read("out"))
  467. IO.popen([*CAT, :in=>"out"]) {|io|
  468. assert_equal("henya\n", io.read)
  469. }
  470. }
  471. end
  472. def test_execopts_redirect_dup2_child
  473. with_tmpchdir {|d|
  474. Process.wait spawn(RUBY, "-e", "STDERR.print 'err'; STDOUT.print 'out'",
  475. STDOUT=>"out", STDERR=>[:child, STDOUT])
  476. assert_equal("errout", File.read("out"))
  477. Process.wait spawn(RUBY, "-e", "STDERR.print 'err'; STDOUT.print 'out'",
  478. STDERR=>"out", STDOUT=>[:child, STDERR])
  479. assert_equal("errout", File.read("out"))
  480. skip "inheritance of fd other than stdin,stdout and stderr is not supported" if windows?
  481. Process.wait spawn(RUBY, "-e", "STDERR.print 'err'; STDOUT.print 'out'",
  482. STDOUT=>"out",
  483. STDERR=>[:child, 3],
  484. 3=>[:child, 4],
  485. 4=>[:child, STDOUT]
  486. )
  487. assert_equal("errout", File.read("out"))
  488. IO.popen([RUBY, "-e", "STDERR.print 'err'; STDOUT.print 'out'", STDERR=>[:child, STDOUT]]) {|io|
  489. assert_equal("errout", io.read)
  490. }
  491. assert_raise(ArgumentError) { Process.wait spawn(*TRUECOMMAND, STDOUT=>[:child, STDOUT]) }
  492. assert_raise(ArgumentError) { Process.wait spawn(*TRUECOMMAND, 3=>[:child, 4], 4=>[:child, 3]) }
  493. assert_raise(ArgumentError) { Process.wait spawn(*TRUECOMMAND, 3=>[:child, 4], 4=>[:child, 5], 5=>[:child, 3]) }
  494. assert_raise(ArgumentError) { Process.wait spawn(*TRUECOMMAND, STDOUT=>[:child, 3]) }
  495. }
  496. end
  497. def test_execopts_exec
  498. with_tmpchdir {|d|
  499. write_file("s", 'exec "echo aaa", STDOUT=>"foo"')
  500. pid = spawn RUBY, 's'
  501. Process.wait pid
  502. assert_equal("aaa\n", File.read("foo"))
  503. }
  504. end
  505. def test_execopts_popen
  506. with_tmpchdir {|d|
  507. IO.popen("#{RUBY} -e 'puts :foo'") {|io| assert_equal("foo\n", io.read) }
  508. assert_raise(Errno::ENOENT) { IO.popen(["echo bar"]) {} } # assuming "echo bar" command not exist.
  509. IO.popen(ECHO["baz"]) {|io| assert_equal("baz\n", io.read) }
  510. assert_raise(ArgumentError) {
  511. IO.popen([*ECHO["qux"], STDOUT=>STDOUT]) {|io| }
  512. }
  513. IO.popen([*ECHO["hoge"], STDERR=>STDOUT]) {|io|
  514. assert_equal("hoge\n", io.read)
  515. }
  516. assert_raise(ArgumentError) {
  517. IO.popen([*ECHO["fuga"], STDOUT=>"out"]) {|io| }
  518. }
  519. skip "inheritance of fd other than stdin,stdout and stderr is not supported" if windows?
  520. with_pipe {|r, w|
  521. IO.popen([RUBY, '-e', 'IO.new(3, "w").puts("a"); puts "b"', 3=>w]) {|io|
  522. assert_equal("b\n", io.read)
  523. }
  524. w.close
  525. assert_equal("a\n", r.read)
  526. }
  527. IO.popen([RUBY, '-e', "IO.new(9, 'w').puts(:b)",
  528. 9=>["out2", File::WRONLY|File::CREAT|File::TRUNC]]) {|io|
  529. assert_equal("", io.read)
  530. }
  531. assert_equal("b\n", File.read("out2"))
  532. }
  533. end
  534. def test_popen_fork
  535. return if /freebsd/ =~ RUBY_PLATFORM # this test freeze in FreeBSD
  536. IO.popen("-") {|io|
  537. if !io
  538. puts "fooo"
  539. else
  540. assert_equal("fooo\n", io.read)
  541. end
  542. }
  543. rescue NotImplementedError
  544. end
  545. def test_fd_inheritance
  546. skip "inheritance of fd other than stdin,stdout and stderr is not supported" if windows?
  547. with_pipe {|r, w|
  548. system(RUBY, '-e', 'IO.new(ARGV[0].to_i, "w").puts(:ba)', w.fileno.to_s)
  549. w.close
  550. assert_equal("ba\n", r.read)
  551. }
  552. with_pipe {|r, w|
  553. Process.wait spawn(RUBY, '-e',
  554. 'IO.new(ARGV[0].to_i, "w").puts("bi") rescue nil',
  555. w.fileno.to_s)
  556. w.close
  557. assert_equal("", r.read)
  558. }
  559. with_pipe {|r, w|
  560. with_tmpchdir {|d|
  561. write_file("s", <<-"End")
  562. exec(#{RUBY.dump}, '-e',
  563. 'IO.new(ARGV[0].to_i, "w").puts("bu") rescue nil',
  564. #{w.fileno.to_s.dump})
  565. End
  566. Process.wait spawn(RUBY, "s", :close_others=>false)
  567. w.close
  568. assert_equal("bu\n", r.read)
  569. }
  570. }
  571. with_pipe {|r, w|
  572. io = IO.popen([RUBY, "-e", "STDERR.reopen(STDOUT); IO.new(#{w.fileno}, 'w').puts('me')"])
  573. w.close
  574. errmsg = io.read
  575. assert_equal("", r.read)
  576. assert_not_equal("", errmsg)
  577. Process.wait
  578. }
  579. with_pipe {|r, w|
  580. errmsg = `#{RUBY} -e "STDERR.reopen(STDOUT); IO.new(#{w.fileno}, 'w').puts(123)"`
  581. w.close
  582. assert_equal("", r.read)
  583. assert_not_equal("", errmsg)
  584. }
  585. end
  586. def test_execopts_close_others
  587. skip "inheritance of fd other than stdin,stdout and stderr is not supported" if windows?
  588. with_tmpchdir {|d|
  589. with_pipe {|r, w|
  590. system(RUBY, '-e', 'STDERR.reopen("err", "w"); IO.new(ARGV[0].to_i, "w").puts("ma")', w.fileno.to_s, :close_others=>true)
  591. w.close
  592. assert_equal("", r.read)
  593. assert_not_equal("", File.read("err"))
  594. File.unlink("err")
  595. }
  596. with_pipe {|r, w|
  597. Process.wait spawn(RUBY, '-e', 'STDERR.reopen("err", "w"); IO.new(ARGV[0].to_i, "w").puts("mi")', w.fileno.to_s, :close_others=>true)
  598. w.close
  599. assert_equal("", r.read)
  600. assert_not_equal("", File.read("err"))
  601. File.unlink("err")
  602. }
  603. with_pipe {|r, w|
  604. Process.wait spawn(RUBY, '-e', 'IO.new(ARGV[0].to_i, "w").puts("bi")', w.fileno.to_s, :close_others=>false)
  605. w.close
  606. assert_equal("bi\n", r.read)
  607. }
  608. with_pipe {|r, w|
  609. write_file("s", <<-"End")
  610. exec(#{RUBY.dump}, '-e',
  611. 'STDERR.reopen("err", "w"); IO.new(ARGV[0].to_i, "w").puts("mu")',
  612. #{w.fileno.to_s.dump},
  613. :close_others=>true)
  614. End
  615. Process.wait spawn(RUBY, "s", :close_others=>false)
  616. w.close
  617. assert_equal("", r.read)
  618. assert_not_equal("", File.read("err"))
  619. File.unlink("err")
  620. }
  621. with_pipe {|r, w|
  622. io = IO.popen([RUBY, "-e", "STDERR.reopen(STDOUT); IO.new(#{w.fileno}, 'w').puts('me')", :close_others=>true])
  623. w.close
  624. errmsg = io.read
  625. assert_equal("", r.read)
  626. assert_not_equal("", errmsg)
  627. Process.wait
  628. }
  629. with_pipe {|r, w|
  630. io = IO.popen([RUBY, "-e", "STDERR.reopen(STDOUT); IO.new(#{w.fileno}, 'w').puts('mo')", :close_others=>false])
  631. w.close
  632. errmsg = io.read
  633. assert_equal("mo\n", r.read)
  634. assert_equal("", errmsg)
  635. Process.wait
  636. }
  637. with_pipe {|r, w|
  638. io = IO.popen([RUBY, "-e", "STDERR.reopen(STDOUT); IO.new(#{w.fileno}, 'w').puts('mo')", :close_others=>nil])
  639. w.close
  640. errmsg = io.read
  641. assert_equal("mo\n", r.read)
  642. assert_equal("", errmsg)
  643. Process.wait
  644. }
  645. }
  646. end
  647. def test_execopts_redirect_self
  648. begin
  649. with_pipe {|r, w|
  650. w << "haha\n"
  651. w.close
  652. r.close_on_exec = true
  653. IO.popen([RUBY, "-e", "print IO.new(#{r.fileno}, 'r').read", r.fileno=>r.fileno, :close_others=>false]) {|io|
  654. assert_equal("haha\n", io.read)
  655. }
  656. }
  657. rescue NotImplementedError
  658. skip "IO#close_on_exec= is not supported"
  659. end
  660. end
  661. def test_execopts_duplex_io
  662. IO.popen("#{RUBY} -e ''", "r+") {|duplex|
  663. assert_raise(ArgumentError) { system("#{RUBY} -e ''", duplex=>STDOUT) }
  664. assert_raise(ArgumentError) { system("#{RUBY} -e ''", STDOUT=>duplex) }
  665. }
  666. end
  667. def test_execopts_modification
  668. h = {}
  669. Process.wait spawn(*TRUECOMMAND, h)
  670. assert_equal({}, h)
  671. h = {}
  672. system(*TRUECOMMAND, h)
  673. assert_equal({}, h)
  674. h = {}
  675. io = IO.popen([*TRUECOMMAND, h])
  676. io.close
  677. assert_equal({}, h)
  678. end
  679. def test_system_noshell
  680. str = "echo non existing command name which contains spaces"
  681. assert_nil(system([str, str]))
  682. end
  683. def test_spawn_noshell
  684. str = "echo non existing command name which contains spaces"
  685. assert_raise(Errno::ENOENT) { spawn([str, str]) }
  686. end
  687. def test_popen_noshell
  688. str = "echo non existing command name which contains spaces"
  689. assert_raise(Errno::ENOENT) { IO.popen([str, str]) }
  690. end
  691. def test_exec_noshell
  692. with_tmpchdir {|d|
  693. write_file("s", <<-"End")
  694. str = "echo non existing command name which contains spaces"
  695. STDERR.reopen(STDOUT)
  696. begin
  697. exec [str, str]
  698. rescue Errno::ENOENT
  699. print "Errno::ENOENT success"
  700. end
  701. End
  702. r = IO.popen([RUBY, "s", :close_others=>false], "r") {|f| f.read}
  703. assert_equal("Errno::ENOENT success", r)
  704. }
  705. end
  706. def test_system_wordsplit
  707. with_tmpchdir {|d|
  708. write_file("script", <<-'End')
  709. File.open("result", "w") {|t| t << "haha pid=#{$$} ppid=#{Process.ppid}" }
  710. exit 5
  711. End
  712. str = "#{RUBY} script"
  713. ret = system(str)
  714. status = $?
  715. assert_equal(false, ret)
  716. assert(status.exited?)
  717. assert_equal(5, status.exitstatus)
  718. assert_equal("haha pid=#{status.pid} ppid=#{$$}", File.read("result"))
  719. }
  720. end
  721. def test_spawn_wordsplit
  722. with_tmpchdir {|d|
  723. write_file("script", <<-'End')
  724. File.open("result", "w") {|t| t << "hihi pid=#{$$} ppid=#{Process.ppid}" }
  725. exit 6
  726. End
  727. str = "#{RUBY} script"
  728. pid = spawn(str)
  729. Process.wait pid
  730. status = $?
  731. assert_equal(pid, status.pid)
  732. assert(status.exited?)
  733. assert_equal(6, status.exitstatus)
  734. assert_equal("hihi pid=#{status.pid} ppid=#{$$}", File.read("result"))
  735. }
  736. end
  737. def test_popen_wordsplit
  738. with_tmpchdir {|d|
  739. write_file("script", <<-'End')
  740. print "fufu pid=#{$$} ppid=#{Process.ppid}"
  741. exit 7
  742. End
  743. str = "#{RUBY} script"
  744. io = IO.popen(str)
  745. pid = io.pid
  746. result = io.read
  747. io.close
  748. status = $?
  749. assert_equal(pid, status.pid)
  750. assert(status.exited?)
  751. assert_equal(7, status.exitstatus)
  752. assert_equal("fufu pid=#{status.pid} ppid=#{$$}", result)
  753. }
  754. end
  755. def test_exec_wordsplit
  756. with_tmpchdir {|d|
  757. write_file("script", <<-'End')
  758. File.open("result", "w") {|t|
  759. if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM
  760. t << "hehe ppid=#{Process.ppid}"
  761. else
  762. t << "hehe pid=#{$$} ppid=#{Process.ppid}"
  763. end
  764. }
  765. exit 6
  766. End
  767. write_file("s", <<-"End")
  768. ruby = #{RUBY.dump}
  769. exec "\#{ruby} script"
  770. End
  771. pid = spawn(RUBY, "s")
  772. Process.wait pid
  773. status = $?
  774. assert_equal(pid, status.pid)
  775. assert(status.exited?)
  776. assert_equal(6, status.exitstatus)
  777. if windows?
  778. expected = "hehe ppid=#{status.pid}"
  779. else
  780. expected = "hehe pid=#{status.pid} ppid=#{$$}"
  781. end
  782. assert_equal(expected, File.read("result"))
  783. }
  784. end
  785. def test_system_shell
  786. with_tmpchdir {|d|
  787. write_file("script1", <<-'End')
  788. File.open("result1", "w") {|t| t << "taka pid=#{$$} ppid=#{Process.ppid}" }
  789. exit 7
  790. End
  791. write_file("script2", <<-'End')
  792. File.open("result2", "w") {|t| t << "taki pid=#{$$} ppid=#{Process.ppid}" }
  793. exit 8
  794. End
  795. ret = system("#{RUBY} script1 || #{RUBY} script2")
  796. status = $?
  797. assert_equal(false, ret)
  798. assert(status.exited?)
  799. result1 = File.read("result1")
  800. result2 = File.read("result2")
  801. assert_match(/\Ataka pid=\d+ ppid=\d+\z/, result1)
  802. assert_match(/\Ataki pid=\d+ ppid=\d+\z/, result2)
  803. assert_not_equal(result1[/\d+/].to_i, status.pid)
  804. if windows?
  805. Dir.mkdir(path = "path with space")
  806. write_file(bat = path + "/bat test.bat", "@echo %1>out")
  807. system(bat, "foo 'bar'")
  808. assert_equal(%["foo 'bar'"\n], File.read("out"), '[ruby-core:22960]')
  809. system(%[#{bat.dump} "foo 'bar'"])
  810. assert_equal(%["foo 'bar'"\n], File.read("out"), '[ruby-core:22960]')
  811. end
  812. }
  813. end
  814. def test_spawn_shell
  815. with_tmpchdir {|d|
  816. write_file("script1", <<-'End')
  817. File.open("result1", "w") {|t| t << "taku pid=#{$$} ppid=#{Process.ppid}" }
  818. exit 7
  819. End
  820. write_file("script2", <<-'End')
  821. File.open("result2", "w") {|t| t << "take pid=#{$$} ppid=#{Process.ppid}" }
  822. exit 8
  823. End
  824. pid = spawn("#{RUBY} script1 || #{RUBY} script2")
  825. Process.wait pid
  826. status = $?
  827. assert(status.exited?)
  828. assert(!status.success?)
  829. result1 = File.read("result1")
  830. result2 = File.read("result2")
  831. assert_match(/\Ataku pid=\d+ ppid=\d+\z/, result1)
  832. assert_match(/\Atake pid=\d+ ppid=\d+\z/, result2)
  833. assert_not_equal(result1[/\d+/].to_i, status.pid)
  834. if windows?
  835. Dir.mkdir(path = "path with space")
  836. write_file(bat = path + "/bat test.bat", "@echo %1>out")
  837. pid = spawn(bat, "foo 'bar'")
  838. Process.wait pid
  839. status = $?
  840. assert(status.exited?)
  841. assert(status.success?)
  842. assert_equal(%["foo 'bar'"\n], File.read("out"), '[ruby-core:22960]')
  843. pid = spawn(%[#{bat.dump} "foo 'bar'"])
  844. Process.wait pid
  845. status = $?
  846. assert(status.exited?)
  847. assert(status.success?)
  848. assert_equal(%["foo 'bar'"\n], File.read("out"), '[ruby-core:22960]')
  849. end
  850. }
  851. end
  852. def test_popen_shell
  853. with_tmpchdir {|d|
  854. write_file("script1", <<-'End')
  855. puts "tako pid=#{$$} ppid=#{Process.ppid}"
  856. exit 7
  857. End
  858. write_file("script2", <<-'End')
  859. puts "tika pid=#{$$} ppid=#{Process.ppid}"
  860. exit 8
  861. End
  862. io = IO.popen("#{RUBY} script1 || #{RUBY} script2")
  863. result = io.read
  864. io.close
  865. status = $?
  866. assert(status.exited?)
  867. assert(!status.success?)
  868. assert_match(/\Atako pid=\d+ ppid=\d+\ntika pid=\d+ ppid=\d+\n\z/, result)
  869. assert_not_equal(result[/\d+/].to_i, status.pid)
  870. if windows?
  871. Dir.mkdir(path = "path with space")
  872. write_file(bat = path + "/bat test.bat", "@echo %1")
  873. r = IO.popen([bat, "foo 'bar'"]) {|f| f.read}
  874. assert_equal(%["foo 'bar'"\n], r, '[ruby-core:22960]')
  875. r = IO.popen(%[#{bat.dump} "foo 'bar'"]) {|f| f.read}
  876. assert_equal(%["foo 'bar'"\n], r, '[ruby-core:22960]')
  877. end
  878. }
  879. end
  880. def test_exec_shell
  881. with_tmpchdir {|d|
  882. write_file("script1", <<-'End')
  883. File.open("result1", "w") {|t| t << "tiki pid=#{$$} ppid=#{Process.ppid}" }
  884. exit 7
  885. End
  886. write_file("script2", <<-'End')
  887. File.open("result2", "w") {|t| t << "tiku pid=#{$$} ppid=#{Process.ppid}" }
  888. exit 8
  889. End
  890. write_file("s", <<-"End")
  891. ruby = #{RUBY.dump}
  892. exec("\#{ruby} script1 || \#{ruby} script2")
  893. End
  894. pid = spawn RUBY, "s"
  895. Process.wait pid
  896. status = $?
  897. assert(status.exited?)
  898. assert(!status.success?)
  899. result1 = File.read("result1")
  900. result2 = File.read("result2")
  901. assert_match(/\Atiki pid=\d+ ppid=\d+\z/, result1)
  902. assert_match(/\Atiku pid=\d+ ppid=\d+\z/, result2)
  903. assert_not_equal(result1[/\d+/].to_i, status.pid)
  904. }
  905. end
  906. def test_argv0
  907. with_tmpchdir {|d|
  908. assert_equal(false, system([RUBY, "asdfg"], "-e", "exit false"))
  909. assert_equal(true, system([RUBY, "zxcvb"], "-e", "exit true"))
  910. Process.wait spawn([RUBY, "poiu"], "-e", "exit 4")
  911. assert_equal(4, $?.exitstatus)
  912. assert_equal("1", IO.popen([[RUBY, "qwerty"], "-e", "print 1"]).read)
  913. Process.wait
  914. write_file("s", <<-"End")
  915. exec([#{RUBY.dump}, "lkjh"], "-e", "exit 5")
  916. End
  917. pid = spawn RUBY, "s"
  918. Process.wait pid
  919. assert_equal(5, $?.exitstatus)
  920. }
  921. end
  922. def with_stdin(filename)
  923. open(filename) {|f|
  924. begin
  925. old = STDIN.dup
  926. begin
  927. STDIN.reopen(filename)
  928. yield
  929. ensure
  930. STDIN.reopen(old)
  931. end
  932. ensure
  933. old.close
  934. end
  935. }
  936. end
  937. def test_argv0_noarg
  938. with_tmpchdir {|d|
  939. open("t", "w") {|f| f.print "exit true" }
  940. open("f", "w") {|f| f.print "exit false" }
  941. with_stdin("t") { assert_equal(true, system([RUBY, "qaz"])) }
  942. with_stdin("f") { assert_equal(false, system([RUBY, "wsx"])) }
  943. with_stdin("t") { Process.wait spawn([RUBY, "edc"]) }
  944. assert($?.success?)
  945. with_stdin("f") { Process.wait spawn([RUBY, "rfv"]) }
  946. assert(!$?.success?)
  947. with_stdin("t") { IO.popen([[RUBY, "tgb"]]) {|io| assert_equal("", io.read) } }
  948. assert($?.success?)
  949. with_stdin("f") { IO.popen([[RUBY, "yhn"]]) {|io| assert_equal("", io.read) } }
  950. assert(!$?.success?)
  951. status = run_in_child "STDIN.reopen('t'); exec([#{RUBY.dump}, 'ujm'])"
  952. assert(status.success?)
  953. status = run_in_child "STDIN.reopen('f'); exec([#{RUBY.dump}, 'ik,'])"
  954. assert(!status.success?)
  955. }
  956. end
  957. def test_status
  958. with_tmpchdir do
  959. s = run_in_child("exit 1")
  960. assert_equal("#<Process::Status: pid #{ s.pid } exit #{ s.exitstatus }>", s.inspect)
  961. assert_equal(s, s)
  962. assert_equal(s, s.to_i)
  963. assert_equal(s.to_i & 0x55555555, s & 0x55555555)
  964. assert_equal(s.to_i >> 1, s >> 1)
  965. assert_equal(false, s.stopped?)
  966. assert_equal(nil, s.stopsig)
  967. end
  968. end
  969. def test_status_kill
  970. return unless Process.respond_to?(:kill)
  971. return unless Signal.list.include?("QUIT")
  972. with_tmpchdir do
  973. write_file("foo", "sleep 30")
  974. pid = spawn(RUBY, "foo")
  975. Thread.new { sleep 1; Process.kill(:SIGQUIT, pid) }
  976. Process.wait(pid)
  977. s = $?
  978. assert_equal([false, true, false],
  979. [s.exited?, s.signaled?, s.stopped?],
  980. "[s.exited?, s.signaled?, s.stopped?]")
  981. assert_send(
  982. [["#<Process::Status: pid #{ s.pid } SIGQUIT (signal #{ s.termsig })>",
  983. "#<Process::Status: pid #{ s.pid } SIGQUIT (signal #{ s.termsig }) (core dumped)>"],
  984. :include?,
  985. s.inspect])
  986. assert_equal(false, s.exited?)
  987. assert_equal(nil, s.success?)
  988. end
  989. end
  990. def test_wait_without_arg
  991. with_tmpchdir do
  992. write_file("foo", "sleep 0.1")
  993. pid = spawn(RUBY, "foo")
  994. assert_equal(pid, Process.wait)
  995. end
  996. end
  997. def test_wait2
  998. with_tmpchdir do
  999. write_file("foo", "sleep 0.1")
  1000. pid = spawn(RUBY, "foo")
  1001. assert_equal([pid, 0], Process.wait2)
  1002. end
  1003. end
  1004. def test_waitall
  1005. with_tmpchdir do
  1006. write_file("foo", "sleep 0.1")
  1007. ps = (0...3).map { spawn(RUBY, "foo") }.sort
  1008. ss = Process.waitall.sort
  1009. ps.zip(ss) do |p1, (p2, s)|
  1010. assert_equal(p1, p2)
  1011. assert_equal(p1, s.pid)
  1012. end
  1013. end
  1014. end
  1015. def test_abort
  1016. with_tmpchdir do
  1017. s = run_in_child("abort")
  1018. assert_not_equal(0, s.exitstatus)
  1019. end
  1020. end
  1021. def test_sleep
  1022. assert_raise(ArgumentError) { sleep(1, 1) }
  1023. end
  1024. def test_getpgid
  1025. assert_kind_of(Integer, Process.getpgid(Process.ppid))
  1026. rescue NotImplementedError
  1027. end
  1028. def test_getpriority
  1029. assert_kind_of(Integer, Process.getpriority(Process::PRIO_PROCESS, $$))
  1030. rescue NameError, NotImplementedError
  1031. end
  1032. def test_setpriority
  1033. if defined? Process::PRIO_USER
  1034. assert_nothing_raised do
  1035. pr = Process.getpriority(Process::PRIO_PROCESS, $$)
  1036. Process.setpriority(Process::PRIO_PROCESS, $$, pr)
  1037. end
  1038. end
  1039. end
  1040. def test_getuid
  1041. assert_kind_of(Integer, Process.uid)
  1042. end
  1043. def test_groups
  1044. gs = Process.groups
  1045. assert_instance_of(Array, gs)
  1046. gs.each {|g| assert_kind_of(Integer, g) }
  1047. rescue NotImplementedError
  1048. end
  1049. def test_maxgroups
  1050. assert_kind_of(Integer, Process.maxgroups)
  1051. rescue NotImplementedError
  1052. end
  1053. def test_geteuid
  1054. assert_kind_of(Integer, Process.egid)
  1055. end
  1056. def test_uid_re_exchangeable_p
  1057. r = Process::UID.re_exchangeable?
  1058. assert(true == r || false == r)
  1059. end
  1060. def test_gid_re_exchangeable_p
  1061. r = Process::GID.re_exchangeable?
  1062. assert(true == r || false == r)
  1063. end
  1064. def test_uid_sid_available?
  1065. r = Process::UID.sid_available?
  1066. assert(true == r || false == r)
  1067. end
  1068. def test_gid_sid_available?
  1069. r = Process::GID.sid_available?
  1070. assert(true == r || false == r)
  1071. end
  1072. def test_pst_inspect
  1073. assert_nothing_raised { Process::Status.allocate.inspect }
  1074. end
  1075. def test_wait_and_sigchild
  1076. if /freebsd|openbsd/ =~ RUBY_PLATFORM
  1077. # this relates #4173
  1078. # When ruby can use 2 cores, signal and wait4 may miss the signal.
  1079. skip "this fails on FreeBSD and OpenBSD on multithreaded environment"
  1080. end
  1081. signal_received = []
  1082. Signal.trap(:CHLD) { signal_received << true }
  1083. pid = fork { sleep 0.1; exit }
  1084. Thread.start { raise }
  1085. Process.wait pid
  1086. sleep 0.1
  1087. assert_equal [true], signal_received, " [ruby-core:19744]"
  1088. rescue NotImplementedError, ArgumentError
  1089. ensure
  1090. begin
  1091. Signal.trap(:CHLD, 'DEFAULT')
  1092. rescue ArgumentError
  1093. end
  1094. end
  1095. def test_no_curdir
  1096. with_tmpchdir {|d|
  1097. Dir.mkdir("vd")
  1098. status = nil
  1099. Dir.chdir("vd") {
  1100. dir = "#{d}/vd"
  1101. # OpenSolaris cannot remove the current directory.
  1102. system(RUBY, "--disable-gems", "-e", "Dir.chdir '..'; Dir.rmdir #{dir.dump}")
  1103. system({"RUBYLIB"=>nil}, RUBY, "--disable-gems", "-e", "exit true")
  1104. status = $?
  1105. }
  1106. assert(status.success?, "[ruby-dev:38105]")
  1107. }
  1108. end unless /mswin|bccwin|mingw/ =~ RUBY_PLATFORM
  1109. def test_fallback_to_sh
  1110. feature = '[ruby-core:32745]'
  1111. with_tmpchdir do |d|
  1112. open("tmp_script.#{$$}", "w") {|f| f.puts ": ;"; f.chmod(0755)}
  1113. assert_not_nil(pid = Process.spawn("./tmp_script.#{$$}"), feature)
  1114. wpid, st = Process.waitpid2(pid)
  1115. assert_equal([pid, true], [wpid, st.success?], feature)
  1116. open("tmp_script.#{$$}", "w") {|f| f.puts "echo $#: $@"; f.chmod(0755)}
  1117. result = IO.popen(["./tmp_script.#{$$}", "a b", "c"]) {|f| f.read}
  1118. assert_equal("2: a b c\n", result, feature)
  1119. end
  1120. end if File.executable?("/bin/sh")
  1121. def test_too_long_path
  1122. bug4314 = '[ruby-core:34842]'
  1123. exs = [Errno::ENOENT]
  1124. exs << Errno::E2BIG if defined?(Errno::E2BIG)
  1125. assert_raise(*exs, bug4314) {Process.spawn("a" * 10_000_000)}
  1126. end
  1127. def test_too_long_path2
  1128. skip
  1129. bug4315 = '[ruby-core:34833]'
  1130. exs = [Errno::ENOENT]
  1131. exs << Errno::E2BIG if defined?(Errno::E2BIG)
  1132. assert_raise(*exs, bug4315) {Process.spawn('"a"|'*10_000_000)}
  1133. end
  1134. def test_system_sigpipe
  1135. return if windows?
  1136. pid = 0
  1137. with_tmpchdir do
  1138. assert_nothing_raised('[ruby-dev:12261]') do
  1139. timeout(3) do
  1140. pid = spawn('yes | ls')
  1141. Process.waitpid pid
  1142. end
  1143. end
  1144. end
  1145. ensure
  1146. Process.kill(:KILL, pid) if (pid != 0) rescue false
  1147. end
  1148. if Process.respond_to?(:daemon)
  1149. def test_daemon_default
  1150. data = IO.popen("-", "r+") do |f|
  1151. break f.read if f
  1152. Process.daemon
  1153. puts "ng"
  1154. end
  1155. assert_equal("", data)
  1156. end
  1157. def test_daemon_noclose
  1158. data = IO.popen("-", "r+") do |f|
  1159. break f.read if f
  1160. Process.daemon(false, true)
  1161. puts "ok", Dir.pwd
  1162. end
  1163. assert_equal("ok\n/\n", data)
  1164. end
  1165. def test_daemon_nochdir_noclose
  1166. data = IO.popen("-", "r+") do |f|
  1167. break f.read if f
  1168. Process.daemon(true, true)
  1169. puts "ok", Dir.pwd
  1170. end
  1171. assert_equal("ok\n#{Dir.pwd}\n", data)
  1172. end
  1173. def test_daemon_readwrite
  1174. data = IO.popen("-", "r+") do |f|
  1175. if f
  1176. f.puts "ok?"
  1177. break f.read
  1178. end
  1179. Process.daemon(true, true)
  1180. puts STDIN.gets
  1181. end
  1182. assert_equal("ok?\n", data)
  1183. end
  1184. if File.directory?("/proc/self/task")
  1185. def test_daemon_no_threads
  1186. pid, data = IO.popen("-", "r+") do |f|
  1187. break f.pid, f.readlines if f
  1188. Process.daemon(true, true)
  1189. puts Dir.entries("/proc/self/task") - %W[. ..]
  1190. end
  1191. bug4920 = '[ruby-dev:43873]'
  1192. assert_equal(2, data.size, bug4920)
  1193. assert_not_include(data.map(&:to_i), pid)
  1194. end
  1195. end
  1196. end
  1197. def test_execopts_new_pgroup
  1198. return unless windows?
  1199. assert_nothing_raised { system(*TRUECOMMAND, :new_pgroup=>true) }
  1200. assert_nothing_raised { system(*TRUECOMMAND, :new_pgroup=>false) }
  1201. assert_nothing_raised { spawn(*TRUECOMMAND, :new_pgroup=>true) }
  1202. assert_nothing_raised { IO.popen([*TRUECOMMAND, :new_pgroup=>true]) {} }
  1203. end
  1204. end