summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLudovic Courtès <ludo@gnu.org>2016-11-16 16:34:17 +0100
committerLudovic Courtès <ludo@gnu.org>2016-11-16 18:00:41 +0100
commit17ab08bcf0ae27ec6a1f07766080ebfbea8837d9 (patch)
treeac1b89effc9cd567fbeeb6f04d515628c7001465
parent1bcc87bb685b7985512add221f10e4cb58b5f6f7 (diff)
tests: Move HTTP server to (guix tests http).
* tests/lint.scm (%http-server-port, %local-url) (%http-server-socket, http-write, %http-server-lock) (%http-server-ready, http-open, stub-http-server) (call-with-http-server, with-http-server): Move to (guix tests http). Adjust tests for %HTTP-SERVER-SOCKET as a promise and %LOCAL-URL as a parameter. * guix/tests/http.scm: New file. * Makefile.am (dist_noinst_DATA): Add it. (GOBJECTS): Add .go files for all of $(dist_noinst_DATA). (make-go): Depend on $(dist_noinst_DATA).
-rw-r--r--Makefile.am8
-rw-r--r--guix/tests/http.scm120
-rw-r--r--tests/lint.scm114
3 files changed, 141 insertions, 101 deletions
diff --git a/Makefile.am b/Makefile.am
index 908eaf6ec0d..5d3639747f2 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -171,8 +171,8 @@ MODULES += \
171 171
172endif BUILD_DAEMON_OFFLOAD 172endif BUILD_DAEMON_OFFLOAD
173 173
174# Internal module with test suite support. 174# Internal modules with test suite support.
175dist_noinst_DATA = guix/tests.scm 175dist_noinst_DATA = guix/tests.scm guix/tests/http.scm
176 176
177# Linux-Libre configurations. 177# Linux-Libre configurations.
178KCONFIGS = \ 178KCONFIGS = \
@@ -189,7 +189,7 @@ EXAMPLES = \
189 gnu/system/examples/desktop.tmpl \ 189 gnu/system/examples/desktop.tmpl \
190 gnu/system/examples/lightweight-desktop.tmpl 190 gnu/system/examples/lightweight-desktop.tmpl
191 191
192GOBJECTS = $(MODULES:%.scm=%.go) guix/config.go guix/tests.go 192GOBJECTS = $(MODULES:%.scm=%.go) guix/config.go $(dist_noinst_DATA:%.scm=%.go)
193 193
194nobase_dist_guilemodule_DATA = \ 194nobase_dist_guilemodule_DATA = \
195 $(MODULES) $(KCONFIGS) $(EXAMPLES) \ 195 $(MODULES) $(KCONFIGS) $(EXAMPLES) \
@@ -407,7 +407,7 @@ CLEANFILES = \
407# the whole thing. Likewise, set 'XDG_CACHE_HOME' to avoid loading possibly 407# the whole thing. Likewise, set 'XDG_CACHE_HOME' to avoid loading possibly
408# stale files from ~/.cache/guile/ccache. 408# stale files from ~/.cache/guile/ccache.
409%.go: make-go ; @: 409%.go: make-go ; @:
410make-go: $(MODULES) guix/config.scm guix/tests.scm 410make-go: $(MODULES) guix/config.scm $(dist_noinst_DATA)
411 $(AM_V_at)echo "Compiling Scheme modules..." ; \ 411 $(AM_V_at)echo "Compiling Scheme modules..." ; \
412 unset GUILE_LOAD_COMPILED_PATH ; \ 412 unset GUILE_LOAD_COMPILED_PATH ; \
413 XDG_CACHE_HOME=/nowhere \ 413 XDG_CACHE_HOME=/nowhere \
diff --git a/guix/tests/http.scm b/guix/tests/http.scm
new file mode 100644
index 00000000000..fe1e120c5d2
--- /dev/null
+++ b/guix/tests/http.scm
@@ -0,0 +1,120 @@
1;;; GNU Guix --- Functional package management for GNU
2;;; Copyright © 2014, 2015, 2016 Ludovic Courtès <ludo@gnu.org>
3;;;
4;;; This file is part of GNU Guix.
5;;;
6;;; GNU Guix is free software; you can redistribute it and/or modify it
7;;; under the terms of the GNU General Public License as published by
8;;; the Free Software Foundation; either version 3 of the License, or (at
9;;; your option) any later version.
10;;;
11;;; GNU Guix is distributed in the hope that it will be useful, but
12;;; WITHOUT ANY WARRANTY; without even the implied warranty of
13;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14;;; GNU General Public License for more details.
15;;;
16;;; You should have received a copy of the GNU General Public License
17;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
18
19(define-module (guix tests http)
20 #:use-module (ice-9 threads)
21 #:use-module (web server)
22 #:use-module (web server http)
23 #:use-module (web response)
24 #:use-module (srfi srfi-39)
25 #:export (with-http-server
26 call-with-http-server
27 %http-server-port
28 %http-server-socket
29 %local-url))
30
31;;; Commentary:
32;;;
33;;; Code to spawn a Web server for testing purposes.
34;;;
35;;; Code:
36
37(define %http-server-port
38 ;; TCP port to use for the stub HTTP server.
39 (make-parameter 9999))
40
41(define (%local-url)
42 ;; URL to use for 'home-page' tests.
43 (string-append "http://localhost:" (number->string (%http-server-port))
44 "/foo/bar"))
45
46(define %http-server-socket
47 ;; Listening socket for the web server. It is useful to export it so that
48 ;; tests can check whether we succeeded opening the socket and tests skip if
49 ;; needed.
50 (delay
51 (catch 'system-error
52 (lambda ()
53 (let ((sock (socket PF_INET SOCK_STREAM 0)))
54 (setsockopt sock SOL_SOCKET SO_REUSEADDR 1)
55 (bind sock
56 (make-socket-address AF_INET INADDR_LOOPBACK
57 (%http-server-port)))
58 sock))
59 (lambda args
60 (let ((err (system-error-errno args)))
61 (format (current-error-port)
62 "warning: cannot run Web server for tests: ~a~%"
63 (strerror err))
64 #f)))))
65
66(define (http-write server client response body)
67 "Write RESPONSE."
68 (let* ((response (write-response response client))
69 (port (response-port response)))
70 (cond
71 ((not body)) ;pass
72 (else
73 (write-response-body response body)))
74 (close-port port)
75 (quit #t) ;exit the server thread
76 (values)))
77
78;; Mutex and condition variable to synchronize with the HTTP server.
79(define %http-server-lock (make-mutex))
80(define %http-server-ready (make-condition-variable))
81
82(define (http-open . args)
83 "Start listening for HTTP requests and signal %HTTP-SERVER-READY."
84 (with-mutex %http-server-lock
85 (let ((result (apply (@@ (web server http) http-open) args)))
86 (signal-condition-variable %http-server-ready)
87 result)))
88
89(define-server-impl stub-http-server
90 ;; Stripped-down version of Guile's built-in HTTP server.
91 http-open
92 (@@ (web server http) http-read)
93 http-write
94 (@@ (web server http) http-close))
95
96(define (call-with-http-server code data thunk)
97 "Call THUNK with an HTTP server running and returning CODE and DATA (a
98string) on HTTP requests."
99 (define (server-body)
100 (define (handle request body)
101 (values (build-response #:code code
102 #:reason-phrase "Such is life")
103 data))
104
105 (catch 'quit
106 (lambda ()
107 (run-server handle stub-http-server
108 `(#:socket ,(force %http-server-socket))))
109 (const #t)))
110
111 (with-mutex %http-server-lock
112 (let ((server (make-thread server-body)))
113 (wait-condition-variable %http-server-ready %http-server-lock)
114 ;; Normally SERVER exits automatically once it has received a request.
115 (thunk))))
116
117(define-syntax-rule (with-http-server code data body ...)
118 (call-with-http-server code data (lambda () body ...)))
119
120;;; http.scm ends here
diff --git a/tests/lint.scm b/tests/lint.scm
index fa2d19b2a6c..cf1b95ee69b 100644
--- a/tests/lint.scm
+++ b/tests/lint.scm
@@ -24,6 +24,7 @@
24 24
25(define-module (test-lint) 25(define-module (test-lint)
26 #:use-module (guix tests) 26 #:use-module (guix tests)
27 #:use-module (guix tests http)
27 #:use-module (guix download) 28 #:use-module (guix download)
28 #:use-module (guix git-download) 29 #:use-module (guix git-download)
29 #:use-module (guix build-system gnu) 30 #:use-module (guix build-system gnu)
@@ -33,101 +34,20 @@
33 #:use-module (gnu packages) 34 #:use-module (gnu packages)
34 #:use-module (gnu packages glib) 35 #:use-module (gnu packages glib)
35 #:use-module (gnu packages pkg-config) 36 #:use-module (gnu packages pkg-config)
36 #:use-module (web server)
37 #:use-module (web server http)
38 #:use-module (web response)
39 #:use-module (ice-9 match) 37 #:use-module (ice-9 match)
40 #:use-module (ice-9 threads)
41 #:use-module (srfi srfi-9 gnu) 38 #:use-module (srfi srfi-9 gnu)
42 #:use-module (srfi srfi-64)) 39 #:use-module (srfi srfi-64))
43 40
44;; Test the linter. 41;; Test the linter.
45 42
46(define %http-server-port 43;; Avoid collisions with other tests.
47 ;; TCP port to use for the stub HTTP server. 44(%http-server-port 9999)
48 9999)
49
50(define %local-url
51 ;; URL to use for 'home-page' tests.
52 (string-append "http://localhost:" (number->string %http-server-port)
53 "/foo/bar"))
54 45
55(define %null-sha256 46(define %null-sha256
56 ;; SHA256 of the empty string. 47 ;; SHA256 of the empty string.
57 (base32 48 (base32
58 "0mdqa9w1p6cmli6976v4wi0sw9r4p5prkj7lzfd1877wk11c9c73")) 49 "0mdqa9w1p6cmli6976v4wi0sw9r4p5prkj7lzfd1877wk11c9c73"))
59 50
60(define %http-server-socket
61 ;; Socket used by the Web server.
62 (catch 'system-error
63 (lambda ()
64 (let ((sock (socket PF_INET SOCK_STREAM 0)))
65 (setsockopt sock SOL_SOCKET SO_REUSEADDR 1)
66 (bind sock
67 (make-socket-address AF_INET INADDR_LOOPBACK
68 %http-server-port))
69 sock))
70 (lambda args
71 (let ((err (system-error-errno args)))
72 (format (current-error-port)
73 "warning: cannot run Web server for tests: ~a~%"
74 (strerror err))
75 #f))))
76
77(define (http-write server client response body)
78 "Write RESPONSE."
79 (let* ((response (write-response response client))
80 (port (response-port response)))
81 (cond
82 ((not body)) ;pass
83 (else
84 (write-response-body response body)))
85 (close-port port)
86 (quit #t) ;exit the server thread
87 (values)))
88
89;; Mutex and condition variable to synchronize with the HTTP server.
90(define %http-server-lock (make-mutex))
91(define %http-server-ready (make-condition-variable))
92
93(define (http-open . args)
94 "Start listening for HTTP requests and signal %HTTP-SERVER-READY."
95 (with-mutex %http-server-lock
96 (let ((result (apply (@@ (web server http) http-open) args)))
97 (signal-condition-variable %http-server-ready)
98 result)))
99
100(define-server-impl stub-http-server
101 ;; Stripped-down version of Guile's built-in HTTP server.
102 http-open
103 (@@ (web server http) http-read)
104 http-write
105 (@@ (web server http) http-close))
106
107(define (call-with-http-server code data thunk)
108 "Call THUNK with an HTTP server running and returning CODE and DATA (a
109string) on HTTP requests."
110 (define (server-body)
111 (define (handle request body)
112 (values (build-response #:code code
113 #:reason-phrase "Such is life")
114 data))
115
116 (catch 'quit
117 (lambda ()
118 (run-server handle stub-http-server
119 `(#:socket ,%http-server-socket)))
120 (const #t)))
121
122 (with-mutex %http-server-lock
123 (let ((server (make-thread server-body)))
124 (wait-condition-variable %http-server-ready %http-server-lock)
125 ;; Normally SERVER exits automatically once it has received a request.
126 (thunk))))
127
128(define-syntax-rule (with-http-server code data body ...)
129 (call-with-http-server code data (lambda () body ...)))
130
131(define %long-string 51(define %long-string
132 (make-string 2000 #\a)) 52 (make-string 2000 #\a))
133 53
@@ -423,28 +343,28 @@ string) on HTTP requests."
423 (check-home-page pkg))) 343 (check-home-page pkg)))
424 "domain not found"))) 344 "domain not found")))
425 345
426(test-skip (if %http-server-socket 0 1)) 346(test-skip (if (force %http-server-socket) 0 1))
427(test-assert "home-page: Connection refused" 347(test-assert "home-page: Connection refused"
428 (->bool 348 (->bool
429 (string-contains 349 (string-contains
430 (with-warnings 350 (with-warnings
431 (let ((pkg (package 351 (let ((pkg (package
432 (inherit (dummy-package "x")) 352 (inherit (dummy-package "x"))
433 (home-page %local-url)))) 353 (home-page (%local-url)))))
434 (check-home-page pkg))) 354 (check-home-page pkg)))
435 "Connection refused"))) 355 "Connection refused")))
436 356
437(test-skip (if %http-server-socket 0 1)) 357(test-skip (if (force %http-server-socket) 0 1))
438(test-equal "home-page: 200" 358(test-equal "home-page: 200"
439 "" 359 ""
440 (with-warnings 360 (with-warnings
441 (with-http-server 200 %long-string 361 (with-http-server 200 %long-string
442 (let ((pkg (package 362 (let ((pkg (package
443 (inherit (dummy-package "x")) 363 (inherit (dummy-package "x"))
444 (home-page %local-url)))) 364 (home-page (%local-url)))))
445 (check-home-page pkg))))) 365 (check-home-page pkg)))))
446 366
447(test-skip (if %http-server-socket 0 1)) 367(test-skip (if (force %http-server-socket) 0 1))
448(test-assert "home-page: 200 but short length" 368(test-assert "home-page: 200 but short length"
449 (->bool 369 (->bool
450 (string-contains 370 (string-contains
@@ -452,11 +372,11 @@ string) on HTTP requests."
452 (with-http-server 200 "This is too small." 372 (with-http-server 200 "This is too small."
453 (let ((pkg (package 373 (let ((pkg (package
454 (inherit (dummy-package "x")) 374 (inherit (dummy-package "x"))
455 (home-page %local-url)))) 375 (home-page (%local-url)))))
456 (check-home-page pkg)))) 376 (check-home-page pkg))))
457 "suspiciously small"))) 377 "suspiciously small")))
458 378
459(test-skip (if %http-server-socket 0 1)) 379(test-skip (if (force %http-server-socket) 0 1))
460(test-assert "home-page: 404" 380(test-assert "home-page: 404"
461 (->bool 381 (->bool
462 (string-contains 382 (string-contains
@@ -464,7 +384,7 @@ string) on HTTP requests."
464 (with-http-server 404 %long-string 384 (with-http-server 404 %long-string
465 (let ((pkg (package 385 (let ((pkg (package
466 (inherit (dummy-package "x")) 386 (inherit (dummy-package "x"))
467 (home-page %local-url)))) 387 (home-page (%local-url)))))
468 (check-home-page pkg)))) 388 (check-home-page pkg))))
469 "not reachable: 404"))) 389 "not reachable: 404")))
470 390
@@ -545,7 +465,7 @@ string) on HTTP requests."
545 (check-source-file-name pkg))) 465 (check-source-file-name pkg)))
546 "file name should contain the package name")))) 466 "file name should contain the package name"))))
547 467
548(test-skip (if %http-server-socket 0 1)) 468(test-skip (if (force %http-server-socket) 0 1))
549(test-equal "source: 200" 469(test-equal "source: 200"
550 "" 470 ""
551 (with-warnings 471 (with-warnings
@@ -554,11 +474,11 @@ string) on HTTP requests."
554 (inherit (dummy-package "x")) 474 (inherit (dummy-package "x"))
555 (source (origin 475 (source (origin
556 (method url-fetch) 476 (method url-fetch)
557 (uri %local-url) 477 (uri (%local-url))
558 (sha256 %null-sha256)))))) 478 (sha256 %null-sha256))))))
559 (check-source pkg))))) 479 (check-source pkg)))))
560 480
561(test-skip (if %http-server-socket 0 1)) 481(test-skip (if (force %http-server-socket) 0 1))
562(test-assert "source: 200 but short length" 482(test-assert "source: 200 but short length"
563 (->bool 483 (->bool
564 (string-contains 484 (string-contains
@@ -568,12 +488,12 @@ string) on HTTP requests."
568 (inherit (dummy-package "x")) 488 (inherit (dummy-package "x"))
569 (source (origin 489 (source (origin
570 (method url-fetch) 490 (method url-fetch)
571 (uri %local-url) 491 (uri (%local-url))
572 (sha256 %null-sha256)))))) 492 (sha256 %null-sha256))))))
573 (check-source pkg)))) 493 (check-source pkg))))
574 "suspiciously small"))) 494 "suspiciously small")))
575 495
576(test-skip (if %http-server-socket 0 1)) 496(test-skip (if (force %http-server-socket) 0 1))
577(test-assert "source: 404" 497(test-assert "source: 404"
578 (->bool 498 (->bool
579 (string-contains 499 (string-contains
@@ -583,7 +503,7 @@ string) on HTTP requests."
583 (inherit (dummy-package "x")) 503 (inherit (dummy-package "x"))
584 (source (origin 504 (source (origin
585 (method url-fetch) 505 (method url-fetch)
586 (uri %local-url) 506 (uri (%local-url))
587 (sha256 %null-sha256)))))) 507 (sha256 %null-sha256))))))
588 (check-source pkg)))) 508 (check-source pkg))))
589 "not reachable: 404"))) 509 "not reachable: 404")))