Speed up collab test a bit by doing less repeated work in multi iteration tests

Lukas Wirth created

Change summary

Cargo.toml                                     |  1 
crates/collab/tests/integration/test_server.rs |  5 -
crates/settings/src/keymap_file.rs             | 26 ++++++
crates/settings/src/settings_file.rs           | 76 ++++++++++---------
crates/settings/src/settings_store.rs          | 12 ++
5 files changed, 77 insertions(+), 43 deletions(-)

Detailed changes

Cargo.toml 🔗

@@ -906,6 +906,7 @@ wasmtime = { opt-level = 3 }
 cranelift-codegen = { opt-level = 3 }
 wasmtime-environ = { opt-level = 3 }
 wasmtime-internal-cranelift = { opt-level = 3 }
+serde_json = { opt-level = 3 }
 # Build single-source-file crates with cg=1 as it helps make `cargo build` of a whole workspace a bit faster
 activity_indicator = { codegen-units = 1 }
 assets = { codegen-units = 1 }

crates/collab/tests/integration/test_server.rs 🔗

@@ -173,7 +173,6 @@ impl TestServer {
             }
             let settings = SettingsStore::test(cx);
             cx.set_global(settings);
-            theme_settings::init(theme::LoadThemes::JustBase, cx);
             release_channel::init(semver::Version::new(0, 0, 0), cx);
         });
 
@@ -352,9 +351,7 @@ impl TestServer {
             collab_ui::init(&app_state, cx);
             file_finder::init(cx);
             menu::init();
-            cx.bind_keys(
-                settings::KeymapFile::load_asset_allow_partial_failure(os_keymap, cx).unwrap(),
-            );
+            cx.bind_keys(settings::KeymapFile::load_asset_cached(os_keymap, cx).unwrap());
             language_model::LanguageModelRegistry::test(cx);
         });
 

crates/settings/src/keymap_file.rs 🔗

@@ -220,6 +220,27 @@ impl KeymapFile {
         }
     }
 
+    #[cfg(any(test, feature = "test-support"))]
+    pub fn load_asset_cached(asset_path: &str, cx: &App) -> anyhow::Result<Vec<KeyBinding>> {
+        static CACHED: std::sync::OnceLock<KeymapFile> = std::sync::OnceLock::new();
+        let keymap = CACHED
+            .get_or_init(|| Self::parse(asset_str::<SettingsAssets>(asset_path).as_ref()).unwrap());
+        match keymap.load_keymap(cx) {
+            KeymapFileLoadResult::SomeFailedToLoad {
+                key_bindings,
+                error_message,
+                ..
+            } if key_bindings.is_empty() => {
+                anyhow::bail!("Error loading built-in keymap \"{asset_path}\": {error_message}")
+            }
+            KeymapFileLoadResult::Success { key_bindings, .. }
+            | KeymapFileLoadResult::SomeFailedToLoad { key_bindings, .. } => Ok(key_bindings),
+            KeymapFileLoadResult::JsonParseFailure { error } => {
+                anyhow::bail!("JSON parse error in built-in keymap \"{asset_path}\": {error}")
+            }
+        }
+    }
+
     #[cfg(feature = "test-support")]
     pub fn load_panic_on_failure(content: &str, cx: &App) -> Vec<KeyBinding> {
         match Self::load(content, cx) {
@@ -240,7 +261,10 @@ impl KeymapFile {
                 return KeymapFileLoadResult::JsonParseFailure { error };
             }
         };
+        keymap_file.load_keymap(cx)
+    }
 
+    pub fn load_keymap(&self, cx: &App) -> KeymapFileLoadResult {
         // Accumulate errors in order to support partial load of user keymap in the presence of
         // errors in context and binding parsing.
         let mut errors = Vec::new();
@@ -252,7 +276,7 @@ impl KeymapFile {
             unbind,
             bindings,
             unrecognized_fields,
-        } in keymap_file.0.iter()
+        } in self.0.iter()
         {
             let context_predicate: Option<Rc<KeyBindingContextPredicate>> = if context.is_empty() {
                 None

crates/settings/src/settings_file.rs 🔗

@@ -89,42 +89,46 @@ pub fn visual_test_settings() -> String {
 }
 
 #[cfg(any(test, feature = "test-support"))]
-pub fn test_settings() -> String {
-    let mut value =
-        crate::parse_json_with_comments::<serde_json::Value>(crate::default_settings().as_ref())
-            .unwrap();
-    #[cfg(not(target_os = "windows"))]
-    util::merge_non_null_json_value_into(
-        serde_json::json!({
-            "ui_font_family": "Courier",
-            "ui_font_features": {},
-            "ui_font_size": 14,
-            "ui_font_fallback": [],
-            "buffer_font_family": "Courier",
-            "buffer_font_features": {},
-            "buffer_font_size": 14,
-            "buffer_font_fallbacks": [],
-            "theme": EMPTY_THEME_NAME,
-        }),
-        &mut value,
-    );
-    #[cfg(target_os = "windows")]
-    util::merge_non_null_json_value_into(
-        serde_json::json!({
-            "ui_font_family": "Courier New",
-            "ui_font_features": {},
-            "ui_font_size": 14,
-            "ui_font_fallback": [],
-            "buffer_font_family": "Courier New",
-            "buffer_font_features": {},
-            "buffer_font_size": 14,
-            "buffer_font_fallbacks": [],
-            "theme": EMPTY_THEME_NAME,
-        }),
-        &mut value,
-    );
-    value.as_object_mut().unwrap().remove("languages");
-    serde_json::to_string(&value).unwrap()
+pub fn test_settings() -> &'static str {
+    static CACHED: std::sync::LazyLock<String> = std::sync::LazyLock::new(|| {
+        let mut value = crate::parse_json_with_comments::<serde_json::Value>(
+            crate::default_settings().as_ref(),
+        )
+        .unwrap();
+        #[cfg(not(target_os = "windows"))]
+        util::merge_non_null_json_value_into(
+            serde_json::json!({
+                "ui_font_family": "Courier",
+                "ui_font_features": {},
+                "ui_font_size": 14,
+                "ui_font_fallback": [],
+                "buffer_font_family": "Courier",
+                "buffer_font_features": {},
+                "buffer_font_size": 14,
+                "buffer_font_fallbacks": [],
+                "theme": EMPTY_THEME_NAME,
+            }),
+            &mut value,
+        );
+        #[cfg(target_os = "windows")]
+        util::merge_non_null_json_value_into(
+            serde_json::json!({
+                "ui_font_family": "Courier New",
+                "ui_font_features": {},
+                "ui_font_size": 14,
+                "ui_font_fallback": [],
+                "buffer_font_family": "Courier New",
+                "buffer_font_features": {},
+                "buffer_font_size": 14,
+                "buffer_font_fallbacks": [],
+                "theme": EMPTY_THEME_NAME,
+            }),
+            &mut value,
+        );
+        value.as_object_mut().unwrap().remove("languages");
+        serde_json::to_string(&value).unwrap()
+    });
+    &CACHED
 }
 
 pub fn watch_config_file(

crates/settings/src/settings_store.rs 🔗

@@ -284,9 +284,13 @@ impl SettingsStore {
     }
 
     pub fn new_with_semantic_tokens(cx: &mut App, default_settings: &str) -> Self {
-        let (setting_file_updates_tx, mut setting_file_updates_rx) = mpsc::unbounded();
         let default_settings: SettingsContent =
             SettingsContent::parse_json_with_comments(default_settings).unwrap();
+        Self::from_settings_content(cx, default_settings)
+    }
+
+    fn from_settings_content(cx: &mut App, default_settings: SettingsContent) -> Self {
+        let (setting_file_updates_tx, mut setting_file_updates_rx) = mpsc::unbounded();
         if !cx.has_global::<DefaultSemanticTokenRules>() {
             cx.set_global::<DefaultSemanticTokenRules>(
                 crate::parse_json_with_comments::<SemanticTokenRules>(
@@ -447,7 +451,11 @@ impl SettingsStore {
 
     #[cfg(any(test, feature = "test-support"))]
     pub fn test(cx: &mut App) -> Self {
-        Self::new(cx, &crate::test_settings())
+        static CACHED_SETTINGS_CONTENT: std::sync::LazyLock<SettingsContent> =
+            std::sync::LazyLock::new(|| {
+                SettingsContent::parse_json_with_comments(crate::test_settings()).unwrap()
+            });
+        Self::from_settings_content(cx, CACHED_SETTINGS_CONTENT.clone())
     }
 
     /// Updates the value of a setting in the user's global configuration.