1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00
v/vlib/vweb/tests/vweb_test.v

343 lines
9.0 KiB
V
Raw Normal View History

2020-08-14 00:51:57 +03:00
import os
import time
import json
2020-08-14 00:51:57 +03:00
import net
import net.http
import io
2020-08-14 00:51:57 +03:00
const (
sport = 12380
localserver = '127.0.0.1:${sport}'
exit_after_time = 12000 // milliseconds
2020-08-14 00:51:57 +03:00
vexe = os.getenv('VEXE')
vweb_logfile = os.getenv('VWEB_LOGFILE')
2020-08-14 00:51:57 +03:00
vroot = os.dir(vexe)
serverexe = os.join_path(os.cache_dir(), 'vweb_test_server.exe')
tcp_r_timeout = 30 * time.second
tcp_w_timeout = 30 * time.second
2020-08-14 00:51:57 +03:00
)
// setup of vweb webserver
fn testsuite_begin() {
2021-08-28 09:35:39 +03:00
os.chdir(vroot) or {}
if os.exists(serverexe) {
os.rm(serverexe) or {}
2020-08-14 00:51:57 +03:00
}
}
fn test_a_simple_vweb_app_can_be_compiled() {
// did_server_compile := os.system('${os.quoted_path(vexe)} -g -o ${os.quoted_path(serverexe)} vlib/vweb/tests/vweb_test_server.v')
// TODO: find out why it does not compile with -usecache and -g
did_server_compile := os.system('${os.quoted_path(vexe)} -o ${os.quoted_path(serverexe)} vlib/vweb/tests/vweb_test_server.v')
2020-08-14 00:51:57 +03:00
assert did_server_compile == 0
assert os.exists(serverexe)
2020-08-14 00:51:57 +03:00
}
fn test_a_simple_vweb_app_runs_in_the_background() {
mut suffix := ''
$if !windows {
suffix = ' > /dev/null &'
}
if vweb_logfile != '' {
suffix = ' 2>> ${os.quoted_path(vweb_logfile)} >> ${os.quoted_path(vweb_logfile)} &'
}
server_exec_cmd := '${os.quoted_path(serverexe)} ${sport} ${exit_after_time} ${suffix}'
2020-08-14 00:51:57 +03:00
$if debug_net_socket_client ? {
eprintln('running:\n${server_exec_cmd}')
2020-08-14 00:51:57 +03:00
}
$if windows {
2022-11-05 10:46:40 +03:00
spawn os.system(server_exec_cmd)
} $else {
res := os.system(server_exec_cmd)
assert res == 0
}
$if macos {
time.sleep(1000 * time.millisecond)
} $else {
time.sleep(100 * time.millisecond)
}
2020-08-14 00:51:57 +03:00
}
// web client tests follow
fn assert_common_headers(received string) {
assert received.starts_with('HTTP/1.1 200 OK\r\n')
assert received.contains('Server: VWeb\r\n')
assert received.contains('Content-Length:')
assert received.contains('Connection: close\r\n')
}
fn test_a_simple_tcp_client_can_connect_to_the_vweb_server() {
received := simple_tcp_client(path: '/') or {
assert err.msg() == ''
2020-08-14 00:51:57 +03:00
return
}
assert_common_headers(received)
assert received.contains('Content-Type: text/plain')
assert received.contains('Content-Length: 15')
assert received.ends_with('Welcome to VWeb')
}
fn test_a_simple_tcp_client_simple_route() {
received := simple_tcp_client(path: '/simple') or {
assert err.msg() == ''
2020-08-14 00:51:57 +03:00
return
}
assert_common_headers(received)
assert received.contains('Content-Type: text/plain')
assert received.contains('Content-Length: 15')
assert received.ends_with('A simple result')
}
fn test_a_simple_tcp_client_zero_content_length() {
// tests that sending a content-length header of 0 doesn't hang on a read timeout
watch := time.new_stopwatch(auto_start: true)
simple_tcp_client(path: '/', headers: 'Content-Length: 0\r\n\r\n') or {
assert err.msg() == ''
return
}
assert watch.elapsed() < 1 * time.second
}
2020-08-14 00:51:57 +03:00
fn test_a_simple_tcp_client_html_page() {
received := simple_tcp_client(path: '/html_page') or {
assert err.msg() == ''
2020-08-14 00:51:57 +03:00
return
}
assert_common_headers(received)
assert received.contains('Content-Type: text/html')
assert received.ends_with('<h1>ok</h1>')
}
// net.http client based tests follow:
fn assert_common_http_headers(x http.Response) ! {
assert x.status() == .ok
assert x.header.get(.server)! == 'VWeb'
assert x.header.get(.content_length)!.int() > 0
assert x.header.get(.connection)! == 'close'
2020-08-14 00:51:57 +03:00
}
fn test_http_client_index() {
x := http.get('http://${localserver}/') or { panic(err) }
assert_common_http_headers(x)!
assert x.header.get(.content_type)! == 'text/plain'
assert x.body == 'Welcome to VWeb'
2020-08-14 00:51:57 +03:00
}
fn test_http_client_404() {
server := 'http://${localserver}'
url_404_list := [
'/zxcnbnm',
'/JHKAJA',
'/unknown',
]
for url in url_404_list {
res := http.get('${server}${url}') or { panic(err) }
assert res.status() == .not_found
assert res.body == '404 on "${url}"'
}
}
fn test_http_client_simple() {
x := http.get('http://${localserver}/simple') or { panic(err) }
assert_common_http_headers(x)!
assert x.header.get(.content_type)! == 'text/plain'
assert x.body == 'A simple result'
2020-08-14 00:51:57 +03:00
}
fn test_http_client_html_page() {
x := http.get('http://${localserver}/html_page') or { panic(err) }
assert_common_http_headers(x)!
assert x.header.get(.content_type)! == 'text/html'
assert x.body == '<h1>ok</h1>'
2020-08-14 00:51:57 +03:00
}
fn test_http_client_settings_page() {
x := http.get('http://${localserver}/bilbo/settings') or { panic(err) }
assert_common_http_headers(x)!
assert x.body == 'username: bilbo'
//
y := http.get('http://${localserver}/kent/settings') or { panic(err) }
assert_common_http_headers(y)!
assert y.body == 'username: kent'
2020-08-14 00:51:57 +03:00
}
fn test_http_client_user_repo_settings_page() {
x := http.get('http://${localserver}/bilbo/gostamp/settings') or { panic(err) }
assert_common_http_headers(x)!
assert x.body == 'username: bilbo | repository: gostamp'
//
y := http.get('http://${localserver}/kent/golang/settings') or { panic(err) }
assert_common_http_headers(y)!
assert y.body == 'username: kent | repository: golang'
//
z := http.get('http://${localserver}/missing/golang/settings') or { panic(err) }
assert z.status() == .not_found
}
struct User {
name string
age int
}
fn test_http_client_json_post() {
ouser := User{
name: 'Bilbo'
age: 123
}
json_for_ouser := json.encode(ouser)
mut x := http.post_json('http://${localserver}/json_echo', json_for_ouser) or { panic(err) }
$if debug_net_socket_client ? {
eprintln('/json_echo endpoint response: ${x}')
}
assert x.header.get(.content_type)! == 'application/json'
assert x.body == json_for_ouser
nuser := json.decode(User, x.body) or { User{} }
assert '${ouser}' == '${nuser}'
2021-01-01 23:29:14 +03:00
//
x = http.post_json('http://${localserver}/json', json_for_ouser) or { panic(err) }
2021-01-01 23:29:14 +03:00
$if debug_net_socket_client ? {
eprintln('/json endpoint response: ${x}')
2021-01-01 23:29:14 +03:00
}
assert x.header.get(.content_type)! == 'application/json'
assert x.body == json_for_ouser
nuser2 := json.decode(User, x.body) or { User{} }
assert '${ouser}' == '${nuser2}'
}
fn test_http_client_multipart_form_data() {
mut form_config := http.PostMultipartFormConfig{
form: {
'foo': 'baz buzz'
}
}
mut x := http.post_multipart_form('http://${localserver}/form_echo', form_config)!
$if debug_net_socket_client ? {
eprintln('/form_echo endpoint response: ${x}')
}
assert x.body == form_config.form['foo']
mut files := []http.FileData{}
files << http.FileData{
filename: 'vweb'
content_type: 'text'
data: '"vweb test"'
}
mut form_config_files := http.PostMultipartFormConfig{
files: {
'file': files
}
}
x = http.post_multipart_form('http://${localserver}/file_echo', form_config_files)!
$if debug_net_socket_client ? {
eprintln('/form_echo endpoint response: ${x}')
}
assert x.body == files[0].data
}
fn test_login_with_multipart_form_data_send_by_fetch() {
mut form_config := http.PostMultipartFormConfig{
form: {
'username': 'myusername'
'password': 'mypassword123'
}
}
x := http.post_multipart_form('http://${localserver}/login', form_config)!
assert x.status_code == 200
assert x.status_msg == 'OK'
assert x.body == 'username: xmyusernamex | password: xmypassword123x'
}
fn test_host() {
mut req := http.Request{
url: 'http://${localserver}/with_host'
method: .get
}
mut x := req.do()!
assert x.status() == .not_found
req.add_header(.host, 'example.com')
x = req.do()!
assert x.status() == .ok
}
fn test_http_client_shutdown_does_not_work_without_a_cookie() {
x := http.get('http://${localserver}/shutdown') or {
assert err.msg() == ''
return
}
assert x.status() == .not_found
}
fn testsuite_end() {
// This test is guaranteed to be called last.
// It sends a request to the server to shutdown.
2021-08-17 18:36:10 +03:00
x := http.fetch(
url: 'http://${localserver}/shutdown'
method: .get
cookies: {
'skey': 'superman'
}
) or {
assert err.msg() == ''
return
}
assert x.status() == .ok
assert x.body == 'good bye'
2020-08-14 00:51:57 +03:00
}
// utility code:
struct SimpleTcpClientConfig {
retries int = 20
2020-08-14 00:51:57 +03:00
host string = 'static.dev'
path string = '/'
agent string = 'v/net.tcp.v'
2021-01-21 13:08:38 +03:00
headers string = '\r\n'
2020-09-09 15:14:44 +03:00
content string
2020-08-14 00:51:57 +03:00
}
fn simple_tcp_client(config SimpleTcpClientConfig) !string {
mut client := &net.TcpConn(unsafe { nil })
mut tries := 0
for tries < config.retries {
tries++
eprintln('> client retries: ${tries}')
client = net.dial_tcp(localserver) or {
if tries > config.retries {
return err
}
2021-02-27 20:41:06 +03:00
time.sleep(100 * time.millisecond)
continue
}
break
2020-08-14 00:51:57 +03:00
}
if client == unsafe { nil } {
eprintln('coult not create a tcp client connection to ${localserver} after ${config.retries} retries')
exit(1)
}
client.set_read_timeout(tcp_r_timeout)
client.set_write_timeout(tcp_w_timeout)
2020-08-14 00:51:57 +03:00
defer {
client.close() or {}
2020-08-14 00:51:57 +03:00
}
message := 'GET ${config.path} HTTP/1.1
Host: ${config.host}
User-Agent: ${config.agent}
2020-08-14 00:51:57 +03:00
Accept: */*
${config.headers}
${config.content}'
2020-08-14 00:51:57 +03:00
$if debug_net_socket_client ? {
eprintln('sending:\n${message}')
2020-08-14 00:51:57 +03:00
}
client.write(message.bytes())!
read := io.read_all(reader: client)!
2020-08-14 00:51:57 +03:00
$if debug_net_socket_client ? {
eprintln('received:\n${read}')
2020-08-14 00:51:57 +03:00
}
return read.bytestr()
2020-08-14 00:51:57 +03:00
}