mirror of
https://github.com/DeusData/codebase-memory-mcp.git
synced 2026-11-08 08:53:43 +08:00
test(pipeline): cover repeated overlay publish
Add a focused pipeline canary for repeated opt-in overlay publishes of the same changed file. The test proves active overlay reads stay idempotent from the caller perspective: canonical base remains unchanged, the overlay view exposes one function, dirty_files remains a single overlay_ready row, and no reserved canonical generation is leaked. This is intentionally test-only. It does not claim overlay generation retention or duplicate-publish suppression is solved; those remain separate compaction/cleanup design items. Validation: make -f Makefile.cbm build/c/test-runner -j8; CBM_ONLY_SUITE=pipeline build/c/test-runner; bash scripts/check-source-safety.sh; git diff --check. Signed-off-by: Andrew Hundt <ATHundt@gmail.com>
This commit is contained in:
+79
-14
@@ -8509,28 +8509,34 @@ static int pipeline_store_dirty_counts(const char *db_path, const char *project,
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int pipeline_store_overlay_file_has_function(const char *db_path, const char *project,
|
||||
const char *rel_path, const char *name) {
|
||||
static int pipeline_store_overlay_file_function_count(const char *db_path, const char *project,
|
||||
const char *rel_path, const char *name) {
|
||||
cbm_store_t *s = cbm_store_open_path_query(db_path);
|
||||
if (!s) {
|
||||
return 0;
|
||||
return CBM_STORE_ERR;
|
||||
}
|
||||
cbm_node_t *nodes = NULL;
|
||||
int count = 0;
|
||||
int found = 0;
|
||||
if (cbm_store_find_nodes_by_file_overlay_view(s, project, rel_path, &nodes, &count) ==
|
||||
int matches = 0;
|
||||
if (cbm_store_find_nodes_by_file_overlay_view(s, project, rel_path, &nodes, &count) !=
|
||||
CBM_STORE_OK) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (nodes[i].label && strcmp(nodes[i].label, "Function") == 0 && nodes[i].name &&
|
||||
strcmp(nodes[i].name, name) == 0) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
cbm_store_free_nodes(nodes, count);
|
||||
cbm_store_close(s);
|
||||
return CBM_STORE_ERR;
|
||||
}
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (nodes[i].label && strcmp(nodes[i].label, "Function") == 0 && nodes[i].name &&
|
||||
strcmp(nodes[i].name, name) == 0) {
|
||||
matches++;
|
||||
}
|
||||
}
|
||||
cbm_store_free_nodes(nodes, count);
|
||||
cbm_store_close(s);
|
||||
return found;
|
||||
return matches;
|
||||
}
|
||||
|
||||
static int pipeline_store_overlay_file_has_function(const char *db_path, const char *project,
|
||||
const char *rel_path, const char *name) {
|
||||
return pipeline_store_overlay_file_function_count(db_path, project, rel_path, name) > 0;
|
||||
}
|
||||
|
||||
static int pipeline_store_generation_status_count(const char *db_path, const char *project,
|
||||
@@ -10750,6 +10756,64 @@ TEST(incremental_overlay_publish_delete_keeps_canonical_base_visible) {
|
||||
PASS();
|
||||
}
|
||||
|
||||
TEST(incremental_overlay_publish_repeated_update_keeps_active_view_idempotent) {
|
||||
if (setup_incremental_repo() != 0) {
|
||||
FAIL("setup failed");
|
||||
}
|
||||
|
||||
cbm_config_t *cfg = incremental_test_config(g_incr_tmpdir);
|
||||
ASSERT_NOT_NULL(cfg);
|
||||
ASSERT_EQ(cbm_config_set(cfg, CBM_CONFIG_OVERLAY_PUBLISH,
|
||||
CBM_CONFIG_OVERLAY_PUBLISH_SMALL_DELTAS),
|
||||
0);
|
||||
cbm_pipeline_t *p = cbm_pipeline_new(g_incr_tmpdir, g_incr_dbpath, CBM_MODE_FAST);
|
||||
ASSERT_NOT_NULL(p);
|
||||
cbm_pipeline_apply_config(p, cfg);
|
||||
ASSERT_EQ(cbm_pipeline_run(p), 0);
|
||||
char *project = cbm_strdup(cbm_pipeline_project_name(p));
|
||||
cbm_pipeline_free(p);
|
||||
ASSERT_NOT_NULL(project);
|
||||
|
||||
char path[CBM_PATH_MAX];
|
||||
int n = snprintf(path, sizeof(path), "%s/leaf.go", g_incr_tmpdir);
|
||||
ASSERT(n >= 0 && (size_t)n < sizeof(path));
|
||||
ASSERT_EQ(th_write_file(path,
|
||||
"package main\n\n"
|
||||
"func Leaf() int {\n\treturn 2\n}\n\n"
|
||||
"func OverlayRetryOnly() int {\n\treturn 77\n}\n"),
|
||||
0);
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
p = cbm_pipeline_new(g_incr_tmpdir, g_incr_dbpath, CBM_MODE_FAST);
|
||||
ASSERT_NOT_NULL(p);
|
||||
cbm_pipeline_apply_config(p, cfg);
|
||||
ASSERT_EQ(cbm_pipeline_run(p), 0);
|
||||
ASSERT_EQ(cbm_pipeline_publish_kind(p), CBM_PIPELINE_PUBLISH_INCREMENTAL_OVERLAY);
|
||||
ASSERT(!cbm_pipeline_graph_changed(p));
|
||||
cbm_pipeline_free(p);
|
||||
}
|
||||
|
||||
ASSERT_EQ(pipeline_store_generation_status_count(g_incr_dbpath, project,
|
||||
CBM_STORE_INDEX_STATUS_RESERVED),
|
||||
0);
|
||||
ASSERT(!pipeline_store_has_function_name(g_incr_dbpath, project, "OverlayRetryOnly"));
|
||||
ASSERT_EQ(pipeline_store_overlay_file_function_count(g_incr_dbpath, project, "leaf.go",
|
||||
"OverlayRetryOnly"),
|
||||
1);
|
||||
int dirty_pending = -1;
|
||||
int dirty_overlay_ready = -1;
|
||||
ASSERT_EQ(pipeline_store_dirty_counts(g_incr_dbpath, project, &dirty_pending,
|
||||
&dirty_overlay_ready),
|
||||
CBM_STORE_OK);
|
||||
ASSERT_EQ(dirty_pending, 0);
|
||||
ASSERT_EQ(dirty_overlay_ready, 1);
|
||||
|
||||
free(project);
|
||||
cbm_config_close(cfg);
|
||||
cleanup_incremental_repo();
|
||||
PASS();
|
||||
}
|
||||
|
||||
TEST(incremental_full_mode_keeps_exact_upsert_disabled) {
|
||||
if (setup_incremental_repo() != 0) {
|
||||
FAIL("setup failed");
|
||||
@@ -12915,6 +12979,7 @@ SUITE(pipeline) {
|
||||
RUN_TEST(incremental_overlay_producer_marks_dirty_ready_without_canonical_mutation);
|
||||
RUN_TEST(incremental_overlay_publish_small_deltas_keeps_canonical_base_visible);
|
||||
RUN_TEST(incremental_overlay_publish_delete_keeps_canonical_base_visible);
|
||||
RUN_TEST(incremental_overlay_publish_repeated_update_keeps_active_view_idempotent);
|
||||
RUN_TEST(incremental_full_mode_keeps_exact_upsert_disabled);
|
||||
RUN_TEST(incremental_detects_same_size_rewrite_with_preserved_mtime);
|
||||
RUN_TEST(incremental_missing_file_state_keeps_legacy_metadata_path);
|
||||
|
||||
Reference in New Issue
Block a user