Recently Written · git

clic

MIRROR ONLY Gopher client with pretty colours in Common Lisp

git clone https://github.com/equwal/clic

Log | Files | Refs


3rdparties/software/cl+ssl-20200427-git/test.lisp (12866 bytes)

1 ;;; Copyright (C) 2008  David Lichteblau
2 ;;; See LICENSE for details.
3 
4 #|
5 (load "test.lisp")
6 |#
7 
8 (defpackage :ssl-test
9   (:use :cl))
10 (in-package :ssl-test)
11 
12 (defvar *port* 8080)
13 (defvar *cert* "/home/david/newcert.pem")
14 (defvar *key* "/home/david/newkey.pem")
15 
16 (eval-when (:compile-toplevel :load-toplevel :execute)
17   (asdf:operate 'asdf:load-op :trivial-sockets)
18   (asdf:operate 'asdf:load-op :bordeaux-threads))
19 
20 (defparameter *tests* '())
21 
22 (defvar *sockets* '())
23 (defvar *sockets-lock* (bordeaux-threads:make-lock))
24 
25 (defun record-socket (socket)
26   (unless (integerp socket)
27     (bordeaux-threads:with-lock-held (*sockets-lock*)
28       (push socket *sockets*)))
29   socket)
30 
31 (defun close-socket (socket &key abort)
32   (if (streamp socket)
33       (close socket :abort abort)
34       (trivial-sockets:close-server socket)))
35 
36 (defun check-sockets ()
37   (let ((failures nil))
38     (bordeaux-threads:with-lock-held (*sockets-lock*)
39       (dolist (socket *sockets*)
40   (when (close-socket socket :abort t)
41     (push socket failures)))
42       (setf *sockets* nil))
43     #-sbcl        ;fixme
44     (when failures
45       (error "failed to close sockets properly:~{  ~A~%~}" failures))))
46 
47 (defmacro deftest (name &body body)
48   `(progn
49      (defun ,name ()
50        (format t "~%----- ~A ----------------------------~%" ',name)
51        (handler-case
52      (progn
53        ,@body
54        (check-sockets)
55        (format t "===== [OK] ~A ====================~%" ',name)
56        t)
57    (error (c)
58      (when (typep c 'trivial-sockets:socket-error)
59        (setf c (trivial-sockets:socket-nested-error c)))
60      (format t "~%===== [FAIL] ~A: ~A~%" ',name c)
61      (handler-case
62          (check-sockets)
63        (error (c)
64          (format t "muffling follow-up error ~A~%" c)))
65      nil)))
66      (push ',name *tests*)))
67 
68 (defun run-all-tests ()
69   (unless (probe-file *cert*) (error "~A not found" *cert*))
70   (unless (probe-file *key*) (error "~A not found" *key*))
71   (let ((n 0)
72   (nok 0))
73     (dolist (test (reverse *tests*))
74       (when (funcall test)
75   (incf nok))
76       (incf n))
77     (format t "~&passed ~D/~D tests~%" nok n)))
78 
79 (define-condition quit (condition)
80   ())
81 
82 (defparameter *please-quit* t)
83 
84 (defun make-test-thread (name init main &rest args)
85   "Start a thread named NAME, wait until it has funcalled INIT with ARGS
86    as arguments, then continue while the thread concurrently funcalls MAIN
87    with INIT's return values as arguments."
88   (let ((cv (bordeaux-threads:make-condition-variable))
89   (lock (bordeaux-threads:make-lock name))
90   ;; redirect io manually, because swan's global redirection isn't as
91   ;; global as one might hope
92   (out *terminal-io*)
93   (init-ok nil))
94     (bordeaux-threads:with-lock-held (lock)
95       (setf *please-quit* nil)
96       (prog1
97     (bordeaux-threads:make-thread
98      (lambda ()
99        (flet ((notify ()
100           (bordeaux-threads:with-lock-held (lock)
101       (bordeaux-threads:condition-notify cv))))
102          (let ((*terminal-io* out)
103          (*standard-output* out)
104          (*trace-output* out)
105          (*error-output* out))
106      (handler-case
107          (let ((values (multiple-value-list (apply init args))))
108            (setf init-ok t)
109            (notify)
110            (apply main values))
111        (quit ()
112          (notify)
113          t)
114        (error (c)
115          (when (typep c 'trivial-sockets:socket-error)
116            (setf c (trivial-sockets:socket-nested-error c)))
117          (format t "aborting test thread ~A: ~A" name c)
118          (notify)
119          nil)))))
120      :name name)
121   (bordeaux-threads:condition-wait cv lock)
122   (unless init-ok
123     (error "failed to start background thread"))))))
124 
125 (defmacro with-thread ((name init main &rest args) &body body)
126   `(invoke-with-thread (lambda () ,@body)
127            ,name
128            ,init
129            ,main
130            ,@args))
131 
132 (defun invoke-with-thread (body name init main &rest args)
133   (let ((thread (apply #'make-test-thread name init main args)))
134     (unwind-protect
135    (funcall body)
136       (setf *please-quit* t)
137       (loop
138    for delay = 0.0001 then (* delay 2)
139    while (and (< delay 0.5) (bordeaux-threads:thread-alive-p thread))
140    do
141      (sleep delay))
142       (when (bordeaux-threads:thread-alive-p thread)
143   (format t "~&thread doesn't want to quit, killing it~%")
144   (force-output)
145   (bordeaux-threads:interrupt-thread thread (lambda () (error 'quit)))
146   (loop
147      for delay = 0.0001 then (* delay 2)
148      while (bordeaux-threads:thread-alive-p thread)
149      do
150      (sleep delay))))))
151 
152 (defun init-server (&key (unwrap-stream-p t))
153   (format t "~&SSL server listening on port ~d~%" *port*)
154   (values (record-socket (trivial-sockets:open-server :port *port*))
155     unwrap-stream-p))
156 
157 (defun test-server (listening-socket unwrap-stream-p)
158   (format t "~&SSL server accepting...~%")
159   (unwind-protect
160        (let* ((socket (record-socket
161            (trivial-sockets:accept-connection
162       listening-socket
163       :element-type '(unsigned-byte 8))))
164         (callback nil))
165    (when (eq unwrap-stream-p :caller)
166      (setf callback (let ((s socket)) (lambda () (close-socket s))))
167      (setf socket (cl+ssl:stream-fd socket))
168      (setf unwrap-stream-p nil))
169    (let ((client (record-socket
170       (cl+ssl:make-ssl-server-stream
171        socket
172        :unwrap-stream-p unwrap-stream-p
173        :close-callback callback
174        :external-format :iso-8859-1
175        :certificate *cert*
176        :key *key*))))
177      (unwind-protect
178     (loop
179        for line = (prog2
180           (when *please-quit* (return))
181           (read-line client nil)
182         (when *please-quit* (return)))
183        while line
184        do
185          (cond
186            ((equal line "freeze")
187       (format t "~&Freezing on client request~%")
188       (loop
189          (sleep 1)
190          (when *please-quit* (return))))
191            (t
192       (format t "~&Responding to query ~A...~%" line)
193       (format client "(echo ~A)~%" line)
194       (force-output client))))
195        (close-socket client))))
196     (close-socket listening-socket)))
197 
198 (defun init-client (&key (unwrap-stream-p t))
199   (let ((socket (record-socket
200      (trivial-sockets:open-stream
201       "127.0.0.1"
202       *port*
203       :element-type '(unsigned-byte 8))))
204   (callback nil))
205     (when (eq unwrap-stream-p :caller)
206       (setf callback (let ((s socket)) (lambda () (close-socket s))))
207       (setf socket (cl+ssl:stream-fd socket))
208       (setf unwrap-stream-p nil))
209     (cl+ssl:make-ssl-client-stream
210      socket
211      :unwrap-stream-p unwrap-stream-p
212      :close-callback callback
213      :external-format :iso-8859-1)))
214 
215 ;; CCL requires specifying the
216 ;; deadline at the socket cration (
217 ;; in constrast to SBCL which has
218 ;; the WITH-TIMEOUT macro).
219 ;;
220 ;; Therefore a separate INIT-CLIENT
221 ;; function is needed for CCL when
222 ;; we need read/write deadlines on
223 ;; the SSL client stream.
224 #+clozure-common-lisp
225 (defun ccl-init-client-with-deadline (&key (unwrap-stream-p t)
226               seconds)
227   (let* ((deadline
228     (+ (get-internal-real-time)
229        (* seconds internal-time-units-per-second)))
230    (low
231     (record-socket
232      (ccl:make-socket
233       :address-family :internet
234       :connect :active
235       :type :stream
236       :remote-host "127.0.0.1"
237       :remote-port *port*
238       :deadline deadline))))
239     (cl+ssl:make-ssl-client-stream
240      low
241      :unwrap-stream-p unwrap-stream-p
242      :external-format :iso-8859-1)))
243 
244 ;;; Simple echo-server test.  Write a line and check that the result
245 ;;; watches, three times in a row.
246 (deftest echo
247   (with-thread ("simple server" #'init-server #'test-server)
248     (with-open-stream (socket (init-client))
249       (write-line "test" socket)
250       (force-output socket)
251       (assert (equal (read-line socket) "(echo test)"))
252       (write-line "test2" socket)
253       (force-output socket)
254       (assert (equal (read-line socket) "(echo test2)"))
255       (write-line "test3" socket)
256       (force-output socket)
257       (assert (equal (read-line socket) "(echo test3)")))))
258 
259 ;;; Run tests with different BIO setup strategies:
260 ;;;   - :UNWRAP-STREAMS T
261 ;;;     In this case, CL+SSL will convert the socket to a file descriptor.
262 ;;;   - :UNWRAP-STREAMS :CLIENT
263 ;;;     Convert the socket to a file descriptor manually, and give that
264 ;;;     to CL+SSL.
265 ;;;   - :UNWRAP-STREAMS NIL
266 ;;;     Let CL+SSL write to the stream directly, using the Lisp BIO.
267 (macrolet ((deftests (name (var &rest values) &body body)
268        `(progn
269     ,@(loop
270          for value in values
271          collect
272          `(deftest ,(intern (format nil "~A-~A" name value))
273       (let ((,var ',value))
274         ,@body))))))
275 
276   (deftests unwrap-strategy (usp nil t :caller)
277     (with-thread ("echo server for strategy test"
278       (lambda () (init-server :unwrap-stream-p usp))
279       #'test-server)
280       (with-open-stream (socket (init-client :unwrap-stream-p usp))
281   (write-line "test" socket)
282   (force-output socket)
283   (assert (equal (read-line socket) "(echo test)")))))
284 
285   #+clozure-common-lisp
286   (deftests read-deadline (usp nil t :caller)
287     (with-thread ("echo server for deadline test"
288       (lambda () (init-server :unwrap-stream-p usp))
289       #'test-server)
290       (with-open-stream
291     (socket
292      (ccl-init-client-with-deadline
293       :unwrap-stream-p usp
294       :seconds 3))
295   (write-line "test" socket)
296   (force-output socket)
297   (assert (equal (read-line socket) "(echo test)"))
298   (handler-case
299       (progn
300         (read-char socket)
301         (error "unexpected data"))
302     (ccl::communication-deadline-expired ())))))
303 
304   #+sbcl
305   (deftests read-deadline (usp nil t :caller)
306     (with-thread ("echo server for deadline test"
307       (lambda () (init-server :unwrap-stream-p usp))
308       #'test-server)
309       (sb-sys:with-deadline (:seconds 3)
310   (with-open-stream (socket (init-client :unwrap-stream-p usp))
311     (write-line "test" socket)
312     (force-output socket)
313     (assert (equal (read-line socket) "(echo test)"))
314     (handler-case
315         (progn
316     (read-char socket)
317     (error "unexpected data"))
318       (sb-sys:deadline-timeout ()))))))
319 
320   #+clozure-common-lisp
321   (deftests write-deadline (usp nil t)
322     (with-thread ("echo server for deadline test"
323       (lambda () (init-server :unwrap-stream-p usp))
324       #'test-server)
325       (with-open-stream
326     (socket
327      (ccl-init-client-with-deadline
328       :unwrap-stream-p usp
329       :seconds 3))
330       (unwind-protect
331      (progn
332        (write-line "test" socket)
333        (force-output socket)
334        (assert (equal (read-line socket) "(echo test)"))
335        (write-line "freeze" socket)
336        (force-output socket)
337        (let ((n 0))
338          (handler-case
339        (loop
340           (write-line "deadbeef" socket)
341           (incf n))
342      (ccl::communication-deadline-expired ()))
343          ;; should have written a couple of lines before the deadline:
344          (assert (> n 100))))
345   (handler-case
346       (close-socket socket :abort t)
347     (ccl::communication-deadline-expired ()))))))
348 
349   #+sbcl
350   (deftests write-deadline (usp nil t)
351     (with-thread ("echo server for deadline test"
352       (lambda () (init-server :unwrap-stream-p usp))
353       #'test-server)
354       (with-open-stream (socket (init-client :unwrap-stream-p usp))
355   (unwind-protect
356        (sb-sys:with-deadline (:seconds 3)
357          (write-line "test" socket)
358          (force-output socket)
359          (assert (equal (read-line socket) "(echo test)"))
360          (write-line "freeze" socket)
361          (force-output socket)
362          (let ((n 0))
363      (handler-case
364          (loop
365       (write-line "deadbeef" socket)
366       (incf n))
367        (sb-sys:deadline-timeout ()))
368      ;; should have written a couple of lines before the deadline:
369      (assert (> n 100))))
370     (handler-case
371         (close-socket socket :abort t)
372       (sb-sys:deadline-timeout ()))))))
373 
374   #+clozure-common-lisp
375   (deftests read-char-no-hang/test (usp nil t :caller)
376     (with-thread ("echo server for read-char-no-hang test"
377       (lambda () (init-server :unwrap-stream-p usp))
378       #'test-server)
379       (with-open-stream
380     (socket (ccl-init-client-with-deadline
381        :unwrap-stream-p usp
382        :seconds 3))
383   (write-line "test" socket)
384   (force-output socket)
385   (assert (equal (read-line socket) "(echo test)"))
386   (handler-case
387       (when (read-char-no-hang socket)
388         (error "unexpected data"))
389     (ccl::communication-deadline-expired ()
390       (error "read-char-no-hang hangs"))))))
391 
392   #+sbcl
393   (deftests read-char-no-hang/test (usp nil t :caller)
394     (with-thread ("echo server for read-char-no-hang test"
395       (lambda () (init-server :unwrap-stream-p usp))
396       #'test-server)
397       (sb-sys:with-deadline (:seconds 3)
398   (with-open-stream (socket (init-client :unwrap-stream-p usp))
399     (write-line "test" socket)
400     (force-output socket)
401     (assert (equal (read-line socket) "(echo test)"))
402     (handler-case
403         (when (read-char-no-hang socket)
404     (error "unexpected data"))
405       (sb-sys:deadline-timeout ()
406         (error "read-char-no-hang hangs"))))))))
407 
408 #+(or)
409 (run-all-tests)