guix package: Always upgrade packages that have propagated inputs.
[jackhill/guix/guix.git] / tests / profiles.scm
CommitLineData
a2078770 1;;; GNU Guix --- Functional package management for GNU
176febe3 2;;; Copyright © 2013, 2014, 2015, 2016, 2017 Ludovic Courtès <ludo@gnu.org>
343745c8 3;;; Copyright © 2014 Alex Kost <alezost@gmail.com>
a2078770
LC
4;;;
5;;; This file is part of GNU Guix.
6;;;
7;;; GNU Guix is free software; you can redistribute it and/or modify it
8;;; under the terms of the GNU General Public License as published by
9;;; the Free Software Foundation; either version 3 of the License, or (at
10;;; your option) any later version.
11;;;
12;;; GNU Guix is distributed in the hope that it will be useful, but
13;;; WITHOUT ANY WARRANTY; without even the implied warranty of
14;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15;;; GNU General Public License for more details.
16;;;
17;;; You should have received a copy of the GNU General Public License
18;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
19
20(define-module (test-profiles)
c1bc358f 21 #:use-module (guix tests)
a2078770 22 #:use-module (guix profiles)
462f5cca
LC
23 #:use-module (guix store)
24 #:use-module (guix monads)
ef8de985 25 #:use-module (guix grafts)
462f5cca
LC
26 #:use-module (guix packages)
27 #:use-module (guix derivations)
a0dac7a0 28 #:use-module (guix build-system trivial)
462f5cca 29 #:use-module (gnu packages bootstrap)
e39d1461 30 #:use-module ((gnu packages base) #:prefix packages:)
dedb17ad 31 #:use-module ((gnu packages guile) #:prefix packages:)
a2078770 32 #:use-module (ice-9 match)
ef8993e2 33 #:use-module (ice-9 regex)
d664f1b4
LC
34 #:use-module (ice-9 popen)
35 #:use-module (rnrs io ports)
ccda8f7d 36 #:use-module (srfi srfi-1)
79601521 37 #:use-module (srfi srfi-11)
a2078770
LC
38 #:use-module (srfi srfi-64))
39
343745c8 40;; Test the (guix profiles) module.
a2078770 41
462f5cca 42(define %store
c1bc358f 43 (open-connection-for-tests))
a2078770 44
ef8de985
LC
45;; Globally disable grafts because they can trigger early builds.
46(%graft? #f)
47
ebf5ad46
LC
48(define-syntax-rule (test-assertm name exp)
49 (test-assert name
50 (run-with-store %store exp
51 #:guile-for-build (%guile-for-build))))
52
22ef06b8
LC
53(define-syntax-rule (test-equalm name value exp)
54 (test-equal name
55 value
56 (run-with-store %store exp
57 #:guile-for-build (%guile-for-build))))
58
a2078770
LC
59;; Example manifest entries.
60
f7554030
AK
61(define guile-1.8.8
62 (manifest-entry
63 (name "guile")
64 (version "1.8.8")
65 (item "/gnu/store/...")
66 (output "out")))
67
a2078770
LC
68(define guile-2.0.9
69 (manifest-entry
70 (name "guile")
71 (version "2.0.9")
a54c94a4 72 (item "/gnu/store/...")
a2078770
LC
73 (output "out")))
74
75(define guile-2.0.9:debug
76 (manifest-entry (inherit guile-2.0.9)
77 (output "debug")))
78
79601521
LC
79(define glibc
80 (manifest-entry
81 (name "glibc")
82 (version "2.19")
83 (item "/gnu/store/...")
84 (output "out")))
85
a2078770
LC
86\f
87(test-begin "profiles")
88
89(test-assert "manifest-installed?"
90 (let ((m (manifest (list guile-2.0.9 guile-2.0.9:debug))))
91 (and (manifest-installed? m (manifest-pattern (name "guile")))
92 (manifest-installed? m (manifest-pattern
93 (name "guile") (output "debug")))
94 (manifest-installed? m (manifest-pattern
95 (name "guile") (output "out")
96 (version "2.0.9")))
97 (not (manifest-installed?
98 m (manifest-pattern (name "guile") (version "1.8.8"))))
99 (not (manifest-installed?
100 m (manifest-pattern (name "guile") (output "foobar")))))))
101
102(test-assert "manifest-matching-entries"
103 (let* ((e (list guile-2.0.9 guile-2.0.9:debug))
104 (m (manifest e)))
105 (and (null? (manifest-matching-entries m
106 (list (manifest-pattern
107 (name "python")))))
108 (equal? e
109 (manifest-matching-entries m
110 (list (manifest-pattern
111 (name "guile")
112 (output #f)))))
113 (equal? (list guile-2.0.9)
114 (manifest-matching-entries m
115 (list (manifest-pattern
116 (name "guile")
117 (version "2.0.9"))))))))
118
119(test-assert "manifest-remove"
120 (let* ((m0 (manifest (list guile-2.0.9 guile-2.0.9:debug)))
121 (m1 (manifest-remove m0
122 (list (manifest-pattern (name "guile")))))
123 (m2 (manifest-remove m1
124 (list (manifest-pattern (name "guile"))))) ; same
125 (m3 (manifest-remove m2
126 (list (manifest-pattern
127 (name "guile") (output "debug")))))
128 (m4 (manifest-remove m3
129 (list (manifest-pattern (name "guile"))))))
130 (match (manifest-entries m2)
131 ((($ <manifest-entry> "guile" "2.0.9" "debug"))
132 (and (equal? m1 m2)
133 (null? (manifest-entries m3))
134 (null? (manifest-entries m4)))))))
135
f7554030
AK
136(test-assert "manifest-add"
137 (let* ((m0 (manifest '()))
138 (m1 (manifest-add m0 (list guile-1.8.8)))
139 (m2 (manifest-add m1 (list guile-2.0.9)))
140 (m3 (manifest-add m2 (list guile-2.0.9:debug)))
141 (m4 (manifest-add m3 (list guile-2.0.9:debug))))
142 (and (match (manifest-entries m1)
143 ((($ <manifest-entry> "guile" "1.8.8" "out")) #t)
144 (_ #f))
145 (match (manifest-entries m2)
146 ((($ <manifest-entry> "guile" "2.0.9" "out")) #t)
147 (_ #f))
148 (equal? m3 m4))))
149
343745c8
AK
150(test-assert "manifest-perform-transaction"
151 (let* ((m0 (manifest (list guile-2.0.9 guile-2.0.9:debug)))
152 (t1 (manifest-transaction
153 (install (list guile-1.8.8))
154 (remove (list (manifest-pattern (name "guile")
155 (output "debug"))))))
156 (t2 (manifest-transaction
157 (remove (list (manifest-pattern (name "guile")
158 (version "2.0.9")
159 (output #f))))))
160 (m1 (manifest-perform-transaction m0 t1))
161 (m2 (manifest-perform-transaction m1 t2))
162 (m3 (manifest-perform-transaction m0 t2)))
163 (and (match (manifest-entries m1)
164 ((($ <manifest-entry> "guile" "1.8.8" "out")) #t)
165 (_ #f))
166 (equal? m1 m2)
167 (null? (manifest-entries m3)))))
168
79601521
LC
169(test-assert "manifest-transaction-effects"
170 (let* ((m0 (manifest (list guile-1.8.8)))
171 (t (manifest-transaction
172 (install (list guile-2.0.9 glibc))
173 (remove (list (manifest-pattern (name "coreutils")))))))
46b23e1a 174 (let-values (((remove install upgrade downgrade)
79601521 175 (manifest-transaction-effects m0 t)))
46b23e1a 176 (and (null? remove) (null? downgrade)
79601521 177 (equal? (list glibc) install)
ef8993e2
LC
178 (equal? (list (cons guile-1.8.8 guile-2.0.9)) upgrade)))))
179
46b23e1a
LC
180(test-assert "manifest-transaction-effects and downgrades"
181 (let* ((m0 (manifest (list guile-2.0.9)))
182 (t (manifest-transaction (install (list guile-1.8.8)))))
183 (let-values (((remove install upgrade downgrade)
184 (manifest-transaction-effects m0 t)))
185 (and (null? remove) (null? install) (null? upgrade)
186 (equal? (list (cons guile-2.0.9 guile-1.8.8)) downgrade)))))
187
3bea13bb
LC
188(test-assert "manifest-transaction-effects and pseudo-upgrades"
189 (let* ((m0 (manifest (list guile-2.0.9)))
190 (t (manifest-transaction (install (list guile-2.0.9)))))
191 (let-values (((remove install upgrade downgrade)
192 (manifest-transaction-effects m0 t)))
193 (and (null? remove) (null? install) (null? downgrade)
194 (equal? (list (cons guile-2.0.9 guile-2.0.9)) upgrade)))))
195
c8c25704
LC
196(test-assert "manifest-transaction-null?"
197 (manifest-transaction-null? (manifest-transaction)))
198
ebf5ad46
LC
199(test-assertm "profile-derivation"
200 (mlet* %store-monad
201 ((entry -> (package->manifest-entry %bootstrap-guile))
202 (guile (package->derivation %bootstrap-guile))
203 (drv (profile-derivation (manifest (list entry))
a6562c7e
LC
204 #:hooks '()
205 #:locales? #f))
ebf5ad46
LC
206 (profile -> (derivation->output-path drv))
207 (bindir -> (string-append profile "/bin"))
208 (_ (built-derivations (list drv))))
209 (return (and (file-exists? (string-append bindir "/guile"))
210 (string=? (dirname (readlink bindir))
211 (derivation->output-path guile))))))
462f5cca 212
e39d1461
LC
213(test-assertm "profile-derivation, inputs"
214 (mlet* %store-monad
215 ((entry -> (package->manifest-entry packages:glibc "debug"))
216 (drv (profile-derivation (manifest (list entry))
a6562c7e
LC
217 #:hooks '()
218 #:locales? #f)))
e39d1461
LC
219 (return (derivation-inputs drv))))
220
176febe3
LC
221(test-assertm "profile-derivation, cross-compilation"
222 (mlet* %store-monad
223 ((manifest -> (packages->manifest (list packages:sed packages:grep)))
224 (target -> "arm-linux-gnueabihf")
225 (grep (package->cross-derivation packages:grep target))
226 (sed (package->cross-derivation packages:sed target))
227 (locales (package->derivation packages:glibc-utf8-locales))
228 (drv (profile-derivation manifest
229 #:hooks '()
230 #:locales? #t
231 #:target target)))
232 (define (find-input name)
233 (let ((name (string-append name ".drv")))
234 (any (lambda (input)
235 (let ((input (derivation-input-path input)))
236 (and (string-suffix? name input) input)))
237 (derivation-inputs drv))))
238
239 ;; The inputs for grep and sed should be cross-build derivations, but that
240 ;; for the glibc-utf8-locales should be a native build.
241 (return (and (string=? (derivation-system drv) (%current-system))
242 (string=? (find-input (package-full-name packages:grep))
243 (derivation-file-name grep))
244 (string=? (find-input (package-full-name packages:sed))
245 (derivation-file-name sed))
246 (string=? (find-input
247 (package-full-name packages:glibc-utf8-locales))
248 (derivation-file-name locales))))))
249
9e90fc77
LC
250(test-assert "package->manifest-entry defaults to \"out\""
251 (let ((outputs (package-outputs packages:glibc)))
252 (equal? (manifest-entry-output
253 (package->manifest-entry (package
254 (inherit packages:glibc)
255 (outputs (reverse outputs)))))
256 (manifest-entry-output
257 (package->manifest-entry packages:glibc))
258 "out")))
259
dedb17ad
LC
260(test-assertm "profile-manifest, search-paths"
261 (mlet* %store-monad
262 ((guile -> (package
263 (inherit %bootstrap-guile)
264 (native-search-paths
265 (package-native-search-paths packages:guile-2.0))))
266 (entry -> (package->manifest-entry guile))
267 (drv (profile-derivation (manifest (list entry))
a6562c7e
LC
268 #:hooks '()
269 #:locales? #f))
dedb17ad
LC
270 (profile -> (derivation->output-path drv)))
271 (mbegin %store-monad
272 (built-derivations (list drv))
273
274 ;; Read the manifest back and make sure search paths are preserved.
275 (let ((manifest (profile-manifest profile)))
276 (match (manifest-entries manifest)
277 ((result)
278 (return (equal? (manifest-entry-search-paths result)
279 (manifest-entry-search-paths entry)
280 (package-native-search-paths
281 packages:guile-2.0)))))))))
d664f1b4 282
ccda8f7d
LC
283(test-assert "package->manifest-entry, search paths"
284 ;; See <http://bugs.gnu.org/22073>.
285 (let ((mpl (@ (gnu packages python) python2-matplotlib)))
286 (lset= eq?
287 (package-transitive-native-search-paths mpl)
288 (manifest-entry-search-paths
289 (package->manifest-entry mpl)))))
290
55b4715f
LC
291(test-equal "packages->manifest, propagated inputs"
292 (map (match-lambda
293 ((label package)
294 (list (package-name package) (package-version package)
295 package)))
296 (package-propagated-inputs packages:guile-2.2))
297 (map (lambda (entry)
298 (list (manifest-entry-name entry)
299 (manifest-entry-version entry)
300 (manifest-entry-item entry)))
301 (manifest-entry-dependencies
302 (package->manifest-entry packages:guile-2.2))))
303
b3a00885
LC
304(test-assert "manifest-entry-parent"
305 (let ((entry (package->manifest-entry packages:guile-2.2)))
306 (match (manifest-entry-dependencies entry)
307 ((dependencies ..1)
308 (and (every (lambda (parent)
309 (eq? entry (force parent)))
310 (map manifest-entry-parent dependencies))
311 (not (force (manifest-entry-parent entry))))))))
312
55b4715f
LC
313(test-assertm "read-manifest"
314 (mlet* %store-monad ((manifest -> (packages->manifest
315 (list (package
316 (inherit %bootstrap-guile)
317 (native-search-paths
318 (package-native-search-paths
319 packages:guile-2.0))))))
320 (drv (profile-derivation manifest
321 #:hooks '()
322 #:locales? #f))
323 (out -> (derivation->output-path drv)))
324 (define (entry->sexp entry)
325 (list (manifest-entry-name entry)
326 (manifest-entry-version entry)
327 (manifest-entry-search-paths entry)
b3a00885
LC
328 (manifest-entry-dependencies entry)
329 (force (manifest-entry-parent entry))))
55b4715f
LC
330
331 (mbegin %store-monad
332 (built-derivations (list drv))
333 (let ((manifest2 (profile-manifest out)))
334 (return (equal? (map entry->sexp (manifest-entries manifest))
335 (map entry->sexp (manifest-entries manifest2))))))))
336
d664f1b4
LC
337(test-assertm "etc/profile"
338 ;; Make sure we get an 'etc/profile' file that at least defines $PATH.
339 (mlet* %store-monad
340 ((guile -> (package
341 (inherit %bootstrap-guile)
342 (native-search-paths
343 (package-native-search-paths packages:guile-2.0))))
344 (entry -> (package->manifest-entry guile))
345 (drv (profile-derivation (manifest (list entry))
a6562c7e
LC
346 #:hooks '()
347 #:locales? #f))
d664f1b4
LC
348 (profile -> (derivation->output-path drv)))
349 (mbegin %store-monad
350 (built-derivations (list drv))
351 (let* ((pipe (open-input-pipe
9e006fb3
TUBK
352 (string-append "unset GUIX_PROFILE; "
353 ;; 'source' is a Bashism; use '.' (dot).
354 ". " profile "/etc/profile; "
355 ;; Don't try to parse set(1) output because
356 ;; it differs among shells; just use echo.
357 "echo $PATH")))
358 (path (get-string-all pipe)))
d664f1b4
LC
359 (return
360 (and (zero? (close-pipe pipe))
9e006fb3 361 (string-contains path (string-append profile "/bin"))))))))
d664f1b4 362
a0dac7a0
LC
363(test-assertm "etc/profile when etc/ already exists"
364 ;; Here 'union-build' makes the profile's etc/ a symlink to the package's
365 ;; etc/ directory, which makes it read-only. Make sure the profile build
366 ;; handles that.
367 (mlet* %store-monad
368 ((thing -> (dummy-package "dummy"
369 (build-system trivial-build-system)
370 (arguments
371 `(#:guile ,%bootstrap-guile
372 #:builder
373 (let ((out (assoc-ref %outputs "out")))
374 (mkdir out)
375 (mkdir (string-append out "/etc"))
376 (call-with-output-file (string-append out "/etc/foo")
377 (lambda (port)
378 (display "foo!" port))))))))
379 (entry -> (package->manifest-entry thing))
380 (drv (profile-derivation (manifest (list entry))
a6562c7e
LC
381 #:hooks '()
382 #:locales? #f))
a0dac7a0
LC
383 (profile -> (derivation->output-path drv)))
384 (mbegin %store-monad
385 (built-derivations (list drv))
386 (return (and (file-exists? (string-append profile "/etc/profile"))
387 (string=? (call-with-input-file
388 (string-append profile "/etc/foo")
389 get-string-all)
390 "foo!"))))))
391
113c17a0
LC
392(test-assertm "etc/profile when etc/ is a symlink"
393 ;; When etc/ is a symlink, the unsymlink code in 0.8.2 would fail
394 ;; gracelessly because 'scandir' would return #f.
395 (mlet* %store-monad
396 ((thing -> (dummy-package "dummy"
397 (build-system trivial-build-system)
398 (arguments
399 `(#:guile ,%bootstrap-guile
400 #:builder
401 (let ((out (assoc-ref %outputs "out")))
402 (mkdir out)
403 (mkdir (string-append out "/foo"))
404 (symlink "foo" (string-append out "/etc"))
405 (call-with-output-file (string-append out "/etc/bar")
406 (lambda (port)
407 (display "foo!" port))))))))
408 (entry -> (package->manifest-entry thing))
409 (drv (profile-derivation (manifest (list entry))
a6562c7e
LC
410 #:hooks '()
411 #:locales? #f))
113c17a0
LC
412 (profile -> (derivation->output-path drv)))
413 (mbegin %store-monad
414 (built-derivations (list drv))
415 (return (and (file-exists? (string-append profile "/etc/profile"))
416 (string=? (call-with-input-file
417 (string-append profile "/etc/bar")
418 get-string-all)
419 "foo!"))))))
420
22ef06b8
LC
421(test-equalm "union vs. dangling symlink" ;<https://bugs.gnu.org/26949>
422 "does-not-exist"
423 (mlet* %store-monad
424 ((thing1 -> (dummy-package "dummy"
425 (build-system trivial-build-system)
426 (arguments
427 `(#:guile ,%bootstrap-guile
428 #:builder
429 (let ((out (assoc-ref %outputs "out")))
430 (mkdir out)
431 (symlink "does-not-exist"
432 (string-append out "/dangling"))
433 #t)))))
434 (thing2 -> (package (inherit thing1) (name "dummy2")))
435 (drv (profile-derivation (packages->manifest
436 (list thing1 thing2))
437 #:hooks '()
438 #:locales? #f))
439 (profile -> (derivation->output-path drv)))
440 (mbegin %store-monad
441 (built-derivations (list drv))
442 (return (readlink (readlink (string-append profile "/dangling")))))))
443
a2078770
LC
444(test-end "profiles")
445
a2078770
LC
446;;; Local Variables:
447;;; eval: (put 'dummy-package 'scheme-indent-function 1)
448;;; End: