Move ExtensionStore tests back to extension_host (#20682)

This PR moves the tests for the `ExtensionStore` back into the
`extension_host` crate.

We now have a separate `TestExtensionRegistrationHooks` to use in the
test that implements the minimal required functionality needed for the
tests. This means that we can depend on the `theme` crate only in the
tests.

Release Notes:

- N/A
This commit is contained in:
Marshall Bowers 2024-11-14 12:09:41 -05:00 committed by GitHub
parent 5d17cfab31
commit d177a1d4e5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 106 additions and 88 deletions

11
Cargo.lock generated
View file

@ -4189,6 +4189,7 @@ dependencies = [
"serde_json_lenient",
"settings",
"task",
"theme",
"toml 0.8.19",
"url",
"util",
@ -4203,36 +4204,26 @@ version = "0.1.0"
dependencies = [
"anyhow",
"assistant_slash_command",
"async-compression",
"async-tar",
"client",
"collections",
"context_servers",
"ctor",
"db",
"editor",
"env_logger 0.11.5",
"extension",
"extension_host",
"fs",
"futures 0.3.30",
"fuzzy",
"gpui",
"http_client",
"indexed_docs",
"language",
"log",
"lsp",
"node_runtime",
"num-format",
"parking_lot",
"picker",
"project",
"release_channel",
"reqwest_client",
"semantic_version",
"serde",
"serde_json",
"settings",
"smallvec",
"snippet_provider",

View file

@ -58,3 +58,4 @@ language = { workspace = true, features = ["test-support"] }
parking_lot.workspace = true
project = { workspace = true, features = ["test-support"] }
reqwest_client.workspace = true
theme = { workspace = true, features = ["test-support"] }

View file

@ -2,6 +2,9 @@ pub mod extension_lsp_adapter;
pub mod extension_settings;
pub mod wasm_host;
#[cfg(test)]
mod extension_store_test;
use crate::{extension_lsp_adapter::ExtensionLspAdapter, wasm_host::wit};
use anyhow::{anyhow, bail, Context as _, Result};
use async_compression::futures::bufread::GzipDecoder;

View file

@ -1,20 +1,17 @@
use assistant_slash_command::SlashCommandRegistry;
use crate::extension_lsp_adapter::ExtensionLspAdapter;
use crate::{
Event, ExtensionIndex, ExtensionIndexEntry, ExtensionIndexLanguageEntry,
ExtensionIndexThemeEntry, ExtensionManifest, ExtensionSettings, ExtensionStore,
GrammarManifestEntry, SchemaVersion, RELOAD_DEBOUNCE_DURATION,
};
use anyhow::Result;
use async_compression::futures::bufread::GzipEncoder;
use collections::BTreeMap;
use context_servers::ContextServerFactoryRegistry;
use extension_host::ExtensionSettings;
use extension_host::SchemaVersion;
use extension_host::{
Event, ExtensionIndex, ExtensionIndexEntry, ExtensionIndexLanguageEntry,
ExtensionIndexThemeEntry, ExtensionManifest, ExtensionStore, GrammarManifestEntry,
RELOAD_DEBOUNCE_DURATION,
};
use fs::{FakeFs, Fs, RealFs};
use futures::{io::BufReader, AsyncReadExt, StreamExt};
use gpui::{Context, SemanticVersion, TestAppContext};
use gpui::{BackgroundExecutor, Context, SemanticVersion, SharedString, Task, TestAppContext};
use http_client::{FakeHttpClient, Response};
use indexed_docs::IndexedDocsRegistry;
use language::{LanguageMatcher, LanguageRegistry, LanguageServerBinaryStatus};
use language::{LanguageMatcher, LanguageRegistry, LanguageServerBinaryStatus, LoadedLanguage};
use lsp::LanguageServerName;
use node_runtime::NodeRuntime;
use parking_lot::Mutex;
@ -23,7 +20,6 @@ use release_channel::AppVersion;
use reqwest_client::ReqwestClient;
use serde_json::json;
use settings::{Settings as _, SettingsStore};
use snippet_provider::SnippetRegistry;
use std::{
ffi::OsString,
path::{Path, PathBuf},
@ -32,6 +28,84 @@ use std::{
use theme::ThemeRegistry;
use util::test::temp_tree;
use crate::ExtensionRegistrationHooks;
struct TestExtensionRegistrationHooks {
executor: BackgroundExecutor,
language_registry: Arc<LanguageRegistry>,
theme_registry: Arc<ThemeRegistry>,
}
impl ExtensionRegistrationHooks for TestExtensionRegistrationHooks {
fn list_theme_names(&self, path: PathBuf, fs: Arc<dyn Fs>) -> Task<Result<Vec<String>>> {
self.executor.spawn(async move {
let themes = theme::read_user_theme(&path, fs).await?;
Ok(themes.themes.into_iter().map(|theme| theme.name).collect())
})
}
fn load_user_theme(&self, theme_path: PathBuf, fs: Arc<dyn fs::Fs>) -> Task<Result<()>> {
let theme_registry = self.theme_registry.clone();
self.executor
.spawn(async move { theme_registry.load_user_theme(&theme_path, fs).await })
}
fn remove_user_themes(&self, themes: Vec<SharedString>) {
self.theme_registry.remove_user_themes(&themes);
}
fn register_language(
&self,
language: language::LanguageName,
grammar: Option<Arc<str>>,
matcher: language::LanguageMatcher,
load: Arc<dyn Fn() -> Result<LoadedLanguage> + 'static + Send + Sync>,
) {
self.language_registry
.register_language(language, grammar, matcher, load)
}
fn remove_languages(
&self,
languages_to_remove: &[language::LanguageName],
grammars_to_remove: &[Arc<str>],
) {
self.language_registry
.remove_languages(&languages_to_remove, &grammars_to_remove);
}
fn register_wasm_grammars(&self, grammars: Vec<(Arc<str>, PathBuf)>) {
self.language_registry.register_wasm_grammars(grammars)
}
fn register_lsp_adapter(
&self,
language_name: language::LanguageName,
adapter: ExtensionLspAdapter,
) {
self.language_registry
.register_lsp_adapter(language_name, Arc::new(adapter));
}
fn update_lsp_status(
&self,
server_name: lsp::LanguageServerName,
status: LanguageServerBinaryStatus,
) {
self.language_registry
.update_lsp_status(server_name, status);
}
fn remove_lsp_adapter(
&self,
language_name: &language::LanguageName,
server_name: &lsp::LanguageServerName,
) {
self.language_registry
.remove_lsp_adapter(language_name, server_name);
}
}
#[cfg(test)]
#[ctor::ctor]
fn init_logger() {
@ -265,27 +339,18 @@ async fn test_extension_store(cx: &mut TestAppContext) {
let language_registry = Arc::new(LanguageRegistry::test(cx.executor()));
let theme_registry = Arc::new(ThemeRegistry::new(Box::new(())));
let slash_command_registry = SlashCommandRegistry::new();
let indexed_docs_registry = Arc::new(IndexedDocsRegistry::new(cx.executor()));
let snippet_registry = Arc::new(SnippetRegistry::new());
let context_server_factory_registry = cx.new_model(|_| ContextServerFactoryRegistry::new());
let registration_hooks = Arc::new(TestExtensionRegistrationHooks {
executor: cx.executor(),
language_registry: language_registry.clone(),
theme_registry: theme_registry.clone(),
});
let node_runtime = NodeRuntime::unavailable();
let store = cx.new_model(|cx| {
let extension_registration_hooks = crate::ConcreteExtensionRegistrationHooks::new(
theme_registry.clone(),
slash_command_registry.clone(),
indexed_docs_registry.clone(),
snippet_registry.clone(),
language_registry.clone(),
context_server_factory_registry.clone(),
cx,
);
ExtensionStore::new(
PathBuf::from("/the-extension-dir"),
None,
extension_registration_hooks,
registration_hooks.clone(),
fs.clone(),
http_client.clone(),
http_client.clone(),
@ -407,20 +472,10 @@ async fn test_extension_store(cx: &mut TestAppContext) {
// Create new extension store, as if Zed were restarting.
drop(store);
let store = cx.new_model(|cx| {
let extension_api = crate::ConcreteExtensionRegistrationHooks::new(
theme_registry.clone(),
slash_command_registry,
indexed_docs_registry,
snippet_registry,
language_registry.clone(),
context_server_factory_registry.clone(),
cx,
);
ExtensionStore::new(
PathBuf::from("/the-extension-dir"),
None,
extension_api,
registration_hooks,
fs.clone(),
http_client.clone(),
http_client.clone(),
@ -505,10 +560,11 @@ async fn test_extension_store_with_test_extension(cx: &mut TestAppContext) {
let language_registry = project.read_with(cx, |project, _cx| project.languages().clone());
let theme_registry = Arc::new(ThemeRegistry::new(Box::new(())));
let slash_command_registry = SlashCommandRegistry::new();
let indexed_docs_registry = Arc::new(IndexedDocsRegistry::new(cx.executor()));
let snippet_registry = Arc::new(SnippetRegistry::new());
let context_server_factory_registry = cx.new_model(|_| ContextServerFactoryRegistry::new());
let registration_hooks = Arc::new(TestExtensionRegistrationHooks {
executor: cx.executor(),
language_registry: language_registry.clone(),
theme_registry: theme_registry.clone(),
});
let node_runtime = NodeRuntime::unavailable();
let mut status_updates = language_registry.language_server_binary_statuses();
@ -599,19 +655,10 @@ async fn test_extension_store_with_test_extension(cx: &mut TestAppContext) {
Arc::new(ReqwestClient::user_agent(&user_agent).expect("Could not create HTTP client"));
let extension_store = cx.new_model(|cx| {
let extension_api = crate::ConcreteExtensionRegistrationHooks::new(
theme_registry.clone(),
slash_command_registry,
indexed_docs_registry,
snippet_registry,
language_registry.clone(),
context_server_factory_registry.clone(),
cx,
);
ExtensionStore::new(
extensions_dir.clone(),
Some(cache_dir),
extension_api,
registration_hooks,
fs.clone(),
extension_client.clone(),
builder_client,
@ -626,7 +673,7 @@ async fn test_extension_store_with_test_extension(cx: &mut TestAppContext) {
let executor = cx.executor();
let _task = cx.executor().spawn(async move {
while let Some(event) = events.next().await {
if let extension_host::Event::StartedReloading = event {
if let Event::StartedReloading = event {
executor.advance_clock(RELOAD_DEBOUNCE_DURATION);
}
}

View file

@ -11,9 +11,6 @@ workspace = true
[lib]
path = "src/extensions_ui.rs"
[features]
test-support = []
[dependencies]
anyhow.workspace = true
assistant_slash_command.workspace = true
@ -25,7 +22,6 @@ editor.workspace = true
extension.workspace = true
extension_host.workspace = true
fs.workspace = true
futures.workspace = true
fuzzy.workspace = true
gpui.workspace = true
indexed_docs.workspace = true
@ -50,21 +46,4 @@ wasmtime-wasi.workspace = true
workspace.workspace = true
[dev-dependencies]
async-compression.workspace = true
async-tar.workspace = true
ctor.workspace = true
editor = { workspace = true, features = ["test-support"] }
env_logger.workspace = true
extension_host = {workspace = true, features = ["test-support"] }
fs = { workspace = true, features = ["test-support"] }
gpui = { workspace = true, features = ["test-support"] }
http_client.workspace = true
indexed_docs.workspace = true
language = { workspace = true, features = ["test-support"] }
lsp.workspace = true
node_runtime.workspace = true
parking_lot.workspace = true
project = { workspace = true, features = ["test-support"] }
reqwest_client.workspace = true
serde_json.workspace = true
workspace = { workspace = true, features = ["test-support"] }

View file

@ -3,9 +3,6 @@ mod extension_registration_hooks;
mod extension_suggest;
mod extension_version_selector;
#[cfg(test)]
mod extension_store_test;
pub use extension_registration_hooks::ConcreteExtensionRegistrationHooks;
use std::ops::DerefMut;