From b62a3ebcdd2ffdd48462096ff84c96493776d5c3 Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Fri, 10 Jul 2015 23:36:26 +0200 Subject: tests: Skip namespace-related tests when that feature is missing. * tests/syscalls.scm ("clone", "setns", "pivot-root"): Skip unless (user-namespace (getpid)) exists. --- tests/syscalls.scm | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'tests') diff --git a/tests/syscalls.scm b/tests/syscalls.scm index 8598f747f1..6b614a5211 100644 --- a/tests/syscalls.scm +++ b/tests/syscalls.scm @@ -80,6 +80,8 @@ (define-module (test-syscalls) (define (user-namespace pid) (string-append "/proc/" (number->string pid) "/ns/user")) +(unless (file-exists? (user-namespace (getpid))) + (test-skip 1)) (test-assert "clone" (match (clone (logior CLONE_NEWUSER SIGCHLD)) (0 (primitive-exit 42)) @@ -91,6 +93,8 @@ (define (user-namespace pid) ((_ . status) (= 42 (status:exit-val status)))))))) +(unless (file-exists? (user-namespace (getpid))) + (test-skip 1)) (test-assert "setns" (match (clone (logior CLONE_NEWUSER SIGCHLD)) (0 (primitive-exit 0)) @@ -118,6 +122,8 @@ (define (user-namespace pid) (waitpid fork-pid) result)))))))) +(unless (file-exists? (user-namespace (getpid))) + (test-skip 1)) (test-assert "pivot-root" (match (pipe) ((in . out) -- cgit v1.2.3 From 895d1eda547708dd46074a2dd2f934de275fb102 Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Mon, 13 Jul 2015 15:52:29 +0200 Subject: substitute: Store cached narinfo in cache-specific sub-directories. This ensures that switching between different substitute servers doesn't lead to a polluted narinfo cache. * guix/scripts/substitute.scm (narinfo-cache-file): Add 'cache-url' parameter. Add the base32 of CACHE-URL as a sub-directory under %NARINFO-CACHE-DIRECTORY. Update callers. (cached-narinfo): Likewise. Call 'mkdir-p' on the dirname of the cache file. Update callers. (remove-expired-cached-narinfos): Add 'directory' parameter and use it instead of %NARINFO-CACHE-DIRECTORY. (narinfo-cache-directories): New procedure. (maybe-remove-expired-cached-narinfo): Call 'remove-expired-cached-narinfos' for each item returned by 'narinfo-cache-directories'. --- guix/scripts/substitute.scm | 58 +++++++++++++++++++++++++++++---------------- tests/store.scm | 6 ++--- 2 files changed, 41 insertions(+), 23 deletions(-) (limited to 'tests') diff --git a/guix/scripts/substitute.scm b/guix/scripts/substitute.scm index 0e61f2f4a7..df5234d0cf 100755 --- a/guix/scripts/substitute.scm +++ b/guix/scripts/substitute.scm @@ -25,6 +25,7 @@ (define-module (guix scripts substitute) #:use-module (guix records) #:use-module (guix serialization) #:use-module (guix hash) + #:use-module (guix base32) #:use-module (guix base64) #:use-module (guix pk-crypto) #:use-module (guix pki) @@ -371,20 +372,23 @@ (define (obsolete? date now ttl) (make-time time-monotonic 0 date))) -(define (narinfo-cache-file path) - "Return the name of the local file that contains an entry for PATH." +(define (narinfo-cache-file cache-url path) + "Return the name of the local file that contains an entry for PATH. The +entry is stored in a sub-directory specific to CACHE-URL." (string-append %narinfo-cache-directory "/" - (store-path-hash-part path))) - -(define (cached-narinfo path) - "Check locally if we have valid info about PATH. Return two values: a -Boolean indicating whether we have valid cached info, and that info, which may -be either #f (when PATH is unavailable) or the narinfo for PATH." + (bytevector->base32-string (sha256 (string->utf8 cache-url))) + "/" (store-path-hash-part path))) + +(define (cached-narinfo cache-url path) + "Check locally if we have valid info about PATH coming from CACHE-URL. +Return two values: a Boolean indicating whether we have valid cached info, and +that info, which may be either #f (when PATH is unavailable) or the narinfo +for PATH." (define now (current-time time-monotonic)) (define cache-file - (narinfo-cache-file path)) + (narinfo-cache-file cache-url path)) (catch 'system-error (lambda () @@ -422,9 +426,12 @@ (define (cache-entry cache-uri narinfo) (date ,(time-second now)) (value ,(and=> narinfo narinfo->string)))) - (with-atomic-file-output (narinfo-cache-file path) - (lambda (out) - (write (cache-entry cache-url narinfo) out))) + (let ((file (narinfo-cache-file cache-url path))) + (mkdir-p (dirname file)) + (with-atomic-file-output file + (lambda (out) + (write (cache-entry cache-url narinfo) out)))) + narinfo) (define (narinfo-request cache-url path) @@ -553,7 +560,7 @@ (define (lookup-narinfos cache paths) (let-values (((cached missing) (fold2 (lambda (path cached missing) (let-values (((valid? value) - (cached-narinfo path))) + (cached-narinfo cache path))) (if valid? (values (cons value cached) missing) (values cached (cons path missing))))) @@ -571,8 +578,8 @@ (define (lookup-narinfo cache path) (match (lookup-narinfos cache (list path)) ((answer) answer))) -(define (remove-expired-cached-narinfos) - "Remove expired narinfo entries from the cache. The sole purpose of this +(define (remove-expired-cached-narinfos directory) + "Remove expired narinfo entries from DIRECTORY. The sole purpose of this function is to make sure `%narinfo-cache-directory' doesn't grow indefinitely." (define now @@ -596,16 +603,25 @@ (define (expired? file) #t))) (for-each (lambda (file) - (let ((file (string-append %narinfo-cache-directory - "/" file))) + (let ((file (string-append directory "/" file))) (when (expired? file) ;; Wrap in `false-if-exception' because FILE might have been ;; deleted in the meantime (TOCTTOU). (false-if-exception (delete-file file))))) - (scandir %narinfo-cache-directory + (scandir directory (lambda (file) (= (string-length file) 32))))) +(define (narinfo-cache-directories) + "Return the list of narinfo cache directories (one per cache URL.)" + (map (cut string-append %narinfo-cache-directory "/" <>) + (scandir %narinfo-cache-directory + (lambda (item) + (and (not (member item '("." ".."))) + (file-is-directory? + (string-append %narinfo-cache-directory + "/" item))))))) + (define (maybe-remove-expired-cached-narinfo) "Remove expired narinfo entries from the cache if deemed necessary." (define now @@ -619,8 +635,10 @@ (define last-expiry-date (call-with-input-file expiry-file read)) 0)) - (when (obsolete? last-expiry-date now %narinfo-expired-cache-entry-removal-delay) - (remove-expired-cached-narinfos) + (when (obsolete? last-expiry-date now + %narinfo-expired-cache-entry-removal-delay) + (for-each remove-expired-cached-narinfos + (narinfo-cache-directories)) (call-with-output-file expiry-file (cute write (time-second now) <>)))) diff --git a/tests/store.scm b/tests/store.scm index faa924fce9..f2d6d513f8 100644 --- a/tests/store.scm +++ b/tests/store.scm @@ -25,6 +25,7 @@ (define-module (test-store) #:use-module (guix packages) #:use-module (guix derivations) #:use-module (guix serialization) + #:use-module (guix build utils) #:use-module (guix gexp) #:use-module (gnu packages) #:use-module (gnu packages bootstrap) @@ -371,9 +372,8 @@ (define (same? x y) (with-derivation-narinfo d ;; Remove entry from the local cache. (false-if-exception - (delete-file (string-append (getenv "XDG_CACHE_HOME") - "/guix/substitute/" - (store-path-hash-part o)))) + (delete-file-recursively (string-append (getenv "XDG_CACHE_HOME") + "/guix/substitute"))) ;; Make sure 'guix substitute' correctly communicates the above ;; data. -- cgit v1.2.3 From 24f5aaaf24e009de7f7402f2d311a26cafbf4f4a Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Mon, 13 Jul 2015 15:46:12 +0200 Subject: substitute: Honor "substitute-urls" option passed by "untrusted" clients. * guix/scripts/substitute.scm (or*): New macro. (%cache-url): Honor "untrusted-substitute-urls". * guix/tests.scm (%test-substitute-urls): New variable. (open-connection-for-tests): Use it. * tests/derivations.scm ("derivation-prerequisites-to-build and substitutes", "derivation-prerequisites-to-build and substitutes, non-substitutable build", "derivation-prerequisites-to-build and substitutes, local build"): Pass it to 'set-build-options'. * tests/guix-daemon.sh: Likewise. * tests/store.scm ("substitute query, alternating URLs"): New test. ("substitute query", "substitute", "substitute + build-things with output path", "substitute, corrupt output hash", "substitute --fallback"): Pass #:substitute-urls to 'set-build-options'. --- guix/scripts/substitute.scm | 13 ++++++++----- guix/tests.scm | 11 ++++++++++- tests/derivations.scm | 9 ++++++--- tests/guix-daemon.sh | 12 +++++++----- tests/store.scm | 45 ++++++++++++++++++++++++++++++++++++++++----- 5 files changed, 71 insertions(+), 19 deletions(-) (limited to 'tests') diff --git a/guix/scripts/substitute.scm b/guix/scripts/substitute.scm index df5234d0cf..5cdda343d1 100755 --- a/guix/scripts/substitute.scm +++ b/guix/scripts/substitute.scm @@ -746,12 +746,15 @@ (define (find-daemon-option option) found." (assoc-ref (daemon-options) option)) +(define-syntax-rule (or* a b) + (let ((first a)) + (if (or (not first) (string-null? first)) + b + first))) + (define %cache-url - (match (and=> ;; TODO: Uncomment the following lines when multiple - ;; substitute sources are supported. - ;; (find-daemon-option "untrusted-substitute-urls") ;client - ;; " " - (find-daemon-option "substitute-urls") ;admin + (match (and=> (or* (find-daemon-option "untrusted-substitute-urls") ;client + (find-daemon-option "substitute-urls")) ;admin string-tokenize) ((url) url) diff --git a/guix/tests.scm b/guix/tests.scm index 16b8cc7f8a..cd8eda2f60 100644 --- a/guix/tests.scm +++ b/guix/tests.scm @@ -36,6 +36,7 @@ (define-module (guix tests) network-reachable? shebang-too-long? mock + %test-substitute-urls %substitute-directory with-derivation-narinfo with-derivation-substitute @@ -49,6 +50,12 @@ (define-module (guix tests) ;;; ;;; Code: +(define %test-substitute-urls + ;; URLs where to look for substitutes during tests. + (make-parameter + (or (and=> (getenv "GUIX_BINARY_SUBSTITUTE_URL") list) + '()))) + (define (open-connection-for-tests) "Open a connection to the build daemon for tests purposes and return it." (guard (c ((nix-error? c) @@ -57,7 +64,9 @@ (define (open-connection-for-tests) #f)) (let ((store (open-connection))) ;; Make sure we build everything by ourselves. - (set-build-options store #:use-substitutes? #f) + (set-build-options store + #:use-substitutes? #f + #:substitute-urls (%test-substitute-urls)) ;; Use the bootstrap Guile when running tests, so we don't end up ;; building everything in the temporary test store. diff --git a/tests/derivations.scm b/tests/derivations.scm index f66ef5cdd7..d2a090c8bc 100644 --- a/tests/derivations.scm +++ b/tests/derivations.scm @@ -612,7 +612,8 @@ (define %coreutils (output (derivation->output-path drv))) ;; Make sure substitutes are usable. - (set-build-options store #:use-substitutes? #t) + (set-build-options store #:use-substitutes? #t + #:substitute-urls (%test-substitute-urls)) (with-derivation-narinfo drv (let-values (((build download) @@ -634,7 +635,8 @@ (define %coreutils (output (derivation->output-path drv))) ;; Make sure substitutes are usable. - (set-build-options store #:use-substitutes? #t) + (set-build-options store #:use-substitutes? #t + #:substitute-urls (%test-substitute-urls)) (with-derivation-narinfo drv (let-values (((build download) @@ -655,7 +657,8 @@ (define %coreutils (output (derivation->output-path drv))) ;; Make sure substitutes are usable. - (set-build-options store #:use-substitutes? #t) + (set-build-options store #:use-substitutes? #t + #:substitute-urls (%test-substitute-urls)) (with-derivation-narinfo drv (let-values (((build download) diff --git a/tests/guix-daemon.sh b/tests/guix-daemon.sh index 87f17def12..0de6f278e4 100644 --- a/tests/guix-daemon.sh +++ b/tests/guix-daemon.sh @@ -1,5 +1,5 @@ # GNU Guix --- Functional package management for GNU -# Copyright © 2012, 2014 Ludovic Courtès +# Copyright © 2012, 2014, 2015 Ludovic Courtès # # This file is part of GNU Guix. # @@ -54,11 +54,12 @@ EOF rm -f "$XDG_CACHE_HOME/guix/substitute/$hash_part" # Make sure we see the substitute. -guile -c ' +guile -c " (use-modules (guix)) (define store (open-connection)) - (set-build-options store #:use-substitutes? #t) - (exit (has-substitutes? store "'"$out"'"))' + (set-build-options store #:use-substitutes? #t + #:substitute-urls (list \"$GUIX_BINARY_SUBSTITUTE_URL\")) + (exit (has-substitutes? store \"$out\"))" # Now, run guix-daemon --no-substitutes. socket="$NIX_STATE_DIR/alternate-socket" @@ -72,6 +73,7 @@ guile -c " (define store (open-connection \"$socket\")) ;; This setting MUST NOT override the daemon's --no-substitutes. - (set-build-options store #:use-substitutes? #t) + (set-build-options store #:use-substitutes? #t + #:substitute-urls (list \"$GUIX_BINARY_SUBSTITUTE_URL\")) (exit (not (has-substitutes? store \"$out\")))" diff --git a/tests/store.scm b/tests/store.scm index f2d6d513f8..96b64781dd 100644 --- a/tests/store.scm +++ b/tests/store.scm @@ -377,7 +377,8 @@ (define (same? x y) ;; Make sure 'guix substitute' correctly communicates the above ;; data. - (set-build-options s #:use-substitutes? #t) + (set-build-options s #:use-substitutes? #t + #:substitute-urls (%test-substitute-urls)) (and (has-substitutes? s o) (equal? (list o) (substitutable-paths s (list o))) (match (pk 'spi (substitutable-path-info s (list o))) @@ -387,6 +388,34 @@ (define (same? x y) (null? (substitutable-references s)) (equal? (substitutable-nar-size s) 1234))))))))) +(test-assert "substitute query, alternating URLs" + (let* ((d (with-store s + (package-derivation s %bootstrap-guile (%current-system)))) + (o (derivation->output-path d))) + (with-derivation-narinfo d + ;; Remove entry from the local cache. + (false-if-exception + (delete-file-recursively (string-append (getenv "XDG_CACHE_HOME") + "/guix/substitute"))) + + ;; Note: We reconnect to the daemon to force a new instance of 'guix + ;; substitute' to be used; otherwise the #:substitute-urls of + ;; 'set-build-options' would have no effect. + + (and (with-store s ;the right substitute URL + (set-build-options s #:use-substitutes? #t + #:substitute-urls (%test-substitute-urls)) + (has-substitutes? s o)) + (with-store s ;the wrong one + (set-build-options s #:use-substitutes? #t + #:substitute-urls (list + "http://does-not-exist")) + (not (has-substitutes? s o))) + (with-store s ;the right one again + (set-build-options s #:use-substitutes? #t + #:substitute-urls (%test-substitute-urls)) + (has-substitutes? s o)))))) + (test-assert "substitute" (with-store s (let* ((c (random-text)) ; contents of the output @@ -400,7 +429,8 @@ (define (same? x y) (package-derivation s %bootstrap-guile (%current-system)))) (o (derivation->output-path d))) (with-derivation-substitute d c - (set-build-options s #:use-substitutes? #t) + (set-build-options s #:use-substitutes? #t + #:substitute-urls (%test-substitute-urls)) (and (has-substitutes? s o) (build-derivations s (list d)) (equal? c (call-with-input-file o get-string-all))))))) @@ -418,7 +448,8 @@ (define (same? x y) (package-derivation s %bootstrap-guile (%current-system)))) (o (derivation->output-path d))) (with-derivation-substitute d c - (set-build-options s #:use-substitutes? #t) + (set-build-options s #:use-substitutes? #t + #:substitute-urls (%test-substitute-urls)) (and (has-substitutes? s o) (build-things s (list o)) ;give the output path (valid-path? s o) @@ -442,7 +473,8 @@ (define (same? x y) ;; Make sure we use 'guix substitute'. (set-build-options s #:use-substitutes? #t - #:fallback? #f) + #:fallback? #f + #:substitute-urls (%test-substitute-urls)) (and (has-substitutes? s o) (guard (c ((nix-protocol-error? c) ;; XXX: the daemon writes "hash mismatch in downloaded @@ -467,13 +499,16 @@ (define (same? x y) ;; Create fake substituter data, to be read by 'guix substitute'. (with-derivation-narinfo d ;; Make sure we use 'guix substitute'. - (set-build-options s #:use-substitutes? #t) + (set-build-options s #:use-substitutes? #t + #:substitute-urls (%test-substitute-urls)) (and (has-substitutes? s o) (guard (c ((nix-protocol-error? c) ;; The substituter failed as expected. Now make ;; sure that #:fallback? #t works correctly. (set-build-options s #:use-substitutes? #t + #:substitute-urls + (%test-substitute-urls) #:fallback? #t) (and (build-derivations s (list d)) (equal? t (call-with-input-file o -- cgit v1.2.3 From 661a1d7924e174a28e0e21bf516aa1a8a44dad73 Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Tue, 14 Jul 2015 15:06:46 +0200 Subject: file-systems: Allow users to specify file system UUIDs as strings. Fixes . Reported by Mark H Weaver . * gnu/system/file-systems.scm (%uuid-rx): New variable. (string->uuid): New procedure. (uuid): New macro. * tests/file-systems.scm: New file. * Makefile.am (SCM_TESTS): Add it. * doc/guix.texi (File Systems): Give an example of UUID. --- Makefile.am | 1 + doc/guix.texi | 18 +++++++++++++- gnu/system/file-systems.scm | 57 +++++++++++++++++++++++++++++++++++++++++++++ tests/file-systems.scm | 46 ++++++++++++++++++++++++++++++++++++ 4 files changed, 121 insertions(+), 1 deletion(-) create mode 100644 tests/file-systems.scm (limited to 'tests') diff --git a/Makefile.am b/Makefile.am index 7059a8f594..5cf9314014 100644 --- a/Makefile.am +++ b/Makefile.am @@ -203,6 +203,7 @@ SCM_TESTS = \ tests/lint.scm \ tests/publish.scm \ tests/size.scm \ + tests/file-systems.scm \ tests/containers.scm if HAVE_GUILE_JSON diff --git a/doc/guix.texi b/doc/guix.texi index 7b1d18a151..ad5b38af31 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -4963,8 +4963,24 @@ interpreted as a file name; when it is @code{label}, then @code{device} is interpreted as a partition label name; when it is @code{uuid}, @code{device} is interpreted as a partition unique identifier (UUID). +UUIDs may be converted from their string representation (as shown by the +@command{tune2fs -l} command) using the @code{uuid} form, like this: + +@example +(file-system + (mount-point "/home") + (type "ext4") + (title 'uuid) + (device (uuid "4dab5feb-d176-45de-b287-9b0a6e4c01cb"))) +@end example + The @code{label} and @code{uuid} options offer a way to refer to disk -partitions without having to hard-code their actual device name. +partitions without having to hard-code their actual device +name@footnote{Note that, while it is tempting to use +@file{/dev/disk/by-uuid} and similar device names to achieve the same +result, this is not recommended: These special device nodes are created +by the udev daemon and may be unavailable at the time the device is +mounted.}. However, when a file system's source is a mapped device (@pxref{Mapped Devices}), its @code{device} field @emph{must} refer to the mapped diff --git a/gnu/system/file-systems.scm b/gnu/system/file-systems.scm index 33926444b6..ece8fb41e6 100644 --- a/gnu/system/file-systems.scm +++ b/gnu/system/file-systems.scm @@ -18,9 +18,13 @@ (define-module (gnu system file-systems) #:use-module (ice-9 match) + #:use-module (ice-9 regex) #:use-module (guix gexp) #:use-module (guix records) #:use-module (guix store) + #:use-module (rnrs bytevectors) + #:use-module ((gnu build file-systems) #:select (uuid->string)) + #:re-export (uuid->string) #:export ( file-system file-system? @@ -35,6 +39,8 @@ (define-module (gnu system file-systems) file-system-create-mount-point? file-system->spec + string->uuid + uuid %fuse-control-file-system %binary-format-file-system @@ -106,6 +112,57 @@ (define (file-system->spec fs) (($ device title mount-point type flags options _ check?) (list device title mount-point type flags options check?)))) +(define %uuid-rx + ;; The regexp of a UUID. + (make-regexp "^([[:xdigit:]]{8})-([[:xdigit:]]{4})-([[:xdigit:]]{4})-([[:xdigit:]]{4})-([[:xdigit:]]{12})$")) + +(define (string->uuid str) + "Parse STR as a DCE UUID (see ) and +return its contents as a 16-byte bytevector. Return #f if STR is not a valid +UUID representation." + (and=> (regexp-exec %uuid-rx str) + (lambda (match) + (letrec-syntax ((hex->number + (syntax-rules () + ((_ index) + (string->number (match:substring match index) + 16)))) + (put! + (syntax-rules () + ((_ bv index (number len) rest ...) + (begin + (bytevector-uint-set! bv index number + (endianness big) len) + (put! bv (+ index len) rest ...))) + ((_ bv index) + bv)))) + (let ((time-low (hex->number 1)) + (time-mid (hex->number 2)) + (time-hi (hex->number 3)) + (clock-seq (hex->number 4)) + (node (hex->number 5)) + (uuid (make-bytevector 16))) + (put! uuid 0 + (time-low 4) (time-mid 2) (time-hi 2) + (clock-seq 2) (node 6))))))) + +(define-syntax uuid + (lambda (s) + "Return the bytevector corresponding to the given UUID representation." + (syntax-case s () + ((_ str) + (string? (syntax->datum #'str)) + ;; A literal string: do the conversion at expansion time. + (with-syntax ((bv (string->uuid (syntax->datum #'str)))) + #''bv)) + ((_ str) + #'(string->uuid str))))) + + +;;; +;;; Common file systems. +;;; + (define %fuse-control-file-system ;; Control file system for Linux' file systems in user-space (FUSE). (file-system diff --git a/tests/file-systems.scm b/tests/file-systems.scm new file mode 100644 index 0000000000..d445b4971f --- /dev/null +++ b/tests/file-systems.scm @@ -0,0 +1,46 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2015 Ludovic Courtès +;;; +;;; This file is part of GNU Guix. +;;; +;;; GNU Guix is free software; you can redistribute it and/or modify it +;;; under the terms of the GNU General Public License as published by +;;; the Free Software Foundation; either version 3 of the License, or (at +;;; your option) any later version. +;;; +;;; GNU Guix is distributed in the hope that it will be useful, but +;;; WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with GNU Guix. If not, see . + +(define-module (test-file-systems) + #:use-module (gnu system file-systems) + #:use-module (srfi srfi-64) + #:use-module (rnrs bytevectors)) + +;; Test the (gnu system file-systems) module. + +(test-begin "file-systems") + +(test-equal "uuid->string" + "c5307e6b-d1ba-499d-89c5-cb0b143577c4" + (uuid->string + #vu8(197 48 126 107 209 186 73 157 137 197 203 11 20 53 119 196))) + +(test-equal "string->uuid" + '(16 "4dab5feb-d176-45de-b287-9b0a6e4c01cb") + (let ((uuid (string->uuid "4dab5feb-d176-45de-b287-9b0a6e4c01cb"))) + (list (bytevector-length uuid) (uuid->string uuid)))) + +(test-assert "uuid" + (let ((str "4dab5feb-d176-45de-b287-9b0a6e4c01cb")) + (bytevector=? (uuid "4dab5feb-d176-45de-b287-9b0a6e4c01cb") + (string->uuid "4dab5feb-d176-45de-b287-9b0a6e4c01cb")))) + +(test-end) + + +(exit (= (test-runner-fail-count (test-runner-current)) 0)) -- cgit v1.2.3