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>
7 ;;; This file is part of GNU Guix.
9 ;;; GNU Guix is free software; you can redistribute it and/or modify it
10 ;;; under the terms of the GNU General Public License as published by
11 ;;; the Free Software Foundation; either version 3 of the License, or (at
12 ;;; your option) any later version.
14 ;;; GNU Guix is distributed in the hope that it will be useful, but
15 ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 ;;; GNU General Public License for more details.
19 ;;; You should have received a copy of the GNU General Public License
20 ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
22 (define-module (gnu tests web)
23 #:use-module (gnu tests)
24 #:use-module (gnu system)
25 #:use-module (gnu system file-systems)
26 #:use-module (gnu system shadow)
27 #:use-module (gnu system vm)
28 #:use-module (gnu services)
29 #:use-module (gnu services web)
30 #:use-module (gnu services networking)
31 #:use-module (guix gexp)
32 #:use-module (guix store)
40 (define %index.html-contents
41 ;; Contents of the /index.html file.
44 (define %make-http-root
45 ;; Create our server root in /srv.
49 (call-with-output-file "/srv/http/index.html"
51 (display #$%index.html-contents port)))))
53 (define* (run-webserver-test name test-os #:key (log-file #f) (http-port 8080))
54 "Run tests in %NGINX-OS, which has nginx running and listening on
57 (marionette-operating-system
59 #:imported-modules '((gnu services herd)
62 (define forwarded-port 8080)
67 (port-forwardings `((,http-port . ,forwarded-port)))))
70 (with-imported-modules '((gnu build marionette))
72 (use-modules (srfi srfi-11) (srfi srfi-64)
73 (gnu build marionette)
79 (make-marionette (list #$vm)))
86 (test-assert #$(string-append name " service running")
89 (use-modules (gnu services herd))
90 (match (start-service '#$(string->symbol name))
92 (('service response-parts ...)
93 (match (assq-ref response-parts 'running)
95 ((pid) (number? pid))))))
98 ;; Retrieve the index.html file we put in /srv.
99 (test-equal "http-get"
100 '(200 #$%index.html-contents)
103 (http-get #$(simple-format
104 #f "http://localhost:~A/index.html" forwarded-port)
106 (list (response-code response) text)))
109 `((test-assert ,(string-append "log file exists " log-file)
111 '(file-exists? ,log-file)
116 (exit (= (test-runner-fail-count (test-runner-current)) 0)))))
118 (gexp->derivation (string-append name "-test") test))
126 (simple-operating-system
127 (dhcp-client-service)
128 (service httpd-service-type
132 (listen '("8080"))))))
133 (simple-service 'make-http-root activation-service-type
139 (description "Connect to a running HTTPD server.")
140 (value (run-webserver-test name %httpd-os
141 #:log-file "/var/log/httpd/error_log"))))
148 (define %nginx-servers
150 (list (nginx-server-configuration
151 (listen '("8080")))))
154 ;; Operating system under test.
155 (simple-operating-system
156 (dhcp-client-service)
157 (service nginx-service-type
159 (log-directory "/var/log/nginx")
160 (server-blocks %nginx-servers)))
161 (simple-service 'make-http-root activation-service-type
167 (description "Connect to a running NGINX server.")
168 (value (run-webserver-test name %nginx-os
169 #:log-file "/var/log/nginx/access.log"))))
180 backend dummy { .host = \"127.1.1.1\"; }
181 sub vcl_recv { return(synth(200, \"OK\")); }
183 synthetic(\"" %index.html-contents "\");
184 set resp.http.Content-Type = \"text/plain\";
189 (simple-operating-system
190 (dhcp-client-service)
191 ;; Pretend to be a web server that serves %index.html-contents.
192 (service varnish-service-type
193 (varnish-configuration
195 ;; Use a small VSL buffer to fit in the test VM.
196 (parameters '(("vsl_space" . "4M")))
198 ;; Proxy the "server" using the builtin configuration.
199 (service varnish-service-type
200 (varnish-configuration
201 (parameters '(("vsl_space" . "4M")))
202 (backend "localhost:80")
203 (listen '(":8080"))))))
205 (define %test-varnish
208 (description "Test the Varnish Cache server.")
209 (value (run-webserver-test "varnish-default" %varnish-os))))
216 (define %make-php-fpm-http-root
217 ;; Create our server root in /srv.
220 (call-with-output-file "/srv/index.php"
224 echo(\"Computed by php:\".((string)(2+3)));
227 (define %php-fpm-nginx-server-blocks
228 (list (nginx-server-configuration
231 (list (nginx-php-location)))
234 (ssl-certificate-key #f))))
237 ;; Operating system under test.
238 (simple-operating-system
239 (dhcp-client-service)
240 (service php-fpm-service-type)
241 (service nginx-service-type
243 (server-blocks %php-fpm-nginx-server-blocks)))
244 (simple-service 'make-http-root activation-service-type
245 %make-php-fpm-http-root)))
247 (define* (run-php-fpm-test #:optional (http-port 8042))
248 "Run tests in %PHP-FPM-OS, which has nginx running and listening on
249 HTTP-PORT, along with php-fpm."
251 (marionette-operating-system
253 #:imported-modules '((gnu services herd)
254 (guix combinators))))
258 (operating-system os)
259 (port-forwardings `((8080 . ,http-port)))))
262 (with-imported-modules '((gnu build marionette)
265 (use-modules (srfi srfi-11) (srfi srfi-64)
266 (gnu build marionette)
272 (make-marionette (list #$vm)))
277 (test-begin "php-fpm")
279 (test-assert "php-fpm running"
282 (use-modules (gnu services herd))
283 (match (start-service 'php-fpm)
285 (('service response-parts ...)
286 (match (assq-ref response-parts 'running)
287 ((pid) (number? pid))))))
290 (test-assert "nginx running"
293 (use-modules (gnu services herd))
294 (start-service 'nginx))
297 (test-equal "http-get"
299 (let-values (((response text)
300 (http-get "http://localhost:8080/index.php"
302 (response-code response)))
304 (test-equal "php computed result is sent"
306 (let-values (((response text)
307 (http-get "http://localhost:8080/index.php"
310 (use-modules (ice-9 regex))
311 (let ((matches (string-match "Computed by php:5" text)))
313 (match:substring matches 0))))))
317 (exit (= (test-runner-fail-count (test-runner-current)) 0)))))
319 (gexp->derivation "php-fpm-test" test))
321 (define %test-php-fpm
324 (description "Test PHP-FPM through nginx.")
325 (value (run-php-fpm-test))))
332 (define* (run-hpcguix-web-server-test name test-os)
333 "Run tests in %HPCGUIX-WEB-OS, which has hpcguix-web running."
335 (marionette-operating-system
337 #:imported-modules '((gnu services herd)
338 (guix combinators))))
342 (operating-system os)
343 (port-forwardings '((8080 . 5000)))))
346 (with-imported-modules '((gnu build marionette))
348 (use-modules (srfi srfi-11) (srfi srfi-64)
349 (gnu build marionette)
355 (make-marionette (list #$vm)))
362 (test-assert "hpcguix-web running"
365 (use-modules (gnu services herd))
366 (match (start-service 'hpcguix-web)
368 (('service response-parts ...)
369 (match (assq-ref response-parts 'running)
370 ((pid) (number? pid))))))
373 (test-equal "http-get"
376 (wait-for-tcp-port 5000 marionette)
377 (let-values (((response text)
378 (http-get "http://localhost:8080")))
379 (response-code response))))
382 (exit (= (test-runner-fail-count (test-runner-current)) 0)))))
384 (gexp->derivation (string-append name "-test") test))
386 (define %hpcguix-web-specs
387 ;; Server config gexp.
388 #~(define site-config
389 (hpcweb-configuration
390 (title-prefix "[TEST] HPCGUIX-WEB"))))
392 (define %hpcguix-web-os
393 (simple-operating-system
394 (dhcp-client-service)
395 (service hpcguix-web-service-type
396 (hpcguix-web-configuration
397 (specs %hpcguix-web-specs)))))
399 (define %test-hpcguix-web
402 (description "Connect to a running hpcguix-web server.")
403 (value (run-hpcguix-web-server-test name %hpcguix-web-os))))
407 ;; Operating system under test.
408 (simple-operating-system
409 (dhcp-client-service)
410 (service tailon-service-type
411 (tailon-configuration
413 (tailon-configuration-file
414 (bind "0.0.0.0:8080")))))))
416 (define* (run-tailon-test #:optional (http-port 8081))
417 "Run tests in %TAILON-OS, which has tailon running and listening on
420 (marionette-operating-system
422 #:imported-modules '((gnu services herd)
423 (guix combinators))))
427 (operating-system os)
428 (port-forwardings `((,http-port . 8080)))))
431 (with-imported-modules '((gnu build marionette))
433 (use-modules (srfi srfi-11) (srfi srfi-64)
435 (gnu build marionette)
441 ;; Forward the guest's HTTP-PORT, where tailon is listening, to
442 ;; port 8080 in the host.
443 (make-marionette (list #$vm)))
448 (test-begin "tailon")
450 (test-assert "service running"
453 (use-modules (gnu services herd))
454 (start-service 'tailon))
457 (define* (retry-on-error f #:key times delay)
458 (let loop ((attempt 1))
470 (if (>= attempt times)
474 (loop (+ 1 attempt))))))))
476 (test-equal "http-get"
480 (let-values (((response text)
483 "http://localhost:~A/"
486 (response-code response)))
491 (exit (= (test-runner-fail-count (test-runner-current)) 0)))))
493 (gexp->derivation "tailon-test" test))
498 (description "Connect to a running Tailon server.")
499 (value (run-tailon-test))))