cl-ds / data /repos /clack /src /test.lisp
j14i's picture
3375 CL macro transformation examples from 85 libraries
43203b4 verified
(in-package :cl-user)
(defpackage clack.test
(:use :cl)
(:import-from :clack
:clackup
:stop)
(:import-from :dexador
:*use-connection-pool*)
(:import-from :rove
:testing)
(:import-from :usocket
:socket-listen
:socket-close
:address-in-use-error
:socket-error)
(:export :*clack-test-handler*
:*clack-test-port*
:*clack-test-access-port*
:*clackup-additional-args*
:*enable-debug*
:*use-https*
:*random-port*
:localhost
:testing-app))
(in-package :clack.test)
(defvar *clack-test-handler* :hunchentoot
"Backend Handler to run tests on. String or Symbol are allowed.")
(defvar *clack-test-port* 4242
"HTTP port number of Handler.")
(defvar *clackup-additional-args* '()
"Additional arguments for clackup.")
(defvar *clack-test-access-port* *clack-test-port*
"Port of localhost to request.
Use if you want to set another port. The default is `*clack-test-port*`.")
(defvar *enable-debug* t)
(defvar *use-https* nil)
(defvar *random-port* t)
(defun port-available-p (port)
(let (socket)
(unwind-protect
(handler-case (progn
(setq socket (usocket:socket-listen "127.0.0.1" port :reuse-address t))
t)
(usocket:address-in-use-error () nil)
#+(and sbcl win32)
(sb-bsd-sockets:socket-error () nil)
(usocket:socket-error (e)
(warn "USOCKET:SOCKET-ERROR: ~A" e)
nil))
(when socket
(usocket:socket-close socket)
t))))
(defun server-running-p (port)
(handler-case (let ((socket (usocket:socket-connect "127.0.0.1" port)))
(usocket:socket-close socket)
t)
#+sbcl (sb-bsd-sockets:interrupted-error () nil)
(usocket:socket-error () nil)
(usocket:connection-refused-error () nil)
(usocket:connection-reset-error () nil)))
(defun random-port ()
"Return a port number not in use from 50000 to 60000."
(loop for port from (+ 50000 (random 1000)) upto 60000
if (port-available-p port)
return port))
(defun localhost (&optional (path "/") (port *clack-test-access-port*))
(check-type path string)
(setf path
(cond
((= 0 (length path)) "/")
((not (char= (aref path 0) #\/))
(concatenate 'string "/" path))
(t path)))
(format nil "http~@[~*s~]://127.0.0.1:~D~A"
*use-https*
port path))
(defun %testing-app (app client)
(let* ((*clack-test-port* (if *random-port*
(random-port)
*clack-test-port*))
(*clack-test-access-port* (if *random-port*
*clack-test-port*
*clack-test-access-port*))
(threads #+thread-support (bt2:all-threads)
#-thread-support '()))
(loop repeat 5
until (port-available-p *clack-test-port*)
do (sleep 0.1)
finally
(unless (port-available-p *clack-test-port*)
(error "Port ~D is already in use." *clack-test-port*)))
(let ((acceptor (apply #'clackup app
:server *clack-test-handler*
:port *clack-test-port*
:debug *enable-debug*
:use-thread t
:silent t
*clackup-additional-args*))
(dex:*use-connection-pool* nil))
(loop until (server-running-p *clack-test-port*)
do (sleep 0.1))
(multiple-value-prog1
(unwind-protect (funcall client)
(stop acceptor)
;; Ensure all threads are finished for preventing from leaking
#+thread-support
(dolist (thread (bt2:all-threads))
(when (and (not (find thread threads))
(bt2:thread-alive-p thread))
(bt2:destroy-thread thread))))
(loop while (server-running-p *clack-test-port*)
do (sleep 0.1))))))
(defmacro testing-app (desc app &body body)
`(%testing-app ,app (lambda () (testing ,desc ,@body))))