AtlatestRepositorysigil-socket

sigil-socket / tree / testtest-socket.sgl

1(import (sigil test)
2 (sigil socket)
3 (sigil fs))
4
5;; ============================================================
6;; TCP echo
7;; ============================================================
8
9(test-group "TCP communication"
10 (test "tcp echo on localhost"
11 (let ((server (tcp-listen 0)))
12 (assert-true (socket? server))
13 (let* ((addr (socket-local-address server))
14 (port (cadr addr))
15 (client (tcp-connect "127.0.0.1" port)))
16 (assert-true (socket? client))
17 (let ((peer (tcp-accept server)))
18 (assert-true (socket? peer))
19 (socket-write-line client "hello")
20 (let ((received (socket-read-line peer)))
21 (assert-equal "hello" received))
22 (socket-close peer))
23 (socket-close client))
24 (socket-close server))))
26;; ============================================================
27;; UDP
28;; ============================================================
30(test-group "UDP communication"
31 (test "udp send and receive on localhost"
32 (let ((sock (udp-socket)))
33 (assert-true (socket? sock))
34 (udp-bind sock 0)
35 (let* ((addr (socket-local-address sock))
36 (port (cadr addr)))
37 (udp-send sock "ping" "127.0.0.1" port)
38 (let ((result (udp-receive sock)))
39 (assert-true (pair? result))
40 (assert-equal "ping" (car result))))
41 (socket-close sock))))
43;; ============================================================
44;; Address info
45;; ============================================================
47(test-group "address info"
48 (test "gethostname returns non-empty string"
49 (let ((name (gethostname)))
50 (assert-true (string? name))
51 (assert-true (> (string-length name) 0))))
53 (test "resolve-hostname localhost"
54 (let ((result (resolve-hostname "localhost")))
55 (assert-true (pair? result))
56 (assert-true (string? (car result))))))
58;; ============================================================
59;; Socket state
60;; ============================================================
62(test-group "socket state"
63 (test "socket-closed? is #f for open socket"
64 (let ((server (tcp-listen 0)))
65 (assert-false (socket-closed? server))
66 (socket-close server)))
68 (test "socket-closed? is #t after close"
69 (let ((server (tcp-listen 0)))
70 (socket-close server)
71 (assert-true (socket-closed? server))))
73 (test "socket-close on already-closed doesn't crash"
74 (let ((server (tcp-listen 0)))
75 (socket-close server)
76 (socket-close server)
77 (assert-true #t))))
79;; ============================================================
80;; Address introspection
81;; ============================================================
83(test-group "address introspection"
84 (test "socket-local-address on bound TCP socket"
85 (let ((server (tcp-listen 0)))
86 (let ((addr (socket-local-address server)))
87 (assert-true (pair? addr))
88 (assert-true (string? (car addr)))
89 (assert-true (number? (cadr addr)))
90 (assert-true (> (cadr addr) 0)))
91 (socket-close server)))
93 (test "socket-remote-address on connected TCP socket"
94 (let ((server (tcp-listen 0)))
95 (let* ((port (cadr (socket-local-address server)))
96 (client (tcp-connect "127.0.0.1" port)))
97 (let ((addr (socket-remote-address client)))
98 (assert-true (pair? addr))
99 (assert-true (string? (car addr)))
100 (assert-equal port (cadr addr)))
101 (socket-close client))
102 (socket-close server))))
104;; ============================================================
105;; Non-blocking I/O
106;; ============================================================
108(test-group "non-blocking I/O"
109 (test "socket-set-non-blocking! and socket-non-blocking?"
110 (let ((server (tcp-listen 0)))
111 (assert-false (socket-non-blocking? server))
112 (socket-set-non-blocking! server #t)
113 (assert-true (socket-non-blocking? server))
114 (socket-set-non-blocking! server #f)
115 (assert-false (socket-non-blocking? server))
116 (socket-close server)))
118 (test "socket-ready? returns #f when no data"
119 (let ((server (tcp-listen 0)))
120 (let* ((port (cadr (socket-local-address server)))
121 (client (tcp-connect "127.0.0.1" port))
122 (peer (tcp-accept server)))
123 ;; No data written yet, peer should not be ready
124 (assert-false (socket-ready? peer))
125 (socket-close peer)
126 (socket-close client))
127 (socket-close server)))
129 (test "socket-ready? returns #t after write"
130 (let ((server (tcp-listen 0)))
131 (let* ((port (cadr (socket-local-address server)))
132 (client (tcp-connect "127.0.0.1" port))
133 (peer (tcp-accept server)))
134 (socket-write-line client "data")
135 ;; Give data time to arrive
136 (assert-true (socket-ready? peer))
137 (socket-close peer)
138 (socket-close client))
139 (socket-close server)))
141 (test "socket-select returns ready sockets"
142 (let ((server (tcp-listen 0)))
143 (let* ((port (cadr (socket-local-address server)))
144 (client (tcp-connect "127.0.0.1" port))
145 (peer (tcp-accept server)))
146 (socket-write-line client "hello")
147 (let* ((result (socket-select (list peer) '() 1000))
148 (readable (car result)))
149 (assert-true (pair? readable))
150 (assert-equal 1 (length readable)))
151 (socket-close peer)
152 (socket-close client))
153 (socket-close server))))
155;; ============================================================
156;; TCP options
157;; ============================================================
159(test-group "TCP options"
160 (test "socket-set-tcp-nodelay! doesn't crash"
161 (let ((server (tcp-listen 0)))
162 (let* ((port (cadr (socket-local-address server)))
163 (client (tcp-connect "127.0.0.1" port)))
164 (socket-set-tcp-nodelay! client #t)
165 (assert-true #t)
166 (socket-close client))
167 (socket-close server))))
169;; ============================================================
170;; Higher-level utilities
171;; ============================================================
173(test-group "higher-level utilities"
174 (test "call-with-tcp-server creates and closes server"
175 (let ((port-num #f))
176 (call-with-tcp-server 0
177 (lambda (server)
178 (set! port-num (cadr (socket-local-address server)))
179 (assert-true (socket? server))
180 (assert-true (> port-num 0))))
181 ;; Server should be closed after proc returns
182 (assert-true (number? port-num))))
184 (test "call-with-tcp-connection connects and closes"
185 (let ((server (tcp-listen 0)))
186 (let ((port (cadr (socket-local-address server))))
187 (call-with-tcp-connection "127.0.0.1" port
188 (lambda (sock)
189 (assert-true (socket? sock))
190 (let ((peer (tcp-accept server)))
191 (socket-write-line peer "hello from server")
192 (socket-close peer))
193 (let ((line (socket-read-line sock)))
194 (assert-equal "hello from server" line)))))
195 (socket-close server)))
197 (test "socket-send-all sends complete data"
198 (let ((server (tcp-listen 0)))
199 (let* ((port (cadr (socket-local-address server)))
200 (client (tcp-connect "127.0.0.1" port))
201 (peer (tcp-accept server)))
202 (assert-true (socket-send-all client "hello world"))
203 (socket-close client)
204 (let ((received (socket-read-all peer)))
205 (assert-equal "hello world" received))
206 (socket-close peer))
207 (socket-close server)))
209 (test "socket-read-all reads until EOF"
210 (let ((server (tcp-listen 0)))
211 (let* ((port (cadr (socket-local-address server)))
212 (client (tcp-connect "127.0.0.1" port))
213 (peer (tcp-accept server)))
214 (socket-write peer "part1")
215 (socket-write peer "part2")
216 (socket-close peer)
217 (let ((all (socket-read-all client)))
218 (assert-equal "part1part2" all))
219 (socket-close client))
220 (socket-close server)))
222 (test "make-line-reader returns complete lines"
223 (let ((server (tcp-listen 0)))
224 (let* ((port (cadr (socket-local-address server)))
225 (client (tcp-connect "127.0.0.1" port))
226 (peer (tcp-accept server))
227 (reader (make-line-reader peer)))
228 (socket-write client "line1\nline2\n")
229 (assert-equal "line1" (reader))
230 (assert-equal "line2" (reader))
231 (socket-close client)
232 (socket-close peer))
233 (socket-close server)))
235 (test "make-line-reader handles CRLF"
236 (let ((server (tcp-listen 0)))
237 (let* ((port (cadr (socket-local-address server)))
238 (client (tcp-connect "127.0.0.1" port))
239 (peer (tcp-accept server))
240 (reader (make-line-reader peer)))
241 (socket-write client "hello\r\nworld\r\n")
242 (assert-equal "hello" (reader))
243 (assert-equal "world" (reader))
244 (socket-close client)
245 (socket-close peer))
246 (socket-close server))))
248;; ============================================================
249;; Error handling
250;; ============================================================
252;; ============================================================
253;; socket-select stress test
254;; ============================================================
256(test-group "socket-select stress"
257 (test "socket-select with many connections"
258 ;; Create 100 TCP connections, write to all, verify socket-select
259 ;; finds all readable.
260 (let ((server (tcp-listen 0)))
261 (let ((port (cadr (socket-local-address server))))
262 (let loop ((i 0) (clients '()) (peers '()))
263 (if (< i 100)
264 (let* ((client (tcp-connect "127.0.0.1" port))
265 (peer (tcp-accept server)))
266 (socket-write client "x")
267 (loop (+ i 1) (cons client clients) (cons peer peers)))
268 ;; All connections established and data written
269 (let* ((result (socket-select peers '() 5000))
270 (readable (car result)))
271 (assert-equal (length peers) (length readable))
272 ;; Clean up
273 (for-each socket-close clients)
274 (for-each socket-close peers)))))
275 (socket-close server))))
277;; ============================================================
278;; Unix domain sockets
279;; ============================================================
281(test-group "Unix domain sockets"
282 (test "unix-listen creates a socket"
283 (let ((server (unix-listen "/tmp/sigil-test-unix.sock")))
284 (assert-true (socket? server))
285 (socket-close server)
286 (delete-file "/tmp/sigil-test-unix.sock")))
288 (test "unix-connect to unix-listen socket"
289 (let ((server (unix-listen "/tmp/sigil-test-unix2.sock")))
290 (let ((client (unix-connect "/tmp/sigil-test-unix2.sock")))
291 (assert-true (socket? client))
292 (socket-close client))
293 (socket-close server)
294 (delete-file "/tmp/sigil-test-unix2.sock")))
296 (test "unix echo via accept"
297 (let ((server (unix-listen "/tmp/sigil-test-unix3.sock")))
298 (let* ((client (unix-connect "/tmp/sigil-test-unix3.sock"))
299 (peer (tcp-accept server)))
300 (assert-true (socket? peer))
301 (socket-write-line client "hello unix")
302 (let ((received (socket-read-line peer)))
303 (assert-equal "hello unix" received))
304 (socket-write-line peer "reply")
305 (let ((reply (socket-read-line client)))
306 (assert-equal "reply" reply))
307 (socket-close peer)
308 (socket-close client))
309 (socket-close server)
310 (delete-file "/tmp/sigil-test-unix3.sock")))
312 (test "unix-listen removes stale socket file"
313 (let ((path "/tmp/sigil-test-unix4.sock"))
314 ;; Create a socket, close it (leaves stale file)
315 (let ((s1 (unix-listen path)))
316 (socket-close s1))
317 ;; Should succeed even though file exists
318 (let ((s2 (unix-listen path)))
319 (assert-true (socket? s2))
320 (socket-close s2)
321 (delete-file path))))
323 (test "unix-connect to nonexistent path returns #f"
324 (let ((result (unix-connect "/tmp/sigil-test-nonexistent.sock")))
325 (assert-false result))))
327(test-group "error handling"
328 (test "tcp-connect to closed port returns #f"
329 ;; Bind a server to get a port, close it, then try to connect
330 (let ((server (tcp-listen 0)))
331 (let ((port (cadr (socket-local-address server))))
332 (socket-close server)
333 (let ((result (tcp-connect "127.0.0.1" port)))
334 (assert-false result))))))
336(run-tests)