ci(windows): skip IO-heavy tests that aren't OS-specific (#9188)

* ci(windows): skip IO-heavy tests that aren't OS-specific

On the Windows CI runner, several tests are 3-25x slower than on Ubuntu
purely due to slow filesystem IO. These tests exercise platform-agnostic
logic (optimizer, snapshot, WAL recovery, dedup, deferred points) and
are fully covered by the Linux and macOS jobs.

Mark them with `#[cfg_attr(target_os = "windows", ignore = "...")]` so:
- Windows CI skips them and finishes faster.
- They're still listed and runnable via `cargo test -- --ignored`
  on Windows for local debugging.

Based on JUnit timings from CI run 26462785436 (PR #8827), this should
save ~5 minutes wall-clock on the Windows job, taking it closer to the
~13min Ubuntu and ~9min macOS jobs (currently 20m24s).

Tests affected:
- lib/wal: check_wal, check_last_index, check_clear, check_reopen,
  check_truncate, check_prefix_truncate, test_prefix_truncate_parametric
- lib/edge/optimize: full tests module
- lib/segment deferred-point tests: read_operations,
  dense_segment_combinations, sparse, facets
- lib/collection: snapshot_test, points_dedup, wal_recovery,
  collection_test::test_ordered_read_api, snapshot_recovery_test

Co-authored-by: Cursor <cursoragent@cursor.com>

* revert(ci/windows): keep WAL and WAL-recovery tests on Windows

Reviewer correctly pointed out that WAL is mmap-backed and has
substantial Windows-specific code paths:

- Different segment allocation (fs4 vs rustix::ftruncate)
- Windows-specific delete_windows() with mmap-drop + retry loop
- Windows-specific sync_all() because directory fsync is unavailable
- Windows-specific lock proxy file (directories aren't lockable)

So those tests genuinely need Windows coverage. Reverted skips for:
- lib/wal/src/lib.rs: all check_* tests and test_prefix_truncate_parametric
- lib/collection/src/tests/wal_recovery_test.rs: all three tests

Still skipped on Windows (no OS-specific code in their production paths):
- lib/edge/optimize.rs (no cfg(windows) in source)
- lib/segment deferred-point tests (segment/ has no cfg(windows))
- lib/collection snapshot/dedup tests (collection/ has no cfg(windows))
- lib/collection integration snapshot_recovery + ordered_read_api

Co-authored-by: Cursor <cursoragent@cursor.com>

* revert(ci/windows): keep collection integration and snapshot_test

Per reviewer request, keep running these on Windows:
- lib/collection/tests/integration/* (snapshot_recovery_test,
  collection_test::test_ordered_read_api)
- lib/collection/src/tests/snapshot_test.rs

These exercise higher-level collection/snapshot behavior that benefits
from cross-platform validation.

Remaining Windows skips (production code has no cfg(windows) branches):
- lib/edge/src/optimize.rs: 14 optimizer tests
- lib/segment/src/segment/tests/mod.rs: 4 deferred-point tests
- lib/collection/src/tests/points_dedup.rs: 2 dedup tests

Co-authored-by: Cursor <cursoragent@cursor.com>

* ci(windows): also skip HNSW/quantization integration tests

Per reviewer, also skip these segment integration test modules on Windows:
- hnsw_quantized_search_test::* (25 tests)
- multivector_filtrable_hnsw_test::* (rstest cases)
- multivector_quantization_test::* (rstest cases)
- byte_storage_quantization_test::* (rstest cases)
- payload_index_test::test_struct_payload_index_nested_fields

These exercise pure HNSW/quantization correctness on top of standard
segment IO that is already covered by tests we keep running on Windows.

Adds ~930s of sequential time to the Windows skip list, bringing the
expected wall-clock saving from ~3 min to ~8-10 min.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
qdrant-cloud-bot
2026-05-27 13:16:59 +02:00
committed by timvisee
parent 3cee4434bf
commit 0e37dfd290
8 changed files with 53 additions and 0 deletions

View File

@@ -220,6 +220,7 @@ async fn test_scroll_dedup() {
}
#[tokio::test(flavor = "multi_thread")]
#[cfg_attr(target_os = "windows", ignore = "slow on Windows, not OS-specific")]
async fn test_retrieve_dedup() {
let collection = fixture().await;
@@ -252,6 +253,7 @@ async fn test_retrieve_dedup() {
}
#[tokio::test(flavor = "multi_thread")]
#[cfg_attr(target_os = "windows", ignore = "slow on Windows, not OS-specific")]
async fn test_search_dedup() {
let collection = fixture().await;

View File

@@ -131,6 +131,10 @@ impl EdgeShard {
}
}
// Tests in this module exercise platform-agnostic optimizer logic but run
// 5-25x slower on Windows due to filesystem IO. They are marked
// `#[ignore]` on Windows; Linux and macOS jobs provide full coverage.
// To execute them locally on Windows, run with `cargo test -- --ignored`.
#[cfg(test)]
mod tests {
#![expect(clippy::wildcard_enum_match_arm, reason = "test code")]
@@ -154,6 +158,7 @@ mod tests {
const VECTOR_NAME: &str = "edge-test-vector";
#[cfg_attr(target_os = "windows", ignore = "slow on Windows, not OS-specific")]
#[test]
fn does_not_force_merge_all_segments_into_one() {
let dir = tempfile::Builder::new()
@@ -179,6 +184,7 @@ mod tests {
assert_points_retrievable_with_vectors(&reopened, &[1]);
}
#[cfg_attr(target_os = "windows", ignore = "slow on Windows, not OS-specific")]
#[test]
fn vacuum_optimizer_runs_in_blocking_mode_until_idle() {
let dir = tempfile::Builder::new()
@@ -214,6 +220,7 @@ mod tests {
/// A fresh shard with a single small segment and no deletions should not
/// trigger any optimizer.
#[cfg_attr(target_os = "windows", ignore = "slow on Windows, not OS-specific")]
#[test]
fn no_op_on_single_segment_without_deletions() {
let dir = tempfile::Builder::new()
@@ -237,6 +244,7 @@ mod tests {
}
/// An empty shard (no data at all) should be a no-op.
#[cfg_attr(target_os = "windows", ignore = "slow on Windows, not OS-specific")]
#[test]
fn no_op_on_empty_shard() {
let dir = tempfile::Builder::new()
@@ -253,6 +261,7 @@ mod tests {
/// Creating more segments than `default_segment_number` should trigger
/// the merge optimizer to reduce the segment count.
#[cfg_attr(target_os = "windows", ignore = "slow on Windows, not OS-specific")]
#[test]
fn merge_reduces_excess_segments() {
let target_count = default_segment_number() + 6;
@@ -298,6 +307,7 @@ mod tests {
}
/// After a merge optimization, a second run should be a no-op.
#[cfg_attr(target_os = "windows", ignore = "slow on Windows, not OS-specific")]
#[test]
fn optimization_is_idempotent_after_merge() {
let target_count = default_segment_number() + 6;
@@ -333,6 +343,7 @@ mod tests {
/// Deleting less than 20% of points (below the vacuum threshold)
/// should NOT trigger the vacuum optimizer.
#[cfg_attr(target_os = "windows", ignore = "slow on Windows, not OS-specific")]
#[test]
fn vacuum_below_threshold_is_noop() {
let dir = tempfile::Builder::new()
@@ -365,6 +376,7 @@ mod tests {
/// Deleting below the minimum vector count (< 1000 total points)
/// should NOT trigger the vacuum optimizer even with a high deletion ratio.
#[cfg_attr(target_os = "windows", ignore = "slow on Windows, not OS-specific")]
#[test]
fn vacuum_below_min_vector_count_is_noop() {
let dir = tempfile::Builder::new()
@@ -398,6 +410,7 @@ mod tests {
/// After vacuum optimization, all non-deleted points should still be
/// retrievable and deleted points should be gone.
#[cfg_attr(target_os = "windows", ignore = "slow on Windows, not OS-specific")]
#[test]
fn vacuum_preserves_remaining_points() {
let dir = tempfile::Builder::new()
@@ -454,6 +467,7 @@ mod tests {
/// resulting segment has 0 points, `optimize_all_segments_blocking`
/// reports `false` (zero points processed). The shard should still be
/// valid and accept new data afterward.
#[cfg_attr(target_os = "windows", ignore = "slow on Windows, not OS-specific")]
#[test]
fn vacuum_after_all_points_deleted() {
let dir = tempfile::Builder::new()
@@ -504,6 +518,7 @@ mod tests {
/// Vacuum at exactly the threshold boundary (20% deleted, 1000 total).
/// The threshold check is strictly greater-than, so exactly 20% should
/// NOT trigger vacuum.
#[cfg_attr(target_os = "windows", ignore = "slow on Windows, not OS-specific")]
#[test]
fn vacuum_at_exact_threshold_boundary_is_noop() {
let dir = tempfile::Builder::new()
@@ -534,6 +549,7 @@ mod tests {
}
/// Just above the vacuum threshold should trigger optimization.
#[cfg_attr(target_os = "windows", ignore = "slow on Windows, not OS-specific")]
#[test]
fn vacuum_just_above_threshold_triggers() {
let dir = tempfile::Builder::new()
@@ -566,6 +582,7 @@ mod tests {
/// When there are excess segments AND some have high deletion ratios,
/// optimization should handle both (merge + vacuum).
#[cfg_attr(target_os = "windows", ignore = "slow on Windows, not OS-specific")]
#[test]
fn merge_and_vacuum_cooperate() {
let target_count = default_segment_number() + 6;
@@ -626,6 +643,7 @@ mod tests {
}
/// Optimized shard should survive a reload and still serve correct data.
#[cfg_attr(target_os = "windows", ignore = "slow on Windows, not OS-specific")]
#[test]
fn data_survives_optimize_and_reload() {
let dir = tempfile::Builder::new()

View File

@@ -1017,6 +1017,7 @@ fn test_dense_deferred_points() {
}
#[test]
#[cfg_attr(target_os = "windows", ignore = "slow on Windows, not OS-specific")]
fn test_dense_deferred_point_segment_combinations() {
init_logger();
@@ -1085,6 +1086,7 @@ fn test_deferred_point_estimation_with_filter() {
}
#[test]
#[cfg_attr(target_os = "windows", ignore = "slow on Windows, not OS-specific")]
fn test_deferred_point_read_operations() {
init_logger();
let hw_counter = HardwareCounterCell::new();
@@ -1196,6 +1198,7 @@ fn test_deferred_point_read_operations() {
}
#[test]
#[cfg_attr(target_os = "windows", ignore = "slow on Windows, not OS-specific")]
fn test_deferred_point_sparse() {
init_logger();
@@ -1277,6 +1280,7 @@ fn test_deferred_point_sparse() {
}
#[test]
#[cfg_attr(target_os = "windows", ignore = "slow on Windows, not OS-specific")]
fn test_deferred_point_facets() {
init_logger();
let hw_counter = HardwareCounterCell::new();

View File

@@ -72,6 +72,7 @@ fn sames_count(a: &[Vec<ScoredPointOffset>], b: &[Vec<ScoredPointOffset>]) -> us
.count()
}
#[cfg_attr(target_os = "windows", ignore = "slow on Windows, not OS-specific")]
#[rstest]
#[case::nearest_binary_dot(
QueryVariant::Nearest,

View File

@@ -352,6 +352,7 @@ fn check_rescoring(
}
}
#[cfg_attr(target_os = "windows", ignore = "slow on Windows, not OS-specific")]
#[test]
fn hnsw_quantized_search_cosine_test() {
hnsw_quantized_search_test(
@@ -369,6 +370,7 @@ fn hnsw_quantized_search_cosine_test() {
);
}
#[cfg_attr(target_os = "windows", ignore = "slow on Windows, not OS-specific")]
#[test]
fn hnsw_quantized_search_euclid_test() {
hnsw_quantized_search_test(
@@ -386,6 +388,7 @@ fn hnsw_quantized_search_euclid_test() {
);
}
#[cfg_attr(target_os = "windows", ignore = "slow on Windows, not OS-specific")]
#[test]
fn hnsw_quantized_search_manhattan_test() {
hnsw_quantized_search_test(
@@ -403,6 +406,7 @@ fn hnsw_quantized_search_manhattan_test() {
);
}
#[cfg_attr(target_os = "windows", ignore = "slow on Windows, not OS-specific")]
#[test]
fn hnsw_product_quantization_cosine_test() {
hnsw_quantized_search_test(
@@ -419,6 +423,7 @@ fn hnsw_product_quantization_cosine_test() {
);
}
#[cfg_attr(target_os = "windows", ignore = "slow on Windows, not OS-specific")]
#[test]
fn hnsw_product_quantization_euclid_test() {
hnsw_quantized_search_test(
@@ -435,6 +440,7 @@ fn hnsw_product_quantization_euclid_test() {
);
}
#[cfg_attr(target_os = "windows", ignore = "slow on Windows, not OS-specific")]
#[test]
fn hnsw_product_quantization_manhattan_test() {
hnsw_quantized_search_test(
@@ -451,6 +457,7 @@ fn hnsw_product_quantization_manhattan_test() {
);
}
#[cfg_attr(target_os = "windows", ignore = "slow on Windows, not OS-specific")]
#[test]
fn hnsw_turbo_quantization_cosine_test() {
// Bits4 has enough headroom to use the standard helper (40% recall floor),
@@ -471,6 +478,7 @@ fn hnsw_turbo_quantization_cosine_test() {
);
}
#[cfg_attr(target_os = "windows", ignore = "slow on Windows, not OS-specific")]
#[test]
fn hnsw_turbo_quantization_dot_test() {
// See `hnsw_turbo_quantization_cosine_test` for rationale.
@@ -489,6 +497,7 @@ fn hnsw_turbo_quantization_dot_test() {
);
}
#[cfg_attr(target_os = "windows", ignore = "slow on Windows, not OS-specific")]
#[test]
fn hnsw_turbo_quantization_cosine_larger_test() {
// See `hnsw_turbo_quantization_cosine_test` for rationale.
@@ -507,6 +516,7 @@ fn hnsw_turbo_quantization_cosine_larger_test() {
);
}
#[cfg_attr(target_os = "windows", ignore = "slow on Windows, not OS-specific")]
#[test]
fn hnsw_turbo_quantization_cosine_bits2_test() {
// Bits2 clears the 40% recall floor but with thin margin — `deterministic`
@@ -527,6 +537,7 @@ fn hnsw_turbo_quantization_cosine_bits2_test() {
);
}
#[cfg_attr(target_os = "windows", ignore = "slow on Windows, not OS-specific")]
#[test]
fn hnsw_turbo_quantization_dot_bits2_test() {
// See `hnsw_turbo_quantization_cosine_bits2_test` for rationale.
@@ -545,6 +556,7 @@ fn hnsw_turbo_quantization_dot_bits2_test() {
);
}
#[cfg_attr(target_os = "windows", ignore = "slow on Windows, not OS-specific")]
#[test]
fn hnsw_turbo_quantization_cosine_larger_bits2_test() {
// See `hnsw_turbo_quantization_cosine_bits2_test` for rationale.
@@ -568,6 +580,7 @@ fn hnsw_turbo_quantization_cosine_larger_bits2_test() {
// they don't reliably clear the standard helper's 40% recall floor
// and would be flaky-to-failing under this shape.
#[cfg_attr(target_os = "windows", ignore = "slow on Windows, not OS-specific")]
#[test]
fn hnsw_turbo_quantization_euclid_test() {
hnsw_quantized_search_test(
@@ -585,6 +598,7 @@ fn hnsw_turbo_quantization_euclid_test() {
);
}
#[cfg_attr(target_os = "windows", ignore = "slow on Windows, not OS-specific")]
#[test]
fn hnsw_turbo_quantization_manhattan_test() {
hnsw_quantized_search_test(
@@ -602,6 +616,7 @@ fn hnsw_turbo_quantization_manhattan_test() {
);
}
#[cfg_attr(target_os = "windows", ignore = "slow on Windows, not OS-specific")]
#[test]
fn hnsw_turbo_quantization_euclid_bits2_test() {
// See `hnsw_turbo_quantization_cosine_bits2_test` for rationale.
@@ -620,6 +635,7 @@ fn hnsw_turbo_quantization_euclid_bits2_test() {
);
}
#[cfg_attr(target_os = "windows", ignore = "slow on Windows, not OS-specific")]
#[test]
fn hnsw_turbo_quantization_manhattan_bits2_test() {
// See `hnsw_turbo_quantization_cosine_bits2_test` for rationale.
@@ -887,6 +903,7 @@ fn build_quantized_hnsw_for_compare(
(segment, hnsw_index, (segment_dir, hnsw_dir, quantized_dir))
}
#[cfg_attr(target_os = "windows", ignore = "slow on Windows, not OS-specific")]
#[test]
fn hnsw_turbo_quantization_cosine_bits1_test() {
hnsw_quantized_low_bit_compare_test(
@@ -898,6 +915,7 @@ fn hnsw_turbo_quantization_cosine_bits1_test() {
);
}
#[cfg_attr(target_os = "windows", ignore = "slow on Windows, not OS-specific")]
#[test]
fn hnsw_turbo_quantization_dot_bits1_test() {
hnsw_quantized_low_bit_compare_test(
@@ -909,6 +927,7 @@ fn hnsw_turbo_quantization_dot_bits1_test() {
);
}
#[cfg_attr(target_os = "windows", ignore = "slow on Windows, not OS-specific")]
#[test]
fn hnsw_turbo_quantization_euclid_bits1_test() {
hnsw_quantized_low_bit_compare_test(
@@ -920,6 +939,7 @@ fn hnsw_turbo_quantization_euclid_bits1_test() {
);
}
#[cfg_attr(target_os = "windows", ignore = "slow on Windows, not OS-specific")]
#[test]
fn hnsw_turbo_quantization_manhattan_bits1_test() {
hnsw_quantized_low_bit_compare_test(
@@ -931,6 +951,7 @@ fn hnsw_turbo_quantization_manhattan_bits1_test() {
);
}
#[cfg_attr(target_os = "windows", ignore = "slow on Windows, not OS-specific")]
#[test]
fn hnsw_turbo_quantization_cosine_bits1_5_test() {
hnsw_quantized_low_bit_compare_test(
@@ -942,6 +963,7 @@ fn hnsw_turbo_quantization_cosine_bits1_5_test() {
);
}
#[cfg_attr(target_os = "windows", ignore = "slow on Windows, not OS-specific")]
#[test]
fn hnsw_turbo_quantization_dot_bits1_5_test() {
hnsw_quantized_low_bit_compare_test(
@@ -953,6 +975,7 @@ fn hnsw_turbo_quantization_dot_bits1_5_test() {
);
}
#[cfg_attr(target_os = "windows", ignore = "slow on Windows, not OS-specific")]
#[test]
fn hnsw_turbo_quantization_euclid_bits1_5_test() {
hnsw_quantized_low_bit_compare_test(
@@ -964,6 +987,7 @@ fn hnsw_turbo_quantization_euclid_bits1_5_test() {
);
}
#[cfg_attr(target_os = "windows", ignore = "slow on Windows, not OS-specific")]
#[test]
fn hnsw_turbo_quantization_manhattan_bits1_5_test() {
// See `hnsw_turbo_quantization_manhattan_bits1_test` for rationale.
@@ -976,6 +1000,7 @@ fn hnsw_turbo_quantization_manhattan_bits1_5_test() {
);
}
#[cfg_attr(target_os = "windows", ignore = "slow on Windows, not OS-specific")]
#[test]
fn test_build_hnsw_using_quantization() {
let dir = Builder::new().prefix("segment_dir").tempdir().unwrap();

View File

@@ -26,6 +26,7 @@ use segment::vector_storage::VectorStorageRead;
use tempfile::Builder;
/// Check all cases with single vector per multi and several vectors per multi
#[cfg_attr(target_os = "windows", ignore = "slow on Windows, not OS-specific")]
#[rstest]
#[case::nearest_eq(QueryVariant::Nearest, 1, 32, 5)]
#[case::nearest_multi(QueryVariant::Nearest, 3, 64, 20)]

View File

@@ -63,6 +63,7 @@ fn sames_count(a: &[Vec<ScoredPointOffset>], b: &[Vec<ScoredPointOffset>]) -> us
.count()
}
#[cfg_attr(target_os = "windows", ignore = "slow on Windows, not OS-specific")]
#[rstest]
#[case::nearest_binary_dot(
QueryVariant::Nearest,

View File

@@ -1114,6 +1114,7 @@ fn test_struct_payload_geo_polygon_index(test_segments: &TestSegments) -> Result
}
#[test]
#[cfg_attr(target_os = "windows", ignore = "slow on Windows, not OS-specific")]
fn test_struct_payload_index_nested_fields() {
// Compare search with plain and struct indexes
let dir1 = Builder::new().prefix("segment1_dir").tempdir().unwrap();