diff options
| author | Ludovic Courtès <ludo@gnu.org> | 2016-11-16 16:34:17 +0100 |
|---|---|---|
| committer | Ludovic Courtès <ludo@gnu.org> | 2016-11-16 18:00:41 +0100 |
| commit | 17ab08bcf0ae27ec6a1f07766080ebfbea8837d9 (patch) | |
| tree | ac1b89effc9cd567fbeeb6f04d515628c7001465 | |
| parent | 1bcc87bb685b7985512add221f10e4cb58b5f6f7 (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.am | 8 | ||||
| -rw-r--r-- | guix/tests/http.scm | 120 | ||||
| -rw-r--r-- | tests/lint.scm | 114 |
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 | ||
| 172 | endif BUILD_DAEMON_OFFLOAD | 172 | endif BUILD_DAEMON_OFFLOAD |
| 173 | 173 | ||
| 174 | # Internal module with test suite support. | 174 | # Internal modules with test suite support. |
| 175 | dist_noinst_DATA = guix/tests.scm | 175 | dist_noinst_DATA = guix/tests.scm guix/tests/http.scm |
| 176 | 176 | ||
| 177 | # Linux-Libre configurations. | 177 | # Linux-Libre configurations. |
| 178 | KCONFIGS = \ | 178 | KCONFIGS = \ |
| @@ -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 | ||
| 192 | GOBJECTS = $(MODULES:%.scm=%.go) guix/config.go guix/tests.go | 192 | GOBJECTS = $(MODULES:%.scm=%.go) guix/config.go $(dist_noinst_DATA:%.scm=%.go) |
| 193 | 193 | ||
| 194 | nobase_dist_guilemodule_DATA = \ | 194 | nobase_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 ; @: |
| 410 | make-go: $(MODULES) guix/config.scm guix/tests.scm | 410 | make-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 | ||
| 98 | string) 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 | ||
| 109 | string) 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"))) |
