Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 310 lines (286 sloc) 14.291 kB
59697b4 @ahyatt Initial checkin of files. These files were initially part of the
authored
1 ;;; websocket-test.el --- Unit tests for the websocket layer
2
3 ;; Copyright (c) 2010 Andrew Hyatt
4 ;;
5 ;; Author: Andrew Hyatt <ahyatt at gmail dot com>
6 ;; Maintainer: Andrew Hyatt <ahyatt at gmail dot com>
7 ;;
8 ;; This program is free software; you can redistribute it and/or
9 ;; modify it under the terms of the GNU General Public License as
10 ;; published by the Free Software Foundation; either version 2 of the
11 ;; License, or (at your option) any later version.
12 ;;
13 ;; This program is distributed in the hope that it will be useful, but
14 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
15 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 ;; General Public License for more details.
17 ;;
18 ;; You should have received a copy of the GNU General Public License
19 ;; along with this program; if not, write to the Free Software
20 ;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 ;; 02110-1301, USA.
22
23 ;;; Commentary:
24 ;; This defines and runs ert unit tests. You can download ert from:
25 ;; http://github.com/ohler/ert, it also comes with Emacs 24 and above.
26
27 (require 'ert)
9d8794a @tkf Suppress compilation warning in websocket-test.el
tkf authored
28 (require 'websocket)
29 (eval-when-compile (require 'cl))
59697b4 @ahyatt Initial checkin of files. These files were initially part of the
authored
30
45245a4 @tkf Add test websocket-genbytes-length
tkf authored
31 (ert-deftest websocket-genbytes-length ()
32 (loop repeat 100
82e85aa @ahyatt Fix test for websocket-genbytes
authored
33 do (should (= (string-bytes (websocket-genbytes 16)) 16))))
45245a4 @tkf Add test websocket-genbytes-length
tkf authored
34
b5bbce1 @ahyatt Add a function to calculate the accept header expected.
authored
35 (ert-deftest websocket-calculate-accept ()
36 ;; This example comes straight from RFC 6455
37 (should
38 (equal "s3pPLMBiTxaQ9kYGzzhZRbK+xOo="
237b190 @ahyatt Various whitespace changes
authored
39 (websocket-calculate-accept "dGhlIHNhbXBsZSBub25jZQ=="))))
b5bbce1 @ahyatt Add a function to calculate the accept header expected.
authored
40
f4e1aa8 @ahyatt Add helper functions for websocket-get-opcode and
authored
41 (defconst websocket-test-hello "\x81\x05\x48\x65\x6c\x6c\x6f"
42 "'Hello' string example, taken from the RFC.")
237b190 @ahyatt Various whitespace changes
authored
43
4c8dbe2 @ahyatt Implement masking and unmasking.
authored
44 (defconst websocket-test-masked-hello
45 "\x81\x85\x37\xfa\x21\x3d\x7f\x9f\x4d\x51\x58"
46 "'Hello' masked string example, taken from the RFC.")
f4e1aa8 @ahyatt Add helper functions for websocket-get-opcode and
authored
47
b948e95 @ahyatt Fixed payload len logic, and rewrote the bit-grabbing bits to just
authored
48 (ert-deftest websocket-get-bytes ()
49 (should (equal #x5 (websocket-get-bytes "\x5" 1)))
50 (should (equal #x101 (websocket-get-bytes "\x1\x1" 2)))
51 (should (equal #x100000001
52 (websocket-get-bytes "\x0\x0\x0\x1\x0\x0\x0\x1" 8)))
53 (should-error (websocket-get-bytes "\x0\x0\x0" 3))
54 (should-error (websocket-get-bytes "\x0" 2)))
55
f4e1aa8 @ahyatt Add helper functions for websocket-get-opcode and
authored
56 (ert-deftest websocket-get-opcode ()
57 (should (equal 'text (websocket-get-opcode websocket-test-hello))))
58
59 (ert-deftest websocket-get-payload-len ()
b948e95 @ahyatt Fixed payload len logic, and rewrote the bit-grabbing bits to just
authored
60 (should (equal '(5 . 1)
61 (websocket-get-payload-len
62 (substring websocket-test-hello 1))))
f4e1aa8 @ahyatt Add helper functions for websocket-get-opcode and
authored
63 (should (equal '(200 . 3)
64 (websocket-get-payload-len
b948e95 @ahyatt Fixed payload len logic, and rewrote the bit-grabbing bits to just
authored
65 (bindat-pack '((:len u8) (:val u16))
66 `((:len . 126)
f4e1aa8 @ahyatt Add helper functions for websocket-get-opcode and
authored
67 (:val . 200))))))
68 ;; we don't want to hit up any limits even on strange emacs builds,
69 ;; so this test has a pretty small test value
70 (should (equal '(70000 . 9)
71 (websocket-get-payload-len
b948e95 @ahyatt Fixed payload len logic, and rewrote the bit-grabbing bits to just
authored
72 (bindat-pack '((:len u8) (:val vec 2 u32))
73 `((:len . 127)
f4e1aa8 @ahyatt Add helper functions for websocket-get-opcode and
authored
74 (:val . [0 70000])))))))
ae51a78 @ahyatt Code to read a frame. Does not yet support masking.
authored
75
76 (ert-deftest websocket-read-frame ()
7900cda @ahyatt Return the length of the websocket frame from websocket-read-frame.
authored
77 (should (equal (make-websocket-frame :opcode 'text :payload "Hello"
b0a2970 @ahyatt Add completep in frame
authored
78 :length (length websocket-test-hello)
79 :completep t)
4c8dbe2 @ahyatt Implement masking and unmasking.
authored
80 (websocket-read-frame websocket-test-hello)))
7900cda @ahyatt Return the length of the websocket frame from websocket-read-frame.
authored
81 (should (equal (make-websocket-frame :opcode 'text :payload "Hello"
b0a2970 @ahyatt Add completep in frame
authored
82 :length (length websocket-test-hello)
83 :completep t)
7900cda @ahyatt Return the length of the websocket frame from websocket-read-frame.
authored
84 (websocket-read-frame (concat websocket-test-hello
85 "should-not-be-read"))))
86 (should (equal (make-websocket-frame :opcode 'text :payload "Hello"
b0a2970 @ahyatt Add completep in frame
authored
87 :length (length websocket-test-masked-hello)
88 :completep t)
51b5764 @ahyatt Ensure the websocket frame is complete, and return NIL if not.
authored
89 (websocket-read-frame websocket-test-masked-hello)))
b0a2970 @ahyatt Add completep in frame
authored
90 (should (equal (make-websocket-frame :opcode 'text :payload "Hello"
91 :length (length websocket-test-hello)
92 :completep nil)
1081075 @ahyatt More whitespace changes
authored
93 (websocket-read-frame
94 (concat (unibyte-string
95 (logand (string-to-char
96 (substring websocket-test-hello 0 1))
97 127))
98 (substring websocket-test-hello 1)))))
51b5764 @ahyatt Ensure the websocket frame is complete, and return NIL if not.
authored
99 (dotimes (i (- (length websocket-test-hello) 1))
100 (should-not (websocket-read-frame
101 (substring websocket-test-hello 0
102 (- (length websocket-test-hello) (+ i 1))))))
103 (dotimes (i (- (length websocket-test-masked-hello) 1))
104 (should-not (websocket-read-frame
105 (substring websocket-test-masked-hello 0
106 (- (length websocket-test-masked-hello) (+ i 1)))))))
8da9119 @ahyatt Separate out the handshake verification logic, and test it. Look for
authored
107
108 (defun websocket-test-make-websocket-with-accept-string (s)
237b190 @ahyatt Various whitespace changes
authored
109 (make-websocket :conn "fake-conn" :url "ws://foo/bar" :filter t
110 :close-callback t :accept-string s))
8da9119 @ahyatt Separate out the handshake verification logic, and test it. Look for
authored
111
112 (ert-deftest websocket-verify-handshake ()
113 ;; This examples comes from the RFC
114 (should (websocket-verify-handshake
237b190 @ahyatt Various whitespace changes
authored
115 (websocket-test-make-websocket-with-accept-string
116 "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=")
8da9119 @ahyatt Separate out the handshake verification logic, and test it. Look for
authored
117 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"))
118 (should-error (websocket-verify-handshake
237b190 @ahyatt Various whitespace changes
authored
119 (websocket-test-make-websocket-with-accept-string
120 "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=")
8da9119 @ahyatt Separate out the handshake verification logic, and test it. Look for
authored
121 "Sec-WebSocket-Accept: foo\r\n")))
3a7798f @ahyatt Added frame processing, and more of the structure to use it.
authored
122
123 (ert-deftest websocket-process-frame ()
124 (let* ((sent)
125 (processed)
126 (deleted)
127 (websocket (make-websocket :conn "fake-conn"
128 :url "ws://foo/bar"
237b190 @ahyatt Various whitespace changes
authored
129 :filter (lambda (frame)
130 (setq
131 processed
132 (websocket-frame-payload frame)))
3a7798f @ahyatt Added frame processing, and more of the structure to use it.
authored
133 :close-callback t
134 :accept-string "accept-string")))
135 (dolist (opcode '(text binary continuation))
136 (setq processed nil)
137 (should (equal
138 "hello"
139 (progn
237b190 @ahyatt Various whitespace changes
authored
140 (websocket-process-frame
141 websocket
142 (make-websocket-frame :opcode opcode :payload "hello"))
3a7798f @ahyatt Added frame processing, and more of the structure to use it.
authored
143 processed))))
144 (setq sent nil)
145 (flet ((websocket-send (websocket content) (setq sent content)))
146 (should (equal
7bc2aae @ahyatt Make websocket-send work on frames, and use it to send pongs.
authored
147 (make-websocket-frame :opcode 'pong :completep t)
3a7798f @ahyatt Added frame processing, and more of the structure to use it.
authored
148 (progn
149 (websocket-process-frame websocket
150 (make-websocket-frame :opcode 'ping))
151 sent))))
152 (flet ((delete-process (conn) (setq deleted t)))
153 (should (progn
154 (websocket-process-frame websocket
155 (make-websocket-frame :opcode 'close))
156 deleted)))))
2148c5a @ahyatt Create the websocket-to-bytes function, to encode a number in a
authored
157
158 (ert-deftest websocket-to-bytes ()
159 ;; We've tested websocket-get-bytes by itself, now we can use it to
160 ;; help test websocket-to-bytes.
161 (should (equal 30 (websocket-get-bytes (websocket-to-bytes 30 1) 1)))
162 (should (equal 300 (websocket-get-bytes (websocket-to-bytes 300 2) 2)))
163 (should (equal 70000 (websocket-get-bytes (websocket-to-bytes 70000 8) 8)))
164 (should-error (websocket-to-bytes 30 3))
165 (should-error (websocket-to-bytes 300 1)))
166
3596d84 @ahyatt Write and test websocket-encode-frame.
authored
167 (ert-deftest websocket-encode-frame ()
168 ;; We've tested websocket-read-frame, now we can use that to help
169 ;; test websocket-encode-frame.
655cf1e @ahyatt Support outbound masking
authored
170 (let ((websocket-mask-frames nil))
171 (should (equal
172 websocket-test-hello
173 (websocket-encode-frame
174 (make-websocket-frame :opcode 'text :payload "Hello" :completep t))))
237b190 @ahyatt Various whitespace changes
authored
175 (dolist (len '(200 70000))
176 (let ((long-string (make-string len ?x)))
177 (should (equal long-string
178 (websocket-frame-payload
179 (websocket-read-frame
180 (websocket-encode-frame
1081075 @ahyatt More whitespace changes
authored
181 (make-websocket-frame :opcode 'text
182 :payload long-string)))))))))
655cf1e @ahyatt Support outbound masking
authored
183 (let ((websocket-mask-frames t))
184 (flet ((websocket-genbytes (n) (substring websocket-test-masked-hello 2 6)))
237b190 @ahyatt Various whitespace changes
authored
185 (should (equal websocket-test-masked-hello
186 (websocket-encode-frame
1081075 @ahyatt More whitespace changes
authored
187 (make-websocket-frame :opcode 'text :payload "Hello"
188 :completep t))))))
3596d84 @ahyatt Write and test websocket-encode-frame.
authored
189 (should-not
190 (websocket-frame-completep
191 (websocket-read-frame
1081075 @ahyatt More whitespace changes
authored
192 (websocket-encode-frame (make-websocket-frame :opcode 'text
193 :payload "Hello"
194 :completep nil)))))
0e04e15 @ahyatt Fix issue with encoding & decoding non-payload frames, and fix the
authored
195 (dolist (opcode '(close ping pong))
3596d84 @ahyatt Write and test websocket-encode-frame.
authored
196 (should (equal
197 opcode
198 (websocket-frame-opcode
199 (websocket-read-frame
0e04e15 @ahyatt Fix issue with encoding & decoding non-payload frames, and fix the
authored
200 (websocket-encode-frame (make-websocket-frame :opcode opcode
201 :completep t))))))))
3596d84 @ahyatt Write and test websocket-encode-frame.
authored
202
33ff92c @ahyatt Update websocket-close and test
authored
203 (ert-deftest websocket-close ()
204 (let ((sent-frames))
205 (flet ((websocket-send (websocket frame) (push frame sent-frames))
206 (websocket-openp (websocket) t)
207 (kill-buffer (buffer))
208 (process-buffer (conn)))
209 (websocket-close (make-websocket :conn "fake-conn"
210 :filter t
211 :url t
212 :accept-string t
213 :close-callback t))
214 (should (equal sent-frames (list
215 (make-websocket-frame :opcode 'close
216 :completep t)))))))
b89e002 @ahyatt Test for websocket-outer-filter, plus removing some useless code from…
authored
217
218 (ert-deftest websocket-outer-filter ()
219 (let* ((fake-ws (make-websocket :conn t :filter t :url t
220 :accept-string t :close-callback t))
221 (processed-frames)
222 (frame1 (make-websocket-frame :opcode 'text :payload "foo" :completep t
223 :length 9))
224 (frame2 (make-websocket-frame :opcode 'text :payload "bar" :completep t
225 :length 9))
226 (websocket-frames
227 (concat
228 (websocket-encode-frame frame1)
229 (websocket-encode-frame frame2))))
230 (flet ((websocket-process-frame (websocket frame)
231 (push frame processed-frames))
232 (websocket-verify-handshake (websocket output) t))
233 (websocket-outer-filter fake-ws "Sec-")
234 (websocket-outer-filter fake-ws "WebSocket-Accept: acceptstring")
235 (websocket-outer-filter fake-ws (concat
236 "\r\n\r\n"
237 (substring websocket-frames 0 2)))
238 (should (websocket-header-read-p fake-ws))
239 (websocket-outer-filter fake-ws (substring websocket-frames 2))
240 (should (equal (list frame2 frame1) processed-frames)))))
a5f1895 @ahyatt Re-apply the error handling, removed by accident during the merge.
authored
241
242 (defun websocket-test-get-filtered-response-with-error
243 (frames &optional callback)
244 (let* ((filter-frames)
245 (websocket
246 (make-websocket :conn "fake-conn"
247 :filter (lambda (frame)
248 (push frame filter-frames)
249 (when callback (funcall callback)))
250 :close-callback (lambda (not-called) (assert nil))
251 :url "ws://foo/bar"
252 :accept-string t))
253 err-list)
254 (dolist (frame frames)
255 (condition-case err
256 (websocket-process-frame websocket frame)
257 (error (push err err-list))))
258 (list (nreverse filter-frames) (nreverse err-list))))
259
260 (defun websocket-test-get-filtered-response (frames)
261 (destructuring-bind (filter-frames err-list)
262 (websocket-test-get-filtered-response-with-error frames)
263 (assert (eq (length err-list) 0))
264 filter-frames))
265
266 (ert-deftest websocket-filter-handle-error-in-filter ()
267 (let ((foo-frame (make-websocket-frame :opcode 'text
268 :payload "foo"
269 :completep t))
270 (bar-frame (make-websocket-frame :opcode 'text
271 :payload "bar"
272 :completep t)))
273 (destructuring-bind (filter-frames err-list)
274 (websocket-test-get-filtered-response-with-error
275 (list foo-frame bar-frame)
276 (lambda () (error "See if websocket can handle this")))
277 (should (equal filter-frames (list foo-frame bar-frame)))
278 (should (equal err-list nil)))
279 (destructuring-bind (filter-frames err-list)
280 (websocket-test-get-filtered-response-with-error
281 (list foo-frame bar-frame)
282 (lambda () "Raise another type of error" (/ 1 0)))
283 (should (equal filter-frames (list foo-frame bar-frame)))
284 (should (equal err-list nil)))
285 (destructuring-bind (filter-frames err-list)
286 (websocket-test-get-filtered-response-with-error
287 (list foo-frame bar-frame)
288 (lambda () (error "See if websocket can handle this")))
289 (should (equal filter-frames (list foo-frame bar-frame)))
290 (should (equal err-list nil)))))
291
d2e4272 @ahyatt Check frame validity, and test it as part of websocket-send
authored
292 (ert-deftest websocket-send ()
293 (let ((ws (make-websocket :conn t :url t :filter t :close-callback t
294 :accept-string t)))
295 (flet ((websocket-ensure-connected (websocket))
296 (websocket-openp (websocket) t)
297 (process-send-string (conn string)))
298 ;; Just make sure there is no error.
299 (websocket-send ws (make-websocket-frame :opcode 'ping
300 :completep t)))
301 (should-error (websocket-send ws
302 (make-websocket-frame :opcode 'text )))
303 (should-error (websocket-send ws
304 (make-websocket-frame :opcode 'close
305 :payload "bye!"
306 :completep t)))
307 (should-error (websocket-send ws
308 (make-websocket-frame :opcode :close)))))
309
Something went wrong with that request. Please try again.