diff --git a/context/src/lib.rs b/context/src/lib.rs index 09334c052..a26011278 100644 --- a/context/src/lib.rs +++ b/context/src/lib.rs @@ -1,4 +1,5 @@ use std::sync::Arc; +use jupiter::tests::test_storage; /// This is the main application context for the Mono application. /// It holds shared state and configuration for the application. @@ -22,8 +23,10 @@ pub struct AppContext { impl AppContext { /// Creates a new application context with the given configuration. pub async fn new(config: common::config::Config) -> Self { + let config = Arc::new(config); + let storage = jupiter::storage::Storage::new(config.clone()).await; let storage_for_vault = storage.clone(); @@ -33,6 +36,7 @@ impl AppContext { .await .expect("VaultCore::new panicked"); + #[cfg(feature = "p2p")] let client = gemini::p2p::client::P2PClient::new(storage.clone(), vault.clone()); @@ -45,9 +49,42 @@ impl AppContext { #[cfg(feature = "p2p")] client, } + + } pub fn wrapped_context(&self) -> Arc { Arc::new(self.clone()) } + + pub async fn mock(config: common::config::Config) -> Self { + + let config = Arc::new(config); + + // use Existing test method + let storage = test_storage(config.base_dir.clone()).await; + + let storage_for_vault = storage.clone(); + let temp_dir = config.base_dir.clone().join("vault"); + let key_path = temp_dir.join("core_key.json"); + std::fs::create_dir_all(&temp_dir).expect("Mock: Failed to create vault dir"); + + let vault = tokio::task::spawn_blocking(move || { + vault::integration::vault_core::VaultCore::config(storage_for_vault, key_path) + }) + .await + .expect("VaultCore::config panicked"); + + #[cfg(feature = "p2p")] + let client = gemini::p2p::client::P2PClient::new(storage.clone(), vault.clone()); + + Self { + storage, + vault, + config, + #[cfg(feature = "p2p")] + client, + } + } } + diff --git a/monobean/Cargo.toml b/monobean/Cargo.toml index 9d5a4e9f1..e6ed96f50 100644 --- a/monobean/Cargo.toml +++ b/monobean/Cargo.toml @@ -42,6 +42,7 @@ home = "0.5.11" smallvec = "1.14.0" directories = "6.0.0" tracing-appender = "0.2.3" +toml = "0.8.22" [build-dependencies] glib-build-tools = "0.20.0" diff --git a/monobean/resources/gtk/theme_selector.ui b/monobean/resources/gtk/theme_selector.ui index b297f10fb..c1363ca98 100644 --- a/monobean/resources/gtk/theme_selector.ui +++ b/monobean/resources/gtk/theme_selector.ui @@ -17,7 +17,7 @@ light false - win.style-variant + style.style-variant 'system' Use system style monobean-lasso-select-symbolic @@ -30,7 +30,7 @@ false - win.style-variant + style.style-variant 'light' Light style monobean-lasso-select-symbolic @@ -44,7 +44,7 @@ light false - win.style-variant + style.style-variant 'dark' Dark style monobean-lasso-select-symbolic diff --git a/monobean/resources/org.Web3Infrastructure.Monobean.gschema.xml b/monobean/resources/org.Web3Infrastructure.Monobean.gschema.xml index c0db5a472..05d019b6d 100644 --- a/monobean/resources/org.Web3Infrastructure.Monobean.gschema.xml +++ b/monobean/resources/org.Web3Infrastructure.Monobean.gschema.xml @@ -18,7 +18,8 @@ - 'system' + + 'light' Settings theme diff --git a/monobean/src/core/mega_core.rs b/monobean/src/core/mega_core.rs index a43e0f3ad..7d6a1eac7 100644 --- a/monobean/src/core/mega_core.rs +++ b/monobean/src/core/mega_core.rs @@ -232,6 +232,11 @@ impl MegaCore { let config = self.config.read().await.clone(); + + #[cfg(test)] + let inner = MegaContext::mock(config.clone()).await; + + #[cfg(not(test))] let inner = MegaContext::new(config.clone()).await; let http_ctx = inner.clone(); @@ -465,11 +470,14 @@ mod tests { use crate::config::APP_NAME; use crate::config::MEGA_CONFIG_PATH; use async_channel::bounded; - use common::config::DbConfig; use common::config::LogConfig; + use common::config::{AuthConfig, DbConfig, LFSConfig, MonoConfig, PackConfig}; use gtk::gio; use gtk::glib; - // use std::net::{IpAddr, Ipv4Addr}; + + use std::fs; + use std::net::{IpAddr, Ipv4Addr}; + use tempfile::TempDir; #[allow(dead_code)] @@ -488,9 +496,21 @@ mod tests { db_path: temp_base.path().to_path_buf().join("test.db"), ..Default::default() }, - ..Default::default() + monorepo: MonoConfig::default(), + pack: PackConfig::default(), + authentication: AuthConfig::default(), + lfs: LFSConfig::default(), + oauth: None, }; + // make config saved in temp dir + let config_dir = temp_base.path().join("etc"); + fs::create_dir_all(&config_dir).unwrap(); + let config_path = config_dir.join("config.toml"); + let toml_str = toml::to_string(&config).unwrap(); + fs::write(&config_path, toml_str).unwrap(); + let config = Config::new(config_path.to_str().unwrap()).unwrap(); + let core = MegaCore::new(tx, cmd_rx, config); core.init().await; core @@ -515,51 +535,46 @@ mod tests { let _ = Config::load_str(content.as_str()).expect("Failed to parse mega core settings"); } - // #[tokio::test] - // async fn test_launch_http() { - // let temp_base = TempDir::new().unwrap(); - - // // 设置环境变量,让 mega_base() 返回临时目录 - // unsafe { - // std::env::set_var("MEGA_BASE_DIR", temp_base.path()); - // } - - // let core = test_core(&temp_base).await; - - // core.process_command(MegaCommands::MegaStart( - // Some(SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 8080)), - // None, - // P2pOptions::default(), - // )) - // .await; - // assert!(core.http_options.read().await.is_some()); - // assert!(!core.ssh_options.read().await.is_some()); - - // core.process_command(MegaCommands::MegaShutdown).await; - // assert!(core.http_options.read().await.is_none()); - // assert!(core.ssh_options.read().await.is_none()); - // } - - // #[tokio::test] - // async fn test_launch_ssh() { - // let temp_base = TempDir::new().unwrap(); - // unsafe { - // std::env::set_var("MEGA_BASE_DIR", temp_base.path()); - // } - // let core = test_core(&temp_base).await; - // core.process_command(MegaCommands::MegaStart( - // None, - // Some(SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 2222)), - // P2pOptions::default(), - // )) - // .await; - // assert!(core.http_options.read().await.is_none()); - // assert!(core.ssh_options.read().await.is_some()); - - // core.process_command(MegaCommands::MegaShutdown).await; - // assert!(core.http_options.read().await.is_none()); - // assert!(core.ssh_options.read().await.is_none()); - // } + + #[tokio::test] + async fn test_launch_http() { + let temp_base = TempDir::new().unwrap(); + + let core = test_core(&temp_base).await; + + core.process_command(MegaCommands::MegaStart( + Some(SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 8080)), + None, + P2pOptions::default(), + )) + .await; + assert!(core.http_options.read().await.is_some()); + assert!(!core.ssh_options.read().await.is_some()); + + core.process_command(MegaCommands::MegaShutdown).await; + assert!(core.http_options.read().await.is_none()); + assert!(core.ssh_options.read().await.is_none()); + } + + #[tokio::test] + async fn test_launch_ssh() { + let temp_base = TempDir::new().unwrap(); + + let core = test_core(&temp_base).await; + core.process_command(MegaCommands::MegaStart( + None, + Some(SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 2222)), + P2pOptions::default(), + )) + .await; + assert!(core.http_options.read().await.is_none()); + assert!(core.ssh_options.read().await.is_some()); + + core.process_command(MegaCommands::MegaShutdown).await; + assert!(core.http_options.read().await.is_none()); + assert!(core.ssh_options.read().await.is_none()); + } + #[tokio::test] async fn test_run_with_config() {} diff --git a/monobean/src/window.rs b/monobean/src/window.rs index 0fb48cbe4..ada5252fb 100644 --- a/monobean/src/window.rs +++ b/monobean/src/window.rs @@ -8,10 +8,14 @@ use crate::components::{mega_tab::MegaTab, repo_tab::RepoTab}; use crate::config::PREFIX; use crate::CONTEXT; use adw::glib::Priority; -use adw::prelude::{Cast, ObjectExt, SettingsExtManual, ToValue}; +use adw::prelude::{ + ActionMapExt, Cast, ObjectExt, SettingsExt, SettingsExtManual, StaticVariantType, ToValue, + ToVariant, +}; use adw::subclass::prelude::*; use adw::{gio, ColorScheme, StyleManager, Toast}; use gtk::gio::Settings; +use gtk::gio::{SimpleAction, SimpleActionGroup}; use gtk::glib; use gtk::prelude::{GtkWindowExt, WidgetExt}; use gtk::CompositeTemplate; @@ -203,6 +207,30 @@ impl MonobeanWindow { let popover = popover.downcast::().unwrap(); let theme = ThemeSelector::new(); popover.add_child(&theme, "theme"); + + // popoverMenu cont find win.(action) change the action group + let action_group = SimpleActionGroup::new(); + + // style-variant action + let settings = self.settings().clone(); + let action = SimpleAction::new_stateful( + "style-variant", + Some(&String::static_variant_type()), + &settings.string("style-variant").to_variant(), + ); + action.connect_activate(move |action, parameter| { + if let Some(param) = parameter { + let value = param.get::().unwrap(); + action.set_state(&value.to_variant()); + settings + .set_string("style-variant", &value) + .expect("Failed to set style-variant in GSettings"); + } + }); + + action_group.add_action(&action); + + popover.insert_action_group("style", Some(&action_group)); } pub fn add_toast(&self, message: String) { diff --git a/vault/src/integration/vault_core.rs b/vault/src/integration/vault_core.rs index c2f8b27ed..d2a381b18 100644 --- a/vault/src/integration/vault_core.rs +++ b/vault/src/integration/vault_core.rs @@ -1,3 +1,4 @@ + use crate::integration::jupiter_backend::JupiterBackend; use common::errors::MegaError; use jupiter::storage::Storage; @@ -6,6 +7,7 @@ use std::{ sync::{Arc, RwLock}, }; + use rusty_vault::{ core::Core, logical::{Operation, Request, Response}, @@ -17,6 +19,8 @@ use tracing::log; const CORE_KEY_FILE: &str = "core_key.json"; // where the core key is stored, like `root_token` + + #[derive(Debug, Clone, Serialize, Deserialize)] struct CoreKey { secret_shares: Vec>, @@ -53,9 +57,10 @@ impl VaultCore { tracing::info!("{key_path:?}"); std::fs::create_dir_all(&dir).expect("Failed to create vault directory"); Self::config(ctx.clone(), key_path) + } - fn config(ctx: Storage, key_path: PathBuf) -> Self { + pub fn config(ctx: Storage, key_path: PathBuf) -> Self { let backend: Arc = Arc::new(JupiterBackend::new(ctx)); let barrier = barrier_aes_gcm::AESGCMBarrier::new(Arc::clone(&backend)); let seal_config = rusty_vault::core::SealConfig { @@ -70,6 +75,7 @@ impl VaultCore { }; let core = Arc::new(RwLock::new(core)); + let key = { let mut managed_core = core.write().unwrap(); managed_core @@ -77,6 +83,8 @@ impl VaultCore { .expect("Failed to configure vault core"); let core_key = if !key_path.exists() { + + let result = managed_core .init(&seal_config) .expect("Failed to initialize vault"); @@ -84,10 +92,12 @@ impl VaultCore { secret_shares: Vec::from(&result.secret_shares[..]), root_token: result.root_token, }; + println!( "[vault] Creating new core_key.json at: {}", key_path.display() ); + let file = std::fs::File::create(&key_path).unwrap(); serde_json::to_writer_pretty(file, &core_key).unwrap(); core_key @@ -201,7 +211,8 @@ mod tests { "Vault core should be initialized" ); } - + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn test_vault_api() { let temp_dir = tempfile::tempdir().expect("Failed to create temporary directory");