acp: Add a basic test for ACP remoting (#38381)

Tests that the downstream project can see custom agents configured in
the remote server's settings, and that it constructs an appropriate
`AgentServerCommand`.

Release Notes:

- N/A
This commit is contained in:
Cole Miller 2025-09-18 00:02:44 -04:00 committed by GitHub
parent ea473eea87
commit eaa1cb0ca3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 102 additions and 1 deletions

2
Cargo.lock generated
View file

@ -13981,6 +13981,7 @@ dependencies = [
"clap",
"client",
"clock",
"collections",
"crash-handler",
"crashes",
"dap",
@ -14009,6 +14010,7 @@ dependencies = [
"minidumper",
"node_runtime",
"paths",
"pretty_assertions",
"project",
"proto",
"release_channel",

View file

@ -77,6 +77,7 @@ assistant_tool.workspace = true
assistant_tools.workspace = true
client = { workspace = true, features = ["test-support"] }
clock = { workspace = true, features = ["test-support"] }
collections.workspace = true
dap = { workspace = true, features = ["test-support"] }
editor = { workspace = true, features = ["test-support"] }
workspace = { workspace = true, features = ["test-support"] }
@ -85,6 +86,7 @@ gpui = { workspace = true, features = ["test-support"] }
http_client = { workspace = true, features = ["test-support"] }
language = { workspace = true, features = ["test-support"] }
node_runtime = { workspace = true, features = ["test-support"] }
pretty_assertions.workspace = true
project = { workspace = true, features = ["test-support"] }
remote = { workspace = true, features = ["test-support"] }
language_model = { workspace = true, features = ["test-support"] }

View file

@ -6,6 +6,7 @@ use assistant_tool::{Tool as _, ToolResultContent};
use assistant_tools::{ReadFileTool, ReadFileToolInput};
use client::{Client, UserStore};
use clock::FakeSystemClock;
use collections::{HashMap, HashSet};
use language_model::{LanguageModelRequest, fake_provider::FakeLanguageModel};
use extension::ExtensionHostProxy;
@ -20,6 +21,7 @@ use lsp::{CompletionContext, CompletionResponse, CompletionTriggerKind, Language
use node_runtime::NodeRuntime;
use project::{
Project, ProjectPath,
agent_server_store::AgentServerCommand,
search::{SearchQuery, SearchResult},
};
use remote::RemoteClient;
@ -27,7 +29,6 @@ use serde_json::json;
use settings::{Settings, SettingsLocation, SettingsStore, initial_server_settings_content};
use smol::stream::StreamExt;
use std::{
collections::HashSet,
path::{Path, PathBuf},
sync::Arc,
};
@ -1770,6 +1771,91 @@ async fn test_remote_agent_fs_tool_calls(cx: &mut TestAppContext, server_cx: &mu
does_not_exist_result.output.await.unwrap_err();
}
#[gpui::test]
async fn test_remote_external_agent_server(
cx: &mut TestAppContext,
server_cx: &mut TestAppContext,
) {
let fs = FakeFs::new(server_cx.executor());
fs.insert_tree(path!("/project"), json!({})).await;
let (project, _headless_project) = init_test(&fs, cx, server_cx).await;
project
.update(cx, |project, cx| {
project.find_or_create_worktree(path!("/project"), true, cx)
})
.await
.unwrap();
let names = project.update(cx, |project, cx| {
project
.agent_server_store()
.read(cx)
.external_agents()
.map(|name| name.to_string())
.collect::<Vec<_>>()
});
pretty_assertions::assert_eq!(names, ["gemini", "claude"]);
server_cx.update_global::<SettingsStore, _>(|settings_store, cx| {
settings_store
.set_raw_server_settings(
Some(json!({
"agent_servers": {
"foo": {
"command": "foo-cli",
"args": ["--flag"],
"env": {
"VAR": "val"
}
}
}
})),
cx,
)
.unwrap();
});
server_cx.run_until_parked();
cx.run_until_parked();
let names = project.update(cx, |project, cx| {
project
.agent_server_store()
.read(cx)
.external_agents()
.map(|name| name.to_string())
.collect::<Vec<_>>()
});
pretty_assertions::assert_eq!(names, ["gemini", "foo", "claude"]);
let (command, root, login) = project
.update(cx, |project, cx| {
project.agent_server_store().update(cx, |store, cx| {
store
.get_external_agent(&"foo".into())
.unwrap()
.get_command(
None,
HashMap::from_iter([("OTHER_VAR".into(), "other-val".into())]),
None,
None,
&mut cx.to_async(),
)
})
})
.await
.unwrap();
assert_eq!(
command,
AgentServerCommand {
path: "ssh".into(),
args: vec!["foo-cli".into(), "--flag".into()],
env: Some(HashMap::from_iter([
("VAR".into(), "val".into()),
("OTHER_VAR".into(), "other-val".into())
]))
}
);
assert_eq!(&PathBuf::from(root), paths::home_dir());
assert!(login.is_none());
}
pub async fn init_test(
server_fs: &Arc<FakeFs>,
cx: &mut TestAppContext,

View file

@ -487,6 +487,17 @@ impl SettingsStore {
Ok(())
}
/// Replaces current settings with the values from the given JSON.
pub fn set_raw_server_settings(
&mut self,
new_settings: Option<Value>,
cx: &mut App,
) -> Result<()> {
self.raw_server_settings = new_settings;
self.recompute_values(None, cx)?;
Ok(())
}
/// Get the configured settings profile names.
pub fn configured_settings_profiles(&self) -> impl Iterator<Item = &str> {
self.raw_user_settings