Skip to content

Commit

Permalink
Add runtime test
Browse files Browse the repository at this point in the history
Signed-off-by: Ryan Levick <ryan.levick@fermyon.com>
  • Loading branch information
rylev committed Dec 22, 2023
1 parent aad8d96 commit 0392714
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 24 deletions.
31 changes: 31 additions & 0 deletions tests/runtime-tests/services/http-echo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
from http.server import SimpleHTTPRequestHandler, HTTPServer
import sys


class EchoHandler(SimpleHTTPRequestHandler):
def log_message(self, format, *args):
# Write logs to stdout instead of stderr
log_entry = "[%s] %s\n" % (self.log_date_time_string(), format % args)
sys.stdout.write(log_entry)

def _set_headers(self):
self.send_response(200)
self.send_header('Content-type', 'text/plain')
self.end_headers()

def do_POST(self):
content_length = int(self.headers['Content-Length'])
body = self.rfile.read(content_length)
self._set_headers()
self.wfile.write(body)


def run(port=8080):
server_address = ('', port)
httpd = HTTPServer(server_address, EchoHandler)
print(f'Starting server on port {port}...')
httpd.serve_forever()


if __name__ == '__main__':
run()
1 change: 1 addition & 0 deletions tests/runtime-tests/tests/wasi-http/services
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
http-echo.py
14 changes: 14 additions & 0 deletions tests/runtime-tests/tests/wasi-http/spin.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
spin_manifest_version = 2

[application]
name = "wasi-http"
authors = ["Fermyon Engineering <engineering@fermyon.com>"]
version = "0.1.0"

[[trigger.http]]
route = "/"
component = "test"

[component.test]
source = "{{wasi-http-v0.2.0-rc-2023-11-10}}"
allowed_outbound_hosts = ["http://localhost:8080"]
18 changes: 12 additions & 6 deletions tests/test-components/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,13 @@

Test components for use in runtime testing. Each test component has a README on what it tests. The components are checked into the repository so that users do not necessarily have to build them from source.

## Building
This crate will build all of the components as part of its `build.rs` build script. It then generates code in the lib.rs file which exposes the paths to the built components as constants. For example, for a component named foo-component, a `FOO_COMPONENT` const will be generated with the path to the built component binary.

Each component is generally built like so:
Additionally, a helper function named `path` is generated that maps a package name to binary path for dynamic lookups.

```
cargo b --target=wasm32-wasi
```
## Building

Additionally, to prevent bloat, the components are run through `wasm-tools strip`.
This crate is built like a normal Rust crate: `cargo build`

## Contract

Expand All @@ -19,3 +17,11 @@ Test components have the following contract with the outside world:
* They do not look at the incoming request.
* If nothing errors a 200 with no body will be returned.
* If an error occurs a 500 with a body describing the error will be returned.

## Adapter support

Components can optionally be adapted using a preview 1 to preview 2 adapter (instead of relying on the Spin runtime to do so).

The adapters can be found in the `adapters` directory. They come from the `wasmtime` project and can be downloaded here:

https://github.com/bytecodealliance/wasmtime/releases
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
The `wasi_snapshot_preview1.reactor.wasm` file in this directory was retrieved
using:
# Wasi HTTP (v0.2.0-rc-2023-11-10)

```
curl -LO https://github.com/bytecodealliance/wasmtime/releases/download/v15.0.1/wasi_snapshot_preview1.reactor.wasm
```
Tests the Wasi HTTP outgoing request handler specifically the 0.2.0-rc-2023-11-10 version.

The `wit` directory was copied from https://github.com/bytecodealliance/wasmtime/tree/v15.0.1/crates/wasi/wit
The `wit` directory was copied from https://github.com/bytecodealliance/wasmtime/tree/v15.0.1/crates/wasi/wit and then modified to only include the parts actually used by this component.

## Expectations

This test component expects the following to be true:
* It has access to an HTTP server on localhost:8080 that accepts POST requests and returns the same bytes in the response body as in the request body.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ wit_bindgen::generate!({
world: "wasi:http/handler@0.2.0-rc-2023-11-10",
});

use helper::ensure_eq;
use helper::{ensure_eq, ensure_ok};
use wasi::http::outgoing_handler;
use wasi::http::types::{Headers, Method, OutgoingBody, OutgoingRequest, Scheme};
use wasi::io::streams::StreamError;
Expand All @@ -12,10 +12,14 @@ helper::define_component!(Component);

impl Component {
fn main() -> Result<(), String> {
let url = url::Url::parse("https://localhost.com:3000").unwrap();
let url = url::Url::parse("http://localhost:8080").unwrap();

let outgoing_request = OutgoingRequest::new(Headers::new());
outgoing_request.set_method(&Method::Get).unwrap();
let headers = Headers::new();
headers
.append(&"Content-Length".into(), &"13".into())
.unwrap();
let outgoing_request = OutgoingRequest::new(headers);
outgoing_request.set_method(&Method::Post).unwrap();
outgoing_request
.set_path_with_query(Some(url.path()))
.unwrap();
Expand All @@ -36,29 +40,28 @@ impl Component {
let message = b"Hello, world!";
let mut offset = 0;
loop {
let write = outgoing_stream.check_write().unwrap();
let write = ensure_ok!(outgoing_stream.check_write());
if write == 0 {
outgoing_stream.subscribe().block();
continue;
} else {
let count = (write as usize).min(message.len() - offset);
outgoing_stream.write(&message[offset..][..count]).unwrap();
offset += count as usize;
ensure_ok!(outgoing_stream.write(&message[offset..][..count]));
offset += count;
if offset == message.len() {
outgoing_stream.flush().unwrap();
ensure_ok!(outgoing_stream.flush());
break;
}
}
}
// The outgoing stream must be dropped before the outgoing body is finished.
drop(outgoing_stream);
OutgoingBody::finish(outgoing_body, None).unwrap();
ensure_ok!(OutgoingBody::finish(outgoing_body, None));

// Send the request and get the response.
let incoming_response = outgoing_handler::handle(outgoing_request, None).unwrap();
let incoming_response = ensure_ok!(outgoing_handler::handle(outgoing_request, None));
let incoming_response = loop {
if let Some(incoming_response) = incoming_response.get() {
break incoming_response.unwrap().unwrap();
break ensure_ok!(incoming_response.unwrap());
} else {
incoming_response.subscribe().block()
}
Expand Down

0 comments on commit 0392714

Please sign in to comment.