1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
|
import os
import net
import net.websocket
import time
import rand
// TODO: fix connecting to ipv4 websockets
// (the server seems to work with .ip, but
// Client can not connect, it needs to be passed
// .ip too?)
struct WebsocketTestResults {
pub mut:
nr_messages int
nr_pong_received int
}
// Do not run these tests everytime, since they are flaky.
// They have their own specialized CI runner.
const github_job = os.getenv('GITHUB_JOB')
const should_skip = github_job != '' && github_job != 'websocket_tests'
// tests with internal ws servers
fn test_ws_ipv6() {
if should_skip {
return
}
port := 30000 + rand.intn(1024)
go start_server(.ip6, port)
time.sleep(500 * time.millisecond)
ws_test(.ip6, 'ws://localhost:$port') or { assert false }
}
// tests with internal ws servers
fn test_ws_ipv4() {
// TODO: fix client
if true || should_skip {
return
}
port := 30000 + rand.intn(1024)
go start_server(.ip, port)
time.sleep(500 * time.millisecond)
ws_test(.ip, 'ws://localhost:$port') or { assert false }
}
fn start_server(family net.AddrFamily, listen_port int) ? {
mut s := websocket.new_server(family, listen_port, '')
// make that in execution test time give time to execute at least one time
s.ping_interval = 1
s.on_connect(fn (mut s websocket.ServerClient) ?bool {
// here you can look att the client info and accept or not accept
// just returning a true/false
if s.resource_name != '/' {
panic('unexpected resource name in test')
return false
}
return true
}) ?
s.on_message(fn (mut ws websocket.Client, msg &websocket.Message) ? {
match msg.opcode {
.pong { ws.write_string('pong') or { panic(err) } }
else { ws.write(msg.payload, msg.opcode) or { panic(err) } }
}
})
s.on_close(fn (mut ws websocket.Client, code int, reason string) ? {
// not used
})
s.listen() or {}
}
// ws_test tests connect to the websocket server from websocket client
fn ws_test(family net.AddrFamily, uri string) ? {
eprintln('connecting to $uri ...')
mut test_results := WebsocketTestResults{}
mut ws := websocket.new_client(uri) ?
ws.on_open(fn (mut ws websocket.Client) ? {
ws.pong() ?
assert true
})
ws.on_error(fn (mut ws websocket.Client, err string) ? {
println('error: $err')
// this can be thrown by internet connection problems
assert false
})
ws.on_message_ref(fn (mut ws websocket.Client, msg &websocket.Message, mut res WebsocketTestResults) ? {
println('client got type: $msg.opcode payload:\n$msg.payload')
if msg.opcode == .text_frame {
smessage := msg.payload.bytestr()
match smessage {
'pong' {
res.nr_pong_received++
}
'a' {
res.nr_messages++
}
else {
assert false
}
}
} else {
println('Binary message: $msg')
}
}, test_results)
ws.connect() or { panic('fail to connect') }
go ws.listen()
text := ['a'].repeat(2)
for msg in text {
ws.write(msg.bytes(), .text_frame) or { panic('fail to write to websocket') }
// sleep to give time to recieve response before send a new one
time.sleep(100 * time.millisecond)
}
// sleep to give time to recieve response before asserts
time.sleep(1500 * time.millisecond)
// We expect at least 2 pongs, one sent directly and one indirectly
assert test_results.nr_pong_received >= 2
assert test_results.nr_messages == 2
}
|