spikard 0.13.0 → 0.15.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.
Files changed (207) hide show
  1. checksums.yaml +4 -4
  2. data/Steepfile +6 -0
  3. data/ext/spikard_rb/extconf.rb +1 -2
  4. data/ext/spikard_rb/{Cargo.lock → native/Cargo.lock} +819 -424
  5. data/ext/spikard_rb/native/Cargo.toml +24 -0
  6. data/ext/spikard_rb/src/lib.rs +5366 -3
  7. data/lib/spikard/native.rb +86 -0
  8. data/lib/spikard/version.rb +6 -1
  9. data/lib/spikard.rb +8 -52
  10. data/lib/spikard_rb.so +0 -0
  11. data/sig/types.rbs +427 -0
  12. metadata +14 -243
  13. data/LICENSE +0 -1
  14. data/README.md +0 -285
  15. data/ext/spikard_rb/Cargo.toml +0 -17
  16. data/lib/spikard/app.rb +0 -458
  17. data/lib/spikard/background.rb +0 -58
  18. data/lib/spikard/config.rb +0 -506
  19. data/lib/spikard/converters.rb +0 -13
  20. data/lib/spikard/grpc.rb +0 -232
  21. data/lib/spikard/handler_wrapper.rb +0 -113
  22. data/lib/spikard/provide.rb +0 -315
  23. data/lib/spikard/response.rb +0 -198
  24. data/lib/spikard/schema.rb +0 -243
  25. data/lib/spikard/sse.rb +0 -111
  26. data/lib/spikard/streaming_response.rb +0 -44
  27. data/lib/spikard/testing.rb +0 -474
  28. data/lib/spikard/upload_file.rb +0 -131
  29. data/lib/spikard/websocket.rb +0 -59
  30. data/sig/spikard.rbs +0 -739
  31. data/vendor/crates/spikard-bindings-shared/Cargo.toml +0 -75
  32. data/vendor/crates/spikard-bindings-shared/examples/config_extraction.rs +0 -132
  33. data/vendor/crates/spikard-bindings-shared/src/config_extractor.rs +0 -905
  34. data/vendor/crates/spikard-bindings-shared/src/conversion_traits.rs +0 -210
  35. data/vendor/crates/spikard-bindings-shared/src/di_traits.rs +0 -252
  36. data/vendor/crates/spikard-bindings-shared/src/error_response.rs +0 -404
  37. data/vendor/crates/spikard-bindings-shared/src/grpc_metadata.rs +0 -199
  38. data/vendor/crates/spikard-bindings-shared/src/handler_base.rs +0 -252
  39. data/vendor/crates/spikard-bindings-shared/src/json_conversion.rs +0 -829
  40. data/vendor/crates/spikard-bindings-shared/src/lazy_cache.rs +0 -587
  41. data/vendor/crates/spikard-bindings-shared/src/lib.rs +0 -33
  42. data/vendor/crates/spikard-bindings-shared/src/lifecycle_base.rs +0 -298
  43. data/vendor/crates/spikard-bindings-shared/src/lifecycle_executor.rs +0 -594
  44. data/vendor/crates/spikard-bindings-shared/src/response_builder.rs +0 -743
  45. data/vendor/crates/spikard-bindings-shared/src/response_interpreter.rs +0 -944
  46. data/vendor/crates/spikard-bindings-shared/src/test_client_base.rs +0 -260
  47. data/vendor/crates/spikard-bindings-shared/src/validation_helpers.rs +0 -369
  48. data/vendor/crates/spikard-bindings-shared/tests/config_extractor_behavior.rs +0 -192
  49. data/vendor/crates/spikard-bindings-shared/tests/error_response_edge_cases.rs +0 -383
  50. data/vendor/crates/spikard-bindings-shared/tests/full_coverage.rs +0 -459
  51. data/vendor/crates/spikard-bindings-shared/tests/handler_base_integration.rs +0 -280
  52. data/vendor/crates/spikard-bindings-shared/tests/integration_tests.rs +0 -669
  53. data/vendor/crates/spikard-core/Cargo.toml +0 -55
  54. data/vendor/crates/spikard-core/src/bindings/mod.rs +0 -3
  55. data/vendor/crates/spikard-core/src/bindings/response.rs +0 -130
  56. data/vendor/crates/spikard-core/src/debug.rs +0 -127
  57. data/vendor/crates/spikard-core/src/di/container.rs +0 -711
  58. data/vendor/crates/spikard-core/src/di/dependency.rs +0 -273
  59. data/vendor/crates/spikard-core/src/di/error.rs +0 -118
  60. data/vendor/crates/spikard-core/src/di/factory.rs +0 -548
  61. data/vendor/crates/spikard-core/src/di/graph.rs +0 -507
  62. data/vendor/crates/spikard-core/src/di/mod.rs +0 -192
  63. data/vendor/crates/spikard-core/src/di/resolved.rs +0 -428
  64. data/vendor/crates/spikard-core/src/di/value.rs +0 -282
  65. data/vendor/crates/spikard-core/src/errors.rs +0 -72
  66. data/vendor/crates/spikard-core/src/http.rs +0 -492
  67. data/vendor/crates/spikard-core/src/lib.rs +0 -29
  68. data/vendor/crates/spikard-core/src/lifecycle.rs +0 -1273
  69. data/vendor/crates/spikard-core/src/metadata.rs +0 -378
  70. data/vendor/crates/spikard-core/src/parameters.rs +0 -2546
  71. data/vendor/crates/spikard-core/src/problem.rs +0 -358
  72. data/vendor/crates/spikard-core/src/request_data.rs +0 -1146
  73. data/vendor/crates/spikard-core/src/router.rs +0 -530
  74. data/vendor/crates/spikard-core/src/schema_registry.rs +0 -197
  75. data/vendor/crates/spikard-core/src/type_hints.rs +0 -311
  76. data/vendor/crates/spikard-core/src/validation/error_mapper.rs +0 -710
  77. data/vendor/crates/spikard-core/src/validation/mod.rs +0 -470
  78. data/vendor/crates/spikard-core/tests/bindings_response_tests.rs +0 -136
  79. data/vendor/crates/spikard-core/tests/di_dependency_defaults.rs +0 -37
  80. data/vendor/crates/spikard-core/tests/error_mapper.rs +0 -761
  81. data/vendor/crates/spikard-core/tests/parameters_edge_cases.rs +0 -106
  82. data/vendor/crates/spikard-core/tests/parameters_full.rs +0 -701
  83. data/vendor/crates/spikard-core/tests/parameters_schema_and_formats.rs +0 -301
  84. data/vendor/crates/spikard-core/tests/request_data_roundtrip.rs +0 -67
  85. data/vendor/crates/spikard-core/tests/validation_coverage.rs +0 -250
  86. data/vendor/crates/spikard-core/tests/validation_error_paths.rs +0 -45
  87. data/vendor/crates/spikard-http/Cargo.toml +0 -82
  88. data/vendor/crates/spikard-http/examples/sse-notifications.rs +0 -148
  89. data/vendor/crates/spikard-http/examples/websocket-chat.rs +0 -92
  90. data/vendor/crates/spikard-http/src/auth.rs +0 -301
  91. data/vendor/crates/spikard-http/src/background.rs +0 -1859
  92. data/vendor/crates/spikard-http/src/bindings/mod.rs +0 -3
  93. data/vendor/crates/spikard-http/src/bindings/response.rs +0 -1
  94. data/vendor/crates/spikard-http/src/body_metadata.rs +0 -8
  95. data/vendor/crates/spikard-http/src/cors.rs +0 -1026
  96. data/vendor/crates/spikard-http/src/debug.rs +0 -128
  97. data/vendor/crates/spikard-http/src/di_handler.rs +0 -1672
  98. data/vendor/crates/spikard-http/src/grpc/framing.rs +0 -653
  99. data/vendor/crates/spikard-http/src/grpc/handler.rs +0 -1211
  100. data/vendor/crates/spikard-http/src/grpc/mod.rs +0 -556
  101. data/vendor/crates/spikard-http/src/grpc/service.rs +0 -706
  102. data/vendor/crates/spikard-http/src/grpc/streaming.rs +0 -319
  103. data/vendor/crates/spikard-http/src/handler_response.rs +0 -901
  104. data/vendor/crates/spikard-http/src/handler_trait.rs +0 -1015
  105. data/vendor/crates/spikard-http/src/handler_trait_tests.rs +0 -290
  106. data/vendor/crates/spikard-http/src/jsonrpc/http_handler.rs +0 -502
  107. data/vendor/crates/spikard-http/src/jsonrpc/method_registry.rs +0 -648
  108. data/vendor/crates/spikard-http/src/jsonrpc/mod.rs +0 -60
  109. data/vendor/crates/spikard-http/src/jsonrpc/openrpc.rs +0 -325
  110. data/vendor/crates/spikard-http/src/jsonrpc/protocol.rs +0 -1207
  111. data/vendor/crates/spikard-http/src/jsonrpc/router.rs +0 -2262
  112. data/vendor/crates/spikard-http/src/lib.rs +0 -566
  113. data/vendor/crates/spikard-http/src/lifecycle/adapter.rs +0 -230
  114. data/vendor/crates/spikard-http/src/lifecycle.rs +0 -1193
  115. data/vendor/crates/spikard-http/src/middleware/mod.rs +0 -560
  116. data/vendor/crates/spikard-http/src/middleware/multipart.rs +0 -912
  117. data/vendor/crates/spikard-http/src/middleware/urlencoded.rs +0 -513
  118. data/vendor/crates/spikard-http/src/middleware/validation.rs +0 -768
  119. data/vendor/crates/spikard-http/src/openapi/mod.rs +0 -309
  120. data/vendor/crates/spikard-http/src/openapi/parameter_extraction.rs +0 -535
  121. data/vendor/crates/spikard-http/src/openapi/schema_conversion.rs +0 -1363
  122. data/vendor/crates/spikard-http/src/openapi/spec_generation.rs +0 -667
  123. data/vendor/crates/spikard-http/src/query_parser.rs +0 -793
  124. data/vendor/crates/spikard-http/src/response.rs +0 -720
  125. data/vendor/crates/spikard-http/src/server/fast_router.rs +0 -186
  126. data/vendor/crates/spikard-http/src/server/grpc_routing.rs +0 -1243
  127. data/vendor/crates/spikard-http/src/server/handler.rs +0 -1661
  128. data/vendor/crates/spikard-http/src/server/lifecycle_execution.rs +0 -253
  129. data/vendor/crates/spikard-http/src/server/mod.rs +0 -1717
  130. data/vendor/crates/spikard-http/src/server/request_extraction.rs +0 -871
  131. data/vendor/crates/spikard-http/src/server/routing_factory.rs +0 -618
  132. data/vendor/crates/spikard-http/src/sse.rs +0 -1409
  133. data/vendor/crates/spikard-http/src/testing/form.rs +0 -52
  134. data/vendor/crates/spikard-http/src/testing/multipart.rs +0 -64
  135. data/vendor/crates/spikard-http/src/testing/test_client.rs +0 -825
  136. data/vendor/crates/spikard-http/src/testing.rs +0 -617
  137. data/vendor/crates/spikard-http/src/websocket.rs +0 -1477
  138. data/vendor/crates/spikard-http/tests/auth_integration.rs +0 -645
  139. data/vendor/crates/spikard-http/tests/background_behavior.rs +0 -832
  140. data/vendor/crates/spikard-http/tests/common/grpc_helpers.rs +0 -1012
  141. data/vendor/crates/spikard-http/tests/common/handlers.rs +0 -309
  142. data/vendor/crates/spikard-http/tests/common/mod.rs +0 -33
  143. data/vendor/crates/spikard-http/tests/common/test_builders.rs +0 -628
  144. data/vendor/crates/spikard-http/tests/di_handler_error_responses.rs +0 -162
  145. data/vendor/crates/spikard-http/tests/di_integration.rs +0 -192
  146. data/vendor/crates/spikard-http/tests/doc_snippets.rs +0 -5
  147. data/vendor/crates/spikard-http/tests/grpc_bidirectional_streaming.rs +0 -430
  148. data/vendor/crates/spikard-http/tests/grpc_client_streaming.rs +0 -738
  149. data/vendor/crates/spikard-http/tests/grpc_error_handling_test.rs +0 -652
  150. data/vendor/crates/spikard-http/tests/grpc_integration_test.rs +0 -334
  151. data/vendor/crates/spikard-http/tests/grpc_metadata_test.rs +0 -532
  152. data/vendor/crates/spikard-http/tests/grpc_server_integration.rs +0 -495
  153. data/vendor/crates/spikard-http/tests/grpc_server_streaming.rs +0 -975
  154. data/vendor/crates/spikard-http/tests/lifecycle_execution.rs +0 -1093
  155. data/vendor/crates/spikard-http/tests/middleware_stack_integration.rs +0 -389
  156. data/vendor/crates/spikard-http/tests/multipart_behavior.rs +0 -656
  157. data/vendor/crates/spikard-http/tests/request_extraction_full.rs +0 -513
  158. data/vendor/crates/spikard-http/tests/server_auth_middleware_behavior.rs +0 -328
  159. data/vendor/crates/spikard-http/tests/server_config_builder.rs +0 -335
  160. data/vendor/crates/spikard-http/tests/server_configured_router_behavior.rs +0 -374
  161. data/vendor/crates/spikard-http/tests/server_cors_preflight.rs +0 -83
  162. data/vendor/crates/spikard-http/tests/server_handler_wrappers.rs +0 -464
  163. data/vendor/crates/spikard-http/tests/server_method_router_additional_behavior.rs +0 -286
  164. data/vendor/crates/spikard-http/tests/server_method_router_coverage.rs +0 -118
  165. data/vendor/crates/spikard-http/tests/server_middleware_behavior.rs +0 -99
  166. data/vendor/crates/spikard-http/tests/server_middleware_branches.rs +0 -204
  167. data/vendor/crates/spikard-http/tests/server_openapi_jsonrpc_static.rs +0 -427
  168. data/vendor/crates/spikard-http/tests/server_router_behavior.rs +0 -121
  169. data/vendor/crates/spikard-http/tests/sse_behavior.rs +0 -620
  170. data/vendor/crates/spikard-http/tests/sse_full_behavior.rs +0 -584
  171. data/vendor/crates/spikard-http/tests/sse_handler_behavior.rs +0 -130
  172. data/vendor/crates/spikard-http/tests/test_client_requests.rs +0 -167
  173. data/vendor/crates/spikard-http/tests/testing_helpers.rs +0 -87
  174. data/vendor/crates/spikard-http/tests/testing_module_coverage.rs +0 -155
  175. data/vendor/crates/spikard-http/tests/urlencoded_content_type.rs +0 -82
  176. data/vendor/crates/spikard-http/tests/websocket_behavior.rs +0 -663
  177. data/vendor/crates/spikard-http/tests/websocket_full_behavior.rs +0 -440
  178. data/vendor/crates/spikard-http/tests/websocket_integration.rs +0 -150
  179. data/vendor/crates/spikard-rb/Cargo.toml +0 -63
  180. data/vendor/crates/spikard-rb/build.rs +0 -200
  181. data/vendor/crates/spikard-rb/src/background.rs +0 -63
  182. data/vendor/crates/spikard-rb/src/config/mod.rs +0 -5
  183. data/vendor/crates/spikard-rb/src/config/server_config.rs +0 -401
  184. data/vendor/crates/spikard-rb/src/conversion.rs +0 -688
  185. data/vendor/crates/spikard-rb/src/di/builder.rs +0 -100
  186. data/vendor/crates/spikard-rb/src/di/mod.rs +0 -410
  187. data/vendor/crates/spikard-rb/src/grpc/handler.rs +0 -875
  188. data/vendor/crates/spikard-rb/src/grpc/mod.rs +0 -13
  189. data/vendor/crates/spikard-rb/src/gvl.rs +0 -80
  190. data/vendor/crates/spikard-rb/src/handler.rs +0 -699
  191. data/vendor/crates/spikard-rb/src/integration/mod.rs +0 -3
  192. data/vendor/crates/spikard-rb/src/lib.rs +0 -2268
  193. data/vendor/crates/spikard-rb/src/lifecycle.rs +0 -334
  194. data/vendor/crates/spikard-rb/src/metadata/mod.rs +0 -5
  195. data/vendor/crates/spikard-rb/src/metadata/route_extraction.rs +0 -507
  196. data/vendor/crates/spikard-rb/src/request.rs +0 -439
  197. data/vendor/crates/spikard-rb/src/runtime/mod.rs +0 -5
  198. data/vendor/crates/spikard-rb/src/runtime/server_runner.rs +0 -368
  199. data/vendor/crates/spikard-rb/src/server.rs +0 -304
  200. data/vendor/crates/spikard-rb/src/sse.rs +0 -231
  201. data/vendor/crates/spikard-rb/src/testing/client.rs +0 -698
  202. data/vendor/crates/spikard-rb/src/testing/mod.rs +0 -7
  203. data/vendor/crates/spikard-rb/src/testing/sse.rs +0 -108
  204. data/vendor/crates/spikard-rb/src/testing/websocket.rs +0 -573
  205. data/vendor/crates/spikard-rb/src/websocket.rs +0 -521
  206. data/vendor/crates/spikard-rb-macros/Cargo.toml +0 -20
  207. data/vendor/crates/spikard-rb-macros/src/lib.rs +0 -51
@@ -1,1012 +0,0 @@
1
- //! gRPC test utilities and helpers for comprehensive integration tests
2
- //!
3
- //! This module provides reusable utilities for writing gRPC integration tests without
4
- //! requiring language bindings. It includes helpers for creating test servers, clients,
5
- //! building protobuf messages, and asserting on responses.
6
- //!
7
- //! # Examples
8
- //!
9
- //! ```ignore
10
- //! use common::grpc_helpers::{
11
- //! GrpcTestServer, create_grpc_test_client, send_unary_request,
12
- //! assert_grpc_response, create_test_metadata, ProtobufMessageBuilder,
13
- //! };
14
- //! use std::sync::Arc;
15
- //! use bytes::Bytes;
16
- //!
17
- //! #[tokio::test]
18
- //! async fn test_grpc_service() {
19
- //! let mut server = GrpcTestServer::new();
20
- //! let metadata = create_test_metadata();
21
- //!
22
- //! let message = ProtobufMessageBuilder::new()
23
- //! .add_field("name", "Alice")
24
- //! .add_field("age", 30)
25
- //! .build()
26
- //! .unwrap();
27
- //!
28
- //! let response = send_unary_request(
29
- //! &server,
30
- //! "mypackage.UserService",
31
- //! "GetUser",
32
- //! message,
33
- //! metadata,
34
- //! )
35
- //! .await
36
- //! .unwrap();
37
- //!
38
- //! assert_grpc_response(response, serde_json::json!({"id": 1}));
39
- //! }
40
- //! ```
41
-
42
- use bytes::Bytes;
43
- use serde_json::{Value, json};
44
- use spikard_http::grpc::{GrpcHandler, GrpcHandlerResult, GrpcRequestData, GrpcResponseData};
45
- use std::future::Future;
46
- use std::pin::Pin;
47
- use std::sync::Arc;
48
- use tonic::Code;
49
- use tonic::metadata::MetadataMap;
50
-
51
- /// Test server for gRPC integration testing
52
- ///
53
- /// Provides a simple in-memory server for registering test handlers and managing
54
- /// their lifecycle. This is useful for testing gRPC services without spinning up
55
- /// a real network server.
56
- ///
57
- /// # Example
58
- ///
59
- /// ```ignore
60
- /// let mut server = GrpcTestServer::new();
61
- /// server.register_service(Arc::new(my_handler));
62
- /// assert!(!server.handlers().is_empty());
63
- /// ```
64
- #[derive(Clone)]
65
- pub struct GrpcTestServer {
66
- handlers: Arc<std::sync::Mutex<Vec<Arc<dyn GrpcHandler>>>>,
67
- base_url: String,
68
- }
69
-
70
- impl GrpcTestServer {
71
- /// Create a new gRPC test server
72
- ///
73
- /// Initializes an empty test server with a default localhost base URL.
74
- pub fn new() -> Self {
75
- Self {
76
- handlers: Arc::new(std::sync::Mutex::new(Vec::new())),
77
- base_url: "http://localhost:50051".to_string(),
78
- }
79
- }
80
-
81
- /// Create a new gRPC test server with a custom base URL
82
- ///
83
- /// # Arguments
84
- ///
85
- /// * `url` - The base URL for the server (e.g., <http://localhost:8080>)
86
- pub fn with_url(url: impl Into<String>) -> Self {
87
- Self {
88
- handlers: Arc::new(std::sync::Mutex::new(Vec::new())),
89
- base_url: url.into(),
90
- }
91
- }
92
-
93
- /// Register a gRPC service handler with the test server
94
- ///
95
- /// # Arguments
96
- ///
97
- /// * `handler` - Arc-wrapped handler implementation to register
98
- ///
99
- /// # Example
100
- ///
101
- /// ```ignore
102
- /// let mut server = GrpcTestServer::new();
103
- /// server.register_service(Arc::new(MyHandler));
104
- /// ```
105
- pub fn register_service(&self, handler: Arc<dyn GrpcHandler>) {
106
- let mut handlers = self.handlers.lock().unwrap();
107
- handlers.push(handler);
108
- }
109
-
110
- /// Get the base URL of the test server
111
- pub fn url(&self) -> &str {
112
- &self.base_url
113
- }
114
-
115
- /// Get all registered handlers
116
- ///
117
- /// Useful for inspecting which handlers have been registered.
118
- pub fn handlers(&self) -> Vec<Arc<dyn GrpcHandler>> {
119
- let handlers = self.handlers.lock().unwrap();
120
- handlers.clone()
121
- }
122
-
123
- /// Find a handler by service name
124
- ///
125
- /// # Arguments
126
- ///
127
- /// * `service_name` - The fully qualified service name to look up
128
- pub fn get_handler(&self, service_name: &str) -> Option<Arc<dyn GrpcHandler>> {
129
- let handlers = self.handlers.lock().unwrap();
130
- handlers.iter().find(|h| h.service_name() == service_name).cloned()
131
- }
132
-
133
- /// Check if a service is registered
134
- ///
135
- /// # Arguments
136
- ///
137
- /// * `service_name` - The service name to check
138
- pub fn has_service(&self, service_name: &str) -> bool {
139
- self.get_handler(service_name).is_some()
140
- }
141
-
142
- /// Get the count of registered services
143
- pub fn service_count(&self) -> usize {
144
- self.handlers.lock().unwrap().len()
145
- }
146
- }
147
-
148
- impl Default for GrpcTestServer {
149
- fn default() -> Self {
150
- Self::new()
151
- }
152
- }
153
-
154
- /// Create a simple gRPC test client for testing
155
- ///
156
- /// In real-world scenarios, you would use a proper gRPC client library like
157
- /// `tonic::Client`. This helper creates a lightweight wrapper for testing
158
- /// without requiring actual network connections.
159
- ///
160
- /// # Example
161
- ///
162
- /// ```ignore
163
- /// let _client = create_grpc_test_client();
164
- /// // Use with send_unary_request
165
- /// ```
166
- pub struct GrpcTestClient;
167
-
168
- impl GrpcTestClient {
169
- /// Create a new test client
170
- pub const fn new() -> Self {
171
- Self
172
- }
173
- }
174
-
175
- impl Default for GrpcTestClient {
176
- fn default() -> Self {
177
- Self::new()
178
- }
179
- }
180
-
181
- /// Factory function to create a gRPC test client
182
- pub const fn create_grpc_test_client() -> GrpcTestClient {
183
- GrpcTestClient::new()
184
- }
185
-
186
- /// Send a unary gRPC request to a test server
187
- ///
188
- /// This is a helper function to simulate sending a unary RPC request to a gRPC service.
189
- /// In a real test, you would use a proper gRPC client library, but this helper
190
- /// allows testing the handler logic directly.
191
- ///
192
- /// # Arguments
193
- ///
194
- /// * `server` - The test server instance
195
- /// * `service` - Fully qualified service name (e.g., "mypackage.UserService")
196
- /// * `method` - Method name (e.g., `GetUser`)
197
- /// * `payload` - Serialized protobuf message bytes
198
- /// * `metadata` - gRPC metadata (headers) to include in the request
199
- ///
200
- /// # Errors
201
- ///
202
- /// Returns an error if:
203
- /// - The service is not registered on the server
204
- /// - The handler returns an error response
205
- ///
206
- /// # Example
207
- ///
208
- /// ```ignore
209
- /// let mut server = GrpcTestServer::new();
210
- /// server.register_service(Arc::new(my_handler));
211
- ///
212
- /// let response = send_unary_request(
213
- /// &server,
214
- /// "mypackage.UserService",
215
- /// "GetUser",
216
- /// Bytes::from("request"),
217
- /// create_test_metadata(),
218
- /// ).await?;
219
- /// ```
220
- pub async fn send_unary_request(
221
- server: &GrpcTestServer,
222
- service: &str,
223
- method: &str,
224
- payload: Bytes,
225
- metadata: MetadataMap,
226
- ) -> Result<GrpcResponseData, Box<dyn std::error::Error>> {
227
- let handler = server.get_handler(service).ok_or_else(|| {
228
- Box::new(std::io::Error::new(
229
- std::io::ErrorKind::NotFound,
230
- format!("Service not found: {service}"),
231
- )) as Box<dyn std::error::Error>
232
- })?;
233
-
234
- let request = GrpcRequestData {
235
- service_name: service.to_string(),
236
- method_name: method.to_string(),
237
- payload,
238
- metadata,
239
- };
240
-
241
- handler.call(request).await.map_err(|e| e.message().into())
242
- }
243
-
244
- /// Assert that a gRPC response payload matches the expected JSON value
245
- ///
246
- /// Parses the response payload as JSON and compares it with the expected value.
247
- /// This is useful for testing JSON-based gRPC messages.
248
- ///
249
- /// # Panics
250
- ///
251
- /// Panics if the payload cannot be parsed as JSON or doesn't match the expected value.
252
- ///
253
- /// # Arguments
254
- ///
255
- /// * `response` - The gRPC response data
256
- /// * `expected` - The expected JSON value
257
- ///
258
- /// # Example
259
- ///
260
- /// ```ignore
261
- /// let response = send_unary_request(...).await?;
262
- /// assert_grpc_response(response, json!({"id": 1, "name": "Alice"}));
263
- /// ```
264
- pub fn assert_grpc_response(response: &GrpcResponseData, expected: &Value) {
265
- let actual = serde_json::from_slice::<Value>(&response.payload).expect("Failed to parse response payload as JSON");
266
-
267
- assert_eq!(
268
- actual, *expected,
269
- "Response payload mismatch.\nExpected: {expected}\nActual: {actual}",
270
- );
271
- }
272
-
273
- /// Assert that a gRPC handler result has a specific status code
274
- ///
275
- /// Useful for testing error handling and status code responses.
276
- ///
277
- /// # Panics
278
- ///
279
- /// Panics if the status code doesn't match.
280
- ///
281
- /// # Arguments
282
- ///
283
- /// * `result` - The gRPC handler result
284
- /// * `expected_status` - The expected `tonic::Code`
285
- ///
286
- /// # Example
287
- ///
288
- /// ```ignore
289
- /// let result = handler.call(request).await;
290
- /// assert_grpc_status(&result, tonic::Code::NotFound);
291
- /// ```
292
- pub fn assert_grpc_status(result: &GrpcHandlerResult, expected_status: Code) {
293
- match result {
294
- Err(status) => {
295
- assert_eq!(
296
- status.code(),
297
- expected_status,
298
- "Expected status {:?} but got {:?}: {}",
299
- expected_status,
300
- status.code(),
301
- status.message()
302
- );
303
- }
304
- Ok(_) => {
305
- panic!("Expected error status {expected_status:?} but got success response");
306
- }
307
- }
308
- }
309
-
310
- /// Fluent builder for creating test protobuf messages
311
- ///
312
- /// Provides a simple way to construct JSON-serializable test messages
313
- /// that can be used as gRPC payloads. In practice, you would use actual
314
- /// protobuf code generation, but this is useful for simple tests.
315
- ///
316
- /// # Example
317
- ///
318
- /// ```ignore
319
- /// let message = ProtobufMessageBuilder::new()
320
- /// .add_field("id", 42)
321
- /// .add_field("name", "Alice")
322
- /// .add_field("email", "alice@example.com")
323
- /// .build()?;
324
- /// ```
325
- pub struct ProtobufMessageBuilder {
326
- fields: serde_json::Map<String, Value>,
327
- }
328
-
329
- impl ProtobufMessageBuilder {
330
- /// Create a new message builder with no fields
331
- pub fn new() -> Self {
332
- Self {
333
- fields: serde_json::Map::new(),
334
- }
335
- }
336
-
337
- /// Add a field to the message
338
- ///
339
- /// # Arguments
340
- ///
341
- /// * `name` - The field name
342
- /// * `value` - The field value (automatically converted to JSON)
343
- ///
344
- /// # Example
345
- ///
346
- /// ```ignore
347
- /// builder.add_field("name", "Alice")
348
- /// .add_field("age", 30)
349
- /// .add_field("active", true);
350
- /// ```
351
- pub fn add_field(&mut self, name: &str, value: impl Into<Value>) -> &mut Self {
352
- self.fields.insert(name.to_string(), value.into());
353
- self
354
- }
355
-
356
- /// Add a string field to the message
357
- pub fn add_string_field(&mut self, name: &str, value: &str) -> &mut Self {
358
- self.fields.insert(name.to_string(), Value::String(value.to_string()));
359
- self
360
- }
361
-
362
- /// Add an integer field to the message
363
- pub fn add_int_field(&mut self, name: &str, value: i64) -> &mut Self {
364
- self.fields.insert(name.to_string(), json!(value));
365
- self
366
- }
367
-
368
- /// Add a boolean field to the message
369
- pub fn add_bool_field(&mut self, name: &str, value: bool) -> &mut Self {
370
- self.fields.insert(name.to_string(), json!(value));
371
- self
372
- }
373
-
374
- /// Add a nested object field to the message
375
- pub fn add_object_field(&mut self, name: &str, value: Value) -> &mut Self {
376
- self.fields.insert(name.to_string(), value);
377
- self
378
- }
379
-
380
- /// Add an array field to the message
381
- pub fn add_array_field(&mut self, name: &str, values: Vec<Value>) -> &mut Self {
382
- self.fields.insert(name.to_string(), Value::Array(values));
383
- self
384
- }
385
-
386
- /// Build the message into serialized bytes
387
- ///
388
- /// # Errors
389
- ///
390
- /// Returns an error if the message cannot be serialized to JSON.
391
- pub fn build(&self) -> Result<Bytes, Box<dyn std::error::Error>> {
392
- let json_value = Value::Object(self.fields.clone());
393
- let serialized = serde_json::to_vec(&json_value)?;
394
- Ok(Bytes::from(serialized))
395
- }
396
-
397
- /// Clear all fields from the message
398
- pub fn clear(&mut self) -> &mut Self {
399
- self.fields.clear();
400
- self
401
- }
402
-
403
- /// Get the current fields as a JSON object
404
- pub fn as_json(&self) -> Value {
405
- Value::Object(self.fields.clone())
406
- }
407
-
408
- /// Get the number of fields in the message
409
- pub fn field_count(&self) -> usize {
410
- self.fields.len()
411
- }
412
- }
413
-
414
- impl Default for ProtobufMessageBuilder {
415
- fn default() -> Self {
416
- Self::new()
417
- }
418
- }
419
-
420
- /// Create test metadata with common default headers
421
- ///
422
- /// Useful for constructing standard gRPC request metadata for testing.
423
- ///
424
- /// # Example
425
- ///
426
- /// ```ignore
427
- /// let metadata = create_test_metadata();
428
- /// // metadata now contains typical gRPC headers
429
- /// ```
430
- pub fn create_test_metadata() -> MetadataMap {
431
- let mut metadata = MetadataMap::new();
432
- metadata.insert("user-agent", "spikard-test/1.0".parse().unwrap());
433
- metadata.insert("content-type", "application/grpc".parse().unwrap());
434
- metadata
435
- }
436
-
437
- /// Create test metadata with custom headers
438
- ///
439
- /// Allows building metadata from a `HashMap` of key-value pairs.
440
- ///
441
- /// # Arguments
442
- ///
443
- /// * `headers` - `HashMap` of header names to values (String-based)
444
- ///
445
- /// # Example
446
- ///
447
- /// ```ignore
448
- /// use std::collections::HashMap;
449
- ///
450
- /// let mut headers = HashMap::new();
451
- /// headers.insert("authorization".to_string(), "Bearer token123".to_string());
452
- /// headers.insert("x-custom".to_string(), "value".to_string());
453
- ///
454
- /// let metadata = create_test_metadata_with_headers(&headers).unwrap();
455
- /// ```
456
- pub fn create_test_metadata_with_headers(
457
- headers: &std::collections::HashMap<String, String>,
458
- ) -> Result<MetadataMap, Box<dyn std::error::Error>> {
459
- use std::str::FromStr;
460
- let mut metadata = MetadataMap::new();
461
- for (key, value) in headers {
462
- let meta_key = tonic::metadata::MetadataKey::from_str(key)?;
463
- metadata.insert(meta_key, value.parse()?);
464
- }
465
- Ok(metadata)
466
- }
467
-
468
- /// Add authentication metadata to an existing `MetadataMap`
469
- ///
470
- /// Adds a standard Bearer token authorization header.
471
- ///
472
- /// # Arguments
473
- ///
474
- /// * `metadata` - The metadata map to modify
475
- /// * `token` - The authentication token
476
- ///
477
- /// # Example
478
- ///
479
- /// ```ignore
480
- /// let mut metadata = create_test_metadata();
481
- /// add_auth_metadata(&mut metadata, "secret_token_123");
482
- /// ```
483
- pub fn add_auth_metadata(metadata: &mut MetadataMap, token: &str) -> Result<(), Box<dyn std::error::Error>> {
484
- let auth_value = format!("Bearer {token}");
485
- metadata.insert("authorization", auth_value.parse()?);
486
- Ok(())
487
- }
488
-
489
- /// Add custom metadata header to an existing `MetadataMap`
490
- ///
491
- /// # Arguments
492
- ///
493
- /// * `metadata` - The metadata map to modify
494
- /// * `key` - The header name
495
- /// * `value` - The header value
496
- ///
497
- /// # Example
498
- ///
499
- /// ```ignore
500
- /// let mut metadata = create_test_metadata();
501
- /// add_metadata_header(&mut metadata, "x-request-id", "req-123")?;
502
- /// ```
503
- pub fn add_metadata_header(
504
- metadata: &mut MetadataMap,
505
- key: &str,
506
- value: &str,
507
- ) -> Result<(), Box<dyn std::error::Error>> {
508
- use std::str::FromStr;
509
- let meta_key = tonic::metadata::MetadataKey::from_str(key)?;
510
- metadata.insert(meta_key, value.parse()?);
511
- Ok(())
512
- }
513
-
514
- /// Mock gRPC handler for testing
515
- ///
516
- /// A simple mock handler that always returns a fixed response. Useful for
517
- /// basic integration tests that just need a handler to exist.
518
- pub struct MockGrpcHandler {
519
- service_name: &'static str,
520
- response_payload: Bytes,
521
- }
522
-
523
- impl MockGrpcHandler {
524
- /// Create a new mock handler
525
- ///
526
- /// # Arguments
527
- ///
528
- /// * `service_name` - The service name this handler serves (must be a static string)
529
- /// * `response_payload` - The payload to return in responses
530
- pub fn new(service_name: &'static str, response_payload: impl Into<Bytes>) -> Self {
531
- Self {
532
- service_name,
533
- response_payload: response_payload.into(),
534
- }
535
- }
536
-
537
- /// Create a mock handler that returns JSON
538
- pub fn with_json(service_name: &'static str, json: &Value) -> Self {
539
- let bytes = serde_json::to_vec(json).unwrap_or_default();
540
- Self::new(service_name, Bytes::from(bytes))
541
- }
542
- }
543
-
544
- impl GrpcHandler for MockGrpcHandler {
545
- fn call(&self, _request: GrpcRequestData) -> Pin<Box<dyn Future<Output = GrpcHandlerResult> + Send>> {
546
- let response = GrpcResponseData {
547
- payload: self.response_payload.clone(),
548
- metadata: MetadataMap::new(),
549
- };
550
- Box::pin(async move { Ok(response) })
551
- }
552
-
553
- fn service_name(&self) -> &'static str {
554
- self.service_name
555
- }
556
- }
557
-
558
- /// Error mock handler for testing error responses
559
- ///
560
- /// A mock handler that always returns an error. Useful for testing error handling.
561
- pub struct ErrorMockHandler {
562
- service_name: String,
563
- error_code: Code,
564
- error_message: String,
565
- }
566
-
567
- impl ErrorMockHandler {
568
- /// Create a new error mock handler
569
- ///
570
- /// # Arguments
571
- ///
572
- /// * `service_name` - The service name this handler serves
573
- /// * `error_code` - The gRPC error code to return
574
- /// * `error_message` - The error message
575
- pub fn new(service_name: impl Into<String>, error_code: Code, error_message: impl Into<String>) -> Self {
576
- Self {
577
- service_name: service_name.into(),
578
- error_code,
579
- error_message: error_message.into(),
580
- }
581
- }
582
- }
583
-
584
- impl GrpcHandler for ErrorMockHandler {
585
- fn call(&self, _request: GrpcRequestData) -> Pin<Box<dyn Future<Output = GrpcHandlerResult> + Send>> {
586
- let message = self.error_message.clone();
587
- let code = self.error_code;
588
- Box::pin(async move { Err(tonic::Status::new(code, message)) })
589
- }
590
-
591
- fn service_name(&self) -> &'static str {
592
- "mock.ErrorMockService"
593
- }
594
- }
595
-
596
- /// Echo mock handler for testing request/response flow
597
- ///
598
- /// A mock handler that echoes the request payload back as the response.
599
- pub struct EchoMockHandler {
600
- service_name: String,
601
- }
602
-
603
- impl EchoMockHandler {
604
- /// Create a new echo mock handler
605
- ///
606
- /// # Arguments
607
- ///
608
- /// * `service_name` - The service name this handler serves
609
- pub fn new(service_name: impl Into<String>) -> Self {
610
- Self {
611
- service_name: service_name.into(),
612
- }
613
- }
614
- }
615
-
616
- impl GrpcHandler for EchoMockHandler {
617
- fn call(&self, request: GrpcRequestData) -> Pin<Box<dyn Future<Output = GrpcHandlerResult> + Send>> {
618
- let payload = request.payload;
619
- Box::pin(async move {
620
- Ok(GrpcResponseData {
621
- payload,
622
- metadata: MetadataMap::new(),
623
- })
624
- })
625
- }
626
-
627
- fn service_name(&self) -> &'static str {
628
- "mock.EchoMockService"
629
- }
630
- }
631
-
632
- #[cfg(test)]
633
- mod tests {
634
- use super::*;
635
-
636
- // Mock handler for testing gRPC functionality
637
- struct TestHandler;
638
- impl GrpcHandler for TestHandler {
639
- fn call(&self, _request: GrpcRequestData) -> Pin<Box<dyn Future<Output = GrpcHandlerResult> + Send>> {
640
- Box::pin(async {
641
- Ok(GrpcResponseData {
642
- payload: serde_json::to_vec(&json!({"result": "success"})).unwrap().into(),
643
- metadata: MetadataMap::new(),
644
- })
645
- })
646
- }
647
- fn service_name(&self) -> &'static str {
648
- "test.TestService"
649
- }
650
- }
651
-
652
- #[test]
653
- fn test_grpc_test_server_new() {
654
- let server = GrpcTestServer::new();
655
- assert_eq!(server.url(), "http://localhost:50051");
656
- assert_eq!(server.service_count(), 0);
657
- assert!(server.handlers().is_empty());
658
- }
659
-
660
- #[test]
661
- fn test_grpc_test_server_with_url() {
662
- let server = GrpcTestServer::with_url("http://localhost:8080");
663
- assert_eq!(server.url(), "http://localhost:8080");
664
- }
665
-
666
- #[test]
667
- fn test_grpc_test_server_register_service() {
668
- let server = GrpcTestServer::new();
669
- let handler = Arc::new(MockGrpcHandler::new("test.Service", "response"));
670
-
671
- server.register_service(handler);
672
-
673
- assert_eq!(server.service_count(), 1);
674
- assert!(!server.handlers().is_empty());
675
- }
676
-
677
- #[test]
678
- fn test_grpc_test_server_register_multiple_services() {
679
- let server = GrpcTestServer::new();
680
- let handler1 = Arc::new(MockGrpcHandler::new("service1", "response1"));
681
- let handler2 = Arc::new(MockGrpcHandler::new("service2", "response2"));
682
-
683
- server.register_service(handler1);
684
- server.register_service(handler2);
685
-
686
- assert_eq!(server.service_count(), 2);
687
- }
688
-
689
- #[test]
690
- fn test_grpc_test_server_default() {
691
- let server = GrpcTestServer::default();
692
- assert_eq!(server.service_count(), 0);
693
- }
694
-
695
- #[tokio::test]
696
- async fn test_mock_grpc_handler_basic() {
697
- let handler = MockGrpcHandler::new("test.Service", Bytes::from("response"));
698
- let request = GrpcRequestData {
699
- service_name: "test.Service".to_string(),
700
- method_name: "TestMethod".to_string(),
701
- payload: Bytes::from("request"),
702
- metadata: MetadataMap::new(),
703
- };
704
-
705
- let result = handler.call(request).await;
706
- assert!(result.is_ok());
707
-
708
- let response = result.unwrap();
709
- assert_eq!(response.payload, Bytes::from("response"));
710
- }
711
-
712
- #[tokio::test]
713
- async fn test_mock_grpc_handler_with_json() {
714
- let json_response = json!({"id": 1, "name": "Alice"});
715
- let handler = MockGrpcHandler::with_json("test.UserService", &json_response);
716
-
717
- let request = GrpcRequestData {
718
- service_name: "test.UserService".to_string(),
719
- method_name: "GetUser".to_string(),
720
- payload: Bytes::from("{}"),
721
- metadata: MetadataMap::new(),
722
- };
723
-
724
- let result = handler.call(request).await;
725
- assert!(result.is_ok());
726
-
727
- let response = result.unwrap();
728
- let deserialized = serde_json::from_slice::<Value>(&response.payload).unwrap();
729
- assert_eq!(deserialized, json_response);
730
- }
731
-
732
- #[tokio::test]
733
- async fn test_error_mock_handler() {
734
- let handler = ErrorMockHandler::new("test.Service", Code::NotFound, "Resource not found");
735
-
736
- let request = GrpcRequestData {
737
- service_name: "test.Service".to_string(),
738
- method_name: "GetResource".to_string(),
739
- payload: Bytes::new(),
740
- metadata: MetadataMap::new(),
741
- };
742
-
743
- let result = handler.call(request).await;
744
- assert!(result.is_err());
745
-
746
- let status = result.unwrap_err();
747
- assert_eq!(status.code(), Code::NotFound);
748
- assert_eq!(status.message(), "Resource not found");
749
- }
750
-
751
- #[tokio::test]
752
- async fn test_echo_mock_handler() {
753
- let handler = EchoMockHandler::new("test.Service");
754
- let payload = Bytes::from("echo this");
755
-
756
- let request = GrpcRequestData {
757
- service_name: "test.Service".to_string(),
758
- method_name: "Echo".to_string(),
759
- payload: payload.clone(),
760
- metadata: MetadataMap::new(),
761
- };
762
-
763
- let result = handler.call(request).await;
764
- assert!(result.is_ok());
765
-
766
- let response = result.unwrap();
767
- assert_eq!(response.payload, payload);
768
- }
769
-
770
- #[test]
771
- fn test_protobuf_message_builder_new() {
772
- let builder = ProtobufMessageBuilder::new();
773
- assert_eq!(builder.field_count(), 0);
774
- }
775
-
776
- #[test]
777
- fn test_protobuf_message_builder_add_field() {
778
- let mut builder = ProtobufMessageBuilder::new();
779
- builder.add_field("name", "Alice").add_field("age", 30);
780
-
781
- assert_eq!(builder.field_count(), 2);
782
- }
783
-
784
- #[test]
785
- fn test_protobuf_message_builder_add_string_field() {
786
- let mut builder = ProtobufMessageBuilder::new();
787
- builder.add_string_field("name", "Bob");
788
-
789
- let json = builder.as_json();
790
- assert_eq!(json["name"], "Bob");
791
- }
792
-
793
- #[test]
794
- fn test_protobuf_message_builder_add_int_field() {
795
- let mut builder = ProtobufMessageBuilder::new();
796
- builder.add_int_field("age", 42);
797
-
798
- let json = builder.as_json();
799
- assert_eq!(json["age"], 42);
800
- }
801
-
802
- #[test]
803
- fn test_protobuf_message_builder_add_bool_field() {
804
- let mut builder = ProtobufMessageBuilder::new();
805
- builder.add_bool_field("active", true);
806
-
807
- let json = builder.as_json();
808
- assert_eq!(json["active"], true);
809
- }
810
-
811
- #[test]
812
- fn test_protobuf_message_builder_add_object_field() {
813
- let mut builder = ProtobufMessageBuilder::new();
814
- builder.add_object_field("user", json!({"name": "Alice", "id": 1}));
815
-
816
- let json = builder.as_json();
817
- assert_eq!(json["user"]["name"], "Alice");
818
- assert_eq!(json["user"]["id"], 1);
819
- }
820
-
821
- #[test]
822
- fn test_protobuf_message_builder_add_array_field() {
823
- let mut builder = ProtobufMessageBuilder::new();
824
- builder.add_array_field("tags", vec![json!("rust"), json!("testing"), json!("grpc")]);
825
-
826
- let json = builder.as_json();
827
- assert_eq!(json["tags"].as_array().unwrap().len(), 3);
828
- assert_eq!(json["tags"][0], "rust");
829
- }
830
-
831
- #[test]
832
- fn test_protobuf_message_builder_build() {
833
- let mut builder = ProtobufMessageBuilder::new();
834
- builder.add_field("id", 1).add_field("name", "Alice");
835
-
836
- let bytes = builder.build().unwrap();
837
- let deserialized = serde_json::from_slice::<Value>(&bytes).unwrap();
838
-
839
- assert_eq!(deserialized["id"], 1);
840
- assert_eq!(deserialized["name"], "Alice");
841
- }
842
-
843
- #[test]
844
- fn test_protobuf_message_builder_clear() {
845
- let mut builder = ProtobufMessageBuilder::new();
846
- builder.add_field("id", 1).add_field("name", "Alice");
847
- assert_eq!(builder.field_count(), 2);
848
-
849
- builder.clear();
850
- assert_eq!(builder.field_count(), 0);
851
- }
852
-
853
- #[test]
854
- fn test_protobuf_message_builder_fluent_api() {
855
- let mut builder = ProtobufMessageBuilder::new();
856
- builder
857
- .add_string_field("email", "alice@example.com")
858
- .add_int_field("age", 30)
859
- .add_bool_field("verified", true);
860
-
861
- assert_eq!(builder.field_count(), 3);
862
-
863
- let json = builder.as_json();
864
- assert_eq!(json["email"], "alice@example.com");
865
- assert_eq!(json["age"], 30);
866
- assert_eq!(json["verified"], true);
867
- }
868
-
869
- #[test]
870
- fn test_create_test_metadata() {
871
- let metadata = create_test_metadata();
872
-
873
- assert!(metadata.get("user-agent").is_some());
874
- assert!(metadata.get("content-type").is_some());
875
- }
876
-
877
- #[test]
878
- fn test_create_test_metadata_with_headers() {
879
- use std::collections::HashMap;
880
-
881
- let mut headers = HashMap::new();
882
- headers.insert("authorization".to_string(), "Bearer token".to_string());
883
- headers.insert("x-custom".to_string(), "value".to_string());
884
-
885
- let metadata = create_test_metadata_with_headers(&headers).unwrap();
886
-
887
- assert!(metadata.get("authorization").is_some());
888
- assert!(metadata.get("x-custom").is_some());
889
- }
890
-
891
- #[test]
892
- fn test_add_auth_metadata() {
893
- let mut metadata = create_test_metadata();
894
- add_auth_metadata(&mut metadata, "secret_token_123").unwrap();
895
-
896
- let auth_header = metadata.get("authorization").unwrap();
897
- assert_eq!(auth_header.to_str().unwrap(), "Bearer secret_token_123");
898
- }
899
-
900
- #[test]
901
- fn test_add_metadata_header() {
902
- let mut metadata = create_test_metadata();
903
- add_metadata_header(&mut metadata, "x-request-id", "req-123").unwrap();
904
-
905
- let header = metadata.get("x-request-id").unwrap();
906
- assert_eq!(header.to_str().unwrap(), "req-123");
907
- }
908
-
909
- #[test]
910
- fn test_assert_grpc_response_matching() {
911
- let response = GrpcResponseData {
912
- payload: Bytes::from(r#"{"id": 1, "name": "Alice"}"#),
913
- metadata: MetadataMap::new(),
914
- };
915
-
916
- let expected = json!({"id": 1, "name": "Alice"});
917
- assert_grpc_response(&response, &expected);
918
- }
919
-
920
- #[test]
921
- fn test_assert_grpc_status_error() {
922
- let result: GrpcHandlerResult = Err(tonic::Status::not_found("Resource not found"));
923
-
924
- assert_grpc_status(&result, Code::NotFound);
925
- }
926
-
927
- #[test]
928
- #[should_panic(expected = "Expected status")]
929
- fn test_assert_grpc_status_mismatch() {
930
- let result: GrpcHandlerResult = Err(tonic::Status::not_found("Resource not found"));
931
-
932
- assert_grpc_status(&result, Code::InvalidArgument);
933
- }
934
-
935
- #[test]
936
- #[should_panic(expected = "Expected error status")]
937
- fn test_assert_grpc_status_on_success() {
938
- let result: GrpcHandlerResult = Ok(GrpcResponseData {
939
- payload: Bytes::new(),
940
- metadata: MetadataMap::new(),
941
- });
942
-
943
- assert_grpc_status(&result, Code::NotFound);
944
- }
945
-
946
- #[test]
947
- fn test_protobuf_message_builder_default() {
948
- let builder = ProtobufMessageBuilder::default();
949
- assert_eq!(builder.field_count(), 0);
950
- }
951
-
952
- #[tokio::test]
953
- async fn test_send_unary_request_with_mock_handler() {
954
- let server = GrpcTestServer::new();
955
- let _response_payload = json!({"result": "success"});
956
-
957
- server.register_service(Arc::new(TestHandler));
958
-
959
- let message = ProtobufMessageBuilder::new()
960
- .add_field("input", "test")
961
- .build()
962
- .unwrap();
963
-
964
- let result = send_unary_request(
965
- &server,
966
- "test.TestService",
967
- "TestMethod",
968
- message,
969
- create_test_metadata(),
970
- )
971
- .await;
972
-
973
- assert!(result.is_ok());
974
- }
975
-
976
- #[tokio::test]
977
- async fn test_send_unary_request_service_not_found() {
978
- let server = GrpcTestServer::new();
979
- let message = Bytes::from("test");
980
-
981
- let result = send_unary_request(
982
- &server,
983
- "nonexistent.Service",
984
- "Method",
985
- message,
986
- create_test_metadata(),
987
- )
988
- .await;
989
-
990
- assert!(result.is_err());
991
- }
992
-
993
- #[test]
994
- fn test_error_mock_handler_invalid_argument() {
995
- let handler = ErrorMockHandler::new("test.Service", Code::InvalidArgument, "Bad input");
996
- assert_eq!(handler.error_code, Code::InvalidArgument);
997
- assert_eq!(handler.error_message, "Bad input");
998
- }
999
-
1000
- #[test]
1001
- fn test_echo_mock_handler_creates_with_service_name() {
1002
- let handler = EchoMockHandler::new("mypackage.EchoService");
1003
- assert_eq!(handler.service_name, "mypackage.EchoService");
1004
- }
1005
-
1006
- #[test]
1007
- fn test_grpc_test_client_creation() {
1008
- let _client = create_grpc_test_client();
1009
- let _new_client = GrpcTestClient::new();
1010
- // Just ensure it can be created without panicking
1011
- }
1012
- }