2021-02-21 17:32:02 +03:00
|
|
|
import os
|
2021-06-13 23:53:38 +03:00
|
|
|
import net
|
2021-07-03 02:56:00 +03:00
|
|
|
import net.websocket
|
2020-08-22 01:50:38 +03:00
|
|
|
import time
|
|
|
|
|
2021-01-23 18:56:38 +03:00
|
|
|
struct WebsocketTestResults {
|
|
|
|
pub mut:
|
|
|
|
nr_messages int
|
|
|
|
nr_pong_received int
|
2023-02-13 15:28:41 +03:00
|
|
|
nr_closes int
|
2021-01-23 18:56:38 +03:00
|
|
|
}
|
|
|
|
|
2021-06-13 23:53:38 +03:00
|
|
|
// Do not run these tests everytime, since they are flaky.
|
|
|
|
// They have their own specialized CI runner.
|
2021-02-21 17:32:02 +03:00
|
|
|
const github_job = os.getenv('GITHUB_JOB')
|
|
|
|
|
2022-06-13 21:09:24 +03:00
|
|
|
const should_skip = get_should_skip()
|
|
|
|
|
|
|
|
fn get_should_skip() bool {
|
|
|
|
return github_job != '' && github_job != 'websocket_tests'
|
|
|
|
}
|
2021-06-13 23:53:38 +03:00
|
|
|
|
|
|
|
// tests with internal ws servers
|
|
|
|
fn test_ws_ipv6() {
|
|
|
|
if should_skip {
|
|
|
|
return
|
|
|
|
}
|
2023-02-25 20:39:08 +03:00
|
|
|
start_server(.ip6, 30001)!
|
|
|
|
|
2023-02-25 15:46:27 +03:00
|
|
|
ws_test(.ip6, 'ws://localhost:30001') or {
|
2022-11-15 16:53:13 +03:00
|
|
|
eprintln('> error while connecting .ip6, err: ${err}')
|
2022-08-07 10:40:05 +03:00
|
|
|
assert false
|
|
|
|
}
|
2021-06-13 23:53:38 +03:00
|
|
|
}
|
|
|
|
|
2020-12-04 03:52:26 +03:00
|
|
|
// tests with internal ws servers
|
2021-06-13 23:53:38 +03:00
|
|
|
fn test_ws_ipv4() {
|
2021-12-06 12:10:25 +03:00
|
|
|
if should_skip {
|
2021-02-21 17:32:02 +03:00
|
|
|
return
|
|
|
|
}
|
2023-02-25 20:39:08 +03:00
|
|
|
start_server(.ip, 30002)!
|
|
|
|
|
2023-02-25 15:46:27 +03:00
|
|
|
ws_test(.ip, 'ws://localhost:30002') or {
|
2022-11-15 16:53:13 +03:00
|
|
|
eprintln('> error while connecting .ip, err: ${err}')
|
2022-08-07 10:40:05 +03:00
|
|
|
assert false
|
|
|
|
}
|
2020-08-22 01:50:38 +03:00
|
|
|
}
|
|
|
|
|
2022-10-16 09:28:57 +03:00
|
|
|
fn start_server(family net.AddrFamily, listen_port int) ! {
|
2023-02-25 15:33:22 +03:00
|
|
|
eprintln('> start_server family:${family} | listen_port: ${listen_port}')
|
2021-06-13 23:53:38 +03:00
|
|
|
mut s := websocket.new_server(family, listen_port, '')
|
2020-12-04 03:52:26 +03:00
|
|
|
// make that in execution test time give time to execute at least one time
|
2021-01-23 18:56:38 +03:00
|
|
|
s.ping_interval = 1
|
|
|
|
|
2022-10-16 09:28:57 +03:00
|
|
|
s.on_connect(fn (mut s websocket.ServerClient) !bool {
|
2020-12-04 03:52:26 +03:00
|
|
|
// here you can look att the client info and accept or not accept
|
2020-08-22 01:50:38 +03:00
|
|
|
// just returning a true/false
|
|
|
|
if s.resource_name != '/' {
|
2020-11-07 19:14:33 +03:00
|
|
|
panic('unexpected resource name in test')
|
2020-08-22 01:50:38 +03:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
return true
|
2022-10-16 09:28:57 +03:00
|
|
|
})!
|
|
|
|
s.on_message(fn (mut ws websocket.Client, msg &websocket.Message) ! {
|
2021-01-23 18:56:38 +03:00
|
|
|
match msg.opcode {
|
2022-10-16 09:28:57 +03:00
|
|
|
.pong { ws.write_string('pong')! }
|
|
|
|
else { ws.write(msg.payload, msg.opcode)! }
|
2021-01-23 18:56:38 +03:00
|
|
|
}
|
2020-08-22 01:50:38 +03:00
|
|
|
})
|
2021-01-23 18:56:38 +03:00
|
|
|
|
2022-10-16 09:28:57 +03:00
|
|
|
s.on_close(fn (mut ws websocket.Client, code int, reason string) ! {
|
2020-12-04 03:52:26 +03:00
|
|
|
// not used
|
2020-08-22 01:50:38 +03:00
|
|
|
})
|
2023-02-25 20:39:08 +03:00
|
|
|
start_server_in_thread_and_wait_till_it_is_ready_to_accept_connections(mut s)
|
|
|
|
eprintln('> start_server finished')
|
|
|
|
}
|
|
|
|
|
|
|
|
fn start_server_in_thread_and_wait_till_it_is_ready_to_accept_connections(mut ws websocket.Server) {
|
|
|
|
eprintln('-----------------------------------------------------------------------------')
|
|
|
|
spawn fn [mut ws] () {
|
|
|
|
ws.listen() or { panic('websocket server could not listen, err: ${err}') }
|
|
|
|
}()
|
|
|
|
for ws.state != .open {
|
|
|
|
time.sleep(10 * time.millisecond)
|
|
|
|
}
|
|
|
|
eprintln('-----------------------------------------------------------------------------')
|
2020-08-22 01:50:38 +03:00
|
|
|
}
|
|
|
|
|
2020-12-04 03:52:26 +03:00
|
|
|
// ws_test tests connect to the websocket server from websocket client
|
2022-10-16 09:28:57 +03:00
|
|
|
fn ws_test(family net.AddrFamily, uri string) ! {
|
2022-11-15 16:53:13 +03:00
|
|
|
eprintln('connecting to ${uri} ...')
|
2021-01-23 18:56:38 +03:00
|
|
|
|
|
|
|
mut test_results := WebsocketTestResults{}
|
2023-02-25 20:39:08 +03:00
|
|
|
mut client := websocket.new_client(uri)!
|
|
|
|
client.on_open(fn (mut client websocket.Client) ! {
|
|
|
|
client.pong()!
|
2020-08-22 01:50:38 +03:00
|
|
|
assert true
|
|
|
|
})
|
2023-02-25 20:39:08 +03:00
|
|
|
client.on_error(fn (mut client websocket.Client, err string) ! {
|
2022-11-15 16:53:13 +03:00
|
|
|
println('error: ${err}')
|
2020-08-22 01:50:38 +03:00
|
|
|
// this can be thrown by internet connection problems
|
|
|
|
assert false
|
|
|
|
})
|
2021-01-23 18:56:38 +03:00
|
|
|
|
2023-02-25 20:39:08 +03:00
|
|
|
client.on_message_ref(fn (mut client websocket.Client, msg &websocket.Message, mut res WebsocketTestResults) ! {
|
2022-11-15 16:53:13 +03:00
|
|
|
println('client got type: ${msg.opcode} payload:\n${msg.payload}')
|
2020-08-22 01:50:38 +03:00
|
|
|
if msg.opcode == .text_frame {
|
2020-08-22 13:29:15 +03:00
|
|
|
smessage := msg.payload.bytestr()
|
2021-01-23 18:56:38 +03:00
|
|
|
match smessage {
|
|
|
|
'pong' {
|
|
|
|
res.nr_pong_received++
|
|
|
|
}
|
|
|
|
'a' {
|
|
|
|
res.nr_messages++
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
assert false
|
|
|
|
}
|
|
|
|
}
|
2020-08-22 01:50:38 +03:00
|
|
|
} else {
|
2022-11-15 16:53:13 +03:00
|
|
|
println('Binary message: ${msg}')
|
2020-08-22 01:50:38 +03:00
|
|
|
}
|
2021-01-23 18:56:38 +03:00
|
|
|
}, test_results)
|
2023-02-25 20:39:08 +03:00
|
|
|
client.connect()!
|
|
|
|
spawn client.listen()
|
|
|
|
|
2020-08-22 01:50:38 +03:00
|
|
|
text := ['a'].repeat(2)
|
|
|
|
for msg in text {
|
2023-02-25 20:39:08 +03:00
|
|
|
client.write(msg.bytes(), .text_frame) or {
|
|
|
|
panic('fail to write to websocket, err: ${err}')
|
|
|
|
}
|
2020-08-22 01:50:38 +03:00
|
|
|
// sleep to give time to recieve response before send a new one
|
2021-02-27 20:41:06 +03:00
|
|
|
time.sleep(100 * time.millisecond)
|
2020-08-22 01:50:38 +03:00
|
|
|
}
|
|
|
|
// sleep to give time to recieve response before asserts
|
2021-02-27 20:41:06 +03:00
|
|
|
time.sleep(1500 * time.millisecond)
|
2021-03-01 02:18:14 +03:00
|
|
|
// We expect at least 2 pongs, one sent directly and one indirectly
|
2021-01-23 18:56:38 +03:00
|
|
|
assert test_results.nr_pong_received >= 2
|
|
|
|
assert test_results.nr_messages == 2
|
2020-08-22 01:50:38 +03:00
|
|
|
}
|
2023-02-13 15:28:41 +03:00
|
|
|
|
|
|
|
fn test_on_close_when_server_closing_connection() ! {
|
2023-02-25 15:33:22 +03:00
|
|
|
mut ws := websocket.new_server(.ip, 30003, '')
|
2023-02-13 15:28:41 +03:00
|
|
|
ws.on_message(fn (mut cli websocket.Client, msg &websocket.Message) ! {
|
|
|
|
if msg.opcode == .text_frame {
|
|
|
|
cli.close(1000, 'closing connection')!
|
|
|
|
}
|
|
|
|
})
|
|
|
|
mut test_results := WebsocketTestResults{}
|
|
|
|
ws.on_close_ref(fn (mut cli websocket.Client, code int, reason string, mut res WebsocketTestResults) ! {
|
|
|
|
res.nr_closes++
|
|
|
|
}, test_results)
|
2023-02-25 20:39:08 +03:00
|
|
|
start_server_in_thread_and_wait_till_it_is_ready_to_accept_connections(mut ws)
|
|
|
|
//
|
2023-02-25 15:46:27 +03:00
|
|
|
mut client := websocket.new_client('ws://localhost:30003')!
|
2023-02-13 15:28:41 +03:00
|
|
|
client.connect()!
|
|
|
|
spawn client.listen()
|
|
|
|
time.sleep(1000 * time.millisecond)
|
|
|
|
client.write_string('a message')!
|
|
|
|
time.sleep(1000 * time.millisecond)
|
|
|
|
assert test_results.nr_closes == 1
|
|
|
|
}
|
|
|
|
|
|
|
|
fn test_on_close_when_client_closing_connection() ! {
|
2023-02-25 15:33:22 +03:00
|
|
|
mut ws := websocket.new_server(.ip, 30004, '')
|
2023-02-25 20:39:08 +03:00
|
|
|
start_server_in_thread_and_wait_till_it_is_ready_to_accept_connections(mut ws)
|
|
|
|
//
|
2023-02-25 15:46:27 +03:00
|
|
|
mut client := websocket.new_client('ws://localhost:30004')!
|
2023-02-13 15:28:41 +03:00
|
|
|
mut test_results := WebsocketTestResults{}
|
|
|
|
client.on_close_ref(fn (mut cli websocket.Client, code int, reason string, mut res WebsocketTestResults) ! {
|
|
|
|
res.nr_closes++
|
|
|
|
}, test_results)
|
|
|
|
client.connect()!
|
|
|
|
spawn client.listen()
|
|
|
|
time.sleep(1000 * time.millisecond)
|
|
|
|
client.close(1000, 'closing connection')!
|
|
|
|
time.sleep(1000 * time.millisecond)
|
|
|
|
assert test_results.nr_closes == 1
|
|
|
|
}
|