1 ;;; GNU Guix --- Functional package management for GNU
2 ;;; Copyright © 2017 Ludovic Courtès <ludo@gnu.org>
3 ;;; Copyright © 2017, 2019 Christopher Baines <mail@cbaines.net>
4 ;;; Copyright © 2017, 2018 Clément Lassieur <clement@lassieur.org>
5 ;;; Copyright © 2018 Pierre-Antoine Rouby <pierre-antoine.rouby@inria.fr>
6 ;;; Copyright © 2018 Marius Bakke <mbakke@fastmail.com>
8 ;;; This file is part of GNU Guix.
10 ;;; GNU Guix is free software; you can redistribute it and/or modify it
11 ;;; under the terms of the GNU General Public License as published by
12 ;;; the Free Software Foundation; either version 3 of the License, or (at
13 ;;; your option) any later version.
15 ;;; GNU Guix is distributed in the hope that it will be useful, but
16 ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ;;; GNU General Public License for more details.
20 ;;; You should have received a copy of the GNU General Public License
21 ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
23 (define-module (gnu tests web)
24 #:use-module (gnu tests)
25 #:use-module (gnu system)
26 #:use-module (gnu system file-systems)
27 #:use-module (gnu system shadow)
28 #:use-module (gnu system vm)
29 #:use-module (gnu services)
30 #:use-module (gnu services web)
31 #:use-module (gnu services databases)
32 #:use-module (gnu services getmail)
33 #:use-module (gnu services networking)
34 #:use-module (gnu services shepherd)
35 #:use-module (gnu services mail)
36 #:use-module (gnu packages databases)
37 #:use-module (gnu packages patchutils)
38 #:use-module (gnu packages python)
39 #:use-module (gnu packages web)
40 #:use-module (guix packages)
41 #:use-module (guix modules)
42 #:use-module (guix records)
43 #:use-module (guix gexp)
44 #:use-module (guix store)
45 #:use-module (guix utils)
46 #:use-module (ice-9 match)
55 (define %index.html-contents
56 ;; Contents of the /index.html file.
59 (define %make-http-root
60 ;; Create our server root in /srv.
64 (call-with-output-file "/srv/http/index.html"
66 (display #$%index.html-contents port)))))
68 (define* (run-webserver-test name test-os #:key (log-file #f) (http-port 8080))
69 "Run tests in %NGINX-OS, which has nginx running and listening on
72 (marionette-operating-system
74 #:imported-modules '((gnu services herd)
77 (define forwarded-port 8080)
82 (port-forwardings `((,http-port . ,forwarded-port)))))
85 (with-imported-modules '((gnu build marionette))
87 (use-modules (srfi srfi-11) (srfi srfi-64)
88 (gnu build marionette)
94 (make-marionette (list #$vm)))
101 (test-assert #$(string-append name " service running")
104 (use-modules (gnu services herd))
105 (match (start-service '#$(string->symbol name))
107 (('service response-parts ...)
108 (match (assq-ref response-parts 'running)
110 ((pid) (number? pid))))))
113 ;; Retrieve the index.html file we put in /srv.
114 (test-equal "http-get"
115 '(200 #$%index.html-contents)
118 (http-get #$(simple-format
119 #f "http://localhost:~A/index.html" forwarded-port)
121 (list (response-code response) text)))
124 `((test-assert ,(string-append "log file exists " log-file)
126 '(file-exists? ,log-file)
131 (exit (= (test-runner-fail-count (test-runner-current)) 0)))))
133 (gexp->derivation (string-append name "-test") test))
141 (simple-operating-system
142 (service dhcp-client-service-type)
143 (service httpd-service-type
147 (listen '("8080"))))))
148 (simple-service 'make-http-root activation-service-type
154 (description "Connect to a running HTTPD server.")
155 (value (run-webserver-test name %httpd-os
156 #:log-file "/var/log/httpd/error_log"))))
163 (define %nginx-servers
165 (list (nginx-server-configuration
166 (listen '("8080")))))
169 ;; Operating system under test.
170 (simple-operating-system
171 (service dhcp-client-service-type)
172 (service nginx-service-type
174 (log-directory "/var/log/nginx")
175 (server-blocks %nginx-servers)))
176 (simple-service 'make-http-root activation-service-type
182 (description "Connect to a running NGINX server.")
183 (value (run-webserver-test name %nginx-os
184 #:log-file "/var/log/nginx/access.log"))))
195 backend dummy { .host = \"127.1.1.1\"; }
196 sub vcl_recv { return(synth(200, \"OK\")); }
198 synthetic(\"" %index.html-contents "\");
199 set resp.http.Content-Type = \"text/plain\";
204 (simple-operating-system
205 (service dhcp-client-service-type)
206 ;; Pretend to be a web server that serves %index.html-contents.
207 (service varnish-service-type
208 (varnish-configuration
210 ;; Use a small VSL buffer to fit in the test VM.
211 (parameters '(("vsl_space" . "4M")))
213 ;; Proxy the "server" using the builtin configuration.
214 (service varnish-service-type
215 (varnish-configuration
216 (parameters '(("vsl_space" . "4M")))
217 (backend "localhost:80")
218 (listen '(":8080"))))))
220 (define %test-varnish
223 (description "Test the Varnish Cache server.")
224 (value (run-webserver-test "varnish-default" %varnish-os))))
231 (define %make-php-fpm-http-root
232 ;; Create our server root in /srv.
235 (call-with-output-file "/srv/index.php"
239 echo(\"Computed by php:\".((string)(2+3)));
242 (define %php-fpm-nginx-server-blocks
243 (list (nginx-server-configuration
246 (list (nginx-php-location)))
249 (ssl-certificate-key #f))))
252 ;; Operating system under test.
253 (simple-operating-system
254 (service dhcp-client-service-type)
255 (service php-fpm-service-type)
256 (service nginx-service-type
258 (server-blocks %php-fpm-nginx-server-blocks)))
259 (simple-service 'make-http-root activation-service-type
260 %make-php-fpm-http-root)))
262 (define* (run-php-fpm-test #:optional (http-port 8042))
263 "Run tests in %PHP-FPM-OS, which has nginx running and listening on
264 HTTP-PORT, along with php-fpm."
266 (marionette-operating-system
268 #:imported-modules '((gnu services herd)
269 (guix combinators))))
273 (operating-system os)
274 (port-forwardings `((8080 . ,http-port)))))
277 (with-imported-modules '((gnu build marionette)
280 (use-modules (srfi srfi-11) (srfi srfi-64)
281 (gnu build marionette)
287 (make-marionette (list #$vm)))
292 (test-begin "php-fpm")
294 (test-assert "php-fpm running"
297 (use-modules (gnu services herd))
298 (match (start-service 'php-fpm)
300 (('service response-parts ...)
301 (match (assq-ref response-parts 'running)
302 ((pid) (number? pid))))))
305 (test-assert "nginx running"
308 (use-modules (gnu services herd))
309 (start-service 'nginx))
312 (test-equal "http-get"
314 (let-values (((response text)
315 (http-get "http://localhost:8080/index.php"
317 (response-code response)))
319 (test-equal "php computed result is sent"
321 (let-values (((response text)
322 (http-get "http://localhost:8080/index.php"
325 (use-modules (ice-9 regex))
326 (let ((matches (string-match "Computed by php:5" text)))
328 (match:substring matches 0))))))
332 (exit (= (test-runner-fail-count (test-runner-current)) 0)))))
334 (gexp->derivation "php-fpm-test" test))
336 (define %test-php-fpm
339 (description "Test PHP-FPM through nginx.")
340 (value (run-php-fpm-test))))
347 (define* (run-hpcguix-web-server-test name test-os)
348 "Run tests in %HPCGUIX-WEB-OS, which has hpcguix-web running."
350 (marionette-operating-system
352 #:imported-modules '((gnu services herd)
353 (guix combinators))))
357 (operating-system os)
358 (port-forwardings '((8080 . 5000)))))
361 (with-imported-modules '((gnu build marionette))
363 (use-modules (srfi srfi-11) (srfi srfi-64)
364 (gnu build marionette)
370 (make-marionette (list #$vm)))
377 (test-assert "hpcguix-web running"
380 (use-modules (gnu services herd))
381 (match (start-service 'hpcguix-web)
383 (('service response-parts ...)
384 (match (assq-ref response-parts 'running)
385 ((pid) (number? pid))))))
388 (test-equal "http-get"
391 (wait-for-tcp-port 5000 marionette)
392 (let-values (((response text)
393 (http-get "http://localhost:8080")))
394 (response-code response))))
397 (exit (= (test-runner-fail-count (test-runner-current)) 0)))))
399 (gexp->derivation (string-append name "-test") test))
401 (define %hpcguix-web-specs
402 ;; Server config gexp.
403 #~(define site-config
404 (hpcweb-configuration
405 (title-prefix "[TEST] HPCGUIX-WEB"))))
407 (define %hpcguix-web-os
408 (simple-operating-system
409 (service dhcp-client-service-type)
410 (service hpcguix-web-service-type
411 (hpcguix-web-configuration
412 (specs %hpcguix-web-specs)))))
414 (define %test-hpcguix-web
417 (description "Connect to a running hpcguix-web server.")
418 (value (run-hpcguix-web-server-test name %hpcguix-web-os))))
422 ;; Operating system under test.
423 (simple-operating-system
424 (service dhcp-client-service-type)
425 (service tailon-service-type
426 (tailon-configuration
428 (tailon-configuration-file
429 (bind "0.0.0.0:8080")))))))
431 (define* (run-tailon-test #:optional (http-port 8081))
432 "Run tests in %TAILON-OS, which has tailon running and listening on
435 (marionette-operating-system
437 #:imported-modules '((gnu services herd)
438 (guix combinators))))
442 (operating-system os)
443 (port-forwardings `((,http-port . 8080)))))
446 (with-imported-modules '((gnu build marionette))
448 (use-modules (srfi srfi-11) (srfi srfi-64)
450 (gnu build marionette)
456 ;; Forward the guest's HTTP-PORT, where tailon is listening, to
457 ;; port 8080 in the host.
458 (make-marionette (list #$vm)))
463 (test-begin "tailon")
465 (test-assert "service running"
468 (use-modules (gnu services herd))
469 (start-service 'tailon))
472 (define* (retry-on-error f #:key times delay)
473 (let loop ((attempt 1))
485 (if (>= attempt times)
489 (loop (+ 1 attempt))))))))
491 (test-equal "http-get"
495 (let-values (((response text)
498 "http://localhost:~A/"
501 (response-code response)))
506 (exit (= (test-runner-fail-count (test-runner-current)) 0)))))
508 (gexp->derivation "tailon-test" test))
513 (description "Connect to a running Tailon server.")
514 (value (run-tailon-test))))
521 (define patchwork-initial-database-setup-service
523 (($ <patchwork-database-configuration>
524 engine name user password host port)
528 (let ((pid (primitive-fork))
529 (postgres (getpwnam "postgres")))
534 (setgid (passwd:gid postgres))
535 (setuid (passwd:uid postgres))
539 (system* #$(file-append postgresql "/bin/createuser")
542 (system* #$(file-append postgresql "/bin/createdb")
543 "-O" #$user #$name)))
548 (zero? (cdr (waitpid pid)))))))
551 (requirement '(postgres))
552 (provision '(patchwork-postgresql-user-and-database))
556 (documentation "Setup patchwork database.")))))
558 (define (patchwork-os patchwork)
559 (simple-operating-system
560 (service dhcp-client-service-type)
561 (service httpd-service-type
565 (listen '("8080"))))))
566 (service postgresql-service-type)
567 (service patchwork-service-type
568 (patchwork-configuration
569 (patchwork patchwork)
572 (patchwork-settings-module
573 (allowed-hosts (list domain))
574 (default-from-email "")))
575 (getmail-retriever-config
576 (getmail-retriever-configuration
577 (type "SimpleIMAPSSLRetriever")
578 (server "imap.example.com")
580 (username "username")
581 (password "password")
583 '((mailboxes . ("INBOX"))))))))
584 (simple-service 'patchwork-database-setup
585 shepherd-root-service-type
587 (patchwork-initial-database-setup-service
588 (patchwork-database-configuration))))))
590 (define (run-patchwork-test patchwork)
591 "Run tests in %NGINX-OS, which has nginx running and listening on
594 (marionette-operating-system
595 (patchwork-os patchwork)
596 #:imported-modules '((gnu services herd)
597 (guix combinators))))
599 (define forwarded-port 8080)
603 (operating-system os)
604 (port-forwardings `((8080 . ,forwarded-port)))))
607 (with-imported-modules '((gnu build marionette))
609 (use-modules (srfi srfi-11) (srfi srfi-64)
610 (gnu build marionette)
616 (make-marionette (list #$vm)))
621 (test-begin "patchwork")
623 (test-assert "patchwork-postgresql-user-and-service started"
626 (use-modules (gnu services herd))
627 (match (start-service 'patchwork-postgresql-user-and-database)
629 (('service response-parts ...)
630 (match (assq-ref response-parts 'running)
632 ((pid) (number? pid))))))
635 (test-assert "httpd running"
638 (use-modules (gnu services herd))
639 (start-service 'httpd))
642 (test-equal "http-get"
646 (http-get #$(simple-format
647 #f "http://localhost:~A/" forwarded-port)
649 (response-code response)))
652 (exit (= (test-runner-fail-count (test-runner-current)) 0)))))
654 (gexp->derivation "patchwork-test" test))
656 (define %test-patchwork
659 (description "Connect to a running Patchwork service.")
660 (value (run-patchwork-test patchwork))))