Skip to content

Commit 6908ea5

Browse files
committed
test(mcp): cover CLI index name override
Signed-off-by: Blank_Answer <97771966+blankanswer@users.noreply.github.com>
1 parent b637e33 commit 6908ea5

1 file changed

Lines changed: 139 additions & 0 deletions

File tree

tests/test_mcp.c

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4125,6 +4125,144 @@ TEST(readonly_query_succeeds_on_readonly_fs) {
41254125

41264126
#undef ROQ_PROJECT
41274127

4128+
/* ══════════════════════════════════════════════════════════════════
4129+
* #823 — CLI/supervised index_repository must preserve name override
4130+
* ══════════════════════════════════════════════════════════════════ */
4131+
4132+
enum {
4133+
IDX823_OK = 0,
4134+
IDX823_NO_SERVER = 61,
4135+
IDX823_NO_RESULT = 62,
4136+
IDX823_NOT_INDEXED = 63,
4137+
IDX823_RESPONSE_NAME_MISSING = 64,
4138+
IDX823_LIST_NAME_MISSING = 65,
4139+
IDX823_SEARCH_FAILED = 66,
4140+
};
4141+
4142+
#ifndef _WIN32 /* helper used only by the POSIX fork harness below */
4143+
static int idx823_supervised_name_override_check(const char *repo_dir, const char *custom_name) {
4144+
/* Match the real CLI/MCP server state: a marked host with the supervisor
4145+
* enabled. The worker receives the same args JSON the CLI forwards. */
4146+
cbm_index_supervisor_mark_host();
4147+
cbm_unsetenv("CBM_INDEX_SUPERVISOR");
4148+
cbm_setenv("CBM_INDEX_MAX_RESTARTS", "1", 1);
4149+
cbm_setenv("CBM_INDEX_WORKER_TIMEOUT_S", "30", 1);
4150+
4151+
cbm_mcp_server_t *srv = cbm_mcp_server_new(NULL);
4152+
if (!srv) {
4153+
return IDX823_NO_SERVER;
4154+
}
4155+
4156+
char args[1024];
4157+
snprintf(args, sizeof(args), "{\"repo_path\":\"%s\",\"mode\":\"fast\",\"name\":\"%s\"}",
4158+
repo_dir, custom_name);
4159+
char *resp = cbm_mcp_handle_tool(srv, "index_repository", args);
4160+
int code = IDX823_OK;
4161+
if (!resp) {
4162+
code = IDX823_NO_RESULT;
4163+
} else if (!response_contains_json_fragment(resp, "\"status\":\"indexed\"")) {
4164+
code = IDX823_NOT_INDEXED;
4165+
} else {
4166+
char expected[256];
4167+
snprintf(expected, sizeof(expected), "\"project\":\"%s\"", custom_name);
4168+
if (!response_contains_json_fragment(resp, expected)) {
4169+
code = IDX823_RESPONSE_NAME_MISSING;
4170+
}
4171+
}
4172+
free(resp);
4173+
4174+
if (code == IDX823_OK) {
4175+
char *projects = cbm_mcp_handle_tool(srv, "list_projects", "{}");
4176+
char expected[256];
4177+
snprintf(expected, sizeof(expected), "\"name\":\"%s\"", custom_name);
4178+
if (!projects || !response_contains_json_fragment(projects, expected)) {
4179+
code = IDX823_LIST_NAME_MISSING;
4180+
}
4181+
free(projects);
4182+
}
4183+
4184+
if (code == IDX823_OK) {
4185+
char q[512];
4186+
snprintf(q, sizeof(q),
4187+
"{\"project\":\"%s\",\"name_pattern\":\"idx823_fn\",\"label\":\"Function\"}",
4188+
custom_name);
4189+
char *sr = cbm_mcp_handle_tool(srv, "search_graph", q);
4190+
if (!sr || !strstr(sr, "idx823_fn")) {
4191+
code = IDX823_SEARCH_FAILED;
4192+
}
4193+
free(sr);
4194+
}
4195+
4196+
cbm_mcp_server_free(srv);
4197+
return code;
4198+
}
4199+
#endif
4200+
4201+
TEST(index_repository_cli_name_override_issue823) {
4202+
#ifdef _WIN32
4203+
SKIP_PLATFORM("POSIX fork harness required to isolate supervisor host mark");
4204+
#else
4205+
char tmp_dir[256];
4206+
snprintf(tmp_dir, sizeof(tmp_dir), "/tmp/cbm-idx823-repo-XXXXXX");
4207+
if (!cbm_mkdtemp(tmp_dir)) {
4208+
FAIL("cbm_mkdtemp repo failed");
4209+
}
4210+
char cache[256];
4211+
snprintf(cache, sizeof(cache), "/tmp/cbm-idx823-cache-XXXXXX");
4212+
if (!cbm_mkdtemp(cache)) {
4213+
th_rmtree(tmp_dir);
4214+
FAIL("cbm_mkdtemp cache failed");
4215+
}
4216+
4217+
const char *saved_cache = getenv("CBM_CACHE_DIR");
4218+
char *saved_cache_copy = saved_cache ? strdup(saved_cache) : NULL;
4219+
cbm_setenv("CBM_CACHE_DIR", cache, 1);
4220+
4221+
char src_path[512];
4222+
snprintf(src_path, sizeof(src_path), "%s/main.py", tmp_dir);
4223+
ASSERT_EQ(th_write_file(src_path, "def idx823_fn():\n return 823\n"), 0);
4224+
4225+
const char *custom_name = "issue823-custom-project";
4226+
int code = -1;
4227+
bool signalled = false;
4228+
int sig = 0;
4229+
4230+
fflush(NULL);
4231+
pid_t pid = fork();
4232+
if (pid == 0) {
4233+
alarm(60);
4234+
_exit(idx823_supervised_name_override_check(tmp_dir, custom_name));
4235+
}
4236+
ASSERT_TRUE(pid > 0);
4237+
int status = 0;
4238+
(void)waitpid(pid, &status, 0);
4239+
if (WIFEXITED(status)) {
4240+
code = WEXITSTATUS(status);
4241+
} else if (WIFSIGNALED(status)) {
4242+
signalled = true;
4243+
sig = WTERMSIG(status);
4244+
}
4245+
4246+
char *path_project = cbm_project_name_from_path(tmp_dir);
4247+
cleanup_project_db(cache, custom_name);
4248+
cleanup_project_db(cache, path_project);
4249+
free(path_project);
4250+
restore_cache_dir(saved_cache_copy);
4251+
free(saved_cache_copy);
4252+
th_rmtree(cache);
4253+
th_rmtree(tmp_dir);
4254+
4255+
if (signalled) {
4256+
printf(" child killed by signal %d (alarm => worker hang)\n", sig);
4257+
} else if (code != IDX823_OK) {
4258+
printf(" child exit code %d (64=response name, 65=list name, 66=search)\n", code);
4259+
}
4260+
ASSERT_FALSE(signalled);
4261+
ASSERT_EQ(code, IDX823_OK);
4262+
PASS();
4263+
#endif
4264+
}
4265+
41284266
/* ══════════════════════════════════════════════════════════════════
41294267
* #845 — supervisor gate must not wrap embedders of cbm_mcp_handle_tool
41304268
* ══════════════════════════════════════════════════════════════════ */
@@ -5083,6 +5221,7 @@ SUITE(mcp) {
50835221
RUN_TEST(tool_manage_adr_unified_backend_issue256);
50845222
RUN_TEST(tool_index_repository_reports_store_backed_adr);
50855223
RUN_TEST(tool_index_repository_dot_uses_absolute_project_key_and_preserves_adr);
5224+
RUN_TEST(index_repository_cli_name_override_issue823);
50865225
RUN_TEST(index_supervisor_gate_requires_marked_host_issue845);
50875226
RUN_TEST(index_bg_paths_route_through_supervisor_issue832);
50885227
RUN_TEST(index_recovery_parallel_quarantines_crasher);

0 commit comments

Comments
 (0)