graph: Add "module" node type.
[jackhill/guix/guix.git] / tests / graph.scm
index daf64dc..5faa192 100644 (file)
@@ -1,5 +1,5 @@
 ;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2015, 2016 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2015, 2016, 2017, 2018 Ludovic Courtès <ludo@gnu.org>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -24,6 +24,7 @@
   #:use-module (guix derivations)
   #:use-module (guix store)
   #:use-module (guix monads)
+  #:use-module (guix grafts)
   #:use-module (guix build-system gnu)
   #:use-module (guix build-system trivial)
   #:use-module (guix gexp)
@@ -31,6 +32,7 @@
   #:use-module (gnu packages)
   #:use-module (gnu packages base)
   #:use-module (gnu packages guile)
+  #:use-module (gnu packages libunistring)
   #:use-module (gnu packages bootstrap)
   #:use-module (ice-9 match)
   #:use-module (srfi srfi-1)
@@ -41,6 +43,9 @@
 (define %store
   (open-connection-for-tests))
 
+;; Globally disable grafts because they can trigger early builds.
+(%graft? #f)
+
 (define (make-recording-backend)
   "Return a <graph-backend> and a thunk that returns the recorded nodes and
 edges."
@@ -53,7 +58,8 @@ edges."
     (define (return)
       (values (reverse nodes) (reverse edges)))
 
-    (values (graph-backend (const #t) (const #t)
+    (values (graph-backend "test" "This is the test backend."
+                           (const #t) (const #t)
                            record-node record-edge)
             return)))
 
@@ -87,25 +93,40 @@ edges."
                           (list p3 p3 p2)
                           (list p2 p1 p1))))))))
 
+(test-assert "reverse package DAG"
+  (let-values (((backend nodes+edges) (make-recording-backend)))
+    (run-with-store %store
+      (export-graph (list libunistring) 'port
+                    #:node-type %reverse-package-node-type
+                    #:backend backend))
+    ;; We should see nothing more than these 3 packages.
+    (let-values (((nodes edges) (nodes+edges)))
+      (and (member (package->tuple guile-2.0) nodes)
+           (->bool (member (edge->tuple libunistring guile-2.0) edges))))))
+
 (test-assert "bag-emerged DAG"
   (let-values (((backend nodes+edges) (make-recording-backend)))
     (let* ((o        (dummy-origin (method (lambda _
                                              (text-file "foo" "bar")))))
            (p        (dummy-package "p" (source o)))
            (implicit (map (match-lambda
-                            ((label package) package))
+                            ((label package) package)
+                            ((label package output) package))
                           (standard-packages))))
       (run-with-store %store
         (export-graph (list p) 'port
                       #:node-type %bag-emerged-node-type
                       #:backend backend))
       ;; We should see exactly P and IMPLICIT, with one edge from P to each
-      ;; element of IMPLICIT.  O must not appear among NODES.
+      ;; element of IMPLICIT.  O must not appear among NODES.  Note: IMPLICIT
+      ;; contains "glibc" twice, once for "out" and a second time for
+      ;; "static", hence the 'delete-duplicates' call below.
       (let-values (((nodes edges) (nodes+edges)))
         (and (equal? (match nodes
                        (((labels names) ...)
                         names))
-                     (map package-full-name (cons p implicit)))
+                     (map package-full-name
+                          (cons p (delete-duplicates implicit))))
              (equal? (match edges
                        (((sources destinations) ...)
                         (zip (map store-path-package-name sources)
@@ -150,7 +171,8 @@ edges."
       (let-values (((nodes edges) (nodes+edges)))
         (run-with-store %store
           (mlet %store-monad ((o* (lower-object o))
-                              (p* (lower-object p)))
+                              (p* (lower-object p))
+                              (g  (lower-object (default-guile))))
             (return
              (and (find (match-lambda
                           ((file "the-uri") #t)
@@ -160,6 +182,13 @@ edges."
                           ((source target)
                            (and (string=? source (derivation-file-name p*))
                                 (string=? target o*))))
+                        edges)
+
+                  ;; There must also be an edge from O to G.
+                  (find (match-lambda
+                          ((source target)
+                           (and (string=? source o*)
+                                (string=? target (derivation-file-name g)))))
                         edges)))))))))
 
 (test-assert "derivation DAG"
@@ -220,11 +249,51 @@ edges."
                           (list out txt))
                   (equal? edges `((,out ,txt)))))))))))
 
+(test-assert "referrer DAG"
+  (let-values (((backend nodes+edges) (make-recording-backend)))
+    (run-with-store %store
+      (mlet* %store-monad ((txt   (text-file "referrer-node" (random-text)))
+                           (drv   (gexp->derivation "referrer"
+                                                    #~(symlink #$txt #$output)))
+                           (out -> (derivation->output-path drv)))
+        ;; We should see only TXT and OUT, with an edge from the former to the
+        ;; latter.
+        (mbegin %store-monad
+          (built-derivations (list drv))
+          (export-graph (list txt) 'port
+                        #:node-type %referrer-node-type
+                        #:backend backend)
+          (let-values (((nodes edges) (nodes+edges)))
+            (return
+             (and (equal? (match nodes
+                            (((ids labels) ...)
+                             ids))
+                          (list txt out))
+                  (equal? edges `((,txt ,out)))))))))))
+
+(test-assert "module graph"
+  (let-values (((backend nodes+edges) (make-recording-backend)))
+    (run-with-store %store
+      (export-graph '((gnu packages guile)) 'port
+                    #:node-type %module-node-type
+                    #:backend backend))
+
+    (let-values (((nodes edges) (nodes+edges)))
+      (and (member '(gnu packages guile)
+                   (match nodes
+                     (((ids labels) ...) ids)))
+           (->bool (and (member (list '(gnu packages guile)
+                                      '(gnu packages libunistring))
+                                edges)
+                        (member (list '(gnu packages guile)
+                                      '(gnu packages bdw-gc))
+                                edges)))))))
+
 (test-assert "node-edges"
   (run-with-store %store
     (let ((packages (fold-packages cons '())))
       (mlet %store-monad ((edges (node-edges %package-node-type packages)))
-        (return (and (null? (edges grep))
+        (return (and (null? (edges sed))
                      (lset= eq?
                             (edges guile-2.0)
                             (match (package-direct-inputs guile-2.0)
@@ -263,7 +332,17 @@ edges."
         (return (lset= eq? (node-transitive-edges (list p2) edges)
                        (list p1a p1b p0)))))))
 
-(test-end "graph")
+(test-equal "node-reachable-count"
+  '(3 3)
+  (run-with-store %store
+    (let* ((p0  (dummy-package "p0"))
+           (p1a (dummy-package "p1a" (inputs `(("p0" ,p0)))))
+           (p1b (dummy-package "p1b" (inputs `(("p0" ,p0)))))
+           (p2  (dummy-package "p2" (inputs `(("p1a" ,p1a) ("p1b" ,p1b))))))
+      (mlet* %store-monad ((all -> (list p2 p1a p1b p0))
+                           (edges  (node-edges %package-node-type all))
+                           (back   (node-back-edges %package-node-type all)))
+        (return (list (node-reachable-count (list p2) edges)
+                      (node-reachable-count (list p0) back)))))))
 
-\f
-(exit (= (test-runner-fail-count (test-runner-current)) 0))
+(test-end "graph")