spikard 0.8.3 → 0.10.2
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 +19 -10
- data/ext/spikard_rb/Cargo.lock +234 -162
- data/ext/spikard_rb/Cargo.toml +2 -2
- data/ext/spikard_rb/extconf.rb +4 -3
- data/lib/spikard/config.rb +88 -12
- data/lib/spikard/testing.rb +3 -1
- data/lib/spikard/version.rb +1 -1
- data/lib/spikard.rb +11 -0
- data/vendor/crates/spikard-bindings-shared/Cargo.toml +3 -6
- data/vendor/crates/spikard-bindings-shared/examples/config_extraction.rs +8 -8
- data/vendor/crates/spikard-bindings-shared/src/config_extractor.rs +2 -2
- data/vendor/crates/spikard-bindings-shared/src/conversion_traits.rs +4 -4
- data/vendor/crates/spikard-bindings-shared/src/di_traits.rs +10 -4
- data/vendor/crates/spikard-bindings-shared/src/error_response.rs +3 -3
- data/vendor/crates/spikard-bindings-shared/src/handler_base.rs +10 -5
- data/vendor/crates/spikard-bindings-shared/src/json_conversion.rs +829 -0
- data/vendor/crates/spikard-bindings-shared/src/lazy_cache.rs +587 -0
- data/vendor/crates/spikard-bindings-shared/src/lib.rs +7 -0
- data/vendor/crates/spikard-bindings-shared/src/lifecycle_base.rs +11 -11
- data/vendor/crates/spikard-bindings-shared/src/lifecycle_executor.rs +9 -37
- data/vendor/crates/spikard-bindings-shared/src/response_builder.rs +436 -3
- data/vendor/crates/spikard-bindings-shared/src/response_interpreter.rs +944 -0
- data/vendor/crates/spikard-bindings-shared/src/test_client_base.rs +4 -4
- data/vendor/crates/spikard-bindings-shared/tests/config_extractor_behavior.rs +3 -2
- data/vendor/crates/spikard-bindings-shared/tests/error_response_edge_cases.rs +13 -13
- data/vendor/crates/spikard-bindings-shared/tests/{comprehensive_coverage.rs → full_coverage.rs} +10 -5
- data/vendor/crates/spikard-bindings-shared/tests/handler_base_integration.rs +14 -14
- data/vendor/crates/spikard-bindings-shared/tests/integration_tests.rs +669 -0
- data/vendor/crates/spikard-core/Cargo.toml +3 -3
- data/vendor/crates/spikard-core/src/di/container.rs +1 -1
- data/vendor/crates/spikard-core/src/di/factory.rs +2 -2
- data/vendor/crates/spikard-core/src/di/resolved.rs +2 -2
- data/vendor/crates/spikard-core/src/di/value.rs +1 -1
- data/vendor/crates/spikard-core/src/http.rs +75 -0
- data/vendor/crates/spikard-core/src/lifecycle.rs +43 -43
- data/vendor/crates/spikard-core/src/parameters.rs +14 -19
- data/vendor/crates/spikard-core/src/problem.rs +1 -1
- data/vendor/crates/spikard-core/src/request_data.rs +7 -16
- data/vendor/crates/spikard-core/src/router.rs +6 -0
- data/vendor/crates/spikard-core/src/schema_registry.rs +2 -3
- data/vendor/crates/spikard-core/src/type_hints.rs +3 -2
- data/vendor/crates/spikard-core/src/validation/error_mapper.rs +1 -1
- data/vendor/crates/spikard-core/src/validation/mod.rs +1 -1
- data/vendor/crates/spikard-core/tests/di_dependency_defaults.rs +1 -1
- data/vendor/crates/spikard-core/tests/error_mapper.rs +2 -2
- data/vendor/crates/spikard-core/tests/parameters_edge_cases.rs +1 -1
- data/vendor/crates/spikard-core/tests/parameters_full.rs +1 -1
- data/vendor/crates/spikard-core/tests/parameters_schema_and_formats.rs +1 -1
- data/vendor/crates/spikard-core/tests/validation_coverage.rs +4 -4
- data/vendor/crates/spikard-http/Cargo.toml +4 -2
- data/vendor/crates/spikard-http/src/cors.rs +32 -11
- data/vendor/crates/spikard-http/src/di_handler.rs +12 -8
- data/vendor/crates/spikard-http/src/grpc/framing.rs +469 -0
- data/vendor/crates/spikard-http/src/grpc/handler.rs +887 -25
- data/vendor/crates/spikard-http/src/grpc/mod.rs +114 -22
- data/vendor/crates/spikard-http/src/grpc/service.rs +232 -2
- data/vendor/crates/spikard-http/src/grpc/streaming.rs +80 -2
- data/vendor/crates/spikard-http/src/handler_trait.rs +204 -27
- data/vendor/crates/spikard-http/src/handler_trait_tests.rs +15 -15
- data/vendor/crates/spikard-http/src/jsonrpc/http_handler.rs +2 -2
- data/vendor/crates/spikard-http/src/jsonrpc/router.rs +2 -2
- data/vendor/crates/spikard-http/src/lib.rs +1 -1
- data/vendor/crates/spikard-http/src/lifecycle/adapter.rs +2 -2
- data/vendor/crates/spikard-http/src/lifecycle.rs +4 -4
- data/vendor/crates/spikard-http/src/openapi/spec_generation.rs +2 -0
- data/vendor/crates/spikard-http/src/server/fast_router.rs +186 -0
- data/vendor/crates/spikard-http/src/server/grpc_routing.rs +324 -23
- data/vendor/crates/spikard-http/src/server/handler.rs +33 -22
- data/vendor/crates/spikard-http/src/server/lifecycle_execution.rs +21 -2
- data/vendor/crates/spikard-http/src/server/mod.rs +125 -20
- data/vendor/crates/spikard-http/src/server/request_extraction.rs +126 -44
- data/vendor/crates/spikard-http/src/server/routing_factory.rs +80 -69
- data/vendor/crates/spikard-http/tests/common/handlers.rs +2 -2
- data/vendor/crates/spikard-http/tests/common/test_builders.rs +12 -12
- data/vendor/crates/spikard-http/tests/di_handler_error_responses.rs +2 -2
- data/vendor/crates/spikard-http/tests/di_integration.rs +6 -6
- data/vendor/crates/spikard-http/tests/grpc_bidirectional_streaming.rs +430 -0
- data/vendor/crates/spikard-http/tests/grpc_client_streaming.rs +738 -0
- data/vendor/crates/spikard-http/tests/grpc_integration_test.rs +13 -9
- data/vendor/crates/spikard-http/tests/grpc_server_streaming.rs +974 -0
- data/vendor/crates/spikard-http/tests/lifecycle_execution.rs +2 -2
- data/vendor/crates/spikard-http/tests/request_extraction_full.rs +4 -4
- data/vendor/crates/spikard-http/tests/server_config_builder.rs +2 -2
- data/vendor/crates/spikard-http/tests/server_cors_preflight.rs +1 -0
- data/vendor/crates/spikard-http/tests/server_openapi_jsonrpc_static.rs +140 -0
- data/vendor/crates/spikard-rb/Cargo.toml +3 -1
- data/vendor/crates/spikard-rb/src/conversion.rs +138 -4
- data/vendor/crates/spikard-rb/src/grpc/handler.rs +706 -229
- data/vendor/crates/spikard-rb/src/grpc/mod.rs +6 -2
- data/vendor/crates/spikard-rb/src/gvl.rs +2 -2
- data/vendor/crates/spikard-rb/src/handler.rs +169 -91
- data/vendor/crates/spikard-rb/src/lib.rs +444 -62
- data/vendor/crates/spikard-rb/src/lifecycle.rs +29 -1
- data/vendor/crates/spikard-rb/src/metadata/route_extraction.rs +108 -43
- data/vendor/crates/spikard-rb/src/request.rs +117 -20
- data/vendor/crates/spikard-rb/src/runtime/server_runner.rs +52 -25
- data/vendor/crates/spikard-rb/src/server.rs +23 -14
- data/vendor/crates/spikard-rb/src/testing/client.rs +5 -4
- data/vendor/crates/spikard-rb/src/testing/sse.rs +1 -36
- data/vendor/crates/spikard-rb/src/testing/websocket.rs +3 -38
- data/vendor/crates/spikard-rb/src/websocket.rs +32 -23
- data/vendor/crates/spikard-rb-macros/Cargo.toml +1 -1
- metadata +14 -4
- data/vendor/bundle/ruby/3.4.0/gems/diff-lcs-1.6.2/mise.toml +0 -5
- data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.10.0/build/buildkitd.toml +0 -2
|
@@ -206,7 +206,7 @@ mod tests {
|
|
|
206
206
|
let metadata_204 = TestResponseMetadata::new(204, headers.clone(), 0, 50);
|
|
207
207
|
let metadata_299 = TestResponseMetadata::new(299, headers.clone(), 100, 50);
|
|
208
208
|
let metadata_300 = TestResponseMetadata::new(300, headers.clone(), 100, 50);
|
|
209
|
-
let metadata_400 = TestResponseMetadata::new(400, headers
|
|
209
|
+
let metadata_400 = TestResponseMetadata::new(400, headers, 100, 50);
|
|
210
210
|
|
|
211
211
|
assert!(metadata_200.is_success());
|
|
212
212
|
assert!(metadata_201.is_success());
|
|
@@ -223,7 +223,7 @@ mod tests {
|
|
|
223
223
|
let metadata_400 = TestResponseMetadata::new(400, headers.clone(), 100, 50);
|
|
224
224
|
let metadata_404 = TestResponseMetadata::new(404, headers.clone(), 100, 50);
|
|
225
225
|
let metadata_499 = TestResponseMetadata::new(499, headers.clone(), 100, 50);
|
|
226
|
-
let metadata_500 = TestResponseMetadata::new(500, headers
|
|
226
|
+
let metadata_500 = TestResponseMetadata::new(500, headers, 100, 50);
|
|
227
227
|
|
|
228
228
|
assert!(!metadata_399.is_client_error());
|
|
229
229
|
assert!(metadata_400.is_client_error());
|
|
@@ -239,7 +239,7 @@ mod tests {
|
|
|
239
239
|
let metadata_500 = TestResponseMetadata::new(500, headers.clone(), 100, 50);
|
|
240
240
|
let metadata_502 = TestResponseMetadata::new(502, headers.clone(), 100, 50);
|
|
241
241
|
let metadata_599 = TestResponseMetadata::new(599, headers.clone(), 100, 50);
|
|
242
|
-
let metadata_600 = TestResponseMetadata::new(600, headers
|
|
242
|
+
let metadata_600 = TestResponseMetadata::new(600, headers, 100, 50);
|
|
243
243
|
|
|
244
244
|
assert!(!metadata_499.is_server_error());
|
|
245
245
|
assert!(metadata_500.is_server_error());
|
|
@@ -252,7 +252,7 @@ mod tests {
|
|
|
252
252
|
fn test_response_metadata_debug() {
|
|
253
253
|
let headers = HashMap::new();
|
|
254
254
|
let metadata = TestResponseMetadata::new(200, headers, 100, 50);
|
|
255
|
-
let debug_str = format!("{:?}"
|
|
255
|
+
let debug_str = format!("{metadata:?}");
|
|
256
256
|
assert!(debug_str.contains("200"));
|
|
257
257
|
assert!(debug_str.contains("100"));
|
|
258
258
|
assert!(debug_str.contains("50"));
|
|
@@ -7,6 +7,7 @@ struct JsonSource {
|
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
impl JsonSource {
|
|
10
|
+
#[allow(clippy::missing_const_for_fn)]
|
|
10
11
|
fn new(value: serde_json::Value) -> Self {
|
|
11
12
|
Self { value }
|
|
12
13
|
}
|
|
@@ -44,7 +45,7 @@ impl ConfigSource for JsonSource {
|
|
|
44
45
|
|
|
45
46
|
fn get_nested(&self, key: &str) -> Option<Box<dyn ConfigSource + '_>> {
|
|
46
47
|
let nested = self.get(key)?.as_object()?;
|
|
47
|
-
Some(Box::new(
|
|
48
|
+
Some(Box::new(Self {
|
|
48
49
|
value: serde_json::Value::Object(nested.clone()),
|
|
49
50
|
}))
|
|
50
51
|
}
|
|
@@ -60,7 +61,7 @@ impl ConfigSource for JsonSource {
|
|
|
60
61
|
fn get_array_element(&self, key: &str, index: usize) -> Option<Box<dyn ConfigSource + '_>> {
|
|
61
62
|
let array = self.get(key)?.as_array()?;
|
|
62
63
|
let element = array.get(index)?.as_object()?;
|
|
63
|
-
Some(Box::new(
|
|
64
|
+
Some(Box::new(Self {
|
|
64
65
|
value: serde_json::Value::Object(element.clone()),
|
|
65
66
|
}))
|
|
66
67
|
}
|
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
//!
|
|
3
3
|
//! These tests cover serialization edge cases and ensure fallback
|
|
4
4
|
//! behavior works correctly when serialization fails.
|
|
5
|
+
#![allow(
|
|
6
|
+
clippy::redundant_clone,
|
|
7
|
+
clippy::uninlined_format_args,
|
|
8
|
+
clippy::doc_markdown,
|
|
9
|
+
reason = "Edge case tests for error handling"
|
|
10
|
+
)]
|
|
5
11
|
|
|
6
12
|
use axum::http::StatusCode;
|
|
7
13
|
use pretty_assertions::assert_eq;
|
|
@@ -99,7 +105,7 @@ fn test_from_structured_error_with_details() {
|
|
|
99
105
|
json!({"field": "username", "reason": "already_exists"}),
|
|
100
106
|
);
|
|
101
107
|
|
|
102
|
-
let (status, body) = ErrorResponseBuilder::from_structured_error(error);
|
|
108
|
+
let (status, body) = ErrorResponseBuilder::from_structured_error(&error);
|
|
103
109
|
assert_eq!(status, StatusCode::INTERNAL_SERVER_ERROR);
|
|
104
110
|
let parsed: Value = serde_json::from_str(&body).unwrap();
|
|
105
111
|
assert_eq!(parsed["code"], "custom_error");
|
|
@@ -201,23 +207,17 @@ fn test_all_convenience_methods_return_valid_json() {
|
|
|
201
207
|
];
|
|
202
208
|
|
|
203
209
|
for (status, body) in test_cases {
|
|
204
|
-
let parsed: Value =
|
|
205
|
-
.unwrap_or_else(|_| panic!("Failed to parse JSON for status {}: {}"
|
|
210
|
+
let parsed: Value =
|
|
211
|
+
serde_json::from_str(&body).unwrap_or_else(|_| panic!("Failed to parse JSON for status {status}: {body}"));
|
|
206
212
|
|
|
207
213
|
assert!(
|
|
208
214
|
parsed.get("error").is_some(),
|
|
209
|
-
"Missing 'error' field for status {}"
|
|
210
|
-
status
|
|
211
|
-
);
|
|
212
|
-
assert!(
|
|
213
|
-
parsed.get("code").is_some(),
|
|
214
|
-
"Missing 'code' field for status {}",
|
|
215
|
-
status
|
|
215
|
+
"Missing 'error' field for status {status}"
|
|
216
216
|
);
|
|
217
|
+
assert!(parsed.get("code").is_some(), "Missing 'code' field for status {status}");
|
|
217
218
|
assert!(
|
|
218
219
|
parsed.get("details").is_some(),
|
|
219
|
-
"Missing 'details' field for status {}"
|
|
220
|
-
status
|
|
220
|
+
"Missing 'details' field for status {status}"
|
|
221
221
|
);
|
|
222
222
|
}
|
|
223
223
|
}
|
|
@@ -336,7 +336,7 @@ fn test_error_message_types() {
|
|
|
336
336
|
let (_, body) = ErrorResponseBuilder::bad_request("test");
|
|
337
337
|
assert!(body.contains("test"));
|
|
338
338
|
|
|
339
|
-
let (_, body) = ErrorResponseBuilder::bad_request(format!("Error: {}", 123));
|
|
339
|
+
let (_, body) = ErrorResponseBuilder::bad_request(format!("Error: {0}", 123));
|
|
340
340
|
assert!(body.contains("Error: 123"));
|
|
341
341
|
}
|
|
342
342
|
|
data/vendor/crates/spikard-bindings-shared/tests/{comprehensive_coverage.rs → full_coverage.rs}
RENAMED
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
//!
|
|
3
3
|
//! This test file ensures full code coverage across all modules in the crate,
|
|
4
4
|
//! testing edge cases, error paths, and integration scenarios.
|
|
5
|
+
#![allow(
|
|
6
|
+
clippy::doc_markdown,
|
|
7
|
+
clippy::items_after_statements,
|
|
8
|
+
clippy::uninlined_format_args,
|
|
9
|
+
clippy::redundant_clone,
|
|
10
|
+
reason = "Integration test with many coverage scenarios"
|
|
11
|
+
)]
|
|
5
12
|
|
|
6
13
|
use axum::http::{Request, StatusCode};
|
|
7
14
|
use pretty_assertions::assert_eq;
|
|
@@ -201,12 +208,10 @@ fn test_lifecycle_hook_types() {
|
|
|
201
208
|
}
|
|
202
209
|
|
|
203
210
|
let continue_result = HookResult::Continue;
|
|
204
|
-
|
|
205
|
-
assert!(matches!(cloned_continue, HookResult::Continue));
|
|
211
|
+
assert!(matches!(continue_result.clone(), HookResult::Continue));
|
|
206
212
|
|
|
207
213
|
let short_circuit = HookResult::ShortCircuit(json!({"status": "error"}));
|
|
208
|
-
|
|
209
|
-
assert!(matches!(cloned_short, HookResult::ShortCircuit(_)));
|
|
214
|
+
assert!(matches!(short_circuit.clone(), HookResult::ShortCircuit(_)));
|
|
210
215
|
}
|
|
211
216
|
|
|
212
217
|
#[test]
|
|
@@ -413,7 +418,7 @@ fn test_conversion_traits_comprehensive() {
|
|
|
413
418
|
fn from_any(value: &(dyn std::any::Any + Send + Sync)) -> Result<Self, Self::Error> {
|
|
414
419
|
value
|
|
415
420
|
.downcast_ref::<i32>()
|
|
416
|
-
.map(|&v|
|
|
421
|
+
.map(|&v| Self { value: v })
|
|
417
422
|
.ok_or_else(|| "Type mismatch".to_string())
|
|
418
423
|
}
|
|
419
424
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//! Integration tests for handler_base module
|
|
1
|
+
//! Integration tests for `handler_base` module
|
|
2
2
|
//!
|
|
3
3
|
//! These tests cover the validation paths and error handling that aren't
|
|
4
4
|
//! covered by unit tests in the module itself.
|
|
@@ -41,7 +41,7 @@ impl LanguageHandler for MockHandler {
|
|
|
41
41
|
if should_fail {
|
|
42
42
|
Err(HandlerError::Execution("Handler failed".to_string()))
|
|
43
43
|
} else {
|
|
44
|
-
Ok(format!("output:{}"
|
|
44
|
+
Ok(format!("output:{input}"))
|
|
45
45
|
}
|
|
46
46
|
})
|
|
47
47
|
}
|
|
@@ -81,10 +81,10 @@ async fn test_handler_executor_with_validation_error() {
|
|
|
81
81
|
let request = Request::builder().body(Body::empty()).unwrap();
|
|
82
82
|
let request_data = RequestData {
|
|
83
83
|
path_params: Arc::new(HashMap::new()),
|
|
84
|
-
query_params: json!({}),
|
|
84
|
+
query_params: Arc::new(json!({})),
|
|
85
85
|
validated_params: None,
|
|
86
86
|
raw_query_params: Arc::new(HashMap::new()),
|
|
87
|
-
body: json!({"username": "john"}),
|
|
87
|
+
body: Arc::new(json!({"username": "john"})),
|
|
88
88
|
raw_body: None,
|
|
89
89
|
headers: Arc::new(HashMap::new()),
|
|
90
90
|
cookies: Arc::new(HashMap::new()),
|
|
@@ -110,10 +110,10 @@ async fn test_handler_executor_prepare_failure() {
|
|
|
110
110
|
let request = Request::builder().body(Body::empty()).unwrap();
|
|
111
111
|
let request_data = RequestData {
|
|
112
112
|
path_params: Arc::new(HashMap::new()),
|
|
113
|
-
query_params: json!({}),
|
|
113
|
+
query_params: Arc::new(json!({})),
|
|
114
114
|
validated_params: None,
|
|
115
115
|
raw_query_params: Arc::new(HashMap::new()),
|
|
116
|
-
body: json!({}),
|
|
116
|
+
body: Arc::new(json!({})),
|
|
117
117
|
raw_body: None,
|
|
118
118
|
headers: Arc::new(HashMap::new()),
|
|
119
119
|
cookies: Arc::new(HashMap::new()),
|
|
@@ -139,10 +139,10 @@ async fn test_handler_executor_invoke_failure() {
|
|
|
139
139
|
let request = Request::builder().body(Body::empty()).unwrap();
|
|
140
140
|
let request_data = RequestData {
|
|
141
141
|
path_params: Arc::new(HashMap::new()),
|
|
142
|
-
query_params: json!({}),
|
|
142
|
+
query_params: Arc::new(json!({})),
|
|
143
143
|
validated_params: None,
|
|
144
144
|
raw_query_params: Arc::new(HashMap::new()),
|
|
145
|
-
body: json!({}),
|
|
145
|
+
body: Arc::new(json!({})),
|
|
146
146
|
raw_body: None,
|
|
147
147
|
headers: Arc::new(HashMap::new()),
|
|
148
148
|
cookies: Arc::new(HashMap::new()),
|
|
@@ -168,10 +168,10 @@ async fn test_handler_executor_interpret_failure() {
|
|
|
168
168
|
let request = Request::builder().body(Body::empty()).unwrap();
|
|
169
169
|
let request_data = RequestData {
|
|
170
170
|
path_params: Arc::new(HashMap::new()),
|
|
171
|
-
query_params: json!({}),
|
|
171
|
+
query_params: Arc::new(json!({})),
|
|
172
172
|
validated_params: None,
|
|
173
173
|
raw_query_params: Arc::new(HashMap::new()),
|
|
174
|
-
body: json!({}),
|
|
174
|
+
body: Arc::new(json!({})),
|
|
175
175
|
raw_body: None,
|
|
176
176
|
headers: Arc::new(HashMap::new()),
|
|
177
177
|
cookies: Arc::new(HashMap::new()),
|
|
@@ -210,10 +210,10 @@ async fn test_handler_executor_with_request_validator() {
|
|
|
210
210
|
|
|
211
211
|
let request_data = RequestData {
|
|
212
212
|
path_params: Arc::new(HashMap::new()),
|
|
213
|
-
query_params: json!({}),
|
|
213
|
+
query_params: Arc::new(json!({})),
|
|
214
214
|
validated_params: None,
|
|
215
215
|
raw_query_params: Arc::new(HashMap::new()),
|
|
216
|
-
body: json!({"name": "test"}),
|
|
216
|
+
body: Arc::new(json!({"name": "test"})),
|
|
217
217
|
raw_body: None,
|
|
218
218
|
headers: Arc::new(headers),
|
|
219
219
|
cookies: Arc::new(HashMap::new()),
|
|
@@ -263,10 +263,10 @@ async fn test_handler_executor_builder_pattern() {
|
|
|
263
263
|
let request = Request::builder().body(Body::empty()).unwrap();
|
|
264
264
|
let request_data = RequestData {
|
|
265
265
|
path_params: Arc::new(HashMap::new()),
|
|
266
|
-
query_params: json!({}),
|
|
266
|
+
query_params: Arc::new(json!({})),
|
|
267
267
|
validated_params: None,
|
|
268
268
|
raw_query_params: Arc::new(HashMap::new()),
|
|
269
|
-
body: json!({"email": "test@example.com"}),
|
|
269
|
+
body: Arc::new(json!({"email": "test@example.com"})),
|
|
270
270
|
raw_body: None,
|
|
271
271
|
headers: Arc::new(HashMap::new()),
|
|
272
272
|
cookies: Arc::new(HashMap::new()),
|