guix build: Gracefully handle type errors in -e and -f.
[jackhill/guix/guix.git] / tests / graph.scm
CommitLineData
88856916
LC
1;;; GNU Guix --- Functional package management for GNU
2;;; Copyright © 2015 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
19(define-module (test-graph)
20 #:use-module (guix tests)
8fb58371 21 #:use-module (guix graph)
88856916
LC
22 #:use-module (guix scripts graph)
23 #:use-module (guix packages)
24 #:use-module (guix derivations)
25 #:use-module (guix store)
26 #:use-module (guix monads)
27 #:use-module (guix build-system gnu)
923d846c 28 #:use-module (guix build-system trivial)
88856916 29 #:use-module (guix gexp)
923d846c 30 #:use-module (guix utils)
88856916 31 #:use-module (gnu packages)
923d846c
LC
32 #:use-module (gnu packages base)
33 #:use-module (gnu packages guile)
88856916
LC
34 #:use-module (gnu packages bootstrap)
35 #:use-module (ice-9 match)
36 #:use-module (srfi srfi-1)
37 #:use-module (srfi srfi-11)
38 #:use-module (srfi srfi-26)
39 #:use-module (srfi srfi-64))
40
41(define %store
42 (open-connection-for-tests))
43
44(define (make-recording-backend)
45 "Return a <graph-backend> and a thunk that returns the recorded nodes and
46edges."
47 (let ((nodes '())
48 (edges '()))
49 (define (record-node id label port)
50 (set! nodes (cons (list id label) nodes)))
51 (define (record-edge source target port)
52 (set! edges (cons (list source target) edges)))
53 (define (return)
54 (values (reverse nodes) (reverse edges)))
55
56 (values (graph-backend (const #t) (const #t)
57 record-node record-edge)
58 return)))
59
60(define (package->tuple package)
61 "Return a tuple representing PACKAGE as produced by %PACKAGE-NODE-TYPE."
62 (list (object-address package)
63 (package-full-name package)))
64
65(define (edge->tuple source target)
66 "Likewise for an edge from SOURCE to TARGET."
67 (list (object-address source)
68 (object-address target)))
69
70\f
71(test-begin "graph")
72
73(test-assert "package DAG"
74 (let-values (((backend nodes+edges) (make-recording-backend)))
75 (let* ((p1 (dummy-package "p1"))
76 (p2 (dummy-package "p2" (inputs `(("p1" ,p1)))))
77 (p3 (dummy-package "p3" (inputs `(("p2" ,p2) ("p1", p1))))))
78 (run-with-store %store
79 (export-graph (list p3) 'port
80 #:node-type %package-node-type
81 #:backend backend))
82 ;; We should see nothing more than these 3 packages.
83 (let-values (((nodes edges) (nodes+edges)))
84 (and (equal? nodes (map package->tuple (list p3 p2 p1)))
85 (equal? edges
86 (map edge->tuple
87 (list p3 p3 p2)
88 (list p2 p1 p1))))))))
89
90(test-assert "bag-emerged DAG"
91 (let-values (((backend nodes+edges) (make-recording-backend)))
92 (let ((p (dummy-package "p"))
93 (implicit (map (match-lambda
94 ((label package) package))
95 (standard-packages))))
96 (run-with-store %store
97 (export-graph (list p) 'port
98 #:node-type %bag-emerged-node-type
99 #:backend backend))
100 ;; We should see exactly P and IMPLICIT, with one edge from P to each
101 ;; element of IMPLICIT.
102 (let-values (((nodes edges) (nodes+edges)))
103 (and (equal? (match nodes
104 (((labels names) ...)
105 names))
106 (map package-full-name (cons p implicit)))
107 (equal? (match edges
108 (((sources destinations) ...)
109 (zip (map store-path-package-name sources)
110 (map store-path-package-name destinations))))
111 (map (lambda (destination)
112 (list "p-0.drv"
113 (string-append
114 (package-full-name destination)
115 ".drv")))
116 implicit)))))))
117
923d846c 118(test-assert "bag DAG" ;a big town in Iraq
88856916
LC
119 (let-values (((backend nodes+edges) (make-recording-backend)))
120 (let ((p (dummy-package "p")))
121 (run-with-store %store
122 (export-graph (list p) 'port
123 #:node-type %bag-node-type
124 #:backend backend))
125 ;; We should see P, its implicit inputs as well as the whole DAG, which
126 ;; should include bootstrap binaries.
127 (let-values (((nodes edges) (nodes+edges)))
128 (every (lambda (name)
129 (find (cut string=? name <>)
130 (match nodes
131 (((labels names) ...)
132 names))))
133 (match %bootstrap-inputs
134 (((labels packages) ...)
135 (map package-full-name packages))))))))
136
38b92daa
LC
137(test-assert "bag DAG, including origins"
138 (let-values (((backend nodes+edges) (make-recording-backend)))
139 (let* ((m (lambda* (uri hash-type hash name #:key system)
140 (text-file "foo-1.2.3.tar.gz" "This is a fake!")))
141 (o (origin (method m) (uri "the-uri") (sha256 #vu8(0 1 2))))
142 (p (dummy-package "p" (source o))))
143 (run-with-store %store
144 (export-graph (list p) 'port
145 #:node-type %bag-with-origins-node-type
146 #:backend backend))
147 ;; We should see O among the nodes, with an edge coming from P.
148 (let-values (((nodes edges) (nodes+edges)))
149 (run-with-store %store
150 (mlet %store-monad ((o* (lower-object o))
151 (p* (lower-object p)))
152 (return
153 (and (find (match-lambda
154 ((file "the-uri") #t)
155 (_ #f))
156 nodes)
157 (find (match-lambda
158 ((source target)
159 (and (string=? source (derivation-file-name p*))
160 (string=? target o*))))
161 edges)))))))))
162
88856916
LC
163(test-assert "derivation DAG"
164 (let-values (((backend nodes+edges) (make-recording-backend)))
165 (run-with-store %store
166 (mlet* %store-monad ((txt (text-file "text-file" "Hello!"))
167 (guile (package->derivation %bootstrap-guile))
168 (drv (gexp->derivation "output"
169 #~(symlink #$txt #$output)
170 #:guile-for-build
171 guile)))
172 ;; We should get at least these 3 nodes and corresponding edges.
173 (mbegin %store-monad
174 (export-graph (list drv) 'port
175 #:node-type %derivation-node-type
176 #:backend backend)
177 (let-values (((nodes edges) (nodes+edges)))
178 ;; XXX: For some reason we need to throw in some 'basename'.
179 (return (and (match nodes
180 (((ids labels) ...)
181 (let ((ids (map basename ids)))
182 (every (lambda (item)
183 (member (basename item) ids))
184 (list txt
185 (derivation-file-name drv)
186 (derivation-file-name guile))))))
187 (every (cut member <>
188 (map (lambda (edge)
189 (map basename edge))
190 edges))
191 (list (map (compose basename derivation-file-name)
192 (list drv guile))
193 (list (basename (derivation-file-name drv))
194 (basename txt))))))))))))
195
196(test-assert "reference DAG"
197 (let-values (((backend nodes+edges) (make-recording-backend)))
198 (run-with-store %store
199 (mlet* %store-monad ((txt (text-file "text-file" "Hello!"))
200 (guile (package->derivation %bootstrap-guile))
201 (drv (gexp->derivation "output"
202 #~(symlink #$txt #$output)
203 #:guile-for-build
204 guile))
205 (out -> (derivation->output-path drv)))
206 ;; We should see only OUT and TXT, with an edge from the former to the
207 ;; latter.
208 (mbegin %store-monad
209 (built-derivations (list drv))
210 (export-graph (list (derivation->output-path drv)) 'port
211 #:node-type %reference-node-type
212 #:backend backend)
213 (let-values (((nodes edges) (nodes+edges)))
214 (return
215 (and (equal? (match nodes
216 (((ids labels) ...)
217 ids))
218 (list out txt))
219 (equal? edges `((,out ,txt)))))))))))
220
923d846c
LC
221(test-assert "node-edges"
222 (run-with-store %store
223 (let ((packages (fold-packages cons '())))
224 (mlet %store-monad ((edges (node-edges %package-node-type packages)))
225 (return (and (null? (edges grep))
226 (lset= eq?
227 (edges guile-2.0)
228 (match (package-direct-inputs guile-2.0)
229 (((labels packages _ ...) ...)
230 packages)))))))))
231
232(test-assert "node-transitive-edges + node-back-edges"
233 (run-with-store %store
234 (let ((packages (fold-packages cons '()))
235 (bootstrap? (lambda (package)
236 (string-contains
237 (location-file (package-location package))
238 "bootstrap.scm")))
239 (trivial? (lambda (package)
240 (eq? (package-build-system package)
241 trivial-build-system))))
242 (mlet %store-monad ((edges (node-back-edges %bag-node-type packages)))
243 (let* ((glibc (canonical-package glibc))
244 (dependents (node-transitive-edges (list glibc) edges))
245 (diff (lset-difference eq? packages dependents)))
246 ;; All the packages depend on libc, except bootstrap packages and
247 ;; some that use TRIVIAL-BUILD-SYSTEM.
248 (return (null? (remove (lambda (package)
249 (or (trivial? package)
250 (bootstrap? package)))
251 diff))))))))
252
88856916
LC
253(test-end "graph")
254
255\f
256(exit (= (test-runner-fail-count (test-runner-current)) 0))