Skip to content

Commit 66f357a

Browse files
authored
Merge pull request #2732 from fermyon/factors-conformance-tests
[Factors] in-process runtime and conformance tests
2 parents 0de32ba + 32f6da4 commit 66f357a

File tree

8 files changed

+250
-154
lines changed

8 files changed

+250
-154
lines changed

Cargo.lock

Lines changed: 4 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/trigger-http2/src/lib.rs

Lines changed: 31 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,9 @@ use serde::Deserialize;
2323
use spin_app::App;
2424
use spin_http::{config::HttpTriggerConfig, routes::Router};
2525
use spin_trigger2::Trigger;
26-
use tokio::net::TcpListener;
2726
use wasmtime_wasi_http::bindings::wasi::http::types::ErrorCode;
2827

29-
use server::HttpServer;
28+
pub use server::HttpServer;
3029

3130
pub use tls::TlsConfig;
3231

@@ -67,7 +66,7 @@ pub(crate) type InstanceState = ();
6766

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

8786
fn new(cli_args: Self::CliArgs, app: &spin_app::App) -> anyhow::Result<Self> {
87+
Self::new(app, cli_args.address, cli_args.into_tls_config())
88+
}
89+
90+
async fn run(self, trigger_app: TriggerApp) -> anyhow::Result<()> {
91+
let server = self.into_server(trigger_app)?;
92+
93+
server.serve().await?;
94+
95+
Ok(())
96+
}
97+
98+
fn supported_host_requirements() -> Vec<&'static str> {
99+
vec![spin_app::locked::SERVICE_CHAINING_KEY]
100+
}
101+
}
102+
103+
impl HttpTrigger {
104+
/// Create a new `HttpTrigger`.
105+
pub fn new(
106+
app: &spin_app::App,
107+
listen_addr: SocketAddr,
108+
tls_config: Option<TlsConfig>,
109+
) -> anyhow::Result<Self> {
88110
Self::validate_app(app)?;
89111

90112
let component_trigger_configs = HashMap::from_iter(
@@ -114,55 +136,32 @@ impl Trigger for HttpTrigger {
114136
"Constructed router: {:?}",
115137
router.routes().collect::<Vec<_>>()
116138
);
117-
118139
Ok(Self {
119-
listen_addr: cli_args.address,
120-
tls_config: cli_args.into_tls_config(),
140+
listen_addr,
141+
tls_config,
121142
router,
122143
component_trigger_configs,
123144
})
124145
}
125146

126-
async fn run(self, trigger_app: TriggerApp) -> anyhow::Result<()> {
147+
/// Turn this [`HttpTrigger`] into an [`HttpServer`].
148+
pub fn into_server(self, trigger_app: TriggerApp) -> anyhow::Result<Arc<HttpServer>> {
127149
let Self {
128150
listen_addr,
129151
tls_config,
130152
router,
131153
component_trigger_configs,
132154
} = self;
133-
134-
let listener = TcpListener::bind(listen_addr)
135-
.await
136-
.with_context(|| format!("Unable to listen on {listen_addr}"))?;
137-
138-
// Get the address the server is actually listening on
139-
// We can't use `self.listen_addr` because it might not
140-
// be fully resolved (e.g, port 0).
141-
let listen_addr = listener
142-
.local_addr()
143-
.context("failed to retrieve address server is listening on")?;
144155
let server = Arc::new(HttpServer::new(
145156
listen_addr,
157+
tls_config,
146158
trigger_app,
147159
router,
148160
component_trigger_configs,
149161
)?);
150-
151-
if let Some(tls_config) = tls_config {
152-
server.serve_tls(listener, tls_config).await?
153-
} else {
154-
server.serve(listener).await?
155-
};
156-
157-
Ok(())
162+
Ok(server)
158163
}
159164

160-
fn supported_host_requirements() -> Vec<&'static str> {
161-
vec![spin_app::locked::SERVICE_CHAINING_KEY]
162-
}
163-
}
164-
165-
impl HttpTrigger {
166165
fn validate_app(app: &App) -> anyhow::Result<()> {
167166
#[derive(Deserialize)]
168167
#[serde(deny_unknown_fields)]

crates/trigger-http2/src/outbound_http.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@ use spin_http::routes::RouteMatch;
1111
use spin_outbound_networking::parse_service_chaining_target;
1212
use wasmtime_wasi_http::types::IncomingResponse;
1313

14-
use crate::server::HttpServer;
14+
use crate::HttpServer;
1515

16+
/// An outbound HTTP interceptor that handles service chaining requests.
1617
pub struct OutboundHttpInterceptor {
1718
server: Arc<HttpServer>,
1819
origin: SelfRequestOrigin,

crates/trigger-http2/src/server.rs

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,20 +36,27 @@ use crate::{
3636
Body, NotFoundRouteKind, TlsConfig, TriggerApp, TriggerInstanceBuilder,
3737
};
3838

39+
/// An HTTP server which runs Spin apps.
3940
pub struct HttpServer {
4041
/// The address the server is listening on.
4142
listen_addr: SocketAddr,
42-
trigger_app: TriggerApp,
43+
/// The TLS configuration for the server.
44+
tls_config: Option<TlsConfig>,
45+
/// Request router.
4346
router: Router,
47+
/// The app being triggered.
48+
trigger_app: TriggerApp,
4449
// Component ID -> component trigger config
4550
component_trigger_configs: HashMap<String, HttpTriggerConfig>,
4651
// Component ID -> handler type
4752
component_handler_types: HashMap<String, HandlerType>,
4853
}
4954

5055
impl HttpServer {
56+
/// Create a new [`HttpServer`].
5157
pub fn new(
5258
listen_addr: SocketAddr,
59+
tls_config: Option<TlsConfig>,
5360
trigger_app: TriggerApp,
5461
router: Router,
5562
component_trigger_configs: HashMap<String, HttpTriggerConfig>,
@@ -64,14 +71,31 @@ impl HttpServer {
6471
.collect::<anyhow::Result<_>>()?;
6572
Ok(Self {
6673
listen_addr,
67-
trigger_app,
74+
tls_config,
6875
router,
76+
trigger_app,
6977
component_trigger_configs,
7078
component_handler_types,
7179
})
7280
}
7381

74-
pub async fn serve(self: Arc<Self>, listener: TcpListener) -> anyhow::Result<()> {
82+
/// Serve incoming requests over the provided [`TcpListener`].
83+
pub async fn serve(self: Arc<Self>) -> anyhow::Result<()> {
84+
let listener = TcpListener::bind(self.listen_addr).await.with_context(|| {
85+
format!(
86+
"Unable to listen on {listen_addr}",
87+
listen_addr = self.listen_addr
88+
)
89+
})?;
90+
if let Some(tls_config) = self.tls_config.clone() {
91+
self.serve_https(listener, tls_config).await?;
92+
} else {
93+
self.serve_http(listener).await?;
94+
}
95+
Ok(())
96+
}
97+
98+
async fn serve_http(self: Arc<Self>, listener: TcpListener) -> anyhow::Result<()> {
7599
self.print_startup_msgs("http", &listener)?;
76100
loop {
77101
let (stream, client_addr) = listener.accept().await?;
@@ -80,7 +104,7 @@ impl HttpServer {
80104
}
81105
}
82106

83-
pub async fn serve_tls(
107+
async fn serve_https(
84108
self: Arc<Self>,
85109
listener: TcpListener,
86110
tls_config: TlsConfig,
@@ -102,7 +126,7 @@ impl HttpServer {
102126
///
103127
/// This method handles well known paths and routes requests to the handler when the router
104128
/// matches the requests path.
105-
async fn handle(
129+
pub async fn handle(
106130
self: &Arc<Self>,
107131
mut req: Request<Body>,
108132
server_scheme: Scheme,

0 commit comments

Comments
 (0)