fastmcp_rust/testing/fixtures/
resources.rs1use fastmcp_protocol::{Resource, ResourceTemplate};
10use serde_json::json;
11
12#[must_use]
23pub fn text_file_resource() -> Resource {
24 Resource {
25 uri: "file:///test/sample.txt".to_string(),
26 name: "sample.txt".to_string(),
27 description: Some("A sample text file for testing".to_string()),
28 mime_type: Some("text/plain".to_string()),
29 icon: None,
30 version: Some("1.0.0".to_string()),
31 tags: vec!["text".to_string(), "sample".to_string()],
32 }
33}
34
35#[must_use]
46pub fn config_json_resource() -> Resource {
47 Resource {
48 uri: "file:///config/settings.json".to_string(),
49 name: "settings.json".to_string(),
50 description: Some("Application configuration in JSON format".to_string()),
51 mime_type: Some("application/json".to_string()),
52 icon: None,
53 version: Some("2.1.0".to_string()),
54 tags: vec!["config".to_string(), "json".to_string()],
55 }
56}
57
58#[must_use]
69pub fn log_file_resource() -> Resource {
70 Resource {
71 uri: "file:///var/log/app.log".to_string(),
72 name: "app.log".to_string(),
73 description: Some("Application log file".to_string()),
74 mime_type: Some("text/plain".to_string()),
75 icon: None,
76 version: None,
77 tags: vec!["log".to_string(), "monitoring".to_string()],
78 }
79}
80
81#[must_use]
92pub fn database_resource() -> Resource {
93 Resource {
94 uri: "db://localhost/test_db/users".to_string(),
95 name: "users table".to_string(),
96 description: Some("User records from the database".to_string()),
97 mime_type: Some("application/json".to_string()),
98 icon: None,
99 version: None,
100 tags: vec!["database".to_string(), "users".to_string()],
101 }
102}
103
104#[must_use]
115pub fn api_resource() -> Resource {
116 Resource {
117 uri: "https://api.example.com/v1/data".to_string(),
118 name: "API Data".to_string(),
119 description: Some("Data from external API".to_string()),
120 mime_type: Some("application/json".to_string()),
121 icon: None,
122 version: Some("1.0.0".to_string()),
123 tags: vec!["api".to_string(), "external".to_string()],
124 }
125}
126
127#[must_use]
129pub fn minimal_resource() -> Resource {
130 Resource {
131 uri: "file:///minimal".to_string(),
132 name: "minimal".to_string(),
133 description: None,
134 mime_type: None,
135 icon: None,
136 version: None,
137 tags: vec![],
138 }
139}
140
141#[must_use]
143pub fn image_resource() -> Resource {
144 Resource {
145 uri: "file:///images/logo.png".to_string(),
146 name: "logo.png".to_string(),
147 description: Some("Application logo image".to_string()),
148 mime_type: Some("image/png".to_string()),
149 icon: None,
150 version: Some("1.0.0".to_string()),
151 tags: vec!["image".to_string(), "binary".to_string()],
152 }
153}
154
155#[must_use]
157pub fn all_sample_resources() -> Vec<Resource> {
158 vec![
159 text_file_resource(),
160 config_json_resource(),
161 log_file_resource(),
162 database_resource(),
163 api_resource(),
164 minimal_resource(),
165 image_resource(),
166 ]
167}
168
169#[must_use]
184pub fn file_path_template() -> ResourceTemplate {
185 ResourceTemplate {
186 uri_template: "file:///{path}".to_string(),
187 name: "File Path".to_string(),
188 description: Some("Access any file by path".to_string()),
189 mime_type: None,
190 icon: None,
191 version: Some("1.0.0".to_string()),
192 tags: vec!["file".to_string(), "template".to_string()],
193 }
194}
195
196#[must_use]
198pub fn database_table_template() -> ResourceTemplate {
199 ResourceTemplate {
200 uri_template: "db://{host}/{database}/{table}".to_string(),
201 name: "Database Table".to_string(),
202 description: Some("Access any database table".to_string()),
203 mime_type: Some("application/json".to_string()),
204 icon: None,
205 version: Some("1.0.0".to_string()),
206 tags: vec!["database".to_string(), "template".to_string()],
207 }
208}
209
210#[must_use]
212pub fn api_endpoint_template() -> ResourceTemplate {
213 ResourceTemplate {
214 uri_template: "https://api.example.com/{version}/{resource}".to_string(),
215 name: "API Endpoint".to_string(),
216 description: Some("Access versioned API endpoints".to_string()),
217 mime_type: Some("application/json".to_string()),
218 icon: None,
219 version: Some("1.0.0".to_string()),
220 tags: vec!["api".to_string(), "template".to_string()],
221 }
222}
223
224#[must_use]
226pub fn user_profile_template() -> ResourceTemplate {
227 ResourceTemplate {
228 uri_template: "user://{user_id}/profile".to_string(),
229 name: "User Profile".to_string(),
230 description: Some("Access user profile by ID".to_string()),
231 mime_type: Some("application/json".to_string()),
232 icon: None,
233 version: None,
234 tags: vec!["user".to_string(), "profile".to_string()],
235 }
236}
237
238#[must_use]
240pub fn all_sample_templates() -> Vec<ResourceTemplate> {
241 vec![
242 file_path_template(),
243 database_table_template(),
244 api_endpoint_template(),
245 user_profile_template(),
246 ]
247}
248
249#[must_use]
255pub fn sample_text_content() -> String {
256 "Hello, World!\nThis is sample text content for testing.\nLine 3.\nLine 4.".to_string()
257}
258
259#[must_use]
261pub fn sample_json_config() -> serde_json::Value {
262 json!({
263 "version": "1.0.0",
264 "settings": {
265 "debug": false,
266 "log_level": "info",
267 "max_connections": 100
268 },
269 "features": {
270 "experimental": false,
271 "beta": true
272 },
273 "database": {
274 "host": "localhost",
275 "port": 5432,
276 "name": "test_db"
277 }
278 })
279}
280
281#[must_use]
283pub fn sample_log_content() -> String {
284 [
285 "[2024-01-15 10:30:00] INFO: Server started",
286 "[2024-01-15 10:30:01] INFO: Listening on port 8080",
287 "[2024-01-15 10:30:05] DEBUG: Connection accepted from 127.0.0.1",
288 "[2024-01-15 10:30:06] INFO: Request processed in 15ms",
289 "[2024-01-15 10:30:10] WARN: High memory usage detected",
290 "[2024-01-15 10:30:15] ERROR: Connection timeout",
291 ]
292 .join("\n")
293}
294
295#[must_use]
301pub fn large_text_content(size_kb: usize) -> String {
302 let line = "This is a line of text for stress testing. ".repeat(10);
303 let lines_needed = (size_kb * 1024) / line.len() + 1;
304 (0..lines_needed)
305 .map(|i| format!("[Line {i:06}] {line}"))
306 .collect::<Vec<_>>()
307 .join("\n")
308}
309
310#[derive(Debug, Clone)]
312pub struct ResourceBuilder {
313 uri: String,
314 name: String,
315 description: Option<String>,
316 mime_type: Option<String>,
317 version: Option<String>,
318 tags: Vec<String>,
319}
320
321impl ResourceBuilder {
322 #[must_use]
324 pub fn new(uri: impl Into<String>, name: impl Into<String>) -> Self {
325 Self {
326 uri: uri.into(),
327 name: name.into(),
328 description: None,
329 mime_type: None,
330 version: None,
331 tags: Vec::new(),
332 }
333 }
334
335 #[must_use]
337 pub fn description(mut self, desc: impl Into<String>) -> Self {
338 self.description = Some(desc.into());
339 self
340 }
341
342 #[must_use]
344 pub fn mime_type(mut self, mime: impl Into<String>) -> Self {
345 self.mime_type = Some(mime.into());
346 self
347 }
348
349 #[must_use]
351 pub fn version(mut self, version: impl Into<String>) -> Self {
352 self.version = Some(version.into());
353 self
354 }
355
356 #[must_use]
358 pub fn tags(mut self, tags: Vec<String>) -> Self {
359 self.tags = tags;
360 self
361 }
362
363 #[must_use]
365 pub fn build(self) -> Resource {
366 Resource {
367 uri: self.uri,
368 name: self.name,
369 description: self.description,
370 mime_type: self.mime_type,
371 icon: None,
372 version: self.version,
373 tags: self.tags,
374 }
375 }
376}
377
378#[cfg(test)]
379mod tests {
380 use super::*;
381
382 #[test]
383 fn test_text_file_resource() {
384 let resource = text_file_resource();
385 assert!(resource.uri.starts_with("file://"));
386 assert_eq!(resource.mime_type, Some("text/plain".to_string()));
387 }
388
389 #[test]
390 fn test_config_json_resource() {
391 let resource = config_json_resource();
392 assert_eq!(resource.mime_type, Some("application/json".to_string()));
393 }
394
395 #[test]
396 fn test_database_resource() {
397 let resource = database_resource();
398 assert!(resource.uri.starts_with("db://"));
399 }
400
401 #[test]
402 fn test_api_resource() {
403 let resource = api_resource();
404 assert!(resource.uri.starts_with("https://"));
405 }
406
407 #[test]
408 fn test_minimal_resource() {
409 let resource = minimal_resource();
410 assert!(resource.description.is_none());
411 assert!(resource.mime_type.is_none());
412 assert!(resource.tags.is_empty());
413 }
414
415 #[test]
416 fn test_all_sample_resources() {
417 let resources = all_sample_resources();
418 assert!(resources.len() >= 5);
419
420 let uris: Vec<_> = resources.iter().map(|r| &r.uri).collect();
422 let unique: std::collections::HashSet<_> = uris.iter().collect();
423 assert_eq!(uris.len(), unique.len());
424 }
425
426 #[test]
427 fn test_file_path_template() {
428 let template = file_path_template();
429 assert!(template.uri_template.contains("{path}"));
430 }
431
432 #[test]
433 fn test_database_table_template() {
434 let template = database_table_template();
435 assert!(template.uri_template.contains("{host}"));
436 assert!(template.uri_template.contains("{database}"));
437 assert!(template.uri_template.contains("{table}"));
438 }
439
440 #[test]
441 fn test_all_sample_templates() {
442 let templates = all_sample_templates();
443 assert!(templates.len() >= 3);
444 }
445
446 #[test]
447 fn test_sample_text_content() {
448 let content = sample_text_content();
449 assert!(content.contains("Hello, World!"));
450 }
451
452 #[test]
453 fn test_sample_json_config() {
454 let config = sample_json_config();
455 assert!(config.get("version").is_some());
456 assert!(config.get("settings").is_some());
457 }
458
459 #[test]
460 fn test_sample_log_content() {
461 let log = sample_log_content();
462 assert!(log.contains("INFO"));
463 assert!(log.contains("ERROR"));
464 }
465
466 #[test]
467 fn test_large_text_content() {
468 let content = large_text_content(10);
469 assert!(content.len() >= 9 * 1024);
471 assert!(content.len() <= 12 * 1024);
472 }
473
474 #[test]
475 fn test_resource_builder() {
476 let resource = ResourceBuilder::new("file:///test", "test")
477 .description("A test resource")
478 .mime_type("text/plain")
479 .version("1.0.0")
480 .tags(vec!["test".to_string()])
481 .build();
482
483 assert_eq!(resource.uri, "file:///test");
484 assert_eq!(resource.name, "test");
485 assert_eq!(resource.description, Some("A test resource".to_string()));
486 }
487}