From 6908ea507589eea8962040e1f119bdcd47636370 Mon Sep 17 00:00:00 2001 From: Blank_Answer <97771966+blankanswer@users.noreply.github.com> Date: Wed, 8 Jul 2026 03:21:46 +0000 Subject: [PATCH] test(mcp): cover CLI index name override Signed-off-by: Blank_Answer <97771966+blankanswer@users.noreply.github.com> --- tests/test_mcp.c | 139 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) diff --git a/tests/test_mcp.c b/tests/test_mcp.c index 7914a8bb..c4a69324 100644 --- a/tests/test_mcp.c +++ b/tests/test_mcp.c @@ -4125,6 +4125,144 @@ TEST(readonly_query_succeeds_on_readonly_fs) { #undef ROQ_PROJECT +/* ══════════════════════════════════════════════════════════════════ + * #823 — CLI/supervised index_repository must preserve name override + * ══════════════════════════════════════════════════════════════════ */ + +enum { + IDX823_OK = 0, + IDX823_NO_SERVER = 61, + IDX823_NO_RESULT = 62, + IDX823_NOT_INDEXED = 63, + IDX823_RESPONSE_NAME_MISSING = 64, + IDX823_LIST_NAME_MISSING = 65, + IDX823_SEARCH_FAILED = 66, +}; + +#ifndef _WIN32 /* helper used only by the POSIX fork harness below */ +static int idx823_supervised_name_override_check(const char *repo_dir, const char *custom_name) { + /* Match the real CLI/MCP server state: a marked host with the supervisor + * enabled. The worker receives the same args JSON the CLI forwards. */ + cbm_index_supervisor_mark_host(); + cbm_unsetenv("CBM_INDEX_SUPERVISOR"); + cbm_setenv("CBM_INDEX_MAX_RESTARTS", "1", 1); + cbm_setenv("CBM_INDEX_WORKER_TIMEOUT_S", "30", 1); + + cbm_mcp_server_t *srv = cbm_mcp_server_new(NULL); + if (!srv) { + return IDX823_NO_SERVER; + } + + char args[1024]; + snprintf(args, sizeof(args), "{\"repo_path\":\"%s\",\"mode\":\"fast\",\"name\":\"%s\"}", + repo_dir, custom_name); + char *resp = cbm_mcp_handle_tool(srv, "index_repository", args); + int code = IDX823_OK; + if (!resp) { + code = IDX823_NO_RESULT; + } else if (!response_contains_json_fragment(resp, "\"status\":\"indexed\"")) { + code = IDX823_NOT_INDEXED; + } else { + char expected[256]; + snprintf(expected, sizeof(expected), "\"project\":\"%s\"", custom_name); + if (!response_contains_json_fragment(resp, expected)) { + code = IDX823_RESPONSE_NAME_MISSING; + } + } + free(resp); + + if (code == IDX823_OK) { + char *projects = cbm_mcp_handle_tool(srv, "list_projects", "{}"); + char expected[256]; + snprintf(expected, sizeof(expected), "\"name\":\"%s\"", custom_name); + if (!projects || !response_contains_json_fragment(projects, expected)) { + code = IDX823_LIST_NAME_MISSING; + } + free(projects); + } + + if (code == IDX823_OK) { + char q[512]; + snprintf(q, sizeof(q), + "{\"project\":\"%s\",\"name_pattern\":\"idx823_fn\",\"label\":\"Function\"}", + custom_name); + char *sr = cbm_mcp_handle_tool(srv, "search_graph", q); + if (!sr || !strstr(sr, "idx823_fn")) { + code = IDX823_SEARCH_FAILED; + } + free(sr); + } + + cbm_mcp_server_free(srv); + return code; +} +#endif + +TEST(index_repository_cli_name_override_issue823) { +#ifdef _WIN32 + SKIP_PLATFORM("POSIX fork harness required to isolate supervisor host mark"); +#else + char tmp_dir[256]; + snprintf(tmp_dir, sizeof(tmp_dir), "/tmp/cbm-idx823-repo-XXXXXX"); + if (!cbm_mkdtemp(tmp_dir)) { + FAIL("cbm_mkdtemp repo failed"); + } + char cache[256]; + snprintf(cache, sizeof(cache), "/tmp/cbm-idx823-cache-XXXXXX"); + if (!cbm_mkdtemp(cache)) { + th_rmtree(tmp_dir); + FAIL("cbm_mkdtemp cache failed"); + } + + const char *saved_cache = getenv("CBM_CACHE_DIR"); + char *saved_cache_copy = saved_cache ? strdup(saved_cache) : NULL; + cbm_setenv("CBM_CACHE_DIR", cache, 1); + + char src_path[512]; + snprintf(src_path, sizeof(src_path), "%s/main.py", tmp_dir); + ASSERT_EQ(th_write_file(src_path, "def idx823_fn():\n return 823\n"), 0); + + const char *custom_name = "issue823-custom-project"; + int code = -1; + bool signalled = false; + int sig = 0; + + fflush(NULL); + pid_t pid = fork(); + if (pid == 0) { + alarm(60); + _exit(idx823_supervised_name_override_check(tmp_dir, custom_name)); + } + ASSERT_TRUE(pid > 0); + int status = 0; + (void)waitpid(pid, &status, 0); + if (WIFEXITED(status)) { + code = WEXITSTATUS(status); + } else if (WIFSIGNALED(status)) { + signalled = true; + sig = WTERMSIG(status); + } + + char *path_project = cbm_project_name_from_path(tmp_dir); + cleanup_project_db(cache, custom_name); + cleanup_project_db(cache, path_project); + free(path_project); + restore_cache_dir(saved_cache_copy); + free(saved_cache_copy); + th_rmtree(cache); + th_rmtree(tmp_dir); + + if (signalled) { + printf(" child killed by signal %d (alarm => worker hang)\n", sig); + } else if (code != IDX823_OK) { + printf(" child exit code %d (64=response name, 65=list name, 66=search)\n", code); + } + ASSERT_FALSE(signalled); + ASSERT_EQ(code, IDX823_OK); + PASS(); +#endif +} + /* ══════════════════════════════════════════════════════════════════ * #845 — supervisor gate must not wrap embedders of cbm_mcp_handle_tool * ══════════════════════════════════════════════════════════════════ */ @@ -5083,6 +5221,7 @@ SUITE(mcp) { RUN_TEST(tool_manage_adr_unified_backend_issue256); RUN_TEST(tool_index_repository_reports_store_backed_adr); RUN_TEST(tool_index_repository_dot_uses_absolute_project_key_and_preserves_adr); + RUN_TEST(index_repository_cli_name_override_issue823); RUN_TEST(index_supervisor_gate_requires_marked_host_issue845); RUN_TEST(index_bg_paths_route_through_supervisor_issue832); RUN_TEST(index_recovery_parallel_quarantines_crasher);