1use serde::{Deserialize, Serialize};
4use std::collections::HashMap;
5
6#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct ServerStatus {
9 pub server_type: String,
11 pub address: Option<String>,
13 pub running: bool,
15 pub start_time: Option<chrono::DateTime<chrono::Utc>>,
17 pub uptime_seconds: Option<u64>,
19 pub active_connections: u64,
21 pub total_requests: u64,
23}
24
25#[derive(Debug, Clone, Serialize, Deserialize)]
27pub struct RouteInfo {
28 pub method: Option<String>,
30 pub path: String,
32 pub priority: i32,
34 pub has_fixtures: bool,
36 pub latency_ms: Option<u64>,
38 pub request_count: u64,
40 pub last_request: Option<chrono::DateTime<chrono::Utc>>,
42 pub error_count: u64,
44}
45
46#[derive(Debug, Clone, Serialize, Deserialize)]
48pub struct RequestLog {
49 pub id: String,
51 pub timestamp: chrono::DateTime<chrono::Utc>,
53 pub method: String,
55 pub path: String,
57 pub status_code: u16,
59 pub response_time_ms: u64,
61 pub client_ip: Option<String>,
63 pub user_agent: Option<String>,
65 pub headers: HashMap<String, String>,
67 pub response_size_bytes: u64,
69 pub error_message: Option<String>,
71}
72
73#[derive(Debug, Clone, Serialize, Deserialize)]
75pub struct SystemInfo {
76 pub version: String,
78 pub uptime_seconds: u64,
80 pub memory_usage_mb: u64,
82 pub cpu_usage_percent: f64,
84 pub active_threads: usize,
86 pub total_routes: usize,
88 pub total_fixtures: usize,
90}
91
92#[derive(Debug, Clone, Serialize, Deserialize)]
94pub struct LatencyProfile {
95 pub name: String,
97 pub base_ms: u64,
99 pub jitter_ms: u64,
101 pub tag_overrides: HashMap<String, u64>,
103}
104
105#[derive(Debug, Clone, Serialize, Deserialize)]
107pub struct FaultConfig {
108 pub enabled: bool,
110 pub failure_rate: f64,
112 pub status_codes: Vec<u16>,
114 pub active_failures: u64,
116}
117
118#[derive(Debug, Clone, Serialize, Deserialize)]
120pub struct ProxyConfig {
121 pub enabled: bool,
123 pub upstream_url: Option<String>,
125 pub timeout_seconds: u64,
127 pub requests_proxied: u64,
129}
130
131#[derive(Debug, Clone, Serialize, Deserialize)]
133pub struct BandwidthConfig {
134 pub enabled: bool,
136 pub max_bytes_per_sec: u64,
138 pub burst_capacity_bytes: u64,
140 pub tag_overrides: HashMap<String, u64>,
142}
143
144#[derive(Debug, Clone, Serialize, Deserialize)]
146pub struct BurstLossConfig {
147 pub enabled: bool,
149 pub burst_probability: f64,
151 pub burst_duration_ms: u64,
153 pub loss_rate_during_burst: f64,
155 pub recovery_time_ms: u64,
157 pub tag_overrides: HashMap<String, BurstLossOverride>,
159}
160
161#[derive(Debug, Clone, Serialize, Deserialize)]
163pub struct BurstLossOverride {
164 pub burst_probability: f64,
165 pub burst_duration_ms: u64,
166 pub loss_rate_during_burst: f64,
167 pub recovery_time_ms: u64,
168}
169
170#[derive(Debug, Clone, Serialize, Deserialize)]
172pub struct TrafficShapingConfig {
173 pub enabled: bool,
175 pub bandwidth: BandwidthConfig,
177 pub burst_loss: BurstLossConfig,
179}
180
181#[derive(Debug, Clone, Serialize, Deserialize)]
183pub struct SimpleMetricsData {
184 pub total_requests: u64,
186 pub active_requests: u64,
188 pub average_response_time: f64,
190 pub error_rate: f64,
192}
193
194#[derive(Debug, Clone, Serialize, Deserialize)]
196pub struct DashboardSystemInfo {
197 pub os: String,
199 pub arch: String,
201 pub uptime: u64,
203 pub memory_usage: u64,
205}
206
207#[derive(Debug, Clone, Serialize, Deserialize)]
209pub struct DashboardData {
210 pub server_info: ServerInfo,
212 pub system_info: DashboardSystemInfo,
214 pub metrics: SimpleMetricsData,
216 pub servers: Vec<ServerStatus>,
218 pub recent_logs: Vec<RequestLog>,
220 pub system: SystemInfo,
222}
223
224#[derive(Debug, Clone, Serialize, Deserialize)]
226pub struct ApiResponse<T> {
227 pub success: bool,
229 pub data: Option<T>,
231 pub error: Option<String>,
233 pub timestamp: chrono::DateTime<chrono::Utc>,
235}
236
237impl<T> ApiResponse<T> {
238 pub fn success(data: T) -> Self {
240 Self {
241 success: true,
242 data: Some(data),
243 error: None,
244 timestamp: chrono::Utc::now(),
245 }
246 }
247
248 pub fn error(message: String) -> Self {
250 Self {
251 success: false,
252 data: None,
253 error: Some(message),
254 timestamp: chrono::Utc::now(),
255 }
256 }
257}
258
259#[derive(Debug, Clone, Serialize, Deserialize)]
261pub struct ConfigUpdate {
262 pub config_type: String,
264 pub data: serde_json::Value,
266}
267
268#[derive(Debug, Clone, Serialize, Deserialize)]
270pub struct RouteUpdate {
271 pub path: String,
273 pub method: Option<String>,
275 pub operation: String,
277 pub data: Option<serde_json::Value>,
279}
280
281#[derive(Debug, Clone, Serialize, Deserialize)]
283pub struct LogFilter {
284 pub method: Option<String>,
286 pub path_pattern: Option<String>,
288 pub status_code: Option<u16>,
290 pub hours_ago: Option<u64>,
292 pub limit: Option<usize>,
294}
295
296impl Default for LogFilter {
297 fn default() -> Self {
298 Self {
299 method: None,
300 path_pattern: None,
301 status_code: None,
302 hours_ago: Some(24),
303 limit: Some(100),
304 }
305 }
306}
307
308#[derive(Debug, Clone, Serialize, Deserialize)]
310pub struct MetricsData {
311 pub requests_by_endpoint: HashMap<String, u64>,
313 pub response_time_percentiles: HashMap<String, u64>,
315 pub error_rate_by_endpoint: HashMap<String, f64>,
317 pub memory_usage_over_time: Vec<(chrono::DateTime<chrono::Utc>, u64)>,
319 pub cpu_usage_over_time: Vec<(chrono::DateTime<chrono::Utc>, f64)>,
321}
322
323#[derive(Debug, Clone, Serialize, Deserialize)]
325pub struct ValidationSettings {
326 pub mode: String,
328 pub aggregate_errors: bool,
330 pub validate_responses: bool,
332 pub overrides: HashMap<String, String>,
334}
335
336#[derive(Debug, Clone, Serialize, Deserialize)]
338pub struct ValidationUpdate {
339 pub mode: String,
341 pub aggregate_errors: bool,
343 pub validate_responses: bool,
345 pub overrides: Option<HashMap<String, String>>,
347}
348
349#[derive(Debug, Clone, Serialize, Deserialize)]
351pub struct LogEntry {
352 pub timestamp: chrono::DateTime<chrono::Utc>,
354 pub status: u16,
356 pub method: String,
358 pub url: String,
360 pub response_time: u64,
362 pub size: u64,
364}
365
366#[derive(Debug, Clone, Serialize, Deserialize)]
368pub struct HealthCheck {
369 pub status: String,
371 pub services: HashMap<String, String>,
373 pub last_check: chrono::DateTime<chrono::Utc>,
375 pub issues: Vec<String>,
377}
378
379impl HealthCheck {
380 pub fn healthy() -> Self {
382 Self {
383 status: "healthy".to_string(),
384 services: HashMap::new(),
385 last_check: chrono::Utc::now(),
386 issues: Vec::new(),
387 }
388 }
389
390 pub fn unhealthy(issues: Vec<String>) -> Self {
392 Self {
393 status: "unhealthy".to_string(),
394 services: HashMap::new(),
395 last_check: chrono::Utc::now(),
396 issues,
397 }
398 }
399
400 pub fn with_service(mut self, name: String, status: String) -> Self {
402 self.services.insert(name, status);
403 self
404 }
405}
406
407#[derive(Debug, Clone, Serialize, Deserialize)]
409pub struct WorkspaceSummary {
410 pub id: String,
412 pub name: String,
414 pub description: Option<String>,
416 pub active: bool,
418 pub folder_count: usize,
420 pub request_count: usize,
422 pub created_at: chrono::DateTime<chrono::Utc>,
424 pub updated_at: chrono::DateTime<chrono::Utc>,
426}
427
428#[derive(Debug, Clone, Serialize, Deserialize)]
430pub struct FolderSummary {
431 pub id: String,
433 pub name: String,
435 pub description: Option<String>,
437 pub parent_id: Option<String>,
439 pub subfolder_count: usize,
441 pub request_count: usize,
443 pub created_at: chrono::DateTime<chrono::Utc>,
445 pub updated_at: chrono::DateTime<chrono::Utc>,
447}
448
449#[derive(Debug, Clone, Serialize, Deserialize)]
451pub struct RequestSummary {
452 pub id: String,
454 pub name: String,
456 pub description: Option<String>,
458 pub method: String,
460 pub path: String,
462 pub status_code: u16,
464 pub created_at: chrono::DateTime<chrono::Utc>,
466 pub updated_at: chrono::DateTime<chrono::Utc>,
468}
469
470#[derive(Debug, Clone, Serialize, Deserialize)]
472pub struct WorkspaceDetail {
473 pub summary: WorkspaceSummary,
475 pub folders: Vec<FolderSummary>,
477 pub requests: Vec<RequestSummary>,
479}
480
481#[derive(Debug, Clone, Serialize, Deserialize)]
483pub struct FolderDetail {
484 pub summary: FolderSummary,
486 pub subfolders: Vec<FolderSummary>,
488 pub requests: Vec<RequestSummary>,
490}
491
492#[derive(Debug, Clone, Serialize, Deserialize)]
494pub struct CreateWorkspaceRequest {
495 pub name: String,
497 pub description: Option<String>,
499}
500
501#[derive(Debug, Clone, Serialize, Deserialize)]
503pub struct CreateFolderRequest {
504 pub name: String,
506 pub description: Option<String>,
508 pub parent_id: Option<String>,
510}
511
512#[derive(Debug, Clone, Serialize, Deserialize)]
514pub struct CreateRequestRequest {
515 pub name: String,
517 pub description: Option<String>,
519 pub method: String,
521 pub path: String,
523 pub status_code: Option<u16>,
525 pub response_body: Option<String>,
527 pub folder_id: Option<String>,
529}
530
531#[derive(Debug, Clone, Serialize, Deserialize)]
533pub struct ImportToWorkspaceRequest {
534 pub format: String,
536 pub data: String,
538 pub folder_id: Option<String>,
540 pub create_folders: Option<bool>,
542 pub selected_routes: Option<Vec<usize>>,
544}
545
546#[derive(Debug, Clone, Serialize, Deserialize)]
548pub struct ExportWorkspacesRequest {
549 pub workspace_ids: Vec<String>,
551}
552
553#[derive(Debug, Clone, Serialize, Deserialize)]
555pub struct WorkspaceExportData {
556 pub workspaces: Vec<mockforge_core::Workspace>,
558 pub version: String,
560 pub exported_at: chrono::DateTime<chrono::Utc>,
562 pub exporter_version: String,
564}
565
566#[derive(Debug, Clone, Serialize, Deserialize)]
568pub struct EnvironmentColor {
569 pub hex: String,
571 pub name: Option<String>,
573}
574
575#[derive(Debug, Clone, Serialize, Deserialize)]
577pub struct EnvironmentSummary {
578 pub id: String,
580 pub name: String,
582 pub description: Option<String>,
584 pub color: Option<EnvironmentColor>,
586 pub variable_count: usize,
588 pub active: bool,
590 pub is_global: bool,
592 pub created_at: chrono::DateTime<chrono::Utc>,
594 pub updated_at: chrono::DateTime<chrono::Utc>,
596}
597
598#[derive(Debug, Clone, Serialize, Deserialize)]
600pub struct EnvironmentVariable {
601 pub name: String,
603 pub value: String,
605 pub from_global: bool,
607}
608
609#[derive(Debug, Clone, Serialize, Deserialize)]
611pub struct CreateEnvironmentRequest {
612 pub name: String,
614 pub description: Option<String>,
616}
617
618#[derive(Debug, Clone, Serialize, Deserialize)]
620pub struct UpdateEnvironmentRequest {
621 pub name: Option<String>,
623 pub description: Option<String>,
625 pub color: Option<EnvironmentColor>,
627}
628
629#[derive(Debug, Clone, Serialize, Deserialize)]
631pub struct SetVariableRequest {
632 pub name: String,
634 pub value: String,
636}
637
638#[derive(Debug, Clone, Serialize, Deserialize)]
640pub struct SyncConfig {
641 pub enabled: bool,
643 pub target_directory: Option<String>,
645 pub directory_structure: SyncDirectoryStructure,
647 pub sync_direction: SyncDirection,
649 pub include_metadata: bool,
651 pub realtime_monitoring: bool,
653 pub filename_pattern: String,
655 pub exclude_pattern: Option<String>,
657 pub force_overwrite: bool,
659}
660
661#[derive(Debug, Clone, Serialize, Deserialize)]
663pub enum SyncDirectoryStructure {
664 Flat,
666 Nested,
668 Grouped,
670}
671
672#[derive(Debug, Clone, Serialize, Deserialize)]
674pub enum SyncDirection {
675 Manual,
677 WorkspaceToDirectory,
679 Bidirectional,
681}
682
683impl From<mockforge_core::workspace::SyncDirection> for SyncDirection {
684 fn from(core: mockforge_core::workspace::SyncDirection) -> Self {
685 match core {
686 mockforge_core::workspace::SyncDirection::Manual => Self::Manual,
687 mockforge_core::workspace::SyncDirection::WorkspaceToDirectory => {
688 Self::WorkspaceToDirectory
689 }
690 mockforge_core::workspace::SyncDirection::Bidirectional => Self::Bidirectional,
691 }
692 }
693}
694
695#[derive(Debug, Clone, Serialize, Deserialize)]
697pub struct SyncStatus {
698 pub workspace_id: String,
700 pub enabled: bool,
702 pub target_directory: Option<String>,
704 pub sync_direction: SyncDirection,
706 pub realtime_monitoring: bool,
708 pub last_sync: Option<chrono::DateTime<chrono::Utc>>,
710 pub status: String,
712}
713
714#[derive(Debug, Clone, Serialize, Deserialize)]
716pub struct SyncChange {
717 pub change_type: String,
719 pub path: String,
721 pub description: String,
723 pub requires_confirmation: bool,
725}
726
727#[derive(Debug, Clone, Serialize, Deserialize)]
729pub struct ConfigureSyncRequest {
730 pub target_directory: String,
732 pub sync_direction: SyncDirection,
734 pub realtime_monitoring: bool,
736 pub directory_structure: Option<SyncDirectoryStructure>,
738 pub filename_pattern: Option<String>,
740}
741
742#[derive(Debug, Clone, Serialize, Deserialize)]
744pub struct ConfirmSyncChangesRequest {
745 pub workspace_id: String,
747 pub changes: Vec<SyncChange>,
749 pub apply_all: bool,
751}
752
753#[derive(Debug, Clone, Serialize, Deserialize)]
755pub struct AutocompleteSuggestion {
756 pub text: String,
758 pub kind: String,
760 pub description: Option<String>,
762}
763
764#[derive(Debug, Clone, Serialize, Deserialize)]
766pub struct AutocompleteRequest {
767 pub input: String,
769 pub cursor_position: usize,
771 pub context: Option<String>,
773}
774
775#[derive(Debug, Clone, Serialize, Deserialize)]
777pub struct AutocompleteResponse {
778 pub suggestions: Vec<AutocompleteSuggestion>,
780 pub start_position: usize,
782 pub end_position: usize,
784}
785
786#[derive(Debug, Clone, Serialize, Deserialize)]
788pub struct TimeSeriesPoint {
789 pub timestamp: chrono::DateTime<chrono::Utc>,
791 pub value: f64,
793}
794
795#[derive(Debug, Clone, Serialize, Deserialize)]
797pub struct TimeSeriesData {
798 pub points: Vec<TimeSeriesPoint>,
800 pub metric: String,
802}
803
804#[derive(Debug, Clone, Serialize, Deserialize)]
806pub struct RestartStatus {
807 pub restarting: bool,
809 pub progress: f64,
811 pub message: String,
813}
814
815#[derive(Debug, Clone, Serialize, Deserialize)]
817pub struct SmokeTestResult {
818 pub test_name: String,
820 pub passed: bool,
822 pub response_time_ms: Option<u64>,
824 pub error_message: Option<String>,
826}
827
828#[derive(Debug, Clone, Serialize, Deserialize)]
830pub struct SmokeTestContext {
831 pub suite_name: String,
833 pub total_tests: usize,
835 pub passed_tests: usize,
837 pub failed_tests: usize,
839 pub start_time: chrono::DateTime<chrono::Utc>,
841 pub end_time: Option<chrono::DateTime<chrono::Utc>>,
843}
844
845#[derive(Debug, Clone, Serialize, Deserialize)]
847pub struct ConfigurationState {
848 pub valid: bool,
850 pub errors: Vec<String>,
852 pub warnings: Vec<String>,
854}
855
856#[derive(Debug, Clone, Serialize, Deserialize)]
858pub struct ImportHistoryEntry {
859 pub id: String,
861 pub format: String,
863 pub timestamp: chrono::DateTime<chrono::Utc>,
865 pub routes_count: usize,
867 pub variables_count: usize,
869 pub warnings_count: usize,
871 pub success: bool,
873 pub filename: Option<String>,
875 pub environment: Option<String>,
877 pub base_url: Option<String>,
879 pub error_message: Option<String>,
881}
882
883#[derive(Debug, Clone, Serialize, Deserialize)]
885pub struct FixtureInfo {
886 pub id: String,
888 pub name: String,
890 pub path: String,
892 pub size_bytes: u64,
894 pub last_modified: chrono::DateTime<chrono::Utc>,
896 pub content_type: Option<String>,
898}
899
900#[derive(Debug, Clone, Serialize, Deserialize)]
902pub struct FixtureDeleteRequest {
903 pub fixture_id: String,
905}
906
907#[derive(Debug, Clone, Serialize, Deserialize)]
909pub struct FixtureBulkDeleteRequest {
910 pub fixture_ids: Vec<String>,
912}
913
914#[derive(Debug, Clone, Serialize, Deserialize)]
916pub struct FixtureBulkDeleteResult {
917 pub deleted: Vec<String>,
919 pub failed: HashMap<String, String>,
921}
922
923#[derive(Debug, Clone, Serialize, Deserialize)]
925pub struct ImportRoute {
926 pub method: String,
928 pub path: String,
930 pub headers: HashMap<String, String>,
932 pub body: Option<String>,
934 pub response: ImportResponse,
936}
937
938#[derive(Debug, Clone, Serialize, Deserialize)]
940pub struct ImportResponse {
941 pub status: u16,
943 pub headers: HashMap<String, String>,
945 pub body: serde_json::Value,
947}
948
949#[derive(Debug, Clone, Serialize, Deserialize)]
951pub struct ImportResult {
952 pub routes: Vec<ImportRoute>,
954 pub warnings: Vec<String>,
956 pub errors: Vec<String>,
958}
959
960#[derive(Debug, Clone, Serialize, Deserialize)]
962pub struct InsomniaImportResult {
963 pub routes: Vec<ImportRoute>,
965 pub variables: HashMap<String, String>,
967 pub warnings: Vec<String>,
969}
970
971#[derive(Debug, Clone, Serialize, Deserialize)]
973pub struct ServerInfo {
974 pub version: String,
976 pub build_time: String,
978 pub git_sha: String,
980 pub http_server: Option<String>,
982 pub ws_server: Option<String>,
984 pub grpc_server: Option<String>,
986 pub graphql_server: Option<String>,
988 pub api_enabled: bool,
990 pub admin_port: u16,
992}
993
994#[cfg(test)]
995mod tests {
996 use super::*;
997
998 #[test]
999 fn test_api_response_success() {
1000 let data = "test data".to_string();
1001 let response = ApiResponse::success(data.clone());
1002
1003 assert!(response.success);
1004 assert_eq!(response.data, Some(data));
1005 assert!(response.error.is_none());
1006 }
1007
1008 #[test]
1009 fn test_api_response_error() {
1010 let error_msg = "Something went wrong".to_string();
1011 let response: ApiResponse<String> = ApiResponse::error(error_msg.clone());
1012
1013 assert!(!response.success);
1014 assert!(response.data.is_none());
1015 assert_eq!(response.error, Some(error_msg));
1016 }
1017
1018 #[test]
1019 fn test_health_check_healthy() {
1020 let health = HealthCheck::healthy();
1021
1022 assert_eq!(health.status, "healthy");
1023 assert!(health.issues.is_empty());
1024 assert!(health.services.is_empty());
1025 }
1026
1027 #[test]
1028 fn test_health_check_unhealthy() {
1029 let issues = vec!["Database down".to_string(), "Cache error".to_string()];
1030 let health = HealthCheck::unhealthy(issues.clone());
1031
1032 assert_eq!(health.status, "unhealthy");
1033 assert_eq!(health.issues, issues);
1034 }
1035
1036 #[test]
1037 fn test_health_check_with_service() {
1038 let health = HealthCheck::healthy()
1039 .with_service("http".to_string(), "running".to_string())
1040 .with_service("grpc".to_string(), "running".to_string());
1041
1042 assert_eq!(health.services.len(), 2);
1043 assert_eq!(health.services.get("http"), Some(&"running".to_string()));
1044 }
1045
1046 #[test]
1047 fn test_log_filter_default() {
1048 let filter = LogFilter::default();
1049
1050 assert!(filter.method.is_none());
1051 assert!(filter.path_pattern.is_none());
1052 assert_eq!(filter.hours_ago, Some(24));
1053 assert_eq!(filter.limit, Some(100));
1054 }
1055
1056 #[test]
1057 fn test_server_status() {
1058 let status = ServerStatus {
1059 server_type: "HTTP".to_string(),
1060 address: Some("127.0.0.1:3000".to_string()),
1061 running: true,
1062 start_time: Some(chrono::Utc::now()),
1063 uptime_seconds: Some(3600),
1064 active_connections: 10,
1065 total_requests: 1000,
1066 };
1067
1068 assert_eq!(status.server_type, "HTTP");
1069 assert!(status.running);
1070 assert_eq!(status.active_connections, 10);
1071 }
1072
1073 #[test]
1074 fn test_route_info() {
1075 let route = RouteInfo {
1076 method: Some("GET".to_string()),
1077 path: "/api/users".to_string(),
1078 priority: 100,
1079 has_fixtures: true,
1080 latency_ms: Some(50),
1081 request_count: 500,
1082 last_request: None,
1083 error_count: 5,
1084 };
1085
1086 assert_eq!(route.method, Some("GET".to_string()));
1087 assert_eq!(route.path, "/api/users");
1088 assert!(route.has_fixtures);
1089 }
1090
1091 #[test]
1092 fn test_sync_direction_conversion() {
1093 let manual = mockforge_core::workspace::SyncDirection::Manual;
1094 let ui_manual: SyncDirection = manual.into();
1095 assert!(matches!(ui_manual, SyncDirection::Manual));
1096 }
1097
1098 #[test]
1099 fn test_environment_color() {
1100 let color = EnvironmentColor {
1101 hex: "#FF5733".to_string(),
1102 name: Some("Orange".to_string()),
1103 };
1104
1105 assert_eq!(color.hex, "#FF5733");
1106 assert_eq!(color.name, Some("Orange".to_string()));
1107 }
1108}