check.scm 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  1. ; Part of Scheme 48 1.9. See file COPYING for notices and license.
  2. ; Authors: Richard Kelsey, Jonathan Rees, Mike Sperber, Robert Ransom
  3. ; A test suite for the POSIX interface.
  4. (define-test-suite posix-core-tests)
  5. (define-test-suite disabled-posix-core-tests) ; signals
  6. ; 1. get the process ID
  7. ; 2. make a /tmp/s48-posix-test-<pid> directory
  8. ; 3. go there and make files, etc.
  9. (define initial-wd (working-directory))
  10. ; doesn't work on Mac OS X
  11. (define directory-name
  12. (string-append "/tmp/s48-posix-test-"
  13. (number->string (process-id->integer (get-process-id)))))
  14. (define-test-case file-mode-predicates posix-core-tests
  15. (let ((mode0 (file-mode set-uid owner-read group-write other-exec))
  16. (mode1 (file-mode set-uid))
  17. (mode2 (file-mode owner-read group-write))
  18. (mode3 (file-mode set-uid other-exec)))
  19. (check (file-mode? mode0))
  20. (check (not (file-mode? 'mode0)))
  21. (check (file-mode=? mode0 mode0))
  22. (check (not (file-mode=? mode0 mode1)))
  23. (check (file-mode<=? mode0 mode0))
  24. (check (not (file-mode<=? mode0 mode1)))
  25. (check (file-mode<=? mode1 mode0))
  26. (check (file-mode>=? mode0 mode0))
  27. (check (file-mode>=? mode0 mode1))
  28. (check (not (file-mode>=? mode1 mode0)))
  29. (for-each (lambda (x)
  30. (check (file-mode=? x
  31. (integer->file-mode
  32. (file-mode->integer x)))))
  33. (list mode0 mode1 mode2 mode3))))
  34. (define-test-case file-modes posix-core-tests
  35. (let ((mode0 (file-mode set-uid owner-read group-write other-exec))
  36. (mode1 (file-mode set-uid))
  37. (mode2 (file-mode owner-read group-write))
  38. (mode3 (file-mode set-uid other-exec)))
  39. (check (file-mode->integer mode0) => #o4421)
  40. (check (file-mode->integer mode1) => #o4000)
  41. (check (file-mode->integer (file-mode+)) => #o0000)
  42. (check (file-mode->integer (file-mode+ mode1)) => #o4000)
  43. (check (file-mode->integer (file-mode+ mode1 mode2 mode3)) => #o4421)
  44. (check (file-mode->integer (file-mode- mode0 mode3)) => #o0420)
  45. (check (file-mode->integer (file-mode other-exec)) => 1)
  46. (check (file-mode->integer (file-mode other-write)) => 2)
  47. (check (file-mode->integer (file-mode other-read)) => 4)
  48. (check (file-mode->integer (file-mode group-exec)) => 8)
  49. (check (file-mode->integer (file-mode group-write)) => 16)
  50. (check (file-mode->integer (file-mode group-read)) => 32)
  51. (check (file-mode->integer (file-mode owner-exec)) => 64)
  52. (check (file-mode->integer (file-mode owner-write)) => 128)
  53. (check (file-mode->integer (file-mode owner-read)) => 256)
  54. (check (file-mode->integer (file-mode set-gid)) => 1024)
  55. (check (file-mode->integer (file-mode set-uid)) => 2048)
  56. (check (file-mode->integer (file-mode other)) => 7)
  57. (check (file-mode->integer (file-mode group)) => 56)
  58. (check (file-mode->integer (file-mode owner)) => 448)
  59. (check (file-mode->integer (file-mode exec)) => 73)
  60. (check (file-mode->integer (file-mode write)) => 146)
  61. (check (file-mode->integer (file-mode read)) => 292)
  62. (check (file-mode->integer (file-mode all)) => 511)))
  63. (define-test-case make-directory posix-core-tests
  64. (check (begin
  65. (make-directory directory-name (integer->file-mode #o700))
  66. (file-info-type (get-file-info directory-name)))
  67. => (file-type directory)))
  68. (define-test-case time posix-core-tests
  69. (sleep 3000) ; three seconds
  70. (let ((now (current-time))
  71. (dir-time (file-info-last-modification
  72. (get-file-info directory-name))))
  73. (check (time? now))
  74. (check (time? dir-time))
  75. (check (not (time? 'now)))
  76. (check (not (time? 20)))
  77. (check (time=? now now))
  78. (check (not (time=? now dir-time)))
  79. (check (not (time=? dir-time now)))
  80. (check (time=? dir-time dir-time))
  81. (check (not (time<? now now)))
  82. (check (not (time<? now dir-time)))
  83. (check (time<? dir-time now))
  84. (check (not (time<? dir-time dir-time)))
  85. (check (not (time>? now now)))
  86. (check (time>? now dir-time))
  87. (check (not (time>? dir-time now)))
  88. (check (not (time>? dir-time dir-time)))
  89. (check (time<=? now now))
  90. (check (not (time<=? now dir-time)))
  91. (check (time<=? dir-time now))
  92. (check (time<=? dir-time dir-time))
  93. (check (time>=? now now))
  94. (check (time>=? now dir-time))
  95. (check (not (time>=? dir-time now)))
  96. (check (time>=? dir-time dir-time))
  97. (check (time-seconds now) => (time-seconds now))
  98. (check (not (= (time-seconds now) (time-seconds dir-time))))
  99. (check (time=? now (make-time (time-seconds now))))
  100. (check (not (time=? now (make-time (time-seconds dir-time)))))
  101. (check (not (time=? dir-time (make-time (time-seconds now)))))
  102. (check (time=? dir-time (make-time (time-seconds dir-time))))
  103. (check (string? (time->string now)))))
  104. (define-test-case set-working-directory! posix-core-tests
  105. (set-working-directory! directory-name)
  106. ;; On Mac OS X, /tmp is soft-linked to /private/tmp
  107. (let ((normalized-wd (os-string->string (working-directory))))
  108. (set-working-directory! normalized-wd)
  109. (check (os-string->string (working-directory)) => normalized-wd)))
  110. (define-test-case i/o-flags posix-core-tests
  111. (let* ((out (open-file "file0"
  112. (file-options create write-only)
  113. (integer->file-mode #o700)))
  114. (flags (i/o-flags out)))
  115. (display "123456" out)
  116. (newline out)
  117. (close-output-port out)
  118. (check (not (file-options-on? flags (file-options append))))
  119. (check (not (file-options-on? flags (file-options synchronized-data))))
  120. (check (file-options-on? flags (file-options nonblocking)))
  121. (check (not (file-options-on? flags (file-options synchronized-read))))
  122. (check (not (file-options-on? flags (file-options synchronized))))
  123. (check (not (file-options-on? flags (file-options read-only))))
  124. (check (not (file-options-on? flags (file-options read-write))))
  125. (check (file-options-on? flags (file-options write-only)))))
  126. (define-test-case append-mode posix-core-tests
  127. (let* ((old-size (file-info-size (get-file-info "file0")))
  128. (out (open-file "file0"
  129. (file-options append write-only))))
  130. (display "123456" out)
  131. (newline out)
  132. (close-output-port out)
  133. (check old-size => 7)
  134. (check (file-info-size (get-file-info "file0")) => 14)))
  135. (define-test-case file-times posix-core-tests
  136. (let ((old-info (get-file-info "file0")))
  137. (sleep 3000) ; three seconds
  138. (let ((in (open-file "file0"
  139. (file-options read-only))))
  140. (read-char in)
  141. (close-input-port in))
  142. (let ((new-info (get-file-info "file0")))
  143. (check-that (file-info-last-modification old-info)
  144. (is time=? (file-info-last-modification new-info)))
  145. ;; On Linux, file-systems may be mounted using the "noatime"
  146. ;; option. That is, just reading the file does not necessarily
  147. ;; update the access time. Hence, we use TIME<=? instead of
  148. ;; TIME<? (which makes this test less useful).
  149. (check-that (file-info-last-access old-info)
  150. (is time<=? (file-info-last-access new-info))))))
  151. (define-test-case link posix-core-tests
  152. (let ((old-link-count (file-info-link-count (get-file-info "file0"))))
  153. (link "file0" "link-to-file0")
  154. (check old-link-count => 1)
  155. (check (file-info-link-count (get-file-info "file0")) => 2)))
  156. (define-test-case rename posix-core-tests
  157. (let ((inode (file-info-inode (get-file-info "file0"))))
  158. (rename "file0" "file1")
  159. (check (file-info-inode (get-file-info "file1"))
  160. => inode)))
  161. (define-test-case listings0 posix-core-tests
  162. (let ((directory (open-directory-stream directory-name)))
  163. (let loop ((names '()))
  164. (let ((next (read-directory-stream directory)))
  165. (if next
  166. (loop (cons next names))
  167. (begin
  168. (close-directory-stream directory)
  169. (check
  170. (sort-list (map os-string->string names) string<=?)
  171. => '("file1" "link-to-file0"))))))))
  172. (define-test-case listings1 posix-core-tests
  173. (check (sort-list (map os-string->string (list-directory ".")) string<=?)
  174. => '("file1" "link-to-file0")))
  175. (define-test-case unlink posix-core-tests
  176. (unlink "link-to-file0")
  177. (check (file-info-link-count (get-file-info "file1")) => 1))
  178. (define-test-case umask posix-core-tests
  179. (let* ((old-mask (set-file-creation-mask! (integer->file-mode #o012)))
  180. (out (open-file "umask-file"
  181. (file-options create write-only)
  182. (integer->file-mode #o777))))
  183. (display "123456" out)
  184. (newline out)
  185. (close-output-port out)
  186. (let* ((my-mask (set-file-creation-mask! old-mask))
  187. (file-mode (file-info-mode (get-file-info "umask-file"))))
  188. (check (file-mode->integer my-mask) => #o012)
  189. (check (file-mode->integer file-mode) => #o765))))
  190. ; This assumes that we are not running as root and that / is owned by root.
  191. (define-test-case users&groups posix-core-tests
  192. (let ((my-info (get-file-info directory-name))
  193. (root-info (get-file-info "/")))
  194. (let ((my-user (user-id->user-info (file-info-owner my-info)))
  195. (root-user (user-id->user-info (file-info-owner root-info)))
  196. (my-group (group-id->group-info (file-info-group my-info)))
  197. (root-group (group-id->group-info (file-info-group root-info))))
  198. (let ((my-other-user (name->user-info (user-info-name my-user)))
  199. (my-other-group (name->group-info (group-info-name my-group))))
  200. (check-that (file-info-owner my-info)
  201. (is user-id=? (user-info-id my-user)))
  202. (check-that (file-info-owner root-info)
  203. (opposite (is user-id=? (user-info-id my-user))))
  204. (check-that (file-info-group my-info)
  205. (is group-id=? (group-info-id my-group)))
  206. ;; doesn't work reliably
  207. ;; (specifically, if the user is member of wheel)
  208. ;; (check (not (group-id=? (file-info-group root-info)
  209. ;; (group-info-id my-group))))
  210. (check-that (os-string->string (user-info-name root-user))
  211. (member-of '("root"
  212. "bin" ; AIX
  213. )))))))
  214. (define-test-case environment posix-core-tests
  215. (let ((env (reverse (environment-alist))))
  216. (if (not (null? env))
  217. (check-that (lookup-environment-variable->string (caar env))
  218. (is (os-string->string (cdar env)))))
  219. (for-each (lambda (x)
  220. (check-that x (is pair?))
  221. (check-that (car x) (is os-string?))
  222. (check-that (cdr x) (is os-string?)))
  223. env))
  224. (check-that (lookup-environment-variable->string "=") (is-false)))
  225. (define-test-case symlinks posix-core-tests
  226. (let ((name (string-append directory-name "/blabla")))
  227. (create-symbolic-link "foo" name)
  228. (check (os-string->string (read-symbolic-link name)) => "foo")
  229. (unlink name)))
  230. ; This assumes that no other process will send us SIGUSR1 or SIGUSR2.
  231. ; TODO - move to utility package
  232. (define-syntax if-let
  233. (syntax-rules ()
  234. ((if-let var test true-expr false-expr)
  235. (let ((var test)) (if var true-expr false-expr)))
  236. ((if-let var test true-expr)
  237. (let ((var test)) (if var true-expr)))))
  238. (define-syntax spawn-named
  239. (syntax-rules ()
  240. ((spawn-named thunk-name)
  241. (spawn thunk-name 'thunk-name))))
  242. (define-test-case signals disabled-posix-core-tests
  243. (let* ((sigusr1 (signal usr1))
  244. (sigusr2 (signal usr2))
  245. (sigq (make-signal-queue (list sigusr1 sigusr2)))
  246. (me (get-process-id))
  247. (sigs-caught-queue (make-queue))
  248. (sigs-caught-lists-ph (make-placeholder)))
  249. (define (send-signal! sig)
  250. (signal-process me sig)
  251. ; FIXME - make the VM check for and handle all interrupts here
  252. (sleep 100)
  253. (let loop ((sigs-caught-rev '()))
  254. (if-let maybe-sig (maybe-dequeue! sigs-caught-queue)
  255. (loop (cons maybe-sig sigs-caught-rev))
  256. (reverse sigs-caught-rev))))
  257. (define (send-signals!)
  258. (placeholder-set! sigs-caught-lists-ph
  259. (map send-signal!
  260. (list sigusr1
  261. sigusr2
  262. sigusr1
  263. sigusr2
  264. sigusr1))))
  265. (define (catch-signals!)
  266. (let loop ()
  267. (let ((sig (dequeue-signal! sigq)))
  268. (enqueue! sigs-caught-queue sig))
  269. (loop)))
  270. (define (signal-list=? l1 l2)
  271. (srfi-1:list= signal=? l1 l2))
  272. (define (signal-list-list=? l1 l2)
  273. (srfi-1:list= signal-list=? l1 l2))
  274. (let* ((catch-thread (spawn-named catch-signals!))
  275. (send-thread (spawn-named send-signals!))
  276. (signals-received (placeholder-value sigs-caught-lists-ph))) ;blocks
  277. (check-that signals-received
  278. (is signal-list-list=? (list (list sigusr1)
  279. (list sigusr2)
  280. (list sigusr1)
  281. (list sigusr2)
  282. (list sigusr1))))
  283. (terminate-thread! catch-thread))))
  284. (define (fork-spawn thunk)
  285. (or (fork)
  286. (begin (thunk)
  287. (exit 0))))
  288. (define-syntax fork-and-run
  289. (syntax-rules ()
  290. ((fork-and-run body ...)
  291. (fork-spawn (lambda () body ...)))))
  292. (define-test-case wait-for-child-process posix-core-tests
  293. (let* ((n-waiters 50)
  294. (waiter-results (make-vector n-waiters #f))
  295. (child-pid (fork-and-run (sleep 5000)))
  296. (waiter-threads
  297. (map (lambda (i)
  298. (spawn (lambda ()
  299. (wait-for-child-process child-pid)
  300. (vector-set! waiter-results i #t))))
  301. (srfi-1:iota n-waiters))))
  302. (sleep 10000)
  303. (check waiter-results => (make-vector n-waiters #t))))
  304. ; This should be last, because it removes the directory.
  305. (define-test-case rmdir posix-core-tests
  306. (let ((before (accessible? directory-name (access-mode exists))))
  307. (for-each unlink (list-directory "."))
  308. (set-working-directory! initial-wd)
  309. (remove-directory directory-name)
  310. (check before)
  311. (check (not (accessible? directory-name (access-mode exists))))))