spikard 0.3.6 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +21 -6
- data/ext/spikard_rb/Cargo.toml +2 -2
- data/lib/spikard/app.rb +33 -14
- data/lib/spikard/testing.rb +47 -12
- data/lib/spikard/version.rb +1 -1
- data/vendor/crates/spikard-bindings-shared/Cargo.toml +63 -0
- data/vendor/crates/spikard-bindings-shared/examples/config_extraction.rs +132 -0
- data/vendor/crates/spikard-bindings-shared/src/config_extractor.rs +752 -0
- data/vendor/crates/spikard-bindings-shared/src/conversion_traits.rs +194 -0
- data/vendor/crates/spikard-bindings-shared/src/di_traits.rs +246 -0
- data/vendor/crates/spikard-bindings-shared/src/error_response.rs +401 -0
- data/vendor/crates/spikard-bindings-shared/src/handler_base.rs +238 -0
- data/vendor/crates/spikard-bindings-shared/src/lib.rs +24 -0
- data/vendor/crates/spikard-bindings-shared/src/lifecycle_base.rs +292 -0
- data/vendor/crates/spikard-bindings-shared/src/lifecycle_executor.rs +616 -0
- data/vendor/crates/spikard-bindings-shared/src/response_builder.rs +305 -0
- data/vendor/crates/spikard-bindings-shared/src/test_client_base.rs +248 -0
- data/vendor/crates/spikard-bindings-shared/src/validation_helpers.rs +351 -0
- data/vendor/crates/spikard-bindings-shared/tests/comprehensive_coverage.rs +454 -0
- data/vendor/crates/spikard-bindings-shared/tests/error_response_edge_cases.rs +383 -0
- data/vendor/crates/spikard-bindings-shared/tests/handler_base_integration.rs +280 -0
- data/vendor/crates/spikard-core/Cargo.toml +4 -4
- data/vendor/crates/spikard-core/src/debug.rs +64 -0
- data/vendor/crates/spikard-core/src/di/container.rs +3 -27
- data/vendor/crates/spikard-core/src/di/factory.rs +1 -5
- data/vendor/crates/spikard-core/src/di/graph.rs +8 -47
- data/vendor/crates/spikard-core/src/di/mod.rs +1 -1
- data/vendor/crates/spikard-core/src/di/resolved.rs +1 -7
- data/vendor/crates/spikard-core/src/di/value.rs +2 -4
- data/vendor/crates/spikard-core/src/errors.rs +30 -0
- data/vendor/crates/spikard-core/src/http.rs +262 -0
- data/vendor/crates/spikard-core/src/lib.rs +1 -1
- data/vendor/crates/spikard-core/src/lifecycle.rs +764 -0
- data/vendor/crates/spikard-core/src/metadata.rs +389 -0
- data/vendor/crates/spikard-core/src/parameters.rs +1962 -159
- data/vendor/crates/spikard-core/src/problem.rs +34 -0
- data/vendor/crates/spikard-core/src/request_data.rs +966 -1
- data/vendor/crates/spikard-core/src/router.rs +263 -2
- data/vendor/crates/spikard-core/src/validation/error_mapper.rs +688 -0
- data/vendor/crates/spikard-core/src/{validation.rs → validation/mod.rs} +26 -268
- data/vendor/crates/spikard-http/Cargo.toml +12 -16
- data/vendor/crates/spikard-http/examples/sse-notifications.rs +148 -0
- data/vendor/crates/spikard-http/examples/websocket-chat.rs +92 -0
- data/vendor/crates/spikard-http/src/auth.rs +65 -16
- data/vendor/crates/spikard-http/src/background.rs +1614 -3
- data/vendor/crates/spikard-http/src/cors.rs +515 -0
- data/vendor/crates/spikard-http/src/debug.rs +65 -0
- data/vendor/crates/spikard-http/src/di_handler.rs +1322 -77
- data/vendor/crates/spikard-http/src/handler_response.rs +711 -0
- data/vendor/crates/spikard-http/src/handler_trait.rs +607 -5
- data/vendor/crates/spikard-http/src/handler_trait_tests.rs +6 -0
- data/vendor/crates/spikard-http/src/lib.rs +33 -28
- data/vendor/crates/spikard-http/src/lifecycle/adapter.rs +81 -0
- data/vendor/crates/spikard-http/src/lifecycle.rs +765 -0
- data/vendor/crates/spikard-http/src/middleware/mod.rs +372 -117
- data/vendor/crates/spikard-http/src/middleware/multipart.rs +836 -10
- data/vendor/crates/spikard-http/src/middleware/urlencoded.rs +409 -43
- data/vendor/crates/spikard-http/src/middleware/validation.rs +513 -65
- data/vendor/crates/spikard-http/src/openapi/parameter_extraction.rs +345 -0
- data/vendor/crates/spikard-http/src/openapi/schema_conversion.rs +1055 -0
- data/vendor/crates/spikard-http/src/openapi/spec_generation.rs +473 -3
- data/vendor/crates/spikard-http/src/query_parser.rs +455 -31
- data/vendor/crates/spikard-http/src/response.rs +321 -0
- data/vendor/crates/spikard-http/src/server/handler.rs +1572 -9
- data/vendor/crates/spikard-http/src/server/lifecycle_execution.rs +136 -0
- data/vendor/crates/spikard-http/src/server/mod.rs +875 -178
- data/vendor/crates/spikard-http/src/server/request_extraction.rs +674 -23
- data/vendor/crates/spikard-http/src/server/routing_factory.rs +599 -0
- data/vendor/crates/spikard-http/src/sse.rs +983 -21
- data/vendor/crates/spikard-http/src/testing/form.rs +38 -0
- data/vendor/crates/spikard-http/src/testing/test_client.rs +0 -2
- data/vendor/crates/spikard-http/src/testing.rs +7 -7
- data/vendor/crates/spikard-http/src/websocket.rs +1055 -4
- data/vendor/crates/spikard-http/tests/background_behavior.rs +832 -0
- data/vendor/crates/spikard-http/tests/common/handlers.rs +309 -0
- data/vendor/crates/spikard-http/tests/common/mod.rs +26 -0
- data/vendor/crates/spikard-http/tests/di_integration.rs +192 -0
- data/vendor/crates/spikard-http/tests/doc_snippets.rs +5 -0
- data/vendor/crates/spikard-http/tests/lifecycle_execution.rs +1093 -0
- data/vendor/crates/spikard-http/tests/multipart_behavior.rs +656 -0
- data/vendor/crates/spikard-http/tests/server_config_builder.rs +314 -0
- data/vendor/crates/spikard-http/tests/sse_behavior.rs +620 -0
- data/vendor/crates/spikard-http/tests/websocket_behavior.rs +663 -0
- data/vendor/crates/spikard-rb/Cargo.toml +10 -4
- data/vendor/crates/spikard-rb/build.rs +196 -5
- data/vendor/crates/spikard-rb/src/config/mod.rs +5 -0
- data/vendor/crates/spikard-rb/src/{config.rs → config/server_config.rs} +100 -109
- data/vendor/crates/spikard-rb/src/conversion.rs +121 -20
- data/vendor/crates/spikard-rb/src/di/builder.rs +100 -0
- data/vendor/crates/spikard-rb/src/{di.rs → di/mod.rs} +12 -46
- data/vendor/crates/spikard-rb/src/handler.rs +100 -107
- data/vendor/crates/spikard-rb/src/integration/mod.rs +3 -0
- data/vendor/crates/spikard-rb/src/lib.rs +467 -1428
- data/vendor/crates/spikard-rb/src/lifecycle.rs +1 -0
- data/vendor/crates/spikard-rb/src/metadata/mod.rs +5 -0
- data/vendor/crates/spikard-rb/src/metadata/route_extraction.rs +447 -0
- data/vendor/crates/spikard-rb/src/runtime/mod.rs +5 -0
- data/vendor/crates/spikard-rb/src/runtime/server_runner.rs +324 -0
- data/vendor/crates/spikard-rb/src/server.rs +47 -22
- data/vendor/crates/spikard-rb/src/{test_client.rs → testing/client.rs} +187 -40
- data/vendor/crates/spikard-rb/src/testing/mod.rs +7 -0
- data/vendor/crates/spikard-rb/src/testing/websocket.rs +635 -0
- data/vendor/crates/spikard-rb/src/websocket.rs +178 -37
- metadata +46 -13
- data/vendor/crates/spikard-http/src/parameters.rs +0 -1
- data/vendor/crates/spikard-http/src/problem.rs +0 -1
- data/vendor/crates/spikard-http/src/router.rs +0 -1
- data/vendor/crates/spikard-http/src/schema_registry.rs +0 -1
- data/vendor/crates/spikard-http/src/type_hints.rs +0 -1
- data/vendor/crates/spikard-http/src/validation.rs +0 -1
- data/vendor/crates/spikard-rb/src/test_websocket.rs +0 -221
- /data/vendor/crates/spikard-rb/src/{test_sse.rs → testing/sse.rs} +0 -0
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
#![allow(dead_code)]
|
|
8
8
|
|
|
9
9
|
use axum::http::Method;
|
|
10
|
+
use axum::Router;
|
|
10
11
|
use axum_test::{TestServer, TestServerConfig, Transport};
|
|
11
12
|
use bytes::Bytes;
|
|
12
13
|
use cookie::Cookie;
|
|
@@ -14,16 +15,22 @@ use magnus::prelude::*;
|
|
|
14
15
|
use magnus::{Error, RHash, Ruby, Value, gc::Marker};
|
|
15
16
|
use serde_json::Value as JsonValue;
|
|
16
17
|
use spikard_http::testing::{
|
|
17
|
-
MultipartFilePart,
|
|
18
|
+
MultipartFilePart,
|
|
19
|
+
ResponseSnapshot,
|
|
20
|
+
SnapshotError,
|
|
21
|
+
build_multipart_body,
|
|
22
|
+
encode_urlencoded_body,
|
|
23
|
+
snapshot_response,
|
|
18
24
|
};
|
|
19
25
|
use spikard_http::{Route, RouteMetadata};
|
|
20
26
|
use std::cell::RefCell;
|
|
21
27
|
use std::collections::HashMap;
|
|
22
28
|
use std::sync::Arc;
|
|
29
|
+
use std::time::Duration;
|
|
30
|
+
use url::Url;
|
|
23
31
|
|
|
24
32
|
use crate::conversion::{parse_request_config, response_to_ruby};
|
|
25
33
|
use crate::handler::RubyHandler;
|
|
26
|
-
use crate::server::GLOBAL_RUNTIME;
|
|
27
34
|
|
|
28
35
|
/// Request configuration built from Ruby options hash.
|
|
29
36
|
pub struct RequestConfig {
|
|
@@ -55,6 +62,12 @@ pub struct TestResponseData {
|
|
|
55
62
|
#[derive(Debug)]
|
|
56
63
|
pub struct NativeRequestError(pub String);
|
|
57
64
|
|
|
65
|
+
#[derive(Debug)]
|
|
66
|
+
enum WebSocketConnectError {
|
|
67
|
+
Timeout,
|
|
68
|
+
Other(String),
|
|
69
|
+
}
|
|
70
|
+
|
|
58
71
|
/// Inner client state containing the test servers and handlers.
|
|
59
72
|
pub struct ClientInner {
|
|
60
73
|
pub http_server: Arc<TestServer>,
|
|
@@ -95,6 +108,7 @@ impl NativeTestClient {
|
|
|
95
108
|
ws_handlers: Value,
|
|
96
109
|
sse_producers: Value,
|
|
97
110
|
) -> Result<(), Error> {
|
|
111
|
+
trace_step("initialize:start");
|
|
98
112
|
let metadata: Vec<RouteMetadata> = serde_json::from_str(&routes_json)
|
|
99
113
|
.map_err(|err| Error::new(ruby.exception_arg_error(), format!("Invalid routes JSON: {err}")))?;
|
|
100
114
|
|
|
@@ -128,6 +142,7 @@ impl NativeTestClient {
|
|
|
128
142
|
route_metadata_vec.push(meta);
|
|
129
143
|
}
|
|
130
144
|
|
|
145
|
+
trace_step("initialize:build_router");
|
|
131
146
|
let mut router = spikard_http::server::build_router_with_handlers_and_config(
|
|
132
147
|
prepared_routes,
|
|
133
148
|
server_config,
|
|
@@ -137,6 +152,7 @@ impl NativeTestClient {
|
|
|
137
152
|
|
|
138
153
|
let mut ws_endpoints = Vec::new();
|
|
139
154
|
if !ws_handlers.is_nil() {
|
|
155
|
+
trace_step("initialize:ws_handlers");
|
|
140
156
|
let ws_hash = RHash::from_value(ws_handlers)
|
|
141
157
|
.ok_or_else(|| Error::new(ruby.exception_arg_error(), "WebSocket handlers must be a Hash"))?;
|
|
142
158
|
|
|
@@ -160,6 +176,7 @@ impl NativeTestClient {
|
|
|
160
176
|
|
|
161
177
|
let mut sse_endpoints = Vec::new();
|
|
162
178
|
if !sse_producers.is_nil() {
|
|
179
|
+
trace_step("initialize:sse_producers");
|
|
163
180
|
let sse_hash = RHash::from_value(sse_producers)
|
|
164
181
|
.ok_or_else(|| Error::new(ruby.exception_arg_error(), "SSE producers must be a Hash"))?;
|
|
165
182
|
|
|
@@ -196,28 +213,19 @@ impl NativeTestClient {
|
|
|
196
213
|
);
|
|
197
214
|
}
|
|
198
215
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
Error::new(
|
|
203
|
-
ruby.exception_runtime_error(),
|
|
204
|
-
format!("Failed to initialise test server: {err}"),
|
|
205
|
-
)
|
|
206
|
-
})?;
|
|
216
|
+
trace_step("initialize:test_server_http");
|
|
217
|
+
let timeout_duration = test_server_timeout();
|
|
218
|
+
let http_server = init_test_server(router.clone(), timeout_duration, "test server", ruby)?;
|
|
207
219
|
|
|
220
|
+
trace_step("initialize:test_server_ws");
|
|
208
221
|
let ws_config = TestServerConfig {
|
|
209
222
|
transport: Some(Transport::HttpRandomPort),
|
|
210
223
|
..Default::default()
|
|
211
224
|
};
|
|
212
|
-
let transport_server =
|
|
213
|
-
|
|
214
|
-
.map_err(|err| {
|
|
215
|
-
Error::new(
|
|
216
|
-
ruby.exception_runtime_error(),
|
|
217
|
-
format!("Failed to initialise WebSocket transport server: {err}"),
|
|
218
|
-
)
|
|
219
|
-
})?;
|
|
225
|
+
let transport_server =
|
|
226
|
+
init_test_server_with_config(router, ws_config, timeout_duration, "WebSocket transport server", ruby)?;
|
|
220
227
|
|
|
228
|
+
trace_step("initialize:done");
|
|
221
229
|
*this.inner.borrow_mut() = Some(ClientInner {
|
|
222
230
|
http_server: Arc::new(http_server),
|
|
223
231
|
transport_server: Arc::new(transport_server),
|
|
@@ -251,13 +259,21 @@ impl NativeTestClient {
|
|
|
251
259
|
|
|
252
260
|
let request_config = parse_request_config(ruby, options)?;
|
|
253
261
|
|
|
254
|
-
let
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
262
|
+
let runtime = crate::server::global_runtime(ruby)?;
|
|
263
|
+
let server = inner.http_server.clone();
|
|
264
|
+
let path_value = path.clone();
|
|
265
|
+
let request_config_value = request_config;
|
|
266
|
+
let response = crate::call_without_gvl!(
|
|
267
|
+
block_on_request,
|
|
268
|
+
args: (
|
|
269
|
+
runtime, &tokio::runtime::Runtime,
|
|
270
|
+
server, Arc<TestServer>,
|
|
271
|
+
http_method, Method,
|
|
272
|
+
path_value, String,
|
|
273
|
+
request_config_value, RequestConfig
|
|
274
|
+
),
|
|
275
|
+
return_type: Result<TestResponseData, NativeRequestError>
|
|
276
|
+
)
|
|
261
277
|
.map_err(|err| {
|
|
262
278
|
Error::new(
|
|
263
279
|
ruby.exception_runtime_error(),
|
|
@@ -285,16 +301,31 @@ impl NativeTestClient {
|
|
|
285
301
|
|
|
286
302
|
drop(inner_borrow);
|
|
287
303
|
|
|
288
|
-
let
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
304
|
+
let timeout_duration = websocket_timeout();
|
|
305
|
+
let ws = crate::call_without_gvl!(
|
|
306
|
+
block_on_websocket_connect,
|
|
307
|
+
args: (
|
|
308
|
+
server, Arc<TestServer>,
|
|
309
|
+
path, String,
|
|
310
|
+
timeout_duration, Duration
|
|
311
|
+
),
|
|
312
|
+
return_type: Result<crate::testing::websocket::WebSocketConnection, WebSocketConnectError>
|
|
313
|
+
)
|
|
314
|
+
.map_err(|err| match err {
|
|
315
|
+
WebSocketConnectError::Timeout => Error::new(
|
|
316
|
+
ruby.exception_runtime_error(),
|
|
317
|
+
format!(
|
|
318
|
+
"WebSocket connect timed out after {}ms",
|
|
319
|
+
timeout_duration.as_millis()
|
|
320
|
+
),
|
|
321
|
+
),
|
|
322
|
+
WebSocketConnectError::Other(message) => Error::new(
|
|
323
|
+
ruby.exception_runtime_error(),
|
|
324
|
+
format!("WebSocket connect failed: {}", message),
|
|
325
|
+
),
|
|
295
326
|
})?;
|
|
296
327
|
|
|
297
|
-
let ws_conn = crate::
|
|
328
|
+
let ws_conn = crate::testing::websocket::WebSocketTestConnection::new(ws);
|
|
298
329
|
Ok(ruby.obj_wrap(ws_conn).as_value())
|
|
299
330
|
}
|
|
300
331
|
|
|
@@ -305,14 +336,41 @@ impl NativeTestClient {
|
|
|
305
336
|
.as_ref()
|
|
306
337
|
.ok_or_else(|| Error::new(ruby.exception_runtime_error(), "TestClient not initialised"))?;
|
|
307
338
|
|
|
308
|
-
let
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
339
|
+
let runtime = crate::server::global_runtime(ruby)?;
|
|
340
|
+
let server = inner.http_server.clone();
|
|
341
|
+
let http_method = Method::GET;
|
|
342
|
+
let request_config = RequestConfig {
|
|
343
|
+
query: None,
|
|
344
|
+
headers: HashMap::new(),
|
|
345
|
+
cookies: HashMap::new(),
|
|
346
|
+
body: None,
|
|
347
|
+
};
|
|
348
|
+
let response = crate::call_without_gvl!(
|
|
349
|
+
block_on_request,
|
|
350
|
+
args: (
|
|
351
|
+
runtime, &tokio::runtime::Runtime,
|
|
352
|
+
server, Arc<TestServer>,
|
|
353
|
+
http_method, Method,
|
|
354
|
+
path, String,
|
|
355
|
+
request_config, RequestConfig
|
|
356
|
+
),
|
|
357
|
+
return_type: Result<TestResponseData, NativeRequestError>
|
|
358
|
+
)
|
|
359
|
+
.map_err(|err| {
|
|
360
|
+
Error::new(
|
|
361
|
+
ruby.exception_runtime_error(),
|
|
362
|
+
format!("SSE request failed: {}", err.0),
|
|
363
|
+
)
|
|
364
|
+
})?;
|
|
314
365
|
|
|
315
|
-
|
|
366
|
+
let body = response.body_text.unwrap_or_default().into_bytes();
|
|
367
|
+
let snapshot = ResponseSnapshot {
|
|
368
|
+
status: response.status,
|
|
369
|
+
headers: response.headers,
|
|
370
|
+
body,
|
|
371
|
+
};
|
|
372
|
+
|
|
373
|
+
crate::testing::sse::sse_stream_from_response(ruby, &snapshot)
|
|
316
374
|
}
|
|
317
375
|
|
|
318
376
|
/// GC mark hook so Ruby keeps handler closures alive.
|
|
@@ -327,6 +385,95 @@ impl NativeTestClient {
|
|
|
327
385
|
}
|
|
328
386
|
}
|
|
329
387
|
|
|
388
|
+
fn websocket_timeout() -> Duration {
|
|
389
|
+
const DEFAULT_TIMEOUT_MS: u64 = 30_000;
|
|
390
|
+
let timeout_ms = std::env::var("SPIKARD_RB_WS_TIMEOUT_MS")
|
|
391
|
+
.ok()
|
|
392
|
+
.and_then(|value| value.parse::<u64>().ok())
|
|
393
|
+
.unwrap_or(DEFAULT_TIMEOUT_MS);
|
|
394
|
+
Duration::from_millis(timeout_ms)
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
fn block_on_request(
|
|
398
|
+
runtime: &tokio::runtime::Runtime,
|
|
399
|
+
server: Arc<TestServer>,
|
|
400
|
+
method: Method,
|
|
401
|
+
path: String,
|
|
402
|
+
config: RequestConfig,
|
|
403
|
+
) -> Result<TestResponseData, NativeRequestError> {
|
|
404
|
+
runtime.block_on(execute_request(server, method, path, config))
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
fn block_on_websocket_connect(
|
|
408
|
+
server: Arc<TestServer>,
|
|
409
|
+
path: String,
|
|
410
|
+
timeout_duration: Duration,
|
|
411
|
+
) -> Result<crate::testing::websocket::WebSocketConnection, WebSocketConnectError> {
|
|
412
|
+
let url = server
|
|
413
|
+
.server_url(&path)
|
|
414
|
+
.map_err(|err| WebSocketConnectError::Other(err.to_string()))?;
|
|
415
|
+
let ws_url = to_ws_url(url)?;
|
|
416
|
+
|
|
417
|
+
match crate::testing::websocket::WebSocketConnection::connect(ws_url, timeout_duration) {
|
|
418
|
+
Ok(ws) => Ok(ws),
|
|
419
|
+
Err(crate::testing::websocket::WebSocketIoError::Timeout) => Err(WebSocketConnectError::Timeout),
|
|
420
|
+
Err(err) => Err(WebSocketConnectError::Other(format!("{:?}", err))),
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
fn to_ws_url(mut url: Url) -> Result<Url, WebSocketConnectError> {
|
|
425
|
+
let scheme = match url.scheme() {
|
|
426
|
+
"https" => "wss",
|
|
427
|
+
_ => "ws",
|
|
428
|
+
};
|
|
429
|
+
url.set_scheme(scheme)
|
|
430
|
+
.map_err(|_| WebSocketConnectError::Other("Failed to set WebSocket scheme".to_string()))?;
|
|
431
|
+
Ok(url)
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
fn test_server_timeout() -> Duration {
|
|
435
|
+
const DEFAULT_TIMEOUT_MS: u64 = 30_000;
|
|
436
|
+
let timeout_ms = std::env::var("SPIKARD_RB_TESTSERVER_TIMEOUT_MS")
|
|
437
|
+
.ok()
|
|
438
|
+
.and_then(|value| value.parse::<u64>().ok())
|
|
439
|
+
.unwrap_or(DEFAULT_TIMEOUT_MS);
|
|
440
|
+
Duration::from_millis(timeout_ms)
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
fn trace_step(message: &str) {
|
|
444
|
+
if std::env::var("SPIKARD_RB_TEST_TRACE").ok().as_deref() == Some("1") {
|
|
445
|
+
eprintln!("[spikard-rb-test] {}", message);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
fn init_test_server(router: Router, _timeout: Duration, label: &str, ruby: &Ruby) -> Result<TestServer, Error> {
|
|
450
|
+
let runtime = crate::server::global_runtime(ruby)?;
|
|
451
|
+
let _guard = runtime.enter();
|
|
452
|
+
TestServer::new(router).map_err(|err| {
|
|
453
|
+
Error::new(
|
|
454
|
+
ruby.exception_runtime_error(),
|
|
455
|
+
format!("Failed to initialise {label}: {err}"),
|
|
456
|
+
)
|
|
457
|
+
})
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
fn init_test_server_with_config(
|
|
461
|
+
router: Router,
|
|
462
|
+
config: TestServerConfig,
|
|
463
|
+
_timeout: Duration,
|
|
464
|
+
label: &str,
|
|
465
|
+
ruby: &Ruby,
|
|
466
|
+
) -> Result<TestServer, Error> {
|
|
467
|
+
let runtime = crate::server::global_runtime(ruby)?;
|
|
468
|
+
let _guard = runtime.enter();
|
|
469
|
+
TestServer::new_with_config(router, config).map_err(|err| {
|
|
470
|
+
Error::new(
|
|
471
|
+
ruby.exception_runtime_error(),
|
|
472
|
+
format!("Failed to initialise {label}: {err}"),
|
|
473
|
+
)
|
|
474
|
+
})
|
|
475
|
+
}
|
|
476
|
+
|
|
330
477
|
/// Execute an HTTP request against a test server.
|
|
331
478
|
///
|
|
332
479
|
/// Handles method routing, query params, headers, cookies, and various body formats.
|