chore: add tests
This commit is contained in:
parent
4f7af0a10d
commit
726bf4d333
@ -24,6 +24,7 @@ log = "0.4"
|
|||||||
tauri = { version = "2.1.0", features = [
|
tauri = { version = "2.1.0", features = [
|
||||||
"protocol-asset",
|
"protocol-asset",
|
||||||
'macos-private-api',
|
'macos-private-api',
|
||||||
|
"test"
|
||||||
] }
|
] }
|
||||||
tauri-plugin-log = "2.0.0-rc"
|
tauri-plugin-log = "2.0.0-rc"
|
||||||
tauri-plugin-shell = "2.2.0"
|
tauri-plugin-shell = "2.2.0"
|
||||||
|
|||||||
@ -1,11 +1,8 @@
|
|||||||
use rmcp::{
|
use rmcp::model::{CallToolRequestParam, CallToolResult, Tool};
|
||||||
model::{CallToolRequestParam, CallToolResult, Tool},
|
|
||||||
object,
|
|
||||||
};
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::{Map, Value};
|
use serde_json::{Map, Value};
|
||||||
use std::{fs, path::PathBuf};
|
use std::{fs, path::PathBuf};
|
||||||
use tauri::{AppHandle, Manager, State};
|
use tauri::{AppHandle, Manager, Runtime, State};
|
||||||
|
|
||||||
use super::{server, setup, state::AppState};
|
use super::{server, setup, state::AppState};
|
||||||
|
|
||||||
@ -26,7 +23,7 @@ impl AppConfiguration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub fn get_app_configurations(app_handle: tauri::AppHandle) -> AppConfiguration {
|
pub fn get_app_configurations<R: Runtime>(app_handle: tauri::AppHandle<R>) -> AppConfiguration {
|
||||||
let mut app_default_configuration = AppConfiguration::default();
|
let mut app_default_configuration = AppConfiguration::default();
|
||||||
|
|
||||||
if std::env::var("CI").unwrap_or_default() == "e2e" {
|
if std::env::var("CI").unwrap_or_default() == "e2e" {
|
||||||
@ -95,7 +92,7 @@ pub fn update_app_configuration(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub fn get_jan_data_folder_path(app_handle: tauri::AppHandle) -> PathBuf {
|
pub fn get_jan_data_folder_path<R: Runtime>(app_handle: tauri::AppHandle<R>) -> PathBuf {
|
||||||
let app_configurations = get_app_configurations(app_handle);
|
let app_configurations = get_app_configurations(app_handle);
|
||||||
PathBuf::from(app_configurations.data_folder)
|
PathBuf::from(app_configurations.data_folder)
|
||||||
}
|
}
|
||||||
@ -137,7 +134,7 @@ pub fn read_theme(app_handle: tauri::AppHandle, theme_name: String) -> Result<St
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub fn get_configuration_file_path(app_handle: tauri::AppHandle) -> PathBuf {
|
pub fn get_configuration_file_path<R: Runtime>(app_handle: tauri::AppHandle<R>) -> PathBuf {
|
||||||
let app_path = app_handle.path().app_data_dir().unwrap_or_else(|err| {
|
let app_path = app_handle.path().app_data_dir().unwrap_or_else(|err| {
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"Failed to get app data directory: {}. Using home directory instead.",
|
"Failed to get app data directory: {}. Using home directory instead.",
|
||||||
@ -158,7 +155,7 @@ pub fn get_configuration_file_path(app_handle: tauri::AppHandle) -> PathBuf {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub fn default_data_folder_path(app_handle: tauri::AppHandle) -> String {
|
pub fn default_data_folder_path<R: Runtime>(app_handle: tauri::AppHandle<R>) -> String {
|
||||||
return app_handle
|
return app_handle
|
||||||
.path()
|
.path()
|
||||||
.app_data_dir()
|
.app_data_dir()
|
||||||
|
|||||||
@ -1,9 +1,10 @@
|
|||||||
use crate::core::cmd::get_jan_data_folder_path;
|
use crate::core::cmd::get_jan_data_folder_path;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use tauri::Runtime;
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub fn rm(app_handle: tauri::AppHandle, args: Vec<String>) -> Result<(), String> {
|
pub fn rm<R: Runtime>(app_handle: tauri::AppHandle<R>, args: Vec<String>) -> Result<(), String> {
|
||||||
if args.is_empty() || args[0].is_empty() {
|
if args.is_empty() || args[0].is_empty() {
|
||||||
return Err("rm error: Invalid argument".to_string());
|
return Err("rm error: Invalid argument".to_string());
|
||||||
}
|
}
|
||||||
@ -12,7 +13,7 @@ pub fn rm(app_handle: tauri::AppHandle, args: Vec<String>) -> Result<(), String>
|
|||||||
fs::remove_dir_all(&path).map_err(|e| e.to_string())
|
fs::remove_dir_all(&path).map_err(|e| e.to_string())
|
||||||
}
|
}
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub fn mkdir(app_handle: tauri::AppHandle, args: Vec<String>) -> Result<(), String> {
|
pub fn mkdir<R: Runtime>(app_handle: tauri::AppHandle<R>, args: Vec<String>) -> Result<(), String> {
|
||||||
if args.is_empty() || args[0].is_empty() {
|
if args.is_empty() || args[0].is_empty() {
|
||||||
return Err("mkdir error: Invalid argument".to_string());
|
return Err("mkdir error: Invalid argument".to_string());
|
||||||
}
|
}
|
||||||
@ -22,7 +23,10 @@ pub fn mkdir(app_handle: tauri::AppHandle, args: Vec<String>) -> Result<(), Stri
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub fn join_path(app_handle: tauri::AppHandle, args: Vec<String>) -> Result<String, String> {
|
pub fn join_path<R: Runtime>(
|
||||||
|
app_handle: tauri::AppHandle<R>,
|
||||||
|
args: Vec<String>,
|
||||||
|
) -> Result<String, String> {
|
||||||
if args.is_empty() {
|
if args.is_empty() {
|
||||||
return Err("join_path error: Invalid argument".to_string());
|
return Err("join_path error: Invalid argument".to_string());
|
||||||
}
|
}
|
||||||
@ -32,7 +36,10 @@ pub fn join_path(app_handle: tauri::AppHandle, args: Vec<String>) -> Result<Stri
|
|||||||
Ok(joined_path.to_string_lossy().to_string())
|
Ok(joined_path.to_string_lossy().to_string())
|
||||||
}
|
}
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub fn exists_sync(app_handle: tauri::AppHandle, args: Vec<String>) -> Result<bool, String> {
|
pub fn exists_sync<R: Runtime>(
|
||||||
|
app_handle: tauri::AppHandle<R>,
|
||||||
|
args: Vec<String>,
|
||||||
|
) -> Result<bool, String> {
|
||||||
if args.is_empty() || args[0].is_empty() {
|
if args.is_empty() || args[0].is_empty() {
|
||||||
return Err("exist_sync error: Invalid argument".to_string());
|
return Err("exist_sync error: Invalid argument".to_string());
|
||||||
}
|
}
|
||||||
@ -42,7 +49,10 @@ pub fn exists_sync(app_handle: tauri::AppHandle, args: Vec<String>) -> Result<bo
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub fn read_file_sync(app_handle: tauri::AppHandle, args: Vec<String>) -> Result<String, String> {
|
pub fn read_file_sync<R: Runtime>(
|
||||||
|
app_handle: tauri::AppHandle<R>,
|
||||||
|
args: Vec<String>,
|
||||||
|
) -> Result<String, String> {
|
||||||
if args.is_empty() || args[0].is_empty() {
|
if args.is_empty() || args[0].is_empty() {
|
||||||
return Err("read_file_sync error: Invalid argument".to_string());
|
return Err("read_file_sync error: Invalid argument".to_string());
|
||||||
}
|
}
|
||||||
@ -52,8 +62,8 @@ pub fn read_file_sync(app_handle: tauri::AppHandle, args: Vec<String>) -> Result
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub fn readdir_sync(
|
pub fn readdir_sync<R: Runtime>(
|
||||||
app_handle: tauri::AppHandle,
|
app_handle: tauri::AppHandle<R>,
|
||||||
args: Vec<String>,
|
args: Vec<String>,
|
||||||
) -> Result<Vec<String>, String> {
|
) -> Result<Vec<String>, String> {
|
||||||
if args.is_empty() || args[0].is_empty() {
|
if args.is_empty() || args[0].is_empty() {
|
||||||
@ -74,7 +84,7 @@ fn normalize_file_path(path: &str) -> String {
|
|||||||
path.replace("file:/", "").replace("file:\\", "")
|
path.replace("file:/", "").replace("file:\\", "")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_path(app_handle: tauri::AppHandle, path: &str) -> PathBuf {
|
fn resolve_path<R: Runtime>(app_handle: tauri::AppHandle<R>, path: &str) -> PathBuf {
|
||||||
let path = if path.starts_with("file:/") || path.starts_with("file:\\") {
|
let path = if path.starts_with("file:/") || path.starts_with("file:\\") {
|
||||||
let normalized = normalize_file_path(path);
|
let normalized = normalize_file_path(path);
|
||||||
let relative_normalized = normalized.strip_prefix("/").unwrap_or(&normalized);
|
let relative_normalized = normalized.strip_prefix("/").unwrap_or(&normalized);
|
||||||
@ -89,3 +99,93 @@ fn resolve_path(app_handle: tauri::AppHandle, path: &str) -> PathBuf {
|
|||||||
path.canonicalize().unwrap_or(path)
|
path.canonicalize().unwrap_or(path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use std::fs::{self, File};
|
||||||
|
use std::io::Write;
|
||||||
|
use tauri::test::mock_app;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_rm() {
|
||||||
|
let app = mock_app();
|
||||||
|
let path = "test_rm_dir";
|
||||||
|
fs::create_dir_all(get_jan_data_folder_path(app.handle().clone()).join(path)).unwrap();
|
||||||
|
let args = vec![format!("file://{}", path).to_string()];
|
||||||
|
let result = rm(app.handle().clone(), args);
|
||||||
|
assert!(result.is_ok());
|
||||||
|
assert!(!get_jan_data_folder_path(app.handle().clone())
|
||||||
|
.join(path)
|
||||||
|
.exists());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_mkdir() {
|
||||||
|
let app = mock_app();
|
||||||
|
let path = "test_mkdir_dir";
|
||||||
|
let args = vec![format!("file://{}", path).to_string()];
|
||||||
|
let result = mkdir(app.handle().clone(), args);
|
||||||
|
assert!(result.is_ok());
|
||||||
|
assert!(get_jan_data_folder_path(app.handle().clone())
|
||||||
|
.join(path)
|
||||||
|
.exists());
|
||||||
|
fs::remove_dir_all(get_jan_data_folder_path(app.handle().clone()).join(path)).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_join_path() {
|
||||||
|
let app = mock_app();
|
||||||
|
let path = "file://test_dir";
|
||||||
|
let args = vec![path.to_string(), "test_file".to_string()];
|
||||||
|
let result = join_path(app.handle().clone(), args).unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
result,
|
||||||
|
get_jan_data_folder_path(app.handle().clone())
|
||||||
|
.join("test_dir/test_file")
|
||||||
|
.to_string_lossy()
|
||||||
|
.to_string()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_exists_sync() {
|
||||||
|
let app = mock_app();
|
||||||
|
let path = "file://test_exists_sync_file";
|
||||||
|
let file_path = get_jan_data_folder_path(app.handle().clone()).join(path);
|
||||||
|
File::create(&file_path).unwrap();
|
||||||
|
let args = vec![path.to_string()];
|
||||||
|
let result = exists_sync(app.handle().clone(), args).unwrap();
|
||||||
|
assert!(result);
|
||||||
|
fs::remove_file(file_path).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_read_file_sync() {
|
||||||
|
let app = mock_app();
|
||||||
|
let path = "file://test_read_file_sync_file";
|
||||||
|
let file_path = get_jan_data_folder_path(app.handle().clone()).join(path);
|
||||||
|
let mut file = File::create(&file_path).unwrap();
|
||||||
|
file.write_all(b"test content").unwrap();
|
||||||
|
let args = vec![path.to_string()];
|
||||||
|
let result = read_file_sync(app.handle().clone(), args).unwrap();
|
||||||
|
assert_eq!(result, "test content".to_string());
|
||||||
|
fs::remove_file(file_path).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_readdir_sync() {
|
||||||
|
let app = mock_app();
|
||||||
|
let path = "file://test_readdir_sync_dir";
|
||||||
|
let dir_path = get_jan_data_folder_path(app.handle().clone()).join(path);
|
||||||
|
fs::create_dir_all(&dir_path).unwrap();
|
||||||
|
File::create(dir_path.join("file1.txt")).unwrap();
|
||||||
|
File::create(dir_path.join("file2.txt")).unwrap();
|
||||||
|
|
||||||
|
let args = vec![path.to_string()];
|
||||||
|
let result = readdir_sync(app.handle().clone(), args).unwrap();
|
||||||
|
assert_eq!(result.len(), 2);
|
||||||
|
|
||||||
|
fs::remove_dir_all(dir_path).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,11 +1,6 @@
|
|||||||
use std::{collections::HashMap, sync::Arc};
|
use std::{collections::HashMap, sync::Arc};
|
||||||
|
|
||||||
use rmcp::{
|
use rmcp::{service::RunningService, transport::TokioChildProcess, RoleClient, ServiceExt};
|
||||||
model::{CallToolRequestParam, GetPromptRequestParam, ReadResourceRequestParam},
|
|
||||||
service::RunningService,
|
|
||||||
transport::TokioChildProcess,
|
|
||||||
RoleClient, ServiceExt,
|
|
||||||
};
|
|
||||||
use tokio::{process::Command, sync::Mutex};
|
use tokio::{process::Command, sync::Mutex};
|
||||||
|
|
||||||
pub async fn run_mcp_commands(
|
pub async fn run_mcp_commands(
|
||||||
@ -71,3 +66,34 @@ pub async fn run_mcp_commands(
|
|||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::Write;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_run_mcp_commands() {
|
||||||
|
// Create a mock mcp_config.json file
|
||||||
|
let config_path = "mcp_config.json";
|
||||||
|
let mut file = File::create(config_path).expect("Failed to create config file");
|
||||||
|
file.write_all(b"{\"mcpServers\":{}}")
|
||||||
|
.expect("Failed to write to config file");
|
||||||
|
|
||||||
|
// Call the run_mcp_commands function
|
||||||
|
let app_path = ".".to_string();
|
||||||
|
let servers_state: Arc<Mutex<HashMap<String, RunningService<RoleClient, ()>>>> =
|
||||||
|
Arc::new(Mutex::new(HashMap::new()));
|
||||||
|
let result = run_mcp_commands(app_path, servers_state).await;
|
||||||
|
|
||||||
|
// Assert that the function returns Ok(())
|
||||||
|
assert!(result.is_ok());
|
||||||
|
|
||||||
|
// Clean up the mock config file
|
||||||
|
std::fs::remove_file(config_path).expect("Failed to remove config file");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
use std::{collections::HashMap, sync::{Arc}};
|
use std::{collections::HashMap, sync::Arc};
|
||||||
|
|
||||||
use rand::{distributions::Alphanumeric, Rng};
|
use rand::{distributions::Alphanumeric, Rng};
|
||||||
use rmcp::{service::RunningService, RoleClient};
|
use rmcp::{service::RunningService, RoleClient};
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user