summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--guix/tests/http.scm133
-rw-r--r--tests/derivations.scm8
-rw-r--r--tests/lint.scm14
3 files changed, 85 insertions, 70 deletions
diff --git a/guix/tests/http.scm b/guix/tests/http.scm
index fe1e120c5d2..a56d6f213d6 100644
--- a/guix/tests/http.scm
+++ b/guix/tests/http.scm
@@ -1,5 +1,5 @@
1;;; GNU Guix --- Functional package management for GNU 1;;; GNU Guix --- Functional package management for GNU
2;;; Copyright © 2014, 2015, 2016 Ludovic Courtès <ludo@gnu.org> 2;;; Copyright © 2014, 2015, 2016, 2017 Ludovic Courtès <ludo@gnu.org>
3;;; 3;;;
4;;; This file is part of GNU Guix. 4;;; This file is part of GNU Guix.
5;;; 5;;;
@@ -25,7 +25,7 @@
25 #:export (with-http-server 25 #:export (with-http-server
26 call-with-http-server 26 call-with-http-server
27 %http-server-port 27 %http-server-port
28 %http-server-socket 28 http-server-can-listen?
29 %local-url)) 29 %local-url))
30 30
31;;; Commentary: 31;;; Commentary:
@@ -38,75 +38,85 @@
38 ;; TCP port to use for the stub HTTP server. 38 ;; TCP port to use for the stub HTTP server.
39 (make-parameter 9999)) 39 (make-parameter 9999))
40 40
41(define (open-http-server-socket)
42 "Return a listening socket for the web server. It is useful to export it so
43that tests can check whether we succeeded opening the socket and tests skip if
44needed."
45 (catch 'system-error
46 (lambda ()
47 (let ((sock (socket PF_INET SOCK_STREAM 0)))
48 (setsockopt sock SOL_SOCKET SO_REUSEADDR 1)
49 (bind sock
50 (make-socket-address AF_INET INADDR_LOOPBACK
51 (%http-server-port)))
52 sock))
53 (lambda args
54 (let ((err (system-error-errno args)))
55 (format (current-error-port)
56 "warning: cannot run Web server for tests: ~a~%"
57 (strerror err))
58 #f))))
59
60(define (http-server-can-listen?)
61 "Return #t if we managed to open a listening socket."
62 (and=> (open-http-server-socket)
63 (lambda (socket)
64 (close-port socket)
65 #t)))
66
41(define (%local-url) 67(define (%local-url)
42 ;; URL to use for 'home-page' tests. 68 ;; URL to use for 'home-page' tests.
43 (string-append "http://localhost:" (number->string (%http-server-port)) 69 (string-append "http://localhost:" (number->string (%http-server-port))
44 "/foo/bar")) 70 "/foo/bar"))
45 71
46(define %http-server-socket 72(define* (call-with-http-server code data thunk
47 ;; Listening socket for the web server. It is useful to export it so that 73 #:key (headers '()))
48 ;; tests can check whether we succeeded opening the socket and tests skip if 74 "Call THUNK with an HTTP server running and returning CODE and DATA (a
49 ;; needed. 75string) on HTTP requests."
50 (delay 76 (define (http-write server client response body)
51 (catch 'system-error 77 "Write RESPONSE."
52 (lambda () 78 (let* ((response (write-response response client))
53 (let ((sock (socket PF_INET SOCK_STREAM 0))) 79 (port (response-port response)))
54 (setsockopt sock SOL_SOCKET SO_REUSEADDR 1) 80 (cond
55 (bind sock 81 ((not body)) ;pass
56 (make-socket-address AF_INET INADDR_LOOPBACK 82 (else
57 (%http-server-port))) 83 (write-response-body response body)))
58 sock)) 84 (close-port port)
59 (lambda args 85 (quit #t) ;exit the server thread
60 (let ((err (system-error-errno args))) 86 (values)))
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 87
78;; Mutex and condition variable to synchronize with the HTTP server. 88 ;; Mutex and condition variable to synchronize with the HTTP server.
79(define %http-server-lock (make-mutex)) 89 (define %http-server-lock (make-mutex))
80(define %http-server-ready (make-condition-variable)) 90 (define %http-server-ready (make-condition-variable))
81 91
82(define (http-open . args) 92 (define (http-open . args)
83 "Start listening for HTTP requests and signal %HTTP-SERVER-READY." 93 "Start listening for HTTP requests and signal %HTTP-SERVER-READY."
84 (with-mutex %http-server-lock 94 (with-mutex %http-server-lock
85 (let ((result (apply (@@ (web server http) http-open) args))) 95 (let ((result (apply (@@ (web server http) http-open) args)))
86 (signal-condition-variable %http-server-ready) 96 (signal-condition-variable %http-server-ready)
87 result))) 97 result)))
88 98
89(define-server-impl stub-http-server 99 (define-server-impl stub-http-server
90 ;; Stripped-down version of Guile's built-in HTTP server. 100 ;; Stripped-down version of Guile's built-in HTTP server.
91 http-open 101 http-open
92 (@@ (web server http) http-read) 102 (@@ (web server http) http-read)
93 http-write 103 http-write
94 (@@ (web server http) http-close)) 104 (@@ (web server http) http-close))
95 105
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) 106 (define (server-body)
100 (define (handle request body) 107 (define (handle request body)
101 (values (build-response #:code code 108 (values (build-response #:code code
102 #:reason-phrase "Such is life") 109 #:reason-phrase "Such is life"
110 #:headers headers)
103 data)) 111 data))
104 112
105 (catch 'quit 113 (let ((socket (open-http-server-socket)))
106 (lambda () 114 (catch 'quit
107 (run-server handle stub-http-server 115 (lambda ()
108 `(#:socket ,(force %http-server-socket)))) 116 (run-server handle stub-http-server
109 (const #t))) 117 `(#:socket ,socket)))
118 (lambda _
119 (close-port socket)))))
110 120
111 (with-mutex %http-server-lock 121 (with-mutex %http-server-lock
112 (let ((server (make-thread server-body))) 122 (let ((server (make-thread server-body)))
@@ -114,7 +124,12 @@ string) on HTTP requests."
114 ;; Normally SERVER exits automatically once it has received a request. 124 ;; Normally SERVER exits automatically once it has received a request.
115 (thunk)))) 125 (thunk))))
116 126
117(define-syntax-rule (with-http-server code data body ...) 127(define-syntax with-http-server
118 (call-with-http-server code data (lambda () body ...))) 128 (syntax-rules ()
129 ((_ (code headers) data body ...)
130 (call-with-http-server code data (lambda () body ...)
131 #:headers headers))
132 ((_ code data body ...)
133 (call-with-http-server code data (lambda () body ...)))))
119 134
120;;; http.scm ends here 135;;; http.scm ends here
diff --git a/tests/derivations.scm b/tests/derivations.scm
index f3aad1b9067..36afd42d05c 100644
--- a/tests/derivations.scm
+++ b/tests/derivations.scm
@@ -222,7 +222,7 @@
222 (build-derivations %store (list drv)) 222 (build-derivations %store (list drv))
223 #f))) 223 #f)))
224 224
225(unless (force %http-server-socket) 225(unless (http-server-can-listen?)
226 (test-skip 1)) 226 (test-skip 1))
227(test-assert "'download' built-in builder" 227(test-assert "'download' built-in builder"
228 (let ((text (random-text))) 228 (let ((text (random-text)))
@@ -238,7 +238,7 @@
238 get-string-all) 238 get-string-all)
239 text)))))) 239 text))))))
240 240
241(unless (force %http-server-socket) 241(unless (http-server-can-listen?)
242 (test-skip 1)) 242 (test-skip 1))
243(test-assert "'download' built-in builder, invalid hash" 243(test-assert "'download' built-in builder, invalid hash"
244 (with-http-server 200 "hello, world!" 244 (with-http-server 200 "hello, world!"
@@ -253,7 +253,7 @@
253 (build-derivations %store (list drv)) 253 (build-derivations %store (list drv))
254 #f)))) 254 #f))))
255 255
256(unless (force %http-server-socket) 256(unless (http-server-can-listen?)
257 (test-skip 1)) 257 (test-skip 1))
258(test-assert "'download' built-in builder, not found" 258(test-assert "'download' built-in builder, not found"
259 (with-http-server 404 "not found" 259 (with-http-server 404 "not found"
@@ -279,7 +279,7 @@
279 (build-derivations %store (list drv)) 279 (build-derivations %store (list drv))
280 #f))) 280 #f)))
281 281
282(unless (force %http-server-socket) 282(unless (http-server-can-listen?)
283 (test-skip 1)) 283 (test-skip 1))
284(test-assert "'download' built-in builder, check mode" 284(test-assert "'download' built-in builder, check mode"
285 ;; Make sure rebuilding the 'builtin:download' derivation in check mode 285 ;; Make sure rebuilding the 'builtin:download' derivation in check mode
diff --git a/tests/lint.scm b/tests/lint.scm
index 7610a91fd3b..d7254bc070d 100644
--- a/tests/lint.scm
+++ b/tests/lint.scm
@@ -388,7 +388,7 @@
388 (check-home-page pkg))) 388 (check-home-page pkg)))
389 "domain not found"))) 389 "domain not found")))
390 390
391(test-skip (if (force %http-server-socket) 0 1)) 391(test-skip (if (http-server-can-listen?) 0 1))
392(test-assert "home-page: Connection refused" 392(test-assert "home-page: Connection refused"
393 (->bool 393 (->bool
394 (string-contains 394 (string-contains
@@ -399,7 +399,7 @@
399 (check-home-page pkg))) 399 (check-home-page pkg)))
400 "Connection refused"))) 400 "Connection refused")))
401 401
402(test-skip (if (force %http-server-socket) 0 1)) 402(test-skip (if (http-server-can-listen?) 0 1))
403(test-equal "home-page: 200" 403(test-equal "home-page: 200"
404 "" 404 ""
405 (with-warnings 405 (with-warnings
@@ -409,7 +409,7 @@
409 (home-page (%local-url))))) 409 (home-page (%local-url)))))
410 (check-home-page pkg))))) 410 (check-home-page pkg)))))
411 411
412(test-skip (if (force %http-server-socket) 0 1)) 412(test-skip (if (http-server-can-listen?) 0 1))
413(test-assert "home-page: 200 but short length" 413(test-assert "home-page: 200 but short length"
414 (->bool 414 (->bool
415 (string-contains 415 (string-contains
@@ -421,7 +421,7 @@
421 (check-home-page pkg)))) 421 (check-home-page pkg))))
422 "suspiciously small"))) 422 "suspiciously small")))
423 423
424(test-skip (if (force %http-server-socket) 0 1)) 424(test-skip (if (http-server-can-listen?) 0 1))
425(test-assert "home-page: 404" 425(test-assert "home-page: 404"
426 (->bool 426 (->bool
427 (string-contains 427 (string-contains
@@ -510,7 +510,7 @@
510 (check-source-file-name pkg))) 510 (check-source-file-name pkg)))
511 "file name should contain the package name")))) 511 "file name should contain the package name"))))
512 512
513(test-skip (if (force %http-server-socket) 0 1)) 513(test-skip (if (http-server-can-listen?) 0 1))
514(test-equal "source: 200" 514(test-equal "source: 200"
515 "" 515 ""
516 (with-warnings 516 (with-warnings
@@ -523,7 +523,7 @@
523 (sha256 %null-sha256)))))) 523 (sha256 %null-sha256))))))
524 (check-source pkg))))) 524 (check-source pkg)))))
525 525
526(test-skip (if (force %http-server-socket) 0 1)) 526(test-skip (if (http-server-can-listen?) 0 1))
527(test-assert "source: 200 but short length" 527(test-assert "source: 200 but short length"
528 (->bool 528 (->bool
529 (string-contains 529 (string-contains
@@ -538,7 +538,7 @@
538 (check-source pkg)))) 538 (check-source pkg))))
539 "suspiciously small"))) 539 "suspiciously small")))
540 540
541(test-skip (if (force %http-server-socket) 0 1)) 541(test-skip (if (http-server-can-listen?) 0 1))
542(test-assert "source: 404" 542(test-assert "source: 404"
543 (->bool 543 (->bool
544 (string-contains 544 (string-contains