PageRenderTime 55ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/rpython/rlib/test/test_rposix.py

https://bitbucket.org/pypy/pypy/
Python | 583 lines | 549 code | 19 blank | 15 comment | 23 complexity | aaf580a31a49d56a5346a0f8624017d5 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. from rpython.rtyper.test.test_llinterp import interpret
  2. from rpython.translator.c.test.test_genc import compile
  3. from rpython.tool.pytest.expecttest import ExpectTest
  4. from rpython.tool.udir import udir
  5. from rpython.rlib import rposix, rposix_stat, rstring
  6. import os, sys
  7. import errno
  8. import py
  9. def rposix_requires(funcname):
  10. return py.test.mark.skipif(not hasattr(rposix, funcname),
  11. reason="Requires rposix.%s()" % funcname)
  12. win_only = py.test.mark.skipif("os.name != 'nt'")
  13. class TestPosixFunction:
  14. def test_access(self):
  15. filename = str(udir.join('test_access.txt'))
  16. fd = file(filename, 'w')
  17. fd.close()
  18. for mode in os.R_OK, os.W_OK, os.X_OK, os.R_OK | os.W_OK | os.X_OK:
  19. result = rposix.access(filename, mode)
  20. assert result == os.access(filename, mode)
  21. def test_times(self):
  22. """
  23. posix.times should compile as an RPython function and should return a
  24. five-tuple giving float-representations (seconds, effectively) of the four
  25. fields from the underlying struct tms and the return value.
  26. """
  27. times = eval(compile(lambda: str(os.times()), ())())
  28. assert isinstance(times, tuple)
  29. assert len(times) == 5
  30. for value in times:
  31. assert isinstance(value, float)
  32. @py.test.mark.skipif("not hasattr(os, 'getlogin')")
  33. def test_getlogin(self):
  34. try:
  35. expected = os.getlogin()
  36. except OSError as e:
  37. py.test.skip("the underlying os.getlogin() failed: %s" % e)
  38. data = rposix.getlogin()
  39. assert data == expected
  40. @win_only
  41. def test_utimes(self):
  42. # Windows support centiseconds
  43. def f(fname, t1):
  44. os.utime(fname, (t1, t1))
  45. fname = udir.join('test_utimes.txt')
  46. fname.ensure()
  47. t1 = 1159195039.25
  48. compile(f, (str, float))(str(fname), t1)
  49. assert t1 == os.stat(str(fname)).st_mtime
  50. t1 = 5000000000.0
  51. compile(f, (str, float))(str(fname), t1)
  52. assert t1 == os.stat(str(fname)).st_mtime
  53. @win_only
  54. def test__getfullpathname(self):
  55. posix = __import__(os.name)
  56. sysdrv = os.getenv('SystemDrive', 'C:')
  57. stuff = sysdrv + 'stuff'
  58. data = rposix.getfullpathname(stuff)
  59. assert data == posix._getfullpathname(stuff)
  60. # the most intriguing failure of ntpath.py should not repeat, here:
  61. assert not data.endswith(stuff)
  62. def test_getcwd(self):
  63. assert rposix.getcwd() == os.getcwd()
  64. def test_chdir(self):
  65. def check_special_envvar():
  66. if sys.platform != 'win32':
  67. return
  68. pwd = os.getcwd()
  69. import ctypes
  70. buf = ctypes.create_string_buffer(1000)
  71. len = ctypes.windll.kernel32.GetEnvironmentVariableA('=%c:' % pwd[0], buf, 1000)
  72. if (len == 0) and "WINGDB_PYTHON" in os.environ:
  73. # the ctypes call seems not to work in the Wing debugger
  74. return
  75. assert str(buf.value).lower() == pwd.lower()
  76. # ctypes returns the drive letter in uppercase,
  77. # os.getcwd does not,
  78. # but there may be uppercase in os.getcwd path
  79. pwd = os.getcwd()
  80. try:
  81. check_special_envvar()
  82. rposix.chdir('..')
  83. assert os.getcwd() == os.path.dirname(pwd)
  84. check_special_envvar()
  85. finally:
  86. os.chdir(pwd)
  87. def test_mkdir(self):
  88. filename = str(udir.join('test_mkdir.dir'))
  89. rposix.mkdir(filename, 0777)
  90. with py.test.raises(OSError) as excinfo:
  91. rposix.mkdir(filename, 0777)
  92. assert excinfo.value.errno == errno.EEXIST
  93. if sys.platform == 'win32':
  94. assert excinfo.type is WindowsError
  95. @rposix_requires('mkdirat')
  96. def test_mkdirat(self):
  97. relpath = 'test_mkdirat.dir'
  98. filename = str(udir.join(relpath))
  99. dirfd = os.open(os.path.dirname(filename), os.O_RDONLY)
  100. try:
  101. rposix.mkdirat(relpath, 0777, dir_fd=dirfd)
  102. with py.test.raises(OSError) as excinfo:
  103. rposix.mkdirat(relpath, 0777, dir_fd=dirfd)
  104. assert excinfo.value.errno == errno.EEXIST
  105. finally:
  106. os.close(dirfd)
  107. def test_strerror(self):
  108. assert rposix.strerror(2) == os.strerror(2)
  109. def test_system(self):
  110. filename = str(udir.join('test_system.txt'))
  111. arg = '%s -c "print 1+1" > %s' % (sys.executable, filename)
  112. data = rposix.system(arg)
  113. assert data == 0
  114. assert file(filename).read().strip() == '2'
  115. os.unlink(filename)
  116. @py.test.mark.skipif("os.name != 'posix'")
  117. def test_execve(self):
  118. EXECVE_ENV = {"foo": "bar", "baz": "quux"}
  119. def run_execve(program, args=None, env=None, do_path_lookup=False):
  120. if args is None:
  121. args = [program]
  122. else:
  123. args = [program] + args
  124. if env is None:
  125. env = {}
  126. # we cannot directly call execve() because it replaces the
  127. # current process.
  128. fd_read, fd_write = os.pipe()
  129. childpid = os.fork()
  130. if childpid == 0:
  131. # in the child
  132. os.close(fd_read)
  133. os.dup2(fd_write, 1) # stdout
  134. os.close(fd_write)
  135. if do_path_lookup:
  136. os.execvp(program, args)
  137. else:
  138. rposix.execve(program, args, env)
  139. assert 0, "should not arrive here"
  140. else:
  141. # in the parent
  142. os.close(fd_write)
  143. child_stdout = []
  144. while True:
  145. data = os.read(fd_read, 4096)
  146. if not data: break # closed
  147. child_stdout.append(data)
  148. pid, status = os.waitpid(childpid, 0)
  149. os.close(fd_read)
  150. return status, ''.join(child_stdout)
  151. # Test exit status and code
  152. result, child_stdout = run_execve("/usr/bin/which", ["true"], do_path_lookup=True)
  153. result, child_stdout = run_execve(child_stdout.strip()) # /bin/true or /usr/bin/true
  154. assert os.WIFEXITED(result)
  155. assert os.WEXITSTATUS(result) == 0
  156. result, child_stdout = run_execve("/usr/bin/which", ["false"], do_path_lookup=True)
  157. result, child_stdout = run_execve(child_stdout.strip()) # /bin/false or /usr/bin/false
  158. assert os.WIFEXITED(result)
  159. assert os.WEXITSTATUS(result) == 1
  160. # Test environment
  161. result, child_stdout = run_execve("/usr/bin/env", env=EXECVE_ENV)
  162. assert os.WIFEXITED(result)
  163. assert os.WEXITSTATUS(result) == 0
  164. assert dict([line.split('=') for line in child_stdout.splitlines()]) == EXECVE_ENV
  165. # The following won't actually execute anything, so they don't need
  166. # a child process helper.
  167. # If the target does not exist, an OSError should result
  168. info = py.test.raises(
  169. OSError, rposix.execve, "this/file/is/non/existent", [], {})
  170. assert info.value.errno == errno.ENOENT
  171. # If the target is not executable, an OSError should result
  172. info = py.test.raises(
  173. OSError, rposix.execve, "/etc/passwd", [], {})
  174. assert info.value.errno == errno.EACCES
  175. def test_os_write(self):
  176. #Same as test in rpython/test/test_rbuiltin
  177. fname = str(udir.join('os_test.txt'))
  178. fd = os.open(fname, os.O_WRONLY|os.O_CREAT, 0777)
  179. assert fd >= 0
  180. rposix.write(fd, 'Hello world')
  181. os.close(fd)
  182. with open(fname) as fid:
  183. assert fid.read() == "Hello world"
  184. fd = os.open(fname, os.O_WRONLY|os.O_CREAT, 0777)
  185. os.close(fd)
  186. py.test.raises(OSError, rposix.write, fd, 'Hello world')
  187. def test_os_close(self):
  188. fname = str(udir.join('os_test.txt'))
  189. fd = os.open(fname, os.O_WRONLY|os.O_CREAT, 0777)
  190. assert fd >= 0
  191. os.write(fd, 'Hello world')
  192. rposix.close(fd)
  193. py.test.raises(OSError, rposix.close, fd)
  194. def test_os_lseek(self):
  195. fname = str(udir.join('os_test.txt'))
  196. fd = os.open(fname, os.O_RDWR|os.O_CREAT, 0777)
  197. assert fd >= 0
  198. os.write(fd, 'Hello world')
  199. rposix.lseek(fd,0,0)
  200. assert os.read(fd, 11) == 'Hello world'
  201. os.close(fd)
  202. py.test.raises(OSError, rposix.lseek, fd, 0, 0)
  203. def test_os_fsync(self):
  204. fname = str(udir.join('os_test.txt'))
  205. fd = os.open(fname, os.O_WRONLY|os.O_CREAT, 0777)
  206. assert fd >= 0
  207. os.write(fd, 'Hello world')
  208. rposix.fsync(fd)
  209. os.close(fd)
  210. fid = open(fname)
  211. assert fid.read() == 'Hello world'
  212. fid.close()
  213. py.test.raises(OSError, rposix.fsync, fd)
  214. @py.test.mark.skipif("not hasattr(os, 'fdatasync')")
  215. def test_os_fdatasync(self):
  216. fname = str(udir.join('os_test.txt'))
  217. fd = os.open(fname, os.O_WRONLY|os.O_CREAT, 0777)
  218. assert fd >= 0
  219. os.write(fd, 'Hello world')
  220. rposix.fdatasync(fd)
  221. fid = open(fname)
  222. assert fid.read() == 'Hello world'
  223. os.close(fd)
  224. py.test.raises(OSError, rposix.fdatasync, fd)
  225. def test_os_kill(self):
  226. import subprocess
  227. import signal
  228. proc = subprocess.Popen([sys.executable, "-c",
  229. "import time;"
  230. "time.sleep(10)",
  231. ],
  232. )
  233. rposix.kill(proc.pid, signal.SIGTERM)
  234. if os.name == 'nt':
  235. expected = signal.SIGTERM
  236. else:
  237. expected = -signal.SIGTERM
  238. assert proc.wait() == expected
  239. def test_isatty(self):
  240. assert rposix.isatty(-1) is False
  241. @py.test.mark.skipif("not hasattr(os, 'ttyname')")
  242. class TestOsExpect(ExpectTest):
  243. def test_ttyname(self):
  244. def f():
  245. import os
  246. from rpython.rtyper.test.test_llinterp import interpret
  247. def ll_to_string(s):
  248. return ''.join(s.chars)
  249. def f(num):
  250. try:
  251. return os.ttyname(num)
  252. except OSError:
  253. return ''
  254. assert ll_to_string(interpret(f, [0])) == f(0)
  255. assert ll_to_string(interpret(f, [338])) == ''
  256. self.run_test(f)
  257. def ll_to_string(s):
  258. return ''.join(s.chars)
  259. class UnicodeWithEncoding:
  260. is_unicode = True
  261. def __init__(self, unistr):
  262. self.unistr = unistr
  263. if sys.platform == 'win32':
  264. def as_bytes(self):
  265. from rpython.rlib.runicode import unicode_encode_mbcs
  266. res = unicode_encode_mbcs(self.unistr, len(self.unistr),
  267. "strict")
  268. return rstring.assert_str0(res)
  269. else:
  270. def as_bytes(self):
  271. from rpython.rlib.runicode import unicode_encode_utf_8
  272. res = unicode_encode_utf_8(self.unistr, len(self.unistr),
  273. "strict")
  274. return rstring.assert_str0(res)
  275. def as_unicode(self):
  276. return self.unistr
  277. class BasePosixUnicodeOrAscii:
  278. def setup_method(self, method):
  279. self.ufilename = self._get_filename()
  280. try:
  281. f = file(self.ufilename, 'w')
  282. except UnicodeEncodeError:
  283. py.test.skip("encoding not good enough")
  284. f.write("test")
  285. f.close()
  286. if sys.platform == 'win32' and isinstance(self.ufilename, str):
  287. self.path = self.ufilename
  288. self.path2 = self.ufilename + ".new"
  289. else:
  290. self.path = UnicodeWithEncoding(self.ufilename)
  291. self.path2 = UnicodeWithEncoding(self.ufilename + ".new")
  292. def _teardown_method(self, method):
  293. for path in [self.ufilename + ".new", self.ufilename]:
  294. if os.path.exists(path):
  295. os.unlink(path)
  296. def test_open(self):
  297. def f():
  298. try:
  299. fd = os.open(self.path, os.O_RDONLY, 0777)
  300. try:
  301. text = os.read(fd, 50)
  302. return text
  303. finally:
  304. os.close(fd)
  305. except OSError:
  306. return ''
  307. assert ll_to_string(interpret(f, [])) == "test"
  308. def test_stat(self):
  309. def f():
  310. return rposix_stat.stat(self.path).st_mtime
  311. if sys.platform == 'win32':
  312. # double vs. float, be satisfied with sub-millisec resolution
  313. assert abs(interpret(f, []) - os.stat(self.ufilename).st_mtime) < 1e-4
  314. else:
  315. assert interpret(f, []) == os.stat(self.ufilename).st_mtime
  316. def test_access(self):
  317. def f():
  318. return rposix.access(self.path, os.R_OK)
  319. assert interpret(f, []) == 1
  320. def test_utime(self):
  321. def f():
  322. return rposix.utime(self.path, None)
  323. interpret(f, []) # does not crash
  324. def test_chmod(self):
  325. def f():
  326. return rposix.chmod(self.path, 0777)
  327. interpret(f, []) # does not crash
  328. def test_unlink(self):
  329. def f():
  330. return rposix.unlink(self.path)
  331. interpret(f, [])
  332. assert not os.path.exists(self.ufilename)
  333. def test_rename(self):
  334. def f():
  335. return rposix.rename(self.path, self.path2)
  336. interpret(f, [])
  337. assert not os.path.exists(self.ufilename)
  338. assert os.path.exists(self.ufilename + '.new')
  339. def test_replace(self):
  340. def f():
  341. return rposix.replace(self.path, self.path2)
  342. interpret(f, [])
  343. assert not os.path.exists(self.ufilename)
  344. assert os.path.exists(self.ufilename + '.new')
  345. def test_listdir(self):
  346. udir = UnicodeWithEncoding(os.path.dirname(self.ufilename))
  347. if sys.platform == 'win32':
  348. def f():
  349. if isinstance(udir.as_unicode(), str):
  350. _udir = udir.as_unicode()
  351. _res = ', '
  352. else:
  353. _udir = udir
  354. _res = u', '
  355. return _res.join(rposix.listdir(_udir))
  356. result = interpret(f, [])
  357. assert os.path.basename(self.ufilename) in ll_to_string(result)
  358. else:
  359. def f():
  360. return ', '.join(rposix.listdir(udir))
  361. result = interpret(f, [])
  362. assert (os.path.basename(self.ufilename).encode('utf-8') in
  363. ll_to_string(result))
  364. def test_chdir(self):
  365. os.unlink(self.ufilename)
  366. def f():
  367. rposix.mkdir(self.path, 0777)
  368. rposix.chdir(self.path)
  369. curdir = os.getcwd()
  370. try:
  371. interpret(f, [])
  372. assert os.getcwdu() == os.path.realpath(self.ufilename)
  373. finally:
  374. os.chdir(curdir)
  375. def g():
  376. rposix.rmdir(self.path)
  377. try:
  378. interpret(g, [])
  379. finally:
  380. try:
  381. os.rmdir(self.ufilename)
  382. except Exception:
  383. pass
  384. @win_only
  385. def test_is_valid_fd(self):
  386. assert rposix.is_valid_fd(0) == 1
  387. fid = open(str(udir.join('validate_test.txt')), 'w')
  388. fd = fid.fileno()
  389. assert rposix.is_valid_fd(fd) == 1
  390. fid.close()
  391. assert rposix.is_valid_fd(fd) == 0
  392. def test_putenv(self):
  393. def f():
  394. rposix.putenv(self.path, self.path)
  395. rposix.unsetenv(self.path)
  396. interpret(f, []) # does not crash
  397. class TestPosixAscii(BasePosixUnicodeOrAscii):
  398. def _get_filename(self):
  399. return str(udir.join('test_open_ascii'))
  400. @rposix_requires('openat')
  401. def test_openat(self):
  402. def f(dirfd):
  403. try:
  404. fd = rposix.openat('test_open_ascii', os.O_RDONLY, 0777, dirfd)
  405. try:
  406. text = os.read(fd, 50)
  407. return text
  408. finally:
  409. os.close(fd)
  410. except OSError:
  411. return ''
  412. dirfd = os.open(os.path.dirname(self.ufilename), os.O_RDONLY)
  413. try:
  414. assert ll_to_string(interpret(f, [dirfd])) == "test"
  415. finally:
  416. os.close(dirfd)
  417. @rposix_requires('unlinkat')
  418. def test_unlinkat(self):
  419. def f(dirfd):
  420. return rposix.unlinkat('test_open_ascii', dir_fd=dirfd)
  421. dirfd = os.open(os.path.dirname(self.ufilename), os.O_RDONLY)
  422. try:
  423. interpret(f, [dirfd])
  424. finally:
  425. os.close(dirfd)
  426. assert not os.path.exists(self.ufilename)
  427. @rposix_requires('utimensat')
  428. def test_utimensat(self):
  429. def f(dirfd):
  430. return rposix.utimensat('test_open_ascii',
  431. 0, rposix.UTIME_NOW, 0, rposix.UTIME_NOW, dir_fd=dirfd)
  432. dirfd = os.open(os.path.dirname(self.ufilename), os.O_RDONLY)
  433. try:
  434. interpret(f, [dirfd]) # does not crash
  435. finally:
  436. os.close(dirfd)
  437. @rposix_requires('fchmodat')
  438. def test_fchmodat(self):
  439. def f(dirfd):
  440. return rposix.fchmodat('test_open_ascii', 0777, dirfd)
  441. dirfd = os.open(os.path.dirname(self.ufilename), os.O_RDONLY)
  442. try:
  443. interpret(f, [dirfd]) # does not crash
  444. finally:
  445. os.close(dirfd)
  446. class TestPosixUnicode(BasePosixUnicodeOrAscii):
  447. def _get_filename(self):
  448. return (unicode(udir.join('test_open')) +
  449. u'\u65e5\u672c.txt') # "Japan"
  450. class TestRegisteredFunctions:
  451. def test_dup(self):
  452. def f():
  453. os.dup(4)
  454. os.dup2(5, 6)
  455. compile(f, ())
  456. def test_open(self):
  457. def f():
  458. os.open('/tmp/t', 0, 0)
  459. os.open(u'/tmp/t', 0, 0)
  460. compile(f, ())
  461. @rposix_requires('fdlistdir')
  462. def test_fdlistdir(tmpdir):
  463. tmpdir.join('file').write('text')
  464. dirfd = os.open(str(tmpdir), os.O_RDONLY)
  465. result = rposix.fdlistdir(dirfd)
  466. # Note: fdlistdir() always closes dirfd
  467. assert result == ['file']
  468. @rposix_requires('symlinkat')
  469. def test_symlinkat(tmpdir):
  470. tmpdir.join('file').write('text')
  471. dirfd = os.open(str(tmpdir), os.O_RDONLY)
  472. try:
  473. rposix.symlinkat('file', 'link', dir_fd=dirfd)
  474. assert os.readlink(str(tmpdir.join('link'))) == 'file'
  475. finally:
  476. os.close(dirfd)
  477. @rposix_requires('renameat')
  478. def test_renameat(tmpdir):
  479. tmpdir.join('file').write('text')
  480. dirfd = os.open(str(tmpdir), os.O_RDONLY)
  481. try:
  482. rposix.renameat('file', 'file2', src_dir_fd=dirfd, dst_dir_fd=dirfd)
  483. finally:
  484. os.close(dirfd)
  485. assert tmpdir.join('file').check(exists=False)
  486. assert tmpdir.join('file2').check(exists=True)
  487. def test_set_inheritable():
  488. fd1, fd2 = os.pipe()
  489. rposix.set_inheritable(fd1, True)
  490. assert rposix.get_inheritable(fd1) == True
  491. rposix.set_inheritable(fd1, False)
  492. assert rposix.get_inheritable(fd1) == False
  493. os.close(fd1)
  494. os.close(fd2)