diff options
| -rw-r--r-- | guix/tests/http.scm | 133 | ||||
| -rw-r--r-- | tests/derivations.scm | 8 | ||||
| -rw-r--r-- | tests/lint.scm | 14 |
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 | ||
| 43 | that tests can check whether we succeeded opening the socket and tests skip if | ||
| 44 | needed." | ||
| 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. | 75 | string) 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 | ||
| 98 | string) 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 |
