1 ;;; GNU Guix --- Functional package management for GNU
2 ;;; Copyright © 2017 Ludovic Courtès <ludo@gnu.org>
3 ;;; Copyright © 2017 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 networking)
32 #:use-module (guix gexp)
33 #:use-module (guix store)
41 (define %index.html-contents
42 ;; Contents of the /index.html file.
45 (define %make-http-root
46 ;; Create our server root in /srv.
50 (call-with-output-file "/srv/http/index.html"
52 (display #$%index.html-contents port)))))
54 (define* (run-webserver-test name test-os #:key (log-file #f) (http-port 8080))
55 "Run tests in %NGINX-OS, which has nginx running and listening on
58 (marionette-operating-system
60 #:imported-modules '((gnu services herd)
63 (define forwarded-port 8080)
68 (port-forwardings `((,http-port . ,forwarded-port)))))
71 (with-imported-modules '((gnu build marionette))
73 (use-modules (srfi srfi-11) (srfi srfi-64)
74 (gnu build marionette)
80 (make-marionette (list #$vm)))
87 (test-assert #$(string-append name " service running")
90 (use-modules (gnu services herd))
91 (match (start-service '#$(string->symbol name))
93 (('service response-parts ...)
94 (match (assq-ref response-parts 'running)
96 ((pid) (number? pid))))))
99 ;; Retrieve the index.html file we put in /srv.
100 (test-equal "http-get"
101 '(200 #$%index.html-contents)
104 (http-get #$(simple-format
105 #f "http://localhost:~A/index.html" forwarded-port)
107 (list (response-code response) text)))
110 `((test-assert ,(string-append "log file exists " log-file)
112 '(file-exists? ,log-file)
117 (exit (= (test-runner-fail-count (test-runner-current)) 0)))))
119 (gexp->derivation (string-append name "-test") test))
127 (simple-operating-system
128 (dhcp-client-service)
129 (service httpd-service-type
133 (listen '("8080"))))))
134 (simple-service 'make-http-root activation-service-type
140 (description "Connect to a running HTTPD server.")
141 (value (run-webserver-test name %httpd-os
142 #:log-file "/var/log/httpd/error_log"))))
149 (define %nginx-servers
151 (list (nginx-server-configuration
152 (listen '("8080")))))
155 ;; Operating system under test.
156 (simple-operating-system
157 (dhcp-client-service)
158 (service nginx-service-type
160 (log-directory "/var/log/nginx")
161 (server-blocks %nginx-servers)))
162 (simple-service 'make-http-root activation-service-type
168 (description "Connect to a running NGINX server.")
169 (value (run-webserver-test name %nginx-os
170 #:log-file "/var/log/nginx/access.log"))))
181 backend dummy { .host = \"127.1.1.1\"; }
182 sub vcl_recv { return(synth(200, \"OK\")); }
184 synthetic(\"" %index.html-contents "\");
185 set resp.http.Content-Type = \"text/plain\";
190 (simple-operating-system
191 (dhcp-client-service)
192 ;; Pretend to be a web server that serves %index.html-contents.
193 (service varnish-service-type
194 (varnish-configuration
196 ;; Use a small VSL buffer to fit in the test VM.
197 (parameters '(("vsl_space" . "4M")))
199 ;; Proxy the "server" using the builtin configuration.
200 (service varnish-service-type
201 (varnish-configuration
202 (parameters '(("vsl_space" . "4M")))
203 (backend "localhost:80")
204 (listen '(":8080"))))))
206 (define %test-varnish
209 (description "Test the Varnish Cache server.")
210 (value (run-webserver-test "varnish-default" %varnish-os))))
217 (define %make-php-fpm-http-root
218 ;; Create our server root in /srv.
221 (call-with-output-file "/srv/index.php"
225 echo(\"Computed by php:\".((string)(2+3)));
228 (define %php-fpm-nginx-server-blocks
229 (list (nginx-server-configuration
232 (list (nginx-php-location)))
235 (ssl-certificate-key #f))))
238 ;; Operating system under test.
239 (simple-operating-system
240 (dhcp-client-service)
241 (service php-fpm-service-type)
242 (service nginx-service-type
244 (server-blocks %php-fpm-nginx-server-blocks)))
245 (simple-service 'make-http-root activation-service-type
246 %make-php-fpm-http-root)))
248 (define* (run-php-fpm-test #:optional (http-port 8042))
249 "Run tests in %PHP-FPM-OS, which has nginx running and listening on
250 HTTP-PORT, along with php-fpm."
252 (marionette-operating-system
254 #:imported-modules '((gnu services herd)
255 (guix combinators))))
259 (operating-system os)
260 (port-forwardings `((8080 . ,http-port)))))
263 (with-imported-modules '((gnu build marionette)
266 (use-modules (srfi srfi-11) (srfi srfi-64)
267 (gnu build marionette)
273 (make-marionette (list #$vm)))
278 (test-begin "php-fpm")
280 (test-assert "php-fpm running"
283 (use-modules (gnu services herd))
284 (match (start-service 'php-fpm)
286 (('service response-parts ...)
287 (match (assq-ref response-parts 'running)
288 ((pid) (number? pid))))))
291 (test-assert "nginx running"
294 (use-modules (gnu services herd))
295 (start-service 'nginx))
298 (test-equal "http-get"
300 (let-values (((response text)
301 (http-get "http://localhost:8080/index.php"
303 (response-code response)))
305 (test-equal "php computed result is sent"
307 (let-values (((response text)
308 (http-get "http://localhost:8080/index.php"
311 (use-modules (ice-9 regex))
312 (let ((matches (string-match "Computed by php:5" text)))
314 (match:substring matches 0))))))
318 (exit (= (test-runner-fail-count (test-runner-current)) 0)))))
320 (gexp->derivation "php-fpm-test" test))
322 (define %test-php-fpm
325 (description "Test PHP-FPM through nginx.")
326 (value (run-php-fpm-test))))
333 (define* (run-hpcguix-web-server-test name test-os)
334 "Run tests in %HPCGUIX-WEB-OS, which has hpcguix-web running."
336 (marionette-operating-system
338 #:imported-modules '((gnu services herd)
339 (guix combinators))))
343 (operating-system os)
344 (port-forwardings '((8080 . 5000)))))
347 (with-imported-modules '((gnu build marionette))
349 (use-modules (srfi srfi-11) (srfi srfi-64)
350 (gnu build marionette)
356 (make-marionette (list #$vm)))
363 (test-assert "hpcguix-web running"
366 (use-modules (gnu services herd))
367 (match (start-service 'hpcguix-web)
369 (('service response-parts ...)
370 (match (assq-ref response-parts 'running)
371 ((pid) (number? pid))))))
374 (test-equal "http-get"
377 (wait-for-tcp-port 5000 marionette)
378 (let-values (((response text)
379 (http-get "http://localhost:8080")))
380 (response-code response))))
383 (exit (= (test-runner-fail-count (test-runner-current)) 0)))))
385 (gexp->derivation (string-append name "-test") test))
387 (define %hpcguix-web-specs
388 ;; Server config gexp.
389 #~(define site-config
390 (hpcweb-configuration
391 (title-prefix "[TEST] HPCGUIX-WEB"))))
393 (define %hpcguix-web-os
394 (simple-operating-system
395 (dhcp-client-service)
396 (service hpcguix-web-service-type
397 (hpcguix-web-configuration
398 (specs %hpcguix-web-specs)))))
400 (define %test-hpcguix-web
403 (description "Connect to a running hpcguix-web server.")
404 (value (run-hpcguix-web-server-test name %hpcguix-web-os))))
408 ;; Operating system under test.
409 (simple-operating-system
410 (dhcp-client-service)
411 (service tailon-service-type
412 (tailon-configuration
414 (tailon-configuration-file
415 (bind "0.0.0.0:8080")))))))
417 (define* (run-tailon-test #:optional (http-port 8081))
418 "Run tests in %TAILON-OS, which has tailon running and listening on
421 (marionette-operating-system
423 #:imported-modules '((gnu services herd)
424 (guix combinators))))
428 (operating-system os)
429 (port-forwardings `((,http-port . 8080)))))
432 (with-imported-modules '((gnu build marionette))
434 (use-modules (srfi srfi-11) (srfi srfi-64)
436 (gnu build marionette)
442 ;; Forward the guest's HTTP-PORT, where tailon is listening, to
443 ;; port 8080 in the host.
444 (make-marionette (list #$vm)))
449 (test-begin "tailon")
451 (test-assert "service running"
454 (use-modules (gnu services herd))
455 (start-service 'tailon))
458 (define* (retry-on-error f #:key times delay)
459 (let loop ((attempt 1))
471 (if (>= attempt times)
475 (loop (+ 1 attempt))))))))
477 (test-equal "http-get"
481 (let-values (((response text)
484 "http://localhost:~A/"
487 (response-code response)))
492 (exit (= (test-runner-fail-count (test-runner-current)) 0)))))
494 (gexp->derivation "tailon-test" test))
499 (description "Connect to a running Tailon server.")
500 (value (run-tailon-test))))