dynamic port choice

also: better error messages in tests
This commit is contained in:
lovasoa
2025-05-26 00:46:04 +02:00
parent 7009f65374
commit e7951ee721
8 changed files with 57 additions and 32 deletions
+1 -1
View File
@@ -13,7 +13,7 @@
<div class="text-muted">
<p>We are sorry, but an error occurred while generating this page. You should contact the site's
administrator.</p>
<pre class="mt-2"><code>{{description}}</code></pre>
<pre class="mt-2"><code class="sqlpage-error-description">{{description}}</code></pre>
{{#if backtrace}}
<details class="mt-2">
<summary>Backtrace</summary>
+7 -4
View File
@@ -137,7 +137,9 @@ fn build_echo_response(body: Vec<u8>, meta: String) -> HttpResponse {
.body(resp)
}
pub fn start_echo_server(shutdown: oneshot::Receiver<()>) -> JoinHandle<()> {
pub fn start_echo_server(shutdown: oneshot::Receiver<()>) -> (JoinHandle<()>, u16) {
let listener = std::net::TcpListener::bind("localhost:0").unwrap();
let port = listener.local_addr().unwrap().port();
let server = HttpServer::new(|| {
App::new().default_service(fn_service(|mut req: ServiceRequest| async move {
let meta = format_request_line_and_headers(&req);
@@ -146,14 +148,15 @@ pub fn start_echo_server(shutdown: oneshot::Receiver<()>) -> JoinHandle<()> {
Ok(req.into_response(resp))
}))
})
.bind("localhost:62802")
.listen(listener)
.unwrap()
.shutdown_timeout(1)
.run();
tokio::spawn(async move {
let handle = tokio::spawn(async move {
tokio::select! {
_ = server => {},
_ = shutdown => {},
}
})
});
(handle, port)
}
@@ -1,10 +1,11 @@
set url = 'http://localhost:' || $echo_port || '/post';
set res = sqlpage.fetch(json_object(
'method', 'POST',
'url', 'http://localhost:62802/post',
'url', $url,
'headers', json_object('x-custom', '1'),
'body', json_array('hello', 'world')
));
set expected = 'POST /post|accept-encoding: br, gzip, deflate, zstd|content-length: 17|content-type: application/json|host: localhost:62802|user-agent: sqlpage|x-custom: 1|["hello","world"]';
set expected = 'POST /post|accept-encoding: br, gzip, deflate, zstd|content-length: 17|content-type: application/json|host: localhost:' || $echo_port || '|user-agent: sqlpage|x-custom: 1|["hello","world"]';
select 'text' as component,
case $res
when $expected then 'It works !'
+6 -9
View File
@@ -1,15 +1,12 @@
set res = sqlpage.fetch('{
"method": "POST",
"url": "http://localhost:62802/post",
"headers": {"x-custom": "1"},
"body": {"hello": "world"}
}');
set expected = 'POST /post|accept-encoding: br, gzip, deflate, zstd|content-length: 18|content-type: application/json|host: localhost:62802|user-agent: sqlpage|x-custom: 1|{"hello": "world"}';
set url = 'http://localhost:' || $echo_port || '/post';
set fetch_request = '{"method": "POST", "url": "' || $url || '", "headers": {"x-custom": "1"}, "body": {"hello": "world"}}';
set res = sqlpage.fetch($fetch_request);
set expected = 'POST /post|accept-encoding: br, gzip, deflate, zstd|content-length: 18|content-type: application/json|host: localhost:' || $echo_port || '|user-agent: sqlpage|x-custom: 1|{"hello": "world"}';
select 'text' as component,
case $res
when $expected then 'It works !'
else 'It failed ! Expected:
' || $expected || '
' || COALESCE($expected, 'null') || '
Got:
' || $res
' || COALESCE($res, 'null')
end as contents;
@@ -1,4 +1,5 @@
set res = sqlpage.fetch('http://localhost:62802/hello_world')
set url = 'http://localhost:' || $echo_port || '/hello_world';
set res = sqlpage.fetch($url);
select 'text' as component,
case
when $res LIKE 'GET /hello_world%' then 'It works !'
@@ -1,10 +1,12 @@
set res = sqlpage.fetch_with_meta('{
set url = 'http://localhost:' || $echo_port || '/hello_world';
set fetch_req = '{
"method": "PUT",
"url": "http://localhost:62802/hello_world",
"url": "' || $url || '",
"headers": {
"user-agent": "myself"
}
}');
}';
set res = sqlpage.fetch_with_meta($fetch_req);
select 'text' as component,
case
@@ -1,9 +1,11 @@
set actual = sqlpage.link('', sqlpage.variables('get'));
set expected = '?x=1';
SELECT
'text' AS component,
CASE sqlpage.link('', sqlpage.variables('get'))
WHEN '?x=1' THEN
CASE $actual
WHEN $expected THEN
'It works !'
ELSE
'Expected "?x=1"'
'Expected ' || COALESCE($expected, 'null') || ' but got ' || COALESCE($actual, 'null')
END AS contents
;
+28 -9
View File
@@ -12,13 +12,13 @@ async fn run_all_sql_test_files() {
// Create a shutdown channel for the echo server
let (shutdown_tx, shutdown_rx) = oneshot::channel();
// Start echo server once for all tests
let echo_handle = crate::common::start_echo_server(shutdown_rx);
let (echo_handle, port) = crate::common::start_echo_server(shutdown_rx);
// Wait for echo server to be ready
wait_for_echo_server().await;
wait_for_echo_server(port).await;
for test_file in test_files {
let test_result = run_sql_test(&test_file, &app_data, &echo_handle).await;
let test_result = run_sql_test(&test_file, &app_data, &echo_handle, port).await;
assert_test_result(test_result, &test_file);
}
@@ -31,13 +31,13 @@ async fn run_all_sql_test_files() {
}
}
async fn wait_for_echo_server() {
async fn wait_for_echo_server(port: u16) {
let client = awc::Client::default();
let start = std::time::Instant::now();
let timeout = Duration::from_secs(5);
while start.elapsed() < timeout {
match client.get("http://localhost:62802/").send().await {
match client.get(format!("http://localhost:{port}/")).send().await {
Ok(_) => return,
Err(_) => {
tokio::time::sleep(Duration::from_millis(100)).await;
@@ -64,13 +64,20 @@ fn get_sql_test_files() -> Vec<std::path::PathBuf> {
.collect()
}
use std::fmt::Write;
async fn run_sql_test(
test_file: &std::path::Path,
app_data: &actix_web::web::Data<AppState>,
_echo_handle: &JoinHandle<()>,
port: u16,
) -> anyhow::Result<String> {
let test_file_path = test_file.to_string_lossy().replace('\\', "/");
let req_str = format!("/{test_file_path}?x=1");
let mut query_params = "x=1".to_string();
if test_file_path.contains("fetch") {
write!(query_params, "&echo_port={port}").unwrap();
}
let req_str = format!("/{test_file_path}?{query_params}");
let resp = tokio::time::timeout(
Duration::from_secs(5),
@@ -114,11 +121,23 @@ fn assert_html_response(body: &str, test_file: &std::path::Path) {
}
fn assert_it_works_tests(body: &str, lowercase_body: &str, test_file: &std::path::Path) {
if body.contains("<code class=\"sqlpage-error-description\">") {
let error_desc = body
.split("<code class=\"sqlpage-error-description\">")
.nth(1)
.and_then(|s| s.split("</code>").next())
.unwrap_or("Unknown error");
panic!(
"\n\n❌ TEST FAILED: {}\n\nFull Response:\n{}\n\nError Description: {}\n",
test_file.display(),
error_desc,
body
);
}
assert!(
body.contains("It works !"),
"{}\n{}\nexpected to contain: It works !",
test_file.display(),
body
"{body}\n❌ Error in file {test_file:?} ❌\n",
);
assert!(
!lowercase_body.contains("error"),