From a301c70bebd3261ee8e872aeab2dcbc3361847c0 Mon Sep 17 00:00:00 2001 From: Lars Wirzenius Date: Sun, 19 Jul 2020 12:51:56 +0300 Subject: test: add -c (--codegen) option to generate test program, not run it This makes it easier to run only specific tests, or to specify a log file for the test program. --- check | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/check b/check index 8d7e56e..912a005 100755 --- a/check +++ b/check @@ -3,14 +3,21 @@ set -eu verbose=false -if [ "$#" -gt 0 ] -then +runtest=true +moar=true +while [ "$#" -gt 0 ] && $moar +do case "$1" in verbose | -v | --verbose) verbose=true + shift 1 + ;; + -c | --codegen) + runtest=false + shift 1 ;; esac -fi +done hideok= if command -v chronic > /dev/null @@ -26,7 +33,12 @@ fi codegen() { - $hideok sp-codegen "$1" --output "$2" --run + local run= + if $runtest + then + run=--run + fi + $hideok sp-codegen "$1" --output "$2" $run } docgen() { -- cgit v1.2.1 From 8fc8c54d9f5973df0a1085ae357bc8bb97fba534 Mon Sep 17 00:00:00 2001 From: Lars Wirzenius Date: Sun, 19 Jul 2020 12:13:29 +0300 Subject: test: add a bit of debug logging to http.py --- http.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/http.py b/http.py index fd552a6..5cff887 100644 --- a/http.py +++ b/http.py @@ -24,7 +24,8 @@ def http_request(ctx, host=None, method=None, url=None): # Check status code of latest HTTP request. def http_status_code_is(ctx, code=None): - logging.debug(f"Verifying status code of previous HTTP request is {code}") + logging.debug(f"Verifying status code of previous HTTP request is {code}") + logging.debug(f" stderr={ctx['stderr']}") pattern = f"\n< HTTP/2 {code} " assert_eq(pattern in ctx["stderr"], True) @@ -40,6 +41,7 @@ def http_header_is(ctx, header=None, value=None): # Check a HTTP body response for latest request has a given value. def http_body_is(ctx, body=None): logging.debug(f"Verifying response body is {body!r}") + logging.debug(f" actual body={ctx['stdout']!r}") s = ctx["stdout"] body = body.encode("UTF8").decode("unicode-escape") assert_eq(body, s) -- cgit v1.2.1 From e50eea1299a337a4c2164e069ab0bfa65609424f Mon Sep 17 00:00:00 2001 From: Lars Wirzenius Date: Sun, 19 Jul 2020 11:45:53 +0300 Subject: test: log call of terminate_process, and its failure This avoids an ugly and unnecessary stack trace when ewww failed to start, and thus there is no process with the assumed pid. Also, this makes debugging test failures a little easier. --- daemon.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/daemon.py b/daemon.py index 33057bd..585fe5a 100644 --- a/daemon.py +++ b/daemon.py @@ -65,5 +65,10 @@ def process_exists(pid): # Terminate process. -def terminate_process(pid, signal): - os.kill(pid, signal) +def terminate_process(pid, signalno): + logging.debug(f"Terminating process {pid} with signal {signalno}") + try: + os.kill(pid, signalno) + except ProcessLookupError: + logging.debug("Process did not actually exist (anymore?)") + pass -- cgit v1.2.1 From ee3c218fea70d02d0bc0e1e4baae8cb8c988074c Mon Sep 17 00:00:00 2001 From: Lars Wirzenius Date: Sun, 19 Jul 2020 11:46:40 +0300 Subject: test: wait for ewww to start, and log stderr if it doesn't When the ewww daemon starts successfully, it'll listen on the assigned port. We wait for that port to be open, for up to five seconds. If that fails, then ewww didn't start successfully, and hopefully there is something useful in its stderr so we read and log that. --- ewww.py | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/ewww.py b/ewww.py index ded5064..8a6e453 100644 --- a/ewww.py +++ b/ewww.py @@ -8,6 +8,7 @@ import random import re import shutil import signal +import socket import subprocess import time import urllib.parse @@ -82,7 +83,7 @@ def start_server(ctx, filename=None): logging.debug(f"Starting ewww with config file {filename}") config = get_file(filename).decode("UTF-8") config = yaml.safe_load(config) - config["port"] = random.randint(2000, 30000) + port = config["port"] = random.randint(2000, 30000) logging.debug(f"Picked randomly port for ewww: {config['port']}") ctx["config"] = config config = yaml.safe_dump(config) @@ -90,6 +91,24 @@ def start_server(ctx, filename=None): start_daemon(ctx, "ewww", [_binary("ewww"), filename]) + if not port_open("localhost", port, 5.0): + stderr = open(ctx["daemon"]["ewww"]["stderr"]).read() + logging.debug(f"Stderr from daemon: {stderr!r}") + + +# Wait for a port to be open +def port_open(host, port, timeout): + logging.debug(f"Waiting for port localhost:{port} to be available") + started = time.time() + while time.time() < started + timeout: + try: + socket.create_connection((host, port), timeout=timeout) + return True + except socket.error: + pass + logging.error(f"Port localhost:{port} is not open") + return False + # Stop previously started server. def stop_server(ctx): -- cgit v1.2.1 From 62b3cd170e603367629f7b1dc2abd02a9524277a Mon Sep 17 00:00:00 2001 From: Lars Wirzenius Date: Sun, 19 Jul 2020 11:46:25 +0300 Subject: feat: serve files from configured webroot --- ewww.md | 15 +++++++++------ src/main.rs | 14 +++++++++++--- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/ewww.md b/ewww.md index ed2f663..536510c 100644 --- a/ewww.md +++ b/ewww.md @@ -88,13 +88,15 @@ for static content only. Every other method returns an error. ## Minimal smoke test ~~~scenario +when I create webroot/foo.html with "this is your web page" given a self-signed certificate as snakeoil.pem, using key snakeoil.key and a running server using config file minimal.yaml -when I request GET https://example.com/ +when I request GET https://example.com/foo.html then I get status code 200 ~~~ ~~~{#minimal.yaml .file .yaml} +webroot: webroot tls_key: snakeoil.key tls_cert: snakeoil.pem ~~~ @@ -104,12 +106,12 @@ tls_cert: snakeoil.pem ~~~scenario given a self-signed certificate as snakeoil.pem, using key snakeoil.key -and a running server using config file smoke.yaml -when I create webroot/foo with "hello, world" -and I request GET https://example.com/foo +when I create webroot/foo.html with "this is your web page" +given a running server using config file smoke.yaml +when I request GET https://example.com/foo.html then I get status code 200 -and header content-type is "text/plain" -and body is "hello, world\n" +and header content-type is "text/html" +and body is "this is your web page" ~~~ ~~~scenario-disabled @@ -145,6 +147,7 @@ scaffolding adds randomly chosen port numbers so that the test can run without being root. ~~~{#smoke.yaml .file .yaml .numberLines} +webroot: webroot tls_cert: snakeoil.pem tls_key: snakeoil.key ~~~ diff --git a/src/main.rs b/src/main.rs index d74a148..37e60d2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,6 +5,7 @@ use warp::Filter; #[derive(Debug, Deserialize)] struct Config { + webroot: PathBuf, port: u16, tls_key: PathBuf, tls_cert: PathBuf, @@ -19,6 +20,9 @@ struct Opt { #[derive(Debug, thiserror::Error)] enum EwwwError { + #[error("Web root {0} does not exist")] + WebrootNotFound(PathBuf), + #[error("TLS certificate {0} does not exist")] TlsCertNotFound(PathBuf), @@ -33,11 +37,12 @@ async fn main() { let opt = Opt::from_args(); let config = read_config(&opt.config).unwrap(); - let hello = warp::any() - .map(|| "hello, world\n".to_string()); + let webroot = config.webroot.canonicalize().unwrap(); + eprintln!("webroot: {:?}", webroot); + let webroot = warp::any().and(warp::fs::dir(webroot)); eprintln!("starting server: {:?}", config); - warp::serve(hello) + warp::serve(webroot) .tls() .key_path(config.tls_key) .cert_path(config.tls_cert) @@ -53,6 +58,9 @@ fn read_config(filename: &Path) -> anyhow::Result { } fn check_config(config: &Config) -> anyhow::Result<()> { + if !config.webroot.exists() { + return Err(EwwwError::WebrootNotFound(config.webroot.clone()).into()); + } if !config.tls_cert.exists() { return Err(EwwwError::TlsCertNotFound(config.tls_cert.clone()).into()); } -- cgit v1.2.1 From b130e74f187b2ba22db6654508a6e7e4c721a16e Mon Sep 17 00:00:00 2001 From: Lars Wirzenius Date: Sun, 19 Jul 2020 13:08:57 +0300 Subject: test: drop minimal smoke test The normal smoke test does the same thing now. --- ewww.md | 45 --------------------------------------------- 1 file changed, 45 deletions(-) diff --git a/ewww.md b/ewww.md index 536510c..1536483 100644 --- a/ewww.md +++ b/ewww.md @@ -85,23 +85,6 @@ for static content only. Every other method returns an error. # Acceptance criteria -## Minimal smoke test - -~~~scenario -when I create webroot/foo.html with "this is your web page" -given a self-signed certificate as snakeoil.pem, using key snakeoil.key -and a running server using config file minimal.yaml -when I request GET https://example.com/foo.html -then I get status code 200 -~~~ - -~~~{#minimal.yaml .file .yaml} -webroot: webroot -tls_key: snakeoil.key -tls_cert: snakeoil.pem -~~~ - - ## Smoke test ~~~scenario @@ -114,34 +97,6 @@ and header content-type is "text/html" and body is "this is your web page" ~~~ -~~~scenario-disabled -given a self-signed certificate as snakeoil.pem, using key snakeoil.key -and a running server using config file smoke.yaml - -when I request GET http://example.com/ -then I am redirected to https://example.com/ - -when I request GET http://example.com/.well-known/foo -then I get status code 404 - -when I create webroot/foo -and I request GET http://example.com/.well-known/foo -then I get status code 200 -and content-type is "application/octet-stream" - -when I request HEAD http://example.com/.well-known/foo -then I get status code 200 - -when I request GET https://example.com/ -then I get status code 200 - -when I request HEAD https://example.com/ -then I get status code 200 - -when I request GET https://www.example.com/ -then I am redirected to https://example.com/ -~~~ - The following config file does not specify port numbers. The test scaffolding adds randomly chosen port numbers so that the test can run without being root. -- cgit v1.2.1