vweb: add tests
							parent
							
								
									fc1f41fc84
								
							
						
					
					
						commit
						712f4bd7f8
					
				| 
						 | 
				
			
			@ -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
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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{}
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue