Merge branch 'master' into staging
[jackhill/guix/guix.git] / gnu / tests / web.scm
CommitLineData
11f3885b 1;;; GNU Guix --- Functional package management for GNU
aa7b3c6c 2;;; Copyright © 2017, 2020 Ludovic Courtès <ludo@gnu.org>
2177d922 3;;; Copyright © 2017, 2019 Christopher Baines <mail@cbaines.net>
c24b1547 4;;; Copyright © 2017, 2018 Clément Lassieur <clement@lassieur.org>
93b83eb3 5;;; Copyright © 2018 Pierre-Antoine Rouby <pierre-antoine.rouby@inria.fr>
4353981e 6;;; Copyright © 2018 Marius Bakke <mbakke@fastmail.com>
11f3885b
LC
7;;;
8;;; This file is part of GNU Guix.
9;;;
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.
14;;;
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.
19;;;
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/>.
22
23(define-module (gnu tests web)
24 #:use-module (gnu tests)
25 #:use-module (gnu system)
11f3885b
LC
26 #:use-module (gnu system file-systems)
27 #:use-module (gnu system shadow)
28 #:use-module (gnu system vm)
29 #:use-module (gnu services)
11f3885b 30 #:use-module (gnu services web)
2177d922
CB
31 #:use-module (gnu services databases)
32 #:use-module (gnu services getmail)
11f3885b 33 #:use-module (gnu services networking)
2177d922
CB
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)
11f3885b
LC
43 #:use-module (guix gexp)
44 #:use-module (guix store)
2177d922
CB
45 #:use-module (guix utils)
46 #:use-module (ice-9 match)
d067e4ba
CB
47 #:export (%test-httpd
48 %test-nginx
3b97a177 49 %test-varnish
93b83eb3 50 %test-php-fpm
19de8273 51 %test-hpcguix-web
2177d922
CB
52 %test-tailon
53 %test-patchwork))
11f3885b
LC
54
55(define %index.html-contents
d9b53081
CB
56 ;; Contents of the /index.html file.
57 "Hello, guix!")
11f3885b
LC
58
59(define %make-http-root
60 ;; Create our server root in /srv.
61 #~(begin
62 (mkdir "/srv")
d9b53081
CB
63 (mkdir "/srv/http")
64 (call-with-output-file "/srv/http/index.html"
11f3885b
LC
65 (lambda (port)
66 (display #$%index.html-contents port)))))
67
d9b53081 68(define* (run-webserver-test name test-os #:key (log-file #f) (http-port 8080))
11f3885b
LC
69 "Run tests in %NGINX-OS, which has nginx running and listening on
70HTTP-PORT."
8b113790
LC
71 (define os
72 (marionette-operating-system
d9b53081 73 test-os
8b113790
LC
74 #:imported-modules '((gnu services herd)
75 (guix combinators))))
76
d9b53081
CB
77 (define forwarded-port 8080)
78
8b113790
LC
79 (define vm
80 (virtual-machine
81 (operating-system os)
d9b53081 82 (port-forwardings `((,http-port . ,forwarded-port)))))
8b113790
LC
83
84 (define test
85 (with-imported-modules '((gnu build marionette))
86 #~(begin
87 (use-modules (srfi srfi-11) (srfi srfi-64)
88 (gnu build marionette)
89 (web uri)
90 (web client)
91 (web response))
92
93 (define marionette
94 (make-marionette (list #$vm)))
95
96 (mkdir #$output)
97 (chdir #$output)
98
d9b53081 99 (test-begin #$name)
8b113790 100
d9b53081 101 (test-assert #$(string-append name " service running")
8b113790
LC
102 (marionette-eval
103 '(begin
104 (use-modules (gnu services herd))
d9b53081
CB
105 (match (start-service '#$(string->symbol name))
106 (#f #f)
107 (('service response-parts ...)
108 (match (assq-ref response-parts 'running)
109 ((#t) #t)
110 ((pid) (number? pid))))))
8b113790
LC
111 marionette))
112
aa7b3c6c
LC
113 (test-assert "HTTP port ready"
114 (wait-for-tcp-port #$forwarded-port marionette))
115
8b113790
LC
116 ;; Retrieve the index.html file we put in /srv.
117 (test-equal "http-get"
118 '(200 #$%index.html-contents)
d9b53081
CB
119 (let-values
120 (((response text)
121 (http-get #$(simple-format
122 #f "http://localhost:~A/index.html" forwarded-port)
123 #:decode-body? #t)))
8b113790
LC
124 (list (response-code response) text)))
125
d9b53081
CB
126 #$@(if log-file
127 `((test-assert ,(string-append "log file exists " log-file)
128 (marionette-eval
129 '(file-exists? ,log-file)
130 marionette)))
131 '())
8b113790
LC
132
133 (test-end)
134 (exit (= (test-runner-fail-count (test-runner-current)) 0)))))
135
d9b53081
CB
136 (gexp->derivation (string-append name "-test") test))
137
138\f
d067e4ba
CB
139;;;
140;;; HTTPD
141;;;
142
143(define %httpd-os
144 (simple-operating-system
39d7fdce 145 (service dhcp-client-service-type)
d067e4ba
CB
146 (service httpd-service-type
147 (httpd-configuration
148 (config
149 (httpd-config-file
150 (listen '("8080"))))))
151 (simple-service 'make-http-root activation-service-type
152 %make-http-root)))
153
154(define %test-httpd
155 (system-test
156 (name "httpd")
157 (description "Connect to a running HTTPD server.")
158 (value (run-webserver-test name %httpd-os
159 #:log-file "/var/log/httpd/error_log"))))
160
161\f
d9b53081
CB
162;;;
163;;; NGINX
164;;;
165
166(define %nginx-servers
167 ;; Server blocks.
168 (list (nginx-server-configuration
169 (listen '("8080")))))
170
171(define %nginx-os
172 ;; Operating system under test.
173 (simple-operating-system
39d7fdce 174 (service dhcp-client-service-type)
d9b53081
CB
175 (service nginx-service-type
176 (nginx-configuration
177 (log-directory "/var/log/nginx")
178 (server-blocks %nginx-servers)))
179 (simple-service 'make-http-root activation-service-type
180 %make-http-root)))
11f3885b
LC
181
182(define %test-nginx
183 (system-test
184 (name "nginx")
185 (description "Connect to a running NGINX server.")
d9b53081
CB
186 (value (run-webserver-test name %nginx-os
187 #:log-file "/var/log/nginx/access.log"))))
64bae723 188
189\f
3b97a177
MB
190;;;
191;;; Varnish
192;;;
193
194(define %varnish-vcl
195 (mixed-text-file
196 "varnish-test.vcl"
197 "vcl 4.0;
198backend dummy { .host = \"127.1.1.1\"; }
199sub vcl_recv { return(synth(200, \"OK\")); }
200sub vcl_synth {
201 synthetic(\"" %index.html-contents "\");
202 set resp.http.Content-Type = \"text/plain\";
203 return(deliver);
204}"))
205
206(define %varnish-os
207 (simple-operating-system
39d7fdce 208 (service dhcp-client-service-type)
3b97a177
MB
209 ;; Pretend to be a web server that serves %index.html-contents.
210 (service varnish-service-type
211 (varnish-configuration
212 (name "/tmp/server")
213 ;; Use a small VSL buffer to fit in the test VM.
214 (parameters '(("vsl_space" . "4M")))
215 (vcl %varnish-vcl)))
216 ;; Proxy the "server" using the builtin configuration.
217 (service varnish-service-type
218 (varnish-configuration
219 (parameters '(("vsl_space" . "4M")))
220 (backend "localhost:80")
221 (listen '(":8080"))))))
222
223(define %test-varnish
224 (system-test
225 (name "varnish")
226 (description "Test the Varnish Cache server.")
227 (value (run-webserver-test "varnish-default" %varnish-os))))
228
229\f
64bae723 230;;;
231;;; PHP-FPM
232;;;
233
234(define %make-php-fpm-http-root
235 ;; Create our server root in /srv.
236 #~(begin
237 (mkdir "/srv")
238 (call-with-output-file "/srv/index.php"
239 (lambda (port)
240 (display "<?php
241phpinfo();
242echo(\"Computed by php:\".((string)(2+3)));
243?>\n" port)))))
244
245(define %php-fpm-nginx-server-blocks
246 (list (nginx-server-configuration
247 (root "/srv")
248 (locations
249 (list (nginx-php-location)))
a1ac7bf3 250 (listen '("8042"))
64bae723 251 (ssl-certificate #f)
252 (ssl-certificate-key #f))))
253
254(define %php-fpm-os
255 ;; Operating system under test.
256 (simple-operating-system
39d7fdce 257 (service dhcp-client-service-type)
64bae723 258 (service php-fpm-service-type)
259 (service nginx-service-type
260 (nginx-configuration
261 (server-blocks %php-fpm-nginx-server-blocks)))
262 (simple-service 'make-http-root activation-service-type
263 %make-php-fpm-http-root)))
264
265(define* (run-php-fpm-test #:optional (http-port 8042))
266 "Run tests in %PHP-FPM-OS, which has nginx running and listening on
267HTTP-PORT, along with php-fpm."
268 (define os
269 (marionette-operating-system
270 %php-fpm-os
271 #:imported-modules '((gnu services herd)
272 (guix combinators))))
273
274 (define vm
275 (virtual-machine
276 (operating-system os)
277 (port-forwardings `((8080 . ,http-port)))))
278
279 (define test
280 (with-imported-modules '((gnu build marionette)
281 (guix build utils))
282 #~(begin
283 (use-modules (srfi srfi-11) (srfi srfi-64)
284 (gnu build marionette)
285 (web uri)
286 (web client)
287 (web response))
288
289 (define marionette
290 (make-marionette (list #$vm)))
291
292 (mkdir #$output)
293 (chdir #$output)
294
295 (test-begin "php-fpm")
296
297 (test-assert "php-fpm running"
298 (marionette-eval
299 '(begin
300 (use-modules (gnu services herd))
301 (match (start-service 'php-fpm)
302 (#f #f)
303 (('service response-parts ...)
304 (match (assq-ref response-parts 'running)
305 ((pid) (number? pid))))))
306 marionette))
307
c24b1547 308 (test-assert "nginx running"
64bae723 309 (marionette-eval
310 '(begin
311 (use-modules (gnu services herd))
c24b1547 312 (start-service 'nginx))
64bae723 313 marionette))
314
315 (test-equal "http-get"
316 200
317 (let-values (((response text)
318 (http-get "http://localhost:8080/index.php"
319 #:decode-body? #t)))
320 (response-code response)))
321
322 (test-equal "php computed result is sent"
323 "Computed by php:5"
324 (let-values (((response text)
325 (http-get "http://localhost:8080/index.php"
326 #:decode-body? #t)))
327 (begin
328 (use-modules (ice-9 regex))
329 (let ((matches (string-match "Computed by php:5" text)))
330 (and matches
331 (match:substring matches 0))))))
332
333 (test-end)
334
335 (exit (= (test-runner-fail-count (test-runner-current)) 0)))))
336
337 (gexp->derivation "php-fpm-test" test))
338
339(define %test-php-fpm
340 (system-test
341 (name "php-fpm")
342 (description "Test PHP-FPM through nginx.")
343 (value (run-php-fpm-test))))
93b83eb3
PAR
344
345\f
346;;;
347;;; hpcguix-web
348;;;
349
350(define* (run-hpcguix-web-server-test name test-os)
351 "Run tests in %HPCGUIX-WEB-OS, which has hpcguix-web running."
352 (define os
353 (marionette-operating-system
354 test-os
355 #:imported-modules '((gnu services herd)
356 (guix combinators))))
357
358 (define vm
359 (virtual-machine
360 (operating-system os)
361 (port-forwardings '((8080 . 5000)))))
362
363 (define test
364 (with-imported-modules '((gnu build marionette))
365 #~(begin
366 (use-modules (srfi srfi-11) (srfi srfi-64)
367 (gnu build marionette)
368 (web uri)
369 (web client)
370 (web response))
371
372 (define marionette
373 (make-marionette (list #$vm)))
374
375 (mkdir #$output)
376 (chdir #$output)
377
378 (test-begin #$name)
379
380 (test-assert "hpcguix-web running"
381 (marionette-eval
382 '(begin
383 (use-modules (gnu services herd))
384 (match (start-service 'hpcguix-web)
385 (#f #f)
386 (('service response-parts ...)
387 (match (assq-ref response-parts 'running)
388 ((pid) (number? pid))))))
389 marionette))
390
391 (test-equal "http-get"
392 200
393 (begin
394 (wait-for-tcp-port 5000 marionette)
395 (let-values (((response text)
396 (http-get "http://localhost:8080")))
397 (response-code response))))
398
399 (test-end)
400 (exit (= (test-runner-fail-count (test-runner-current)) 0)))))
401
402 (gexp->derivation (string-append name "-test") test))
403
404(define %hpcguix-web-specs
405 ;; Server config gexp.
406 #~(define site-config
407 (hpcweb-configuration
408 (title-prefix "[TEST] HPCGUIX-WEB"))))
409
410(define %hpcguix-web-os
411 (simple-operating-system
39d7fdce 412 (service dhcp-client-service-type)
93b83eb3
PAR
413 (service hpcguix-web-service-type
414 (hpcguix-web-configuration
415 (specs %hpcguix-web-specs)))))
416
417(define %test-hpcguix-web
418 (system-test
419 (name "hpcguix-web")
420 (description "Connect to a running hpcguix-web server.")
421 (value (run-hpcguix-web-server-test name %hpcguix-web-os))))
19de8273
LC
422
423\f
424(define %tailon-os
425 ;; Operating system under test.
426 (simple-operating-system
39d7fdce 427 (service dhcp-client-service-type)
19de8273
LC
428 (service tailon-service-type
429 (tailon-configuration
430 (config-file
431 (tailon-configuration-file
432 (bind "0.0.0.0:8080")))))))
433
434(define* (run-tailon-test #:optional (http-port 8081))
435 "Run tests in %TAILON-OS, which has tailon running and listening on
436HTTP-PORT."
437 (define os
438 (marionette-operating-system
439 %tailon-os
440 #:imported-modules '((gnu services herd)
441 (guix combinators))))
442
443 (define vm
444 (virtual-machine
445 (operating-system os)
446 (port-forwardings `((,http-port . 8080)))))
447
448 (define test
449 (with-imported-modules '((gnu build marionette))
450 #~(begin
451 (use-modules (srfi srfi-11) (srfi srfi-64)
452 (ice-9 match)
453 (gnu build marionette)
454 (web uri)
455 (web client)
456 (web response))
457
458 (define marionette
459 ;; Forward the guest's HTTP-PORT, where tailon is listening, to
460 ;; port 8080 in the host.
461 (make-marionette (list #$vm)))
462
463 (mkdir #$output)
464 (chdir #$output)
465
466 (test-begin "tailon")
467
468 (test-assert "service running"
469 (marionette-eval
470 '(begin
471 (use-modules (gnu services herd))
472 (start-service 'tailon))
473 marionette))
474
475 (define* (retry-on-error f #:key times delay)
476 (let loop ((attempt 1))
477 (match (catch
478 #t
479 (lambda ()
480 (cons #t
481 (f)))
482 (lambda args
483 (cons #f
484 args)))
485 ((#t . return-value)
486 return-value)
487 ((#f . error-args)
488 (if (>= attempt times)
489 error-args
490 (begin
491 (sleep delay)
492 (loop (+ 1 attempt))))))))
493
494 (test-equal "http-get"
495 200
496 (retry-on-error
497 (lambda ()
498 (let-values (((response text)
499 (http-get #$(format
500 #f
501 "http://localhost:~A/"
502 http-port)
503 #:decode-body? #t)))
504 (response-code response)))
505 #:times 10
506 #:delay 5))
507
508 (test-end)
509 (exit (= (test-runner-fail-count (test-runner-current)) 0)))))
510
511 (gexp->derivation "tailon-test" test))
512
513(define %test-tailon
514 (system-test
515 (name "tailon")
516 (description "Connect to a running Tailon server.")
517 (value (run-tailon-test))))
2177d922
CB
518
519\f
520;;;
521;;; Patchwork
522;;;
523
5cd9cd64
JL
524(define (patchwork-initial-database-setup-service configuration)
525 (define start-gexp
526 #~(lambda ()
527 (let ((pid (primitive-fork))
528 (postgres (getpwnam "postgres")))
529 (if (eq? pid 0)
530 (dynamic-wind
531 (const #t)
532 (lambda ()
533 (setgid (passwd:gid postgres))
534 (setuid (passwd:uid postgres))
535 (primitive-exit
536 (if (and
537 (zero?
538 (system* #$(file-append postgresql "/bin/createuser")
539 #$(patchwork-database-configuration-user
540 configuration)))
541 (zero?
542 (system* #$(file-append postgresql "/bin/createdb")
543 "-O"
544 #$(patchwork-database-configuration-user
545 configuration)
546 #$(patchwork-database-configuration-name
547 configuration))))
548 0
549 1)))
550 (lambda ()
551 (primitive-exit 1)))
552 (zero? (cdr (waitpid pid)))))))
553
554 (shepherd-service
555 (requirement '(postgres))
556 (provision '(patchwork-postgresql-user-and-database))
557 (start start-gexp)
558 (stop #~(const #f))
559 (respawn? #f)
560 (documentation "Setup patchwork database.")))
2177d922
CB
561
562(define (patchwork-os patchwork)
563 (simple-operating-system
564 (service dhcp-client-service-type)
565 (service httpd-service-type
566 (httpd-configuration
567 (config
568 (httpd-config-file
569 (listen '("8080"))))))
bdcf4d88
CB
570 (service postgresql-service-type
571 (postgresql-configuration
572 (postgresql postgresql-10)))
2177d922
CB
573 (service patchwork-service-type
574 (patchwork-configuration
575 (patchwork patchwork)
576 (domain "localhost")
577 (settings-module
578 (patchwork-settings-module
579 (allowed-hosts (list domain))
580 (default-from-email "")))
581 (getmail-retriever-config
582 (getmail-retriever-configuration
583 (type "SimpleIMAPSSLRetriever")
584 (server "imap.example.com")
585 (port 993)
586 (username "username")
587 (password "password")
588 (extra-parameters
589 '((mailboxes . ("INBOX"))))))))
590 (simple-service 'patchwork-database-setup
591 shepherd-root-service-type
592 (list
593 (patchwork-initial-database-setup-service
594 (patchwork-database-configuration))))))
595
596(define (run-patchwork-test patchwork)
597 "Run tests in %NGINX-OS, which has nginx running and listening on
598HTTP-PORT."
599 (define os
600 (marionette-operating-system
601 (patchwork-os patchwork)
602 #:imported-modules '((gnu services herd)
603 (guix combinators))))
604
605 (define forwarded-port 8080)
606
607 (define vm
608 (virtual-machine
609 (operating-system os)
610 (port-forwardings `((8080 . ,forwarded-port)))))
611
612 (define test
613 (with-imported-modules '((gnu build marionette))
614 #~(begin
615 (use-modules (srfi srfi-11) (srfi srfi-64)
616 (gnu build marionette)
617 (web uri)
618 (web client)
619 (web response))
620
621 (define marionette
622 (make-marionette (list #$vm)))
623
624 (mkdir #$output)
625 (chdir #$output)
626
627 (test-begin "patchwork")
628
629 (test-assert "patchwork-postgresql-user-and-service started"
630 (marionette-eval
631 '(begin
632 (use-modules (gnu services herd))
633 (match (start-service 'patchwork-postgresql-user-and-database)
634 (#f #f)
635 (('service response-parts ...)
636 (match (assq-ref response-parts 'running)
637 ((#t) #t)
638 ((pid) (number? pid))))))
639 marionette))
640
641 (test-assert "httpd running"
642 (marionette-eval
643 '(begin
644 (use-modules (gnu services herd))
645 (start-service 'httpd))
646 marionette))
647
648 (test-equal "http-get"
649 200
650 (let-values
651 (((response text)
652 (http-get #$(simple-format
653 #f "http://localhost:~A/" forwarded-port)
654 #:decode-body? #t)))
655 (response-code response)))
656
657 (test-end)
658 (exit (= (test-runner-fail-count (test-runner-current)) 0)))))
659
660 (gexp->derivation "patchwork-test" test))
661
662(define %test-patchwork
663 (system-test
664 (name "patchwork")
665 (description "Connect to a running Patchwork service.")
666 (value (run-patchwork-test patchwork))))