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)