vweb: add tests

pull/6129/head
Delyan Angelov 2020-08-14 00:51:57 +03:00
parent fc1f41fc84
commit 712f4bd7f8
2 changed files with 258 additions and 0 deletions

View File

@ -0,0 +1,189 @@
import os
import time
import net
import net.http
const (
sport = 12380
exit_after_time = 1000 // milliseconds
vexe = os.getenv('VEXE')
vroot = os.dir(vexe)
serverexe = os.join_path(os.cache_dir(), 'vweb_test_server.exe')
)
// setup of vweb webserver
fn testsuite_begin() {
os.chdir(vroot)
if os.exists(serverexe) {
os.rm(serverexe)
}
// prevent failing tests when vweb_test.v is rerun quickly
// and the previous webserver has not yet timed out.
for i := 0; i < 10; i++ {
if client := net.dial('127.0.0.1', sport) {
client.close() or { }
eprintln('previous webserver has not yet stopped ($i); waiting...')
time.sleep_ms(exit_after_time / 10)
continue
} else {
return
}
}
}
fn test_a_simple_vweb_app_can_be_compiled() {
did_server_compile := os.system('$vexe -o $serverexe vlib/vweb/tests/vweb_test_server.v')
assert did_server_compile == 0
assert os.exists(serverexe)
}
fn test_a_simple_vweb_app_runs_in_the_background() {
server_exec_cmd := '$serverexe $sport $exit_after_time > /dev/null &'
$if debug_net_socket_client ? {
eprintln('running:\n$server_exec_cmd')
}
res := os.system(server_exec_cmd)
assert res == 0
time.sleep_ms(100)
}
// 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({}) or {
assert err == ''
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 == ''
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_html_page() {
received := simple_tcp_client({
path: '/html_page'
}) or {
assert err == ''
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_code == 200
assert x.headers['Server'] == 'VWeb'
assert x.headers['Content-Length'].int() > 0
assert x.headers['Connection'] == 'close'
}
fn test_http_client_index() {
x := http.get('http://127.0.0.1:$sport/') or {
panic(err)
}
assert_common_http_headers(x)
assert x.headers['Content-Type'] == 'text/plain'
assert x.text == 'Welcome to VWeb'
}
fn test_http_client_simple() {
x := http.get('http://127.0.0.1:$sport/simple') or {
panic(err)
}
assert_common_http_headers(x)
assert x.headers['Content-Type'] == 'text/plain'
assert x.text == 'A simple result'
}
fn test_http_client_html_page() {
x := http.get('http://127.0.0.1:$sport/html_page') or {
panic(err)
}
assert_common_http_headers(x)
assert x.headers['Content-Type'] == 'text/html'
assert x.text == '<h1>ok</h1>'
}
fn test_http_client_settings_page() {
x := http.get('http://127.0.0.1:$sport/bilbo/settings') or {
panic(err)
}
assert_common_http_headers(x)
assert x.text == 'username: bilbo'
y := http.get('http://127.0.0.1:$sport/kent/settings') or {
panic(err)
}
assert_common_http_headers(y)
assert y.text == 'username: kent'
}
fn test_http_client_user_repo_settings_page() {
x := http.get('http://127.0.0.1:$sport/bilbo/gostamp/settings') or {
panic(err)
}
assert_common_http_headers(x)
assert x.text == 'username: bilbo | repository: gostamp'
y := http.get('http://127.0.0.1:$sport/kent/golang/settings') or {
panic(err)
}
assert_common_http_headers(y)
assert y.text == 'username: kent | repository: golang'
}
// utility code:
struct SimpleTcpClientConfig {
host string = 'static.dev'
path string = '/'
agent string = 'v/net.tcp.v'
headers string = ''
content string = ''
}
fn simple_tcp_client(config SimpleTcpClientConfig) ?string {
client := net.dial('127.0.0.1', sport) or {
return error(err)
}
defer {
client.close() or { }
}
message := 'GET $config.path HTTP/1.1
Host: $config.host
User-Agent: $config.agent
Accept: */*
$config.headers
$config.content'
$if debug_net_socket_client ? {
eprintln('sending:\n$message')
}
client.send(message.str, message.len) or {
return error(err)
}
bytes, blen := client.recv(4096)
received := unsafe {bytes.vstring_with_len(blen)}
$if debug_net_socket_client ? {
eprintln('received:\n$received')
}
return received
}

View File

@ -0,0 +1,69 @@
module main
import os
import vweb
import time
struct App {
port int
timeout int
pub mut:
vweb vweb.Context
}
fn exit_after_timeout(timeout_in_ms int) {
time.sleep_ms(timeout_in_ms)
// eprintln('webserver is exiting ...')
exit(0)
}
fn main() {
if os.args.len != 3 {
panic('Usage: `vweb_test_server.exe PORT TIMEOUT_IN_MILLISECONDS`')
}
http_port := os.args[1].int()
assert http_port > 0
timeout := os.args[2].int()
assert timeout > 0
go exit_after_timeout(timeout)
//
mut app := App{
port: http_port
timeout: timeout
}
vweb.run_app<App>(mut app, http_port)
}
pub fn (mut app App) init() {
}
pub fn (mut app App) init_once() {
eprintln('Started webserver on http://127.0.0.1:$app.port/ , with maximum runtime of $app.timeout milliseconds.')
}
pub fn (mut app App) index() {
app.vweb.text('Welcome to VWeb')
}
pub fn (mut app App) simple() vweb.Result {
app.vweb.text('A simple result')
return vweb.Result{}
}
pub fn (mut app App) html_page() vweb.Result {
app.vweb.html('<h1>ok</h1>')
return vweb.Result{}
}
// the following serve custom routes
['/:user/settings']
pub fn (mut app App) settings(username string) vweb.Result {
app.vweb.html('username: $username')
return vweb.Result{}
}
['/:user/:repo/settings']
pub fn (mut app App) user_repo_settings(username, repository string) vweb.Result {
app.vweb.html('username: $username | repository: $repository')
return vweb.Result{}
}