mirror of
https://github.com/openai/codex.git
synced 2026-05-03 04:42:20 +03:00
spitballing
This commit is contained in:
88
codex-rs/cli/tests/mcp_add_remove.rs
Normal file
88
codex-rs/cli/tests/mcp_add_remove.rs
Normal file
@@ -0,0 +1,88 @@
|
||||
use assert_cmd::prelude::*;
|
||||
use std::fs;
|
||||
use std::process::Command;
|
||||
|
||||
fn write(path: &std::path::Path, contents: &str) {
|
||||
fs::write(path, contents).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn add_and_remove_user_scope() {
|
||||
let codex_home = tempfile::tempdir().unwrap();
|
||||
// Pre-create CODEX_HOME for canonicalization logic
|
||||
let config_path = codex_home.path().join("config.toml");
|
||||
|
||||
let project_dir = tempfile::tempdir().unwrap();
|
||||
write(&project_dir.path().join(".git"), "gitdir: nowhere");
|
||||
|
||||
// Add
|
||||
Command::cargo_bin("codex")
|
||||
.unwrap()
|
||||
.current_dir(project_dir.path())
|
||||
.env("CODEX_HOME", codex_home.path())
|
||||
.args([
|
||||
"mcp", "add", "svc", "--scope", "user", "--", "tool", "--flag",
|
||||
])
|
||||
.assert()
|
||||
.success();
|
||||
|
||||
let config = fs::read_to_string(&config_path).unwrap();
|
||||
assert!(config.contains("[mcp_servers.svc]"));
|
||||
assert!(config.contains("command = \"tool\""));
|
||||
|
||||
// Remove
|
||||
Command::cargo_bin("codex")
|
||||
.unwrap()
|
||||
.current_dir(project_dir.path())
|
||||
.env("CODEX_HOME", codex_home.path())
|
||||
.args(["mcp", "remove", "svc", "--scope", "user"])
|
||||
.assert()
|
||||
.success();
|
||||
|
||||
let config_after = fs::read_to_string(&config_path).unwrap();
|
||||
assert!(!config_after.contains("[mcp_servers.svc]"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn add_local_and_project_scopes() {
|
||||
let codex_home = tempfile::tempdir().unwrap();
|
||||
let project_dir = tempfile::tempdir().unwrap();
|
||||
write(&project_dir.path().join(".git"), "gitdir: nowhere");
|
||||
|
||||
// Add project
|
||||
Command::cargo_bin("codex")
|
||||
.unwrap()
|
||||
.current_dir(project_dir.path())
|
||||
.env("CODEX_HOME", codex_home.path())
|
||||
.args(["mcp", "add", "svc", "--scope", "project", "--", "toolp"])
|
||||
.assert()
|
||||
.success();
|
||||
let proj = fs::read_to_string(project_dir.path().join(".mcp.toml")).unwrap();
|
||||
assert!(proj.contains("[mcp_servers.svc]"));
|
||||
assert!(proj.contains("toolp"));
|
||||
|
||||
// Add local (override in precedence for merged view)
|
||||
Command::cargo_bin("codex")
|
||||
.unwrap()
|
||||
.current_dir(project_dir.path())
|
||||
.env("CODEX_HOME", codex_home.path())
|
||||
.args(["mcp", "add", "svc", "--scope", "local", "--", "tooll"])
|
||||
.assert()
|
||||
.success();
|
||||
let local = fs::read_to_string(project_dir.path().join(".mcp.local.toml")).unwrap();
|
||||
assert!(local.contains("tooll"));
|
||||
|
||||
// Remove all
|
||||
Command::cargo_bin("codex")
|
||||
.unwrap()
|
||||
.current_dir(project_dir.path())
|
||||
.env("CODEX_HOME", codex_home.path())
|
||||
.args(["mcp", "remove", "svc", "--all"])
|
||||
.assert()
|
||||
.success();
|
||||
|
||||
let proj_after = fs::read_to_string(project_dir.path().join(".mcp.toml")).unwrap();
|
||||
assert!(!proj_after.contains("[mcp_servers.svc]"));
|
||||
let local_after = fs::read_to_string(project_dir.path().join(".mcp.local.toml")).unwrap();
|
||||
assert!(!local_after.contains("[mcp_servers.svc]"));
|
||||
}
|
||||
133
codex-rs/cli/tests/mcp_add_toml.rs
Normal file
133
codex-rs/cli/tests/mcp_add_toml.rs
Normal file
@@ -0,0 +1,133 @@
|
||||
use assert_cmd::prelude::*;
|
||||
use serde_json::Value;
|
||||
use std::fs;
|
||||
use std::process::Command;
|
||||
|
||||
fn write(path: &std::path::Path, contents: &str) {
|
||||
fs::write(path, contents).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn add_toml_local_filters_non_stdio_and_lists() {
|
||||
let codex_home = tempfile::tempdir().unwrap();
|
||||
let project_dir = tempfile::tempdir().unwrap();
|
||||
write(&project_dir.path().join(".git"), "gitdir: nowhere");
|
||||
|
||||
let import = tempfile::NamedTempFile::new().unwrap();
|
||||
write(
|
||||
import.path(),
|
||||
r#"[mcp_servers.ok]
|
||||
type = "stdio"
|
||||
command = "tool"
|
||||
args = ["--x"]
|
||||
env = { K = "V" }
|
||||
|
||||
[mcp_servers.bad]
|
||||
type = "http"
|
||||
url = "https://example.invalid/mcp"
|
||||
|
||||
[mcp_servers.missing]
|
||||
type = "stdio"
|
||||
"#,
|
||||
);
|
||||
|
||||
// Import into local scope
|
||||
Command::cargo_bin("codex")
|
||||
.unwrap()
|
||||
.current_dir(project_dir.path())
|
||||
.env("CODEX_HOME", codex_home.path())
|
||||
.args([
|
||||
"mcp",
|
||||
"add-toml",
|
||||
"--scope",
|
||||
"local",
|
||||
import.path().to_str().unwrap(),
|
||||
])
|
||||
.assert()
|
||||
.success();
|
||||
|
||||
// Verify file contents
|
||||
let local_contents = fs::read_to_string(project_dir.path().join(".mcp.local.toml")).unwrap();
|
||||
assert!(local_contents.contains("[mcp_servers.ok]"));
|
||||
assert!(local_contents.contains("command = \"tool\""));
|
||||
assert!(!local_contents.contains("[mcp_servers.bad]"));
|
||||
assert!(!local_contents.contains("[mcp_servers.missing]"));
|
||||
|
||||
// And list shows only the accepted entry, with local scope
|
||||
let out = Command::cargo_bin("codex")
|
||||
.unwrap()
|
||||
.current_dir(project_dir.path())
|
||||
.env("CODEX_HOME", codex_home.path())
|
||||
.args(["mcp", "list", "--json"])
|
||||
.assert()
|
||||
.success()
|
||||
.get_output()
|
||||
.stdout
|
||||
.clone();
|
||||
let v: Value = serde_json::from_slice(&out).unwrap();
|
||||
let arr = v.as_array().unwrap();
|
||||
let mut seen_ok = false;
|
||||
for e in arr {
|
||||
if e.get("name").and_then(|x| x.as_str()) == Some("ok") {
|
||||
assert_eq!(e.get("scope").and_then(|x| x.as_str()), Some("local"));
|
||||
seen_ok = true;
|
||||
}
|
||||
assert_ne!(e.get("name").and_then(|x| x.as_str()), Some("bad"));
|
||||
assert_ne!(e.get("name").and_then(|x| x.as_str()), Some("missing"));
|
||||
}
|
||||
assert!(
|
||||
seen_ok,
|
||||
"expected to find imported 'ok' entry in list output"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn add_toml_user_and_get() {
|
||||
let codex_home = tempfile::tempdir().unwrap();
|
||||
let project_dir = tempfile::tempdir().unwrap();
|
||||
write(&project_dir.path().join(".git"), "gitdir: nowhere");
|
||||
|
||||
let import = tempfile::NamedTempFile::new().unwrap();
|
||||
write(
|
||||
import.path(),
|
||||
r#"[mcp_servers.userok]
|
||||
type = "stdio"
|
||||
command = "utool"
|
||||
"#,
|
||||
);
|
||||
|
||||
// Import into user scope
|
||||
Command::cargo_bin("codex")
|
||||
.unwrap()
|
||||
.current_dir(project_dir.path())
|
||||
.env("CODEX_HOME", codex_home.path())
|
||||
.args([
|
||||
"mcp",
|
||||
"add-toml",
|
||||
"--scope",
|
||||
"user",
|
||||
import.path().to_str().unwrap(),
|
||||
])
|
||||
.assert()
|
||||
.success();
|
||||
|
||||
// Get shows the user scope
|
||||
let out = Command::cargo_bin("codex")
|
||||
.unwrap()
|
||||
.current_dir(project_dir.path())
|
||||
.env("CODEX_HOME", codex_home.path())
|
||||
.args(["mcp", "get", "userok", "--json"])
|
||||
.assert()
|
||||
.success()
|
||||
.get_output()
|
||||
.stdout
|
||||
.clone();
|
||||
let v: Value = serde_json::from_slice(&out).unwrap();
|
||||
assert_eq!(v.get("scope").and_then(|x| x.as_str()), Some("user"));
|
||||
assert_eq!(
|
||||
v.get("config")
|
||||
.and_then(|c| c.get("command"))
|
||||
.and_then(|x| x.as_str()),
|
||||
Some("utool")
|
||||
);
|
||||
}
|
||||
52
codex-rs/cli/tests/mcp_get.rs
Normal file
52
codex-rs/cli/tests/mcp_get.rs
Normal file
@@ -0,0 +1,52 @@
|
||||
use assert_cmd::prelude::*;
|
||||
use serde_json::Value;
|
||||
use std::fs;
|
||||
use std::process::Command;
|
||||
|
||||
fn write(path: &std::path::Path, contents: &str) {
|
||||
fs::write(path, contents).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_returns_winning_scope() {
|
||||
let codex_home = tempfile::tempdir().unwrap();
|
||||
write(
|
||||
&codex_home.path().join("config.toml"),
|
||||
r#"[mcp_servers.svc]
|
||||
command = "user-cmd"
|
||||
"#,
|
||||
);
|
||||
|
||||
let project_dir = tempfile::tempdir().unwrap();
|
||||
write(&project_dir.path().join(".git"), "gitdir: nowhere");
|
||||
write(
|
||||
&project_dir.path().join(".mcp.toml"),
|
||||
r#"[mcp_servers.svc]
|
||||
command = "project-cmd"
|
||||
"#,
|
||||
);
|
||||
write(
|
||||
&project_dir.path().join(".mcp.local.toml"),
|
||||
r#"[mcp_servers.svc]
|
||||
command = "local-cmd"
|
||||
"#,
|
||||
);
|
||||
|
||||
let assert = Command::cargo_bin("codex")
|
||||
.unwrap()
|
||||
.current_dir(project_dir.path())
|
||||
.env("CODEX_HOME", codex_home.path())
|
||||
.args(["mcp", "get", "svc", "--json"])
|
||||
.assert()
|
||||
.success();
|
||||
let out = String::from_utf8(assert.get_output().stdout.clone()).unwrap();
|
||||
let v: Value = serde_json::from_str(&out).unwrap();
|
||||
assert_eq!(v.get("name").and_then(|x| x.as_str()), Some("svc"));
|
||||
assert_eq!(v.get("scope").and_then(|x| x.as_str()), Some("local"));
|
||||
assert_eq!(
|
||||
v.get("config")
|
||||
.and_then(|c| c.get("command"))
|
||||
.and_then(|x| x.as_str()),
|
||||
Some("local-cmd")
|
||||
);
|
||||
}
|
||||
71
codex-rs/cli/tests/mcp_list.rs
Normal file
71
codex-rs/cli/tests/mcp_list.rs
Normal file
@@ -0,0 +1,71 @@
|
||||
use assert_cmd::prelude::*;
|
||||
use serde_json::Value;
|
||||
use std::fs;
|
||||
use std::process::Command;
|
||||
|
||||
fn write(path: &std::path::Path, contents: &str) {
|
||||
fs::write(path, contents).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn list_shows_scopes_for_user_project_local() {
|
||||
let codex_home = tempfile::tempdir().unwrap();
|
||||
write(
|
||||
&codex_home.path().join("config.toml"),
|
||||
r#"[mcp_servers.user_svc]
|
||||
command = "user-cmd"
|
||||
"#,
|
||||
);
|
||||
|
||||
let project_dir = tempfile::tempdir().unwrap();
|
||||
// Mark git root for nicer parity with real use
|
||||
write(&project_dir.path().join(".git"), "gitdir: nowhere");
|
||||
write(
|
||||
&project_dir.path().join(".mcp.toml"),
|
||||
r#"[mcp_servers.proj_svc]
|
||||
command = "proj-cmd"
|
||||
"#,
|
||||
);
|
||||
write(
|
||||
&project_dir.path().join(".mcp.local.toml"),
|
||||
r#"[mcp_servers.local_svc]
|
||||
command = "local-cmd"
|
||||
"#,
|
||||
);
|
||||
|
||||
let assert = Command::cargo_bin("codex")
|
||||
.unwrap()
|
||||
.current_dir(project_dir.path())
|
||||
.env("CODEX_HOME", codex_home.path())
|
||||
.args(["mcp", "list", "--json"])
|
||||
.assert()
|
||||
.success();
|
||||
let out = String::from_utf8(assert.get_output().stdout.clone()).unwrap();
|
||||
let v: Value = serde_json::from_str(&out).unwrap();
|
||||
let arr = v.as_array().unwrap();
|
||||
|
||||
let mut found = (false, false, false);
|
||||
for e in arr {
|
||||
let name = e.get("name").and_then(|x| x.as_str()).unwrap();
|
||||
let scope = e.get("scope").and_then(|x| x.as_str()).unwrap();
|
||||
match name {
|
||||
"user_svc" => {
|
||||
assert_eq!(scope, "user");
|
||||
found.0 = true;
|
||||
}
|
||||
"proj_svc" => {
|
||||
assert_eq!(scope, "project");
|
||||
found.1 = true;
|
||||
}
|
||||
"local_svc" => {
|
||||
assert_eq!(scope, "local");
|
||||
found.2 = true;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
assert!(
|
||||
found.0 && found.1 && found.2,
|
||||
"expected three entries across scopes"
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user