Skip to content

Commit 6e5feeb

Browse files
test(dbt): regression fixture for ingest_dbt_manifest (#576)
Signed-off-by: alexisperinger-ux <alexis.peringer@iss-stoxx.com>
1 parent ccd683f commit 6e5feeb

1 file changed

Lines changed: 95 additions & 0 deletions

File tree

tests/test_mcp.c

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2143,6 +2143,100 @@ TEST(tool_bad_project_name_no_overflow_issue235) {
21432143
}
21442144
#undef ISSUE235_DBNAME
21452145

2146+
/* Issue #576: ingest_dbt_manifest parses a compiled dbt manifest.json and
2147+
* upserts model/seed/snapshot as graph nodes, source as Source nodes, and each
2148+
* node's depends_on.nodes as DEPENDS_ON edges, keyed by dbt unique_id. The
2149+
* handler opens (and creates) the project's on-disk store at
2150+
* <CBM_CACHE_DIR>/<project>.db, so an isolated cache dir plus a small fixture
2151+
* manifest exercises the whole path. The fixture carries 3 models + 1 seed +
2152+
* 1 snapshot + 2 sources and one `test` node that must be skipped, so the
2153+
* reported counts pin both the resource-type filter and the lineage edges. */
2154+
static const char *DBT_MANIFEST_FIXTURE =
2155+
"{\"nodes\":{"
2156+
"\"model.shop.stg_orders\":{\"resource_type\":\"model\",\"name\":\"stg_orders\","
2157+
"\"depends_on\":{\"nodes\":[\"source.shop.raw.orders\"]}},"
2158+
"\"model.shop.stg_customers\":{\"resource_type\":\"model\",\"name\":\"stg_customers\","
2159+
"\"depends_on\":{\"nodes\":[\"source.shop.raw.customers\"]}},"
2160+
"\"model.shop.fct_orders\":{\"resource_type\":\"model\",\"name\":\"fct_orders\","
2161+
"\"depends_on\":{\"nodes\":[\"model.shop.stg_orders\",\"model.shop.stg_customers\"]}},"
2162+
"\"seed.shop.country_codes\":{\"resource_type\":\"seed\",\"name\":\"country_codes\","
2163+
"\"depends_on\":{\"nodes\":[]}},"
2164+
"\"snapshot.shop.orders_snap\":{\"resource_type\":\"snapshot\",\"name\":\"orders_snap\","
2165+
"\"depends_on\":{\"nodes\":[\"model.shop.fct_orders\"]}},"
2166+
"\"test.shop.not_null_fct_orders\":{\"resource_type\":\"test\",\"name\":\"not_null\","
2167+
"\"depends_on\":{\"nodes\":[\"model.shop.fct_orders\"]}}"
2168+
"},\"sources\":{"
2169+
"\"source.shop.raw.orders\":{\"resource_type\":\"source\",\"name\":\"orders\"},"
2170+
"\"source.shop.raw.customers\":{\"resource_type\":\"source\",\"name\":\"customers\"}"
2171+
"}}";
2172+
2173+
TEST(tool_ingest_dbt_manifest_issue576) {
2174+
char cache[256];
2175+
snprintf(cache, sizeof(cache), "/tmp/cbm-dbt-manifest-XXXXXX");
2176+
if (!cbm_mkdtemp(cache)) {
2177+
PASS(); /* skip if mkdtemp fails */
2178+
}
2179+
2180+
const char *saved = getenv("CBM_CACHE_DIR");
2181+
char *saved_copy = saved ? strdup(saved) : NULL;
2182+
cbm_setenv("CBM_CACHE_DIR", cache, 1);
2183+
2184+
/* Write the fixture manifest into the isolated cache dir. */
2185+
char manifest_path[512];
2186+
snprintf(manifest_path, sizeof(manifest_path), "%s/manifest.json", cache);
2187+
FILE *fp = fopen(manifest_path, "w");
2188+
ASSERT_NOT_NULL(fp);
2189+
fputs(DBT_MANIFEST_FIXTURE, fp);
2190+
fclose(fp);
2191+
2192+
/* The handler opens (and creates) <CBM_CACHE_DIR>/<project>.db itself. */
2193+
const char *project = "test-dbt-manifest";
2194+
char req[2048];
2195+
snprintf(req, sizeof(req),
2196+
"{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"tools/call\",\"params\":{\"name\":"
2197+
"\"ingest_dbt_manifest\",\"arguments\":{\"project\":\"%s\",\"manifest_path\":\"%s\"}}}",
2198+
project, manifest_path);
2199+
2200+
cbm_mcp_server_t *srv = cbm_mcp_server_new(NULL);
2201+
ASSERT_NOT_NULL(srv);
2202+
char *resp = cbm_mcp_server_handle(srv, req);
2203+
ASSERT_NOT_NULL(resp);
2204+
2205+
char *inner = extract_text_content(resp);
2206+
ASSERT_NOT_NULL(inner);
2207+
/* 3 models + 1 seed + 1 snapshot = 5 lineage-bearing nodes; the `test`
2208+
* node is skipped (so models is 5, not 6). */
2209+
ASSERT_NOT_NULL(strstr(inner, "\"status\":\"ingested\""));
2210+
ASSERT_NOT_NULL(strstr(inner, "\"models\":5"));
2211+
ASSERT_NOT_NULL(strstr(inner, "\"sources\":2"));
2212+
/* stg_orders/stg_customers -> source, fct_orders -> 2 stg, snap -> fct = 5
2213+
* DEPENDS_ON edges; the skipped test node contributes none. */
2214+
ASSERT_NOT_NULL(strstr(inner, "\"edges\":5"));
2215+
2216+
free(inner);
2217+
free(resp);
2218+
cbm_mcp_server_free(srv);
2219+
2220+
if (saved_copy) {
2221+
cbm_setenv("CBM_CACHE_DIR", saved_copy, 1);
2222+
free(saved_copy);
2223+
} else {
2224+
cbm_unsetenv("CBM_CACHE_DIR");
2225+
}
2226+
char dbpath[512];
2227+
snprintf(dbpath, sizeof(dbpath), "%s/%s.db", cache, project);
2228+
char dbwal[576];
2229+
char dbshm[576];
2230+
snprintf(dbwal, sizeof(dbwal), "%s-wal", dbpath);
2231+
snprintf(dbshm, sizeof(dbshm), "%s-shm", dbpath);
2232+
cbm_unlink(dbwal);
2233+
cbm_unlink(dbshm);
2234+
cbm_unlink(dbpath);
2235+
cbm_unlink(manifest_path);
2236+
cbm_rmdir(cache);
2237+
PASS();
2238+
}
2239+
21462240
/* ══════════════════════════════════════════════════════════════════
21472241
* SUITE
21482242
* ══════════════════════════════════════════════════════════════════ */
@@ -2217,6 +2311,7 @@ SUITE(mcp) {
22172311
RUN_TEST(tool_search_graph_includes_node_properties);
22182312
RUN_TEST(tool_search_graph_query_honors_file_pattern_issue552);
22192313
RUN_TEST(tool_query_graph_basic);
2314+
RUN_TEST(tool_ingest_dbt_manifest_issue576);
22202315
RUN_TEST(tool_index_status_no_project);
22212316
RUN_TEST(tool_index_status_includes_git_metadata);
22222317

0 commit comments

Comments
 (0)