Skip to content

Commit

Permalink
Merge pull request #2732 from fermyon/factors-conformance-tests
Browse files Browse the repository at this point in the history
[Factors] in-process runtime and conformance tests
  • Loading branch information
rylev committed Aug 21, 2024
2 parents 0de32ba + 32f6da4 commit 66f357a
Show file tree
Hide file tree
Showing 8 changed files with 250 additions and 154 deletions.
6 changes: 4 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

63 changes: 31 additions & 32 deletions crates/trigger-http2/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,9 @@ use serde::Deserialize;
use spin_app::App;
use spin_http::{config::HttpTriggerConfig, routes::Router};
use spin_trigger2::Trigger;
use tokio::net::TcpListener;
use wasmtime_wasi_http::bindings::wasi::http::types::ErrorCode;

use server::HttpServer;
pub use server::HttpServer;

pub use tls::TlsConfig;

Expand Down Expand Up @@ -67,7 +66,7 @@ pub(crate) type InstanceState = ();

/// The Spin HTTP trigger.
pub struct HttpTrigger {
/// The address the server will listen on.
/// The address the server should listen on.
///
/// Note that this might not be the actual socket address that ends up being bound to.
/// If the port is set to 0, the actual address will be determined by the OS.
Expand All @@ -85,6 +84,29 @@ impl Trigger for HttpTrigger {
type InstanceState = InstanceState;

fn new(cli_args: Self::CliArgs, app: &spin_app::App) -> anyhow::Result<Self> {
Self::new(app, cli_args.address, cli_args.into_tls_config())
}

async fn run(self, trigger_app: TriggerApp) -> anyhow::Result<()> {
let server = self.into_server(trigger_app)?;

server.serve().await?;

Ok(())
}

fn supported_host_requirements() -> Vec<&'static str> {
vec![spin_app::locked::SERVICE_CHAINING_KEY]
}
}

impl HttpTrigger {
/// Create a new `HttpTrigger`.
pub fn new(
app: &spin_app::App,
listen_addr: SocketAddr,
tls_config: Option<TlsConfig>,
) -> anyhow::Result<Self> {
Self::validate_app(app)?;

let component_trigger_configs = HashMap::from_iter(
Expand Down Expand Up @@ -114,55 +136,32 @@ impl Trigger for HttpTrigger {
"Constructed router: {:?}",
router.routes().collect::<Vec<_>>()
);

Ok(Self {
listen_addr: cli_args.address,
tls_config: cli_args.into_tls_config(),
listen_addr,
tls_config,
router,
component_trigger_configs,
})
}

async fn run(self, trigger_app: TriggerApp) -> anyhow::Result<()> {
/// Turn this [`HttpTrigger`] into an [`HttpServer`].
pub fn into_server(self, trigger_app: TriggerApp) -> anyhow::Result<Arc<HttpServer>> {
let Self {
listen_addr,
tls_config,
router,
component_trigger_configs,
} = self;

let listener = TcpListener::bind(listen_addr)
.await
.with_context(|| format!("Unable to listen on {listen_addr}"))?;

// Get the address the server is actually listening on
// We can't use `self.listen_addr` because it might not
// be fully resolved (e.g, port 0).
let listen_addr = listener
.local_addr()
.context("failed to retrieve address server is listening on")?;
let server = Arc::new(HttpServer::new(
listen_addr,
tls_config,
trigger_app,
router,
component_trigger_configs,
)?);

if let Some(tls_config) = tls_config {
server.serve_tls(listener, tls_config).await?
} else {
server.serve(listener).await?
};

Ok(())
Ok(server)
}

fn supported_host_requirements() -> Vec<&'static str> {
vec![spin_app::locked::SERVICE_CHAINING_KEY]
}
}

impl HttpTrigger {
fn validate_app(app: &App) -> anyhow::Result<()> {
#[derive(Deserialize)]
#[serde(deny_unknown_fields)]
Expand Down
3 changes: 2 additions & 1 deletion crates/trigger-http2/src/outbound_http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ use spin_http::routes::RouteMatch;
use spin_outbound_networking::parse_service_chaining_target;
use wasmtime_wasi_http::types::IncomingResponse;

use crate::server::HttpServer;
use crate::HttpServer;

/// An outbound HTTP interceptor that handles service chaining requests.
pub struct OutboundHttpInterceptor {
server: Arc<HttpServer>,
origin: SelfRequestOrigin,
Expand Down
34 changes: 29 additions & 5 deletions crates/trigger-http2/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,20 +36,27 @@ use crate::{
Body, NotFoundRouteKind, TlsConfig, TriggerApp, TriggerInstanceBuilder,
};

/// An HTTP server which runs Spin apps.
pub struct HttpServer {
/// The address the server is listening on.
listen_addr: SocketAddr,
trigger_app: TriggerApp,
/// The TLS configuration for the server.
tls_config: Option<TlsConfig>,
/// Request router.
router: Router,
/// The app being triggered.
trigger_app: TriggerApp,
// Component ID -> component trigger config
component_trigger_configs: HashMap<String, HttpTriggerConfig>,
// Component ID -> handler type
component_handler_types: HashMap<String, HandlerType>,
}

impl HttpServer {
/// Create a new [`HttpServer`].
pub fn new(
listen_addr: SocketAddr,
tls_config: Option<TlsConfig>,
trigger_app: TriggerApp,
router: Router,
component_trigger_configs: HashMap<String, HttpTriggerConfig>,
Expand All @@ -64,14 +71,31 @@ impl HttpServer {
.collect::<anyhow::Result<_>>()?;
Ok(Self {
listen_addr,
trigger_app,
tls_config,
router,
trigger_app,
component_trigger_configs,
component_handler_types,
})
}

pub async fn serve(self: Arc<Self>, listener: TcpListener) -> anyhow::Result<()> {
/// Serve incoming requests over the provided [`TcpListener`].
pub async fn serve(self: Arc<Self>) -> anyhow::Result<()> {
let listener = TcpListener::bind(self.listen_addr).await.with_context(|| {
format!(
"Unable to listen on {listen_addr}",
listen_addr = self.listen_addr
)
})?;
if let Some(tls_config) = self.tls_config.clone() {
self.serve_https(listener, tls_config).await?;
} else {
self.serve_http(listener).await?;
}
Ok(())
}

async fn serve_http(self: Arc<Self>, listener: TcpListener) -> anyhow::Result<()> {
self.print_startup_msgs("http", &listener)?;
loop {
let (stream, client_addr) = listener.accept().await?;
Expand All @@ -80,7 +104,7 @@ impl HttpServer {
}
}

pub async fn serve_tls(
async fn serve_https(
self: Arc<Self>,
listener: TcpListener,
tls_config: TlsConfig,
Expand All @@ -102,7 +126,7 @@ impl HttpServer {
///
/// This method handles well known paths and routes requests to the handler when the router
/// matches the requests path.
async fn handle(
pub async fn handle(
self: &Arc<Self>,
mut req: Request<Body>,
server_scheme: Scheme,
Expand Down
Loading

0 comments on commit 66f357a

Please sign in to comment.