test: add marker replay idempotence checks for list pagination

This commit is contained in:
houseme
2026-06-30 00:17:26 +08:00
parent c79bb20b00
commit 057bf36575
2 changed files with 61 additions and 2 deletions
+53
View File
@@ -3312,6 +3312,59 @@ mod test {
assert!(!cancel.is_cancelled());
}
#[test]
fn list_path_forward_past_is_idempotent_for_same_marker() {
let mut first_page = sorted_entries(&["obj-0001", "obj-0002", "obj-0003", "obj-0004"]);
first_page.forward_past(Some("obj-0002".to_string()));
let first_page_names = first_page
.entries()
.into_iter()
.map(|entry| entry.name.clone())
.collect::<Vec<_>>();
let mut second_page = sorted_entries(&["obj-0001", "obj-0002", "obj-0003", "obj-0004"]);
second_page.forward_past(Some("obj-0002".to_string()));
let second_page_names = second_page
.entries()
.into_iter()
.map(|entry| entry.name.clone())
.collect::<Vec<_>>();
assert_eq!(first_page_names, second_page_names);
assert_eq!(first_page_names, vec!["obj-0003".to_string(), "obj-0004".to_string()]);
}
#[test]
fn list_path_parse_marker_replay_still_stable() {
let marker = "photos/2026/image.jpg[rustfs_cache:v1,id:list-cache-id,p:3,s:7]".to_string();
let mut parsed = ListPathOptions {
marker: Some(marker),
..Default::default()
};
parsed.parse_marker();
assert_eq!(parsed.marker.as_deref(), Some("photos/2026/image.jpg"));
assert_eq!(parsed.id.as_deref(), Some("list-cache-id"));
assert_eq!(parsed.pool_idx, Some(3));
assert_eq!(parsed.set_idx, Some(7));
let base_marker = parsed.marker.clone().expect("marker should parse");
let replay_marker = parsed.encode_marker(base_marker.as_str());
let mut replay = ListPathOptions {
marker: Some(replay_marker),
..Default::default()
};
replay.parse_marker();
assert_eq!(replay.marker.as_deref(), Some("photos/2026/image.jpg"));
assert_eq!(replay.id.as_deref(), Some("list-cache-id"));
assert_eq!(replay.pool_idx, Some(3));
assert_eq!(replay.set_idx, Some(7));
assert_eq!(replay.create, false);
}
#[test]
fn test_max_keys_plus_one_caps_before_lookahead() {
assert_eq!(max_keys_plus_one(999, true), 1000);
+8 -2
View File
@@ -41,6 +41,8 @@ run_unit_checks() {
list_path_gather_results_returns_after_limit_without_waiting_for_input_close
list_path_gather_results_keeps_marker_entry_for_version_marker_listing
list_path_gather_results_skips_marker_entry_by_default
list_path_forward_past_is_idempotent_for_same_marker
list_path_parse_marker_replay_still_stable
normalize_list_quorum_falls_back_to_strict
list_objects_quorum_from_env_defaults_to_optimal
)
@@ -91,8 +93,12 @@ run_live_smoke() {
run_metrics_context() {
log_info "Collecting local metric symbol index for review"
local metric_log="$OUT_DIR/issue-785-metrics-context.log"
rg -n "record_stage_duration\(\"store_list_objects_|record_stage_duration\(\"sets_list_objects_|record_stage_duration\(\"set_disks_list_objects_" "$PROJECT_ROOT/crates/ecstore/src/store/list_objects.rs" > "$metric_log"
log_info "Metric context saved: $metric_log"
if rg -n "record_stage_duration\(" "$PROJECT_ROOT/crates/ecstore/src/store/list_objects.rs" > "$metric_log"; then
log_info "Metric context saved: $metric_log"
else
log_error "No metric stage context found"
return 1
fi
}
parse_args() {