store.scm 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995
  1. ;;; GNU Guix --- Functional package management for GNU
  2. ;;; Copyright © 2012, 2013, 2014, 2015, 2016, 2017 Ludovic Courtès <ludo@gnu.org>
  3. ;;;
  4. ;;; This file is part of GNU Guix.
  5. ;;;
  6. ;;; GNU Guix is free software; you can redistribute it and/or modify it
  7. ;;; under the terms of the GNU General Public License as published by
  8. ;;; the Free Software Foundation; either version 3 of the License, or (at
  9. ;;; your option) any later version.
  10. ;;;
  11. ;;; GNU Guix is distributed in the hope that it will be useful, but
  12. ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
  13. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. ;;; GNU General Public License for more details.
  15. ;;;
  16. ;;; You should have received a copy of the GNU General Public License
  17. ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
  18. (define-module (test-store)
  19. #:use-module (guix tests)
  20. #:use-module (guix store)
  21. #:use-module (guix utils)
  22. #:use-module (guix monads)
  23. #:use-module (guix hash)
  24. #:use-module (guix base32)
  25. #:use-module (guix packages)
  26. #:use-module (guix derivations)
  27. #:use-module (guix serialization)
  28. #:use-module (guix build utils)
  29. #:use-module (guix gexp)
  30. #:use-module (gnu packages)
  31. #:use-module (gnu packages bootstrap)
  32. #:use-module (ice-9 match)
  33. #:use-module (rnrs bytevectors)
  34. #:use-module (rnrs io ports)
  35. #:use-module (web uri)
  36. #:use-module (srfi srfi-1)
  37. #:use-module (srfi srfi-11)
  38. #:use-module (srfi srfi-26)
  39. #:use-module (srfi srfi-34)
  40. #:use-module (srfi srfi-64))
  41. ;; Test the (guix store) module.
  42. (define %store
  43. (open-connection-for-tests))
  44. (test-begin "store")
  45. (test-assert "open-connection with file:// URI"
  46. (let ((store (open-connection (string-append "file://"
  47. (%daemon-socket-uri)))))
  48. (and (add-text-to-store store "foo" "bar")
  49. (begin
  50. (close-connection store)
  51. #t))))
  52. (test-equal "connection handshake error"
  53. EPROTO
  54. (let ((port (%make-void-port "rw")))
  55. (guard (c ((nix-connection-error? c)
  56. (and (eq? port (nix-connection-error-file c))
  57. (nix-connection-error-code c))))
  58. (open-connection #f #:port port)
  59. 'broken)))
  60. (test-equal "store-path-hash-part"
  61. "283gqy39v3g9dxjy26rynl0zls82fmcg"
  62. (store-path-hash-part
  63. (string-append (%store-prefix)
  64. "/283gqy39v3g9dxjy26rynl0zls82fmcg-guile-2.0.7")))
  65. (test-equal "store-path-hash-part #f"
  66. #f
  67. (store-path-hash-part
  68. (string-append (%store-prefix)
  69. "/foo/bar/283gqy39v3g9dxjy26rynl0zls82fmcg-guile-2.0.7")))
  70. (test-equal "store-path-package-name"
  71. "guile-2.0.7"
  72. (store-path-package-name
  73. (string-append (%store-prefix)
  74. "/283gqy39v3g9dxjy26rynl0zls82fmcg-guile-2.0.7")))
  75. (test-equal "store-path-package-name #f"
  76. #f
  77. (store-path-package-name
  78. "/foo/bar/283gqy39v3g9dxjy26rynl0zls82fmcg-guile-2.0.7"))
  79. (test-assert "direct-store-path?"
  80. (and (direct-store-path?
  81. (string-append (%store-prefix)
  82. "/283gqy39v3g9dxjy26rynl0zls82fmcg-guile-2.0.7"))
  83. (not (direct-store-path?
  84. (string-append
  85. (%store-prefix)
  86. "/283gqy39v3g9dxjy26rynl0zls82fmcg-guile-2.0.7/bin/guile")))
  87. (not (direct-store-path? (%store-prefix)))))
  88. (test-skip (if %store 0 13))
  89. (test-equal "add-data-to-store"
  90. #vu8(1 2 3 4 5)
  91. (call-with-input-file (add-data-to-store %store "data" #vu8(1 2 3 4 5))
  92. get-bytevector-all))
  93. (test-assert "valid-path? live"
  94. (let ((p (add-text-to-store %store "hello" "hello, world")))
  95. (valid-path? %store p)))
  96. (test-assert "valid-path? false"
  97. (not (valid-path? %store
  98. (string-append (%store-prefix) "/"
  99. (make-string 32 #\e) "-foobar"))))
  100. (test-assert "valid-path? error"
  101. (with-store s
  102. (guard (c ((nix-protocol-error? c) #t))
  103. (valid-path? s "foo")
  104. #f)))
  105. (test-assert "valid-path? recovery"
  106. ;; Prior to Nix commit 51800e0 (18 Mar. 2014), the daemon would immediately
  107. ;; close the connection after receiving a 'valid-path?' RPC with a non-store
  108. ;; file name. See
  109. ;; <http://article.gmane.org/gmane.linux.distributions.nixos/12411> for
  110. ;; details.
  111. (with-store s
  112. (let-syntax ((true-if-error (syntax-rules ()
  113. ((_ exp)
  114. (guard (c ((nix-protocol-error? c) #t))
  115. exp #f)))))
  116. (and (true-if-error (valid-path? s "foo"))
  117. (true-if-error (valid-path? s "bar"))
  118. (true-if-error (valid-path? s "baz"))
  119. (true-if-error (valid-path? s "chbouib"))
  120. (valid-path? s (add-text-to-store s "valid" "yeah"))))))
  121. (test-assert "hash-part->path"
  122. (let ((p (add-text-to-store %store "hello" "hello, world")))
  123. (equal? (hash-part->path %store (store-path-hash-part p))
  124. p)))
  125. (test-assert "dead-paths"
  126. (let ((p (add-text-to-store %store "random-text" (random-text))))
  127. (->bool (member p (dead-paths %store)))))
  128. ;; FIXME: Find a test for `live-paths'.
  129. ;;
  130. ;; (test-assert "temporary root is in live-paths"
  131. ;; (let* ((p1 (add-text-to-store %store "random-text"
  132. ;; (random-text) '()))
  133. ;; (b (add-text-to-store %store "link-builder"
  134. ;; (format #f "echo ~a > $out" p1)
  135. ;; '()))
  136. ;; (d1 (derivation %store "link"
  137. ;; "/bin/sh" `("-e" ,b)
  138. ;; #:inputs `((,b) (,p1))))
  139. ;; (p2 (derivation->output-path d1)))
  140. ;; (and (add-temp-root %store p2)
  141. ;; (build-derivations %store (list d1))
  142. ;; (valid-path? %store p1)
  143. ;; (member (pk p2) (live-paths %store)))))
  144. (test-assert "permanent root"
  145. (let* ((p (with-store store
  146. (let ((p (add-text-to-store store "random-text"
  147. (random-text))))
  148. (add-permanent-root p)
  149. (add-permanent-root p) ; should not throw
  150. p))))
  151. (and (member p (live-paths %store))
  152. (begin
  153. (remove-permanent-root p)
  154. (->bool (member p (dead-paths %store)))))))
  155. (test-assert "dead path can be explicitly collected"
  156. (let ((p (add-text-to-store %store "random-text"
  157. (random-text) '())))
  158. (let-values (((paths freed) (delete-paths %store (list p))))
  159. (and (equal? paths (list p))
  160. ;; XXX: On some file systems (notably Btrfs), freed
  161. ;; may return 0. See <https://bugs.gnu.org/29363>.
  162. ;;(> freed 0)
  163. (not (file-exists? p))))))
  164. (test-assert "add-text-to-store vs. delete-paths"
  165. ;; Before, 'add-text-to-store' would return PATH2 without noticing that it
  166. ;; is no longer valid.
  167. (with-store store
  168. (let* ((text (random-text))
  169. (path (add-text-to-store store "delete-me" text))
  170. (deleted (delete-paths store (list path)))
  171. (path2 (add-text-to-store store "delete-me" text)))
  172. (and (string=? path path2)
  173. (equal? deleted (list path))
  174. (valid-path? store path)
  175. (file-exists? path)))))
  176. (test-assert "add-to-store vs. delete-paths"
  177. ;; Same as above.
  178. (with-store store
  179. (let* ((file (search-path %load-path "guix.scm"))
  180. (path (add-to-store store "delete-me" #t "sha256" file))
  181. (deleted (delete-paths store (list path)))
  182. (path2 (add-to-store store "delete-me" #t "sha256" file)))
  183. (and (string=? path path2)
  184. (equal? deleted (list path))
  185. (valid-path? store path)
  186. (file-exists? path)))))
  187. (test-assert "references"
  188. (let* ((t1 (add-text-to-store %store "random1"
  189. (random-text)))
  190. (t2 (add-text-to-store %store "random2"
  191. (random-text) (list t1))))
  192. (and (equal? (list t1) (references %store t2))
  193. (equal? (list t2) (referrers %store t1))
  194. (null? (references %store t1))
  195. (null? (referrers %store t2)))))
  196. (test-assert "references/substitutes missing reference info"
  197. (with-store s
  198. (set-build-options s #:use-substitutes? #f)
  199. (guard (c ((nix-protocol-error? c) #t))
  200. (let* ((b (add-to-store s "bash" #t "sha256"
  201. (search-bootstrap-binary "bash"
  202. (%current-system))))
  203. (d (derivation s "the-thing" b '("--help")
  204. #:inputs `((,b)))))
  205. (references/substitutes s (list (derivation->output-path d) b))
  206. #f))))
  207. (test-assert "references/substitutes with substitute info"
  208. (with-store s
  209. (set-build-options s #:use-substitutes? #t)
  210. (let* ((t1 (add-text-to-store s "random1" (random-text)))
  211. (t2 (add-text-to-store s "random2" (random-text)
  212. (list t1)))
  213. (t3 (add-text-to-store s "build" "echo -n $t2 > $out"))
  214. (b (add-to-store s "bash" #t "sha256"
  215. (search-bootstrap-binary "bash"
  216. (%current-system))))
  217. (d (derivation s "the-thing" b `("-e" ,t3)
  218. #:inputs `((,b) (,t3) (,t2))
  219. #:env-vars `(("t2" . ,t2))))
  220. (o (derivation->output-path d)))
  221. (with-derivation-narinfo d
  222. (sha256 => (sha256 (string->utf8 t2)))
  223. (references => (list t2))
  224. (equal? (references/substitutes s (list o t3 t2 t1))
  225. `((,t2) ;refs of O
  226. () ;refs of T3
  227. (,t1) ;refs of T2
  228. ())))))) ;refs of T1
  229. (test-equal "substitutable-path-info when substitutes are turned off"
  230. '()
  231. (with-store s
  232. (set-build-options s #:use-substitutes? #f)
  233. (let* ((b (add-to-store s "bash" #t "sha256"
  234. (search-bootstrap-binary "bash"
  235. (%current-system))))
  236. (d (derivation s "the-thing" b '("--version")
  237. #:inputs `((,b))))
  238. (o (derivation->output-path d)))
  239. (with-derivation-narinfo d
  240. (substitutable-path-info s (list o))))))
  241. (test-equal "substitutable-paths when substitutes are turned off"
  242. '()
  243. (with-store s
  244. (set-build-options s #:use-substitutes? #f)
  245. (let* ((b (add-to-store s "bash" #t "sha256"
  246. (search-bootstrap-binary "bash"
  247. (%current-system))))
  248. (d (derivation s "the-thing" b '("--version")
  249. #:inputs `((,b))))
  250. (o (derivation->output-path d)))
  251. (with-derivation-narinfo d
  252. (substitutable-paths s (list o))))))
  253. (test-assert "requisites"
  254. (let* ((t1 (add-text-to-store %store "random1"
  255. (random-text) '()))
  256. (t2 (add-text-to-store %store "random2"
  257. (random-text) (list t1)))
  258. (t3 (add-text-to-store %store "random3"
  259. (random-text) (list t2)))
  260. (t4 (add-text-to-store %store "random4"
  261. (random-text) (list t1 t3))))
  262. (define (same? x y)
  263. (and (= (length x) (length y))
  264. (lset= equal? x y)))
  265. (and (same? (requisites %store (list t1)) (list t1))
  266. (same? (requisites %store (list t2)) (list t1 t2))
  267. (same? (requisites %store (list t3)) (list t1 t2 t3))
  268. (same? (requisites %store (list t4)) (list t1 t2 t3 t4))
  269. (same? (requisites %store (list t1 t2 t3 t4))
  270. (list t1 t2 t3 t4)))))
  271. (test-assert "derivers"
  272. (let* ((b (add-text-to-store %store "build" "echo $foo > $out" '()))
  273. (s (add-to-store %store "bash" #t "sha256"
  274. (search-bootstrap-binary "bash"
  275. (%current-system))))
  276. (d (derivation %store "the-thing"
  277. s `("-e" ,b)
  278. #:env-vars `(("foo" . ,(random-text)))
  279. #:inputs `((,b) (,s))))
  280. (o (derivation->output-path d)))
  281. (and (build-derivations %store (list d))
  282. (equal? (query-derivation-outputs %store (derivation-file-name d))
  283. (list o))
  284. (equal? (valid-derivers %store o)
  285. (list (derivation-file-name d))))))
  286. (test-assert "topologically-sorted, one item"
  287. (let* ((a (add-text-to-store %store "a" "a"))
  288. (b (add-text-to-store %store "b" "b" (list a)))
  289. (c (add-text-to-store %store "c" "c" (list b)))
  290. (d (add-text-to-store %store "d" "d" (list c)))
  291. (s (topologically-sorted %store (list d))))
  292. (equal? s (list a b c d))))
  293. (test-assert "topologically-sorted, several items"
  294. (let* ((a (add-text-to-store %store "a" "a"))
  295. (b (add-text-to-store %store "b" "b" (list a)))
  296. (c (add-text-to-store %store "c" "c" (list b)))
  297. (d (add-text-to-store %store "d" "d" (list c)))
  298. (s1 (topologically-sorted %store (list d a c b)))
  299. (s2 (topologically-sorted %store (list b d c a b d))))
  300. (equal? s1 s2 (list a b c d))))
  301. (test-assert "topologically-sorted, more difficult"
  302. (let* ((a (add-text-to-store %store "a" "a"))
  303. (b (add-text-to-store %store "b" "b" (list a)))
  304. (c (add-text-to-store %store "c" "c" (list b)))
  305. (d (add-text-to-store %store "d" "d" (list c)))
  306. (w (add-text-to-store %store "w" "w"))
  307. (x (add-text-to-store %store "x" "x" (list w)))
  308. (y (add-text-to-store %store "y" "y" (list x d)))
  309. (s1 (topologically-sorted %store (list y)))
  310. (s2 (topologically-sorted %store (list c y)))
  311. (s3 (topologically-sorted %store (cons y (references %store y)))))
  312. ;; The order in which 'references' returns the references of Y is
  313. ;; unspecified, so accommodate.
  314. (let* ((x-then-d? (equal? (references %store y) (list x d))))
  315. (and (equal? s1
  316. (if x-then-d?
  317. (list w x a b c d y)
  318. (list a b c d w x y)))
  319. (equal? s2
  320. (if x-then-d?
  321. (list a b c w x d y)
  322. (list a b c d w x y)))
  323. (lset= string=? s1 s3)))))
  324. (test-assert "current-build-output-port, UTF-8"
  325. ;; Are UTF-8 strings in the build log properly interpreted?
  326. (string-contains
  327. (with-fluids ((%default-port-encoding "UTF-8")) ;for the string port
  328. (call-with-output-string
  329. (lambda (port)
  330. (parameterize ((current-build-output-port port))
  331. (let* ((s "Here’s a Greek letter: λ.")
  332. (d (build-expression->derivation
  333. %store "foo" `(display ,s)
  334. #:guile-for-build
  335. (package-derivation s %bootstrap-guile (%current-system)))))
  336. (guard (c ((nix-protocol-error? c) #t))
  337. (build-derivations %store (list d))))))))
  338. "Here’s a Greek letter: λ."))
  339. (test-assert "current-build-output-port, UTF-8 + garbage"
  340. ;; What about a mixture of UTF-8 + garbage?
  341. (string-contains
  342. (with-fluids ((%default-port-encoding "UTF-8")) ;for the string port
  343. (call-with-output-string
  344. (lambda (port)
  345. (parameterize ((current-build-output-port port))
  346. (let ((d (build-expression->derivation
  347. %store "foo"
  348. `(begin
  349. (use-modules (rnrs io ports))
  350. (display "garbage: ")
  351. (put-bytevector (current-output-port) #vu8(128))
  352. (display "lambda: λ\n"))
  353. #:guile-for-build
  354. (package-derivation %store %bootstrap-guile))))
  355. (guard (c ((nix-protocol-error? c) #t))
  356. (build-derivations %store (list d))))))))
  357. (cond-expand
  358. (guile-2.2 "garbage: �lambda: λ")
  359. (else "garbage: ?lambda: λ"))))
  360. (test-assert "log-file, derivation"
  361. (let* ((b (add-text-to-store %store "build" "echo $foo > $out" '()))
  362. (s (add-to-store %store "bash" #t "sha256"
  363. (search-bootstrap-binary "bash"
  364. (%current-system))))
  365. (d (derivation %store "the-thing"
  366. s `("-e" ,b)
  367. #:env-vars `(("foo" . ,(random-text)))
  368. #:inputs `((,b) (,s)))))
  369. (and (build-derivations %store (list d))
  370. (file-exists? (pk (log-file %store (derivation-file-name d)))))))
  371. (test-assert "log-file, output file name"
  372. (let* ((b (add-text-to-store %store "build" "echo $foo > $out" '()))
  373. (s (add-to-store %store "bash" #t "sha256"
  374. (search-bootstrap-binary "bash"
  375. (%current-system))))
  376. (d (derivation %store "the-thing"
  377. s `("-e" ,b)
  378. #:env-vars `(("foo" . ,(random-text)))
  379. #:inputs `((,b) (,s))))
  380. (o (derivation->output-path d)))
  381. (and (build-derivations %store (list d))
  382. (file-exists? (pk (log-file %store o)))
  383. (string=? (log-file %store (derivation-file-name d))
  384. (log-file %store o)))))
  385. (test-assert "no substitutes"
  386. (with-store s
  387. (let* ((d1 (package-derivation s %bootstrap-guile (%current-system)))
  388. (d2 (package-derivation s %bootstrap-glibc (%current-system)))
  389. (o (map derivation->output-path (list d1 d2))))
  390. (set-build-options s #:use-substitutes? #f)
  391. (and (not (has-substitutes? s (derivation-file-name d1)))
  392. (not (has-substitutes? s (derivation-file-name d2)))
  393. (null? (substitutable-paths s o))
  394. (null? (substitutable-path-info s o))))))
  395. (test-assert "build-things with output path"
  396. (with-store s
  397. (let* ((c (random-text)) ;contents of the output
  398. (d (build-expression->derivation
  399. s "substitute-me"
  400. `(call-with-output-file %output
  401. (lambda (p)
  402. (display ,c p)))
  403. #:guile-for-build
  404. (package-derivation s %bootstrap-guile (%current-system))))
  405. (o (derivation->output-path d)))
  406. (set-build-options s #:use-substitutes? #f)
  407. ;; Pass 'build-things' the output file name, O. However, since there
  408. ;; are no substitutes for O, it will just do nothing.
  409. (build-things s (list o))
  410. (not (valid-path? s o)))))
  411. (test-skip (if (getenv "GUIX_BINARY_SUBSTITUTE_URL") 0 1))
  412. (test-assert "substitute query"
  413. (with-store s
  414. (let* ((d (package-derivation s %bootstrap-guile (%current-system)))
  415. (o (derivation->output-path d)))
  416. ;; Create fake substituter data, to be read by 'guix substitute'.
  417. (with-derivation-narinfo d
  418. ;; Remove entry from the local cache.
  419. (false-if-exception
  420. (delete-file-recursively (string-append (getenv "XDG_CACHE_HOME")
  421. "/guix/substitute")))
  422. ;; Make sure 'guix substitute' correctly communicates the above
  423. ;; data.
  424. (set-build-options s #:use-substitutes? #t
  425. #:substitute-urls (%test-substitute-urls))
  426. (and (has-substitutes? s o)
  427. (equal? (list o) (substitutable-paths s (list o)))
  428. (match (pk 'spi (substitutable-path-info s (list o)))
  429. (((? substitutable? s))
  430. (and (string=? (substitutable-deriver s)
  431. (derivation-file-name d))
  432. (null? (substitutable-references s))
  433. (equal? (substitutable-nar-size s) 1234)))))))))
  434. (test-assert "substitute query, alternating URLs"
  435. (let* ((d (with-store s
  436. (package-derivation s %bootstrap-guile (%current-system))))
  437. (o (derivation->output-path d)))
  438. (with-derivation-narinfo d
  439. ;; Remove entry from the local cache.
  440. (false-if-exception
  441. (delete-file-recursively (string-append (getenv "XDG_CACHE_HOME")
  442. "/guix/substitute")))
  443. ;; Note: We reconnect to the daemon to force a new instance of 'guix
  444. ;; substitute' to be used; otherwise the #:substitute-urls of
  445. ;; 'set-build-options' would have no effect.
  446. (and (with-store s ;the right substitute URL
  447. (set-build-options s #:use-substitutes? #t
  448. #:substitute-urls (%test-substitute-urls))
  449. (has-substitutes? s o))
  450. (with-store s ;the wrong one
  451. (set-build-options s #:use-substitutes? #t
  452. #:substitute-urls (list
  453. "http://does-not-exist"))
  454. (not (has-substitutes? s o)))
  455. (with-store s ;the right one again
  456. (set-build-options s #:use-substitutes? #t
  457. #:substitute-urls (%test-substitute-urls))
  458. (has-substitutes? s o))
  459. (with-store s ;empty list of URLs
  460. (set-build-options s #:use-substitutes? #t
  461. #:substitute-urls '())
  462. (not (has-substitutes? s o)))))))
  463. (test-assert "substitute"
  464. (with-store s
  465. (let* ((c (random-text)) ; contents of the output
  466. (d (build-expression->derivation
  467. s "substitute-me"
  468. `(call-with-output-file %output
  469. (lambda (p)
  470. (exit 1) ; would actually fail
  471. (display ,c p)))
  472. #:guile-for-build
  473. (package-derivation s %bootstrap-guile (%current-system))))
  474. (o (derivation->output-path d)))
  475. (with-derivation-substitute d c
  476. (set-build-options s #:use-substitutes? #t
  477. #:substitute-urls (%test-substitute-urls))
  478. (and (has-substitutes? s o)
  479. (build-derivations s (list d))
  480. (equal? c (call-with-input-file o get-string-all)))))))
  481. (test-assert "substitute + build-things with output path"
  482. (with-store s
  483. (let* ((c (random-text)) ;contents of the output
  484. (d (build-expression->derivation
  485. s "substitute-me"
  486. `(call-with-output-file %output
  487. (lambda (p)
  488. (exit 1) ;would actually fail
  489. (display ,c p)))
  490. #:guile-for-build
  491. (package-derivation s %bootstrap-guile (%current-system))))
  492. (o (derivation->output-path d)))
  493. (with-derivation-substitute d c
  494. (set-build-options s #:use-substitutes? #t
  495. #:substitute-urls (%test-substitute-urls))
  496. (and (has-substitutes? s o)
  497. (build-things s (list o)) ;give the output path
  498. (valid-path? s o)
  499. (equal? c (call-with-input-file o get-string-all)))))))
  500. (test-assert "substitute, corrupt output hash"
  501. ;; Tweak the substituter into installing a substitute whose hash doesn't
  502. ;; match the one announced in the narinfo. The daemon must notice this and
  503. ;; raise an error.
  504. (with-store s
  505. (let* ((c "hello, world") ; contents of the output
  506. (d (build-expression->derivation
  507. s "corrupt-substitute"
  508. `(mkdir %output)
  509. #:guile-for-build
  510. (package-derivation s %bootstrap-guile (%current-system))))
  511. (o (derivation->output-path d)))
  512. (with-derivation-substitute d c
  513. (sha256 => (make-bytevector 32 0)) ;select a hash that doesn't match C
  514. ;; Make sure we use 'guix substitute'.
  515. (set-build-options s
  516. #:use-substitutes? #t
  517. #:fallback? #f
  518. #:substitute-urls (%test-substitute-urls))
  519. (and (has-substitutes? s o)
  520. (guard (c ((nix-protocol-error? c)
  521. ;; XXX: the daemon writes "hash mismatch in downloaded
  522. ;; path", but the actual error returned to the client
  523. ;; doesn't mention that.
  524. (pk 'corrupt c)
  525. (not (zero? (nix-protocol-error-status c)))))
  526. (build-derivations s (list d))
  527. #f))))))
  528. (test-assert "substitute --fallback"
  529. (with-store s
  530. (let* ((t (random-text)) ; contents of the output
  531. (d (build-expression->derivation
  532. s "substitute-me-not"
  533. `(call-with-output-file %output
  534. (lambda (p)
  535. (display ,t p)))
  536. #:guile-for-build
  537. (package-derivation s %bootstrap-guile (%current-system))))
  538. (o (derivation->output-path d)))
  539. ;; Create fake substituter data, to be read by 'guix substitute'.
  540. (with-derivation-narinfo d
  541. ;; Make sure we use 'guix substitute'.
  542. (set-build-options s #:use-substitutes? #t
  543. #:substitute-urls (%test-substitute-urls))
  544. (and (has-substitutes? s o)
  545. (guard (c ((nix-protocol-error? c)
  546. ;; The substituter failed as expected. Now make
  547. ;; sure that #:fallback? #t works correctly.
  548. (set-build-options s
  549. #:use-substitutes? #t
  550. #:substitute-urls
  551. (%test-substitute-urls)
  552. #:fallback? #t)
  553. (and (build-derivations s (list d))
  554. (equal? t (call-with-input-file o
  555. get-string-all)))))
  556. ;; Should fail.
  557. (build-derivations s (list d))
  558. #f))))))
  559. (test-assert "export/import several paths"
  560. (let* ((texts (unfold (cut >= <> 10)
  561. (lambda _ (random-text))
  562. 1+
  563. 0))
  564. (files (map (cut add-text-to-store %store "text" <>) texts))
  565. (dump (call-with-bytevector-output-port
  566. (cut export-paths %store files <>))))
  567. (delete-paths %store files)
  568. (and (every (negate file-exists?) files)
  569. (let* ((source (open-bytevector-input-port dump))
  570. (imported (import-paths %store source)))
  571. (and (equal? imported files)
  572. (every file-exists? files)
  573. (equal? texts
  574. (map (lambda (file)
  575. (call-with-input-file file
  576. get-string-all))
  577. files)))))))
  578. (test-assert "export/import paths, ensure topological order"
  579. (let* ((file0 (add-text-to-store %store "baz" (random-text)))
  580. (file1 (add-text-to-store %store "foo" (random-text)
  581. (list file0)))
  582. (file2 (add-text-to-store %store "bar" (random-text)
  583. (list file1)))
  584. (files (list file1 file2))
  585. (dump1 (call-with-bytevector-output-port
  586. (cute export-paths %store (list file1 file2) <>)))
  587. (dump2 (call-with-bytevector-output-port
  588. (cute export-paths %store (list file2 file1) <>))))
  589. (delete-paths %store files)
  590. (and (every (negate file-exists?) files)
  591. (bytevector=? dump1 dump2)
  592. (let* ((source (open-bytevector-input-port dump1))
  593. (imported (import-paths %store source)))
  594. ;; DUMP1 should contain exactly FILE1 and FILE2, not FILE0.
  595. (and (equal? imported (list file1 file2))
  596. (every file-exists? files)
  597. (equal? (list file0) (references %store file1))
  598. (equal? (list file1) (references %store file2)))))))
  599. (test-assert "export/import incomplete"
  600. (let* ((file0 (add-text-to-store %store "baz" (random-text)))
  601. (file1 (add-text-to-store %store "foo" (random-text)
  602. (list file0)))
  603. (file2 (add-text-to-store %store "bar" (random-text)
  604. (list file1)))
  605. (dump (call-with-bytevector-output-port
  606. (cute export-paths %store (list file2) <>))))
  607. (delete-paths %store (list file0 file1 file2))
  608. (guard (c ((nix-protocol-error? c)
  609. (and (not (zero? (nix-protocol-error-status c)))
  610. (string-contains (nix-protocol-error-message c)
  611. "not valid"))))
  612. ;; Here we get an exception because DUMP does not include FILE0 and
  613. ;; FILE1, which are dependencies of FILE2.
  614. (import-paths %store (open-bytevector-input-port dump)))))
  615. (test-assert "export/import recursive"
  616. (let* ((file0 (add-text-to-store %store "baz" (random-text)))
  617. (file1 (add-text-to-store %store "foo" (random-text)
  618. (list file0)))
  619. (file2 (add-text-to-store %store "bar" (random-text)
  620. (list file1)))
  621. (dump (call-with-bytevector-output-port
  622. (cute export-paths %store (list file2) <>
  623. #:recursive? #t))))
  624. (delete-paths %store (list file0 file1 file2))
  625. (let ((imported (import-paths %store (open-bytevector-input-port dump))))
  626. (and (equal? imported (list file0 file1 file2))
  627. (every file-exists? (list file0 file1 file2))
  628. (equal? (list file0) (references %store file1))
  629. (equal? (list file1) (references %store file2))))))
  630. (test-assert "write-file & export-path yield the same result"
  631. ;; Here we compare 'write-file' and the daemon's own implementation.
  632. ;; 'write-file' is the reference because we know it sorts file
  633. ;; deterministically. Conversely, the daemon uses 'readdir' and the entries
  634. ;; currently happen to be sorted as a side-effect of some unrelated
  635. ;; operation (search for 'unhacked' in archive.cc.) Make sure we detect any
  636. ;; changes there.
  637. (run-with-store %store
  638. (mlet* %store-monad ((drv1 (package->derivation %bootstrap-guile))
  639. (out1 -> (derivation->output-path drv1))
  640. (data -> (unfold (cut >= <> 26)
  641. (lambda (i)
  642. (random-bytevector 128))
  643. 1+ 0))
  644. (build
  645. -> #~(begin
  646. (use-modules (rnrs io ports) (srfi srfi-1))
  647. (let ()
  648. (define letters
  649. (map (lambda (i)
  650. (string
  651. (integer->char
  652. (+ i (char->integer #\a)))))
  653. (iota 26)))
  654. (define (touch file data)
  655. (call-with-output-file file
  656. (lambda (port)
  657. (put-bytevector port data))))
  658. (mkdir #$output)
  659. (chdir #$output)
  660. ;; The files must be different so they have
  661. ;; different inode numbers, and the inode
  662. ;; order must differ from the lexicographic
  663. ;; order.
  664. (for-each touch
  665. (append (drop letters 10)
  666. (take letters 10))
  667. (list #$@data))
  668. #t)))
  669. (drv2 (gexp->derivation "bunch" build))
  670. (out2 -> (derivation->output-path drv2))
  671. (item-info -> (store-lift query-path-info)))
  672. (mbegin %store-monad
  673. (built-derivations (list drv1 drv2))
  674. (foldm %store-monad
  675. (lambda (item result)
  676. (define ref-hash
  677. (let-values (((port get) (open-sha256-port)))
  678. (write-file item port)
  679. (close-port port)
  680. (get)))
  681. ;; 'query-path-info' returns a hash produced by using the
  682. ;; daemon's C++ 'dump' function, which is the implementation
  683. ;; under test.
  684. (>>= (item-info item)
  685. (lambda (info)
  686. (return
  687. (and result
  688. (bytevector=? (path-info-hash info) ref-hash))))))
  689. #t
  690. (list out1 out2))))
  691. #:guile-for-build (%guile-for-build)))
  692. (test-assert "import corrupt path"
  693. (let* ((text (random-text))
  694. (file (add-text-to-store %store "text" text))
  695. (dump (call-with-bytevector-output-port
  696. (cut export-paths %store (list file) <>))))
  697. (delete-paths %store (list file))
  698. ;; Flip a bit in the stream's payload. INDEX here falls in the middle of
  699. ;; the file contents in DUMP, regardless of the store prefix.
  700. (let* ((index #x70)
  701. (byte (bytevector-u8-ref dump index)))
  702. (bytevector-u8-set! dump index (logxor #xff byte)))
  703. (and (not (file-exists? file))
  704. (guard (c ((nix-protocol-error? c)
  705. (pk 'c c)
  706. (and (not (zero? (nix-protocol-error-status c)))
  707. (string-contains (nix-protocol-error-message c)
  708. "corrupt"))))
  709. (let* ((source (open-bytevector-input-port dump))
  710. (imported (import-paths %store source)))
  711. (pk 'corrupt-imported imported)
  712. #f)))))
  713. (test-assert "register-path"
  714. (let ((file (string-append (%store-prefix) "/" (make-string 32 #\f)
  715. "-fake")))
  716. (when (valid-path? %store file)
  717. (delete-paths %store (list file)))
  718. (false-if-exception (delete-file file))
  719. (let ((ref (add-text-to-store %store "ref-of-fake" (random-text)))
  720. (drv (string-append file ".drv")))
  721. (call-with-output-file file
  722. (cut display "This is a fake store item.\n" <>))
  723. (register-path file
  724. #:references (list ref)
  725. #:deriver drv)
  726. (and (valid-path? %store file)
  727. (equal? (references %store file) (list ref))
  728. (null? (valid-derivers %store file))
  729. (null? (referrers %store file))))))
  730. (test-assert "verify-store"
  731. (let* ((text (random-text))
  732. (file1 (add-text-to-store %store "foo" text))
  733. (file2 (add-text-to-store %store "bar" (random-text)
  734. (list file1))))
  735. (and (pk 'verify1 (verify-store %store)) ;hopefully OK ;
  736. (begin
  737. (delete-file file1)
  738. (not (pk 'verify2 (verify-store %store)))) ;bad! ;
  739. (begin
  740. ;; Using 'add-text-to-store' here wouldn't work: It would succeed ;
  741. ;; without actually creating the file. ;
  742. (call-with-output-file file1
  743. (lambda (port)
  744. (display text port)))
  745. (pk 'verify3 (verify-store %store)))))) ;OK again
  746. (test-assert "verify-store + check-contents"
  747. ;; XXX: This test is I/O intensive.
  748. (with-store s
  749. (let* ((text (random-text))
  750. (drv (build-expression->derivation
  751. s "corrupt"
  752. `(let ((out (assoc-ref %outputs "out")))
  753. (call-with-output-file out
  754. (lambda (port)
  755. (display ,text port)))
  756. #t)
  757. #:guile-for-build
  758. (package-derivation s %bootstrap-guile (%current-system))))
  759. (file (derivation->output-path drv)))
  760. (with-derivation-substitute drv text
  761. (and (build-derivations s (list drv))
  762. (verify-store s #:check-contents? #t) ;should be OK
  763. (begin
  764. (chmod file #o644)
  765. (call-with-output-file file
  766. (lambda (port)
  767. (display "corrupt!" port)))
  768. #t)
  769. ;; Make sure the corruption is detected. We don't test repairing
  770. ;; because only "trusted" users are allowed to do it, but we
  771. ;; don't expose that notion of trusted users that nix-daemon
  772. ;; supports because it seems dubious and redundant with what the
  773. ;; OS provides (in Nix "trusted" users have additional
  774. ;; privileges, such as overriding the set of substitute URLs, but
  775. ;; we instead want to allow anyone to modify them, provided
  776. ;; substitutes are signed by a root-approved key.)
  777. (not (verify-store s #:check-contents? #t))
  778. ;; Delete the corrupt item to leave the store in a clean state.
  779. (delete-paths s (list file)))))))
  780. (test-assert "build-things, check mode"
  781. (with-store store
  782. (call-with-temporary-output-file
  783. (lambda (entropy entropy-port)
  784. (write (random-text) entropy-port)
  785. (force-output entropy-port)
  786. (let* ((drv (build-expression->derivation
  787. store "non-deterministic"
  788. `(begin
  789. (use-modules (rnrs io ports))
  790. (let ((out (assoc-ref %outputs "out")))
  791. (call-with-output-file out
  792. (lambda (port)
  793. ;; Rely on the fact that tests do not use the
  794. ;; chroot, and thus ENTROPY is readable.
  795. (display (call-with-input-file ,entropy
  796. get-string-all)
  797. port)))
  798. #t))
  799. #:guile-for-build
  800. (package-derivation store %bootstrap-guile (%current-system))))
  801. (file (derivation->output-path drv)))
  802. (and (build-things store (list (derivation-file-name drv)))
  803. (begin
  804. (write (random-text) entropy-port)
  805. (force-output entropy-port)
  806. (guard (c ((nix-protocol-error? c)
  807. (pk 'determinism-exception c)
  808. (and (not (zero? (nix-protocol-error-status c)))
  809. (string-contains (nix-protocol-error-message c)
  810. "deterministic"))))
  811. ;; This one will produce a different result. Since we're in
  812. ;; 'check' mode, this must fail.
  813. (build-things store (list (derivation-file-name drv))
  814. (build-mode check))
  815. #f))))))))
  816. (test-assert "build multiple times"
  817. (with-store store
  818. ;; Ask to build twice.
  819. (set-build-options store #:rounds 2 #:use-substitutes? #f)
  820. (call-with-temporary-output-file
  821. (lambda (entropy entropy-port)
  822. (write (random-text) entropy-port)
  823. (force-output entropy-port)
  824. (let* ((drv (build-expression->derivation
  825. store "non-deterministic"
  826. `(begin
  827. (use-modules (rnrs io ports))
  828. (let ((out (assoc-ref %outputs "out")))
  829. (call-with-output-file out
  830. (lambda (port)
  831. ;; Rely on the fact that tests do not use the
  832. ;; chroot, and thus ENTROPY is accessible.
  833. (display (call-with-input-file ,entropy
  834. get-string-all)
  835. port)
  836. (call-with-output-file ,entropy
  837. (lambda (port)
  838. (write 'foobar port)))))
  839. #t))
  840. #:guile-for-build
  841. (package-derivation store %bootstrap-guile (%current-system))))
  842. (file (derivation->output-path drv)))
  843. (guard (c ((nix-protocol-error? c)
  844. (pk 'multiple-build c)
  845. (and (not (zero? (nix-protocol-error-status c)))
  846. (string-contains (nix-protocol-error-message c)
  847. "deterministic"))))
  848. ;; This one will produce a different result on the second run.
  849. (current-build-output-port (current-error-port))
  850. (build-things store (list (derivation-file-name drv)))
  851. #f))))))
  852. (test-equal "store-lower"
  853. "Lowered."
  854. (let* ((add (store-lower text-file))
  855. (file (add %store "foo" "Lowered.")))
  856. (call-with-input-file file get-string-all)))
  857. (test-equal "current-system"
  858. "bar"
  859. (parameterize ((%current-system "frob"))
  860. (run-with-store %store
  861. (mbegin %store-monad
  862. (set-current-system "bar")
  863. (current-system))
  864. #:system "foo")))
  865. (test-assert "query-path-info"
  866. (let* ((ref (add-text-to-store %store "ref" "foo"))
  867. (item (add-text-to-store %store "item" "bar" (list ref)))
  868. (info (query-path-info %store item)))
  869. (and (equal? (path-info-references info) (list ref))
  870. (equal? (path-info-hash info)
  871. (sha256
  872. (string->utf8
  873. (call-with-output-string (cut write-file item <>))))))))
  874. (test-assert "path-info-deriver"
  875. (let* ((b (add-text-to-store %store "build" "echo $foo > $out" '()))
  876. (s (add-to-store %store "bash" #t "sha256"
  877. (search-bootstrap-binary "bash"
  878. (%current-system))))
  879. (d (derivation %store "the-thing"
  880. s `("-e" ,b)
  881. #:env-vars `(("foo" . ,(random-text)))
  882. #:inputs `((,b) (,s))))
  883. (o (derivation->output-path d)))
  884. (and (build-derivations %store (list d))
  885. (not (path-info-deriver (query-path-info %store b)))
  886. (string=? (derivation-file-name d)
  887. (path-info-deriver (query-path-info %store o))))))
  888. (test-equal "build-cores"
  889. (list 0 42)
  890. (with-store store
  891. (let* ((build (add-text-to-store store "build.sh"
  892. "echo $NIX_BUILD_CORES > $out"))
  893. (bash (add-to-store store "bash" #t "sha256"
  894. (search-bootstrap-binary "bash"
  895. (%current-system))))
  896. (drv1 (derivation store "the-thing" bash
  897. `("-e" ,build)
  898. #:inputs `((,bash) (,build))
  899. #:env-vars `(("x" . ,(random-text)))))
  900. (drv2 (derivation store "the-thing" bash
  901. `("-e" ,build)
  902. #:inputs `((,bash) (,build))
  903. #:env-vars `(("x" . ,(random-text))))))
  904. (and (build-derivations store (list drv1))
  905. (begin
  906. (set-build-options store #:build-cores 42)
  907. (build-derivations store (list drv2)))
  908. (list (call-with-input-file (derivation->output-path drv1)
  909. read)
  910. (call-with-input-file (derivation->output-path drv2)
  911. read))))))
  912. (test-end "store")