//! DTO contract tests for local model-server IPC. use app_tauri_lib::dto::{ ModelServerConfigDto, ModelServerKindDto, SaveModelServerRequestDto, StopPolicyDto, save_model_server_input, }; use domain::model_server::{ ExecutablePath, LocalModelRef, LocalModelServerConfig, LocalModelServerKind, ModelPath, ModelServerEndpoint, }; use domain::{LocalModelServerId, StopPolicy}; use serde_json::json; use uuid::Uuid; fn sid(n: u128) -> LocalModelServerId { LocalModelServerId::from_uuid(Uuid::from_u128(n)) } fn domain_config(id: LocalModelServerId, model_id: &str) -> LocalModelServerConfig { LocalModelServerConfig::new( id, LocalModelServerKind::LlamaCpp, "Local Qwen", ModelServerEndpoint::new("http://localhost:8080", 8080).unwrap(), LocalModelRef::new( model_id, "Qwen", Some(ModelPath::new("/models/qwen.gguf").unwrap()), "qwen3-coder", ) .unwrap(), Some(ExecutablePath::new("/usr/bin/llama-server").unwrap()), vec!["--ctx-size".to_owned(), "4096".to_owned()], true, StopPolicy::StopOnAppExit, ) .unwrap() } #[test] fn model_server_dto_serialises_flat_camelcase_wire_shape() { let dto = ModelServerConfigDto::from_domain(domain_config(sid(35), "internal-model-id")); let value = serde_json::to_value(dto).unwrap(); assert_eq!(value["id"], sid(35).to_string()); assert_eq!(value["kind"], "llamaCpp"); assert_eq!(value["baseURL"], "http://localhost:8080/v1"); assert_eq!(value["modelPath"], "/models/qwen.gguf"); assert_eq!(value["servedModelName"], "qwen3-coder"); assert_eq!(value["binaryPath"], "/usr/bin/llama-server"); assert_eq!(value["stopPolicy"], "stopOnAppExit"); assert!(value.get("model").is_none(), "domain model must not leak"); assert!(value.get("endpoint").is_none(), "domain endpoint must not leak"); } #[test] fn model_server_dto_deserialises_flat_wire_shape_and_generates_model_id() { let raw = json!({ "id": sid(36).to_string(), "kind": "llamaCpp", "name": "Local Qwen", "baseURL": "http://localhost:8081", "port": 8081, "modelPath": "/models/qwen.gguf", "servedModelName": "qwen3-coder", "binaryPath": "/usr/bin/llama-server", "args": ["--ctx-size", "4096"], "autoStart": true, "stopPolicy": "stopOnAppExit" }); let request = SaveModelServerRequestDto { config: serde_json::from_value(raw).unwrap(), }; let input = save_model_server_input(request, None).unwrap(); assert_eq!(input.config.id, sid(36)); assert_eq!(input.config.kind, LocalModelServerKind::LlamaCpp); assert_eq!(input.config.endpoint.base_url, "http://localhost:8081/v1"); assert_eq!( input.config.model.path.unwrap().as_str(), "/models/qwen.gguf" ); assert_eq!(input.config.model.served_name, "qwen3-coder"); assert_eq!(input.config.model.label, "qwen3-coder"); assert!(!input.config.model.id.is_empty()); } #[test] fn model_server_dto_preserves_existing_internal_model_id_on_upsert() { let existing = domain_config(sid(37), "stable-internal-id"); let dto = ModelServerConfigDto { id: sid(37).to_string(), kind: ModelServerKindDto::LlamaCpp, name: "Updated Qwen".to_owned(), base_url: "http://localhost:8082/v1".to_owned(), port: 8082, model_path: Some("/models/qwen-updated.gguf".to_owned()), served_model_name: "qwen3-coder-updated".to_owned(), binary_path: Some("/usr/bin/llama-server".to_owned()), args: Vec::new(), auto_start: true, stop_policy: StopPolicyDto::StopOnAppExit, }; let config = dto.into_domain(Some(&existing)).unwrap(); assert_eq!(config.model.id, "stable-internal-id"); assert_eq!(config.model.served_name, "qwen3-coder-updated"); }