- Added a new `file_count` column to the `content_kinds` table to track the number of content identities for each kind, improving statistics calculation efficiency. - Implemented a migration script to add the `file_count` column and ensure backward compatibility. - Updated the `Library` struct to include a method for updating content kind counts based on existing content identities. - Introduced a new query for retrieving content kind statistics, including file counts, to facilitate better data analysis and reporting. - Refactored related components to support the new statistics functionality, enhancing overall data integrity and performance.
Test Helpers
Shared utilities for integration tests to reduce duplication and improve maintainability.
Modules
indexing_harness.rs - Indexing Test Utilities
Provides a comprehensive test harness for indexing integration tests, eliminating boilerplate and making it easy to test change detection.
Key Components:
IndexingHarnessBuilder
Builder for creating pre-configured indexing test environments.
let harness = IndexingHarnessBuilder::new("my_test")
.build()
.await?;
Automatically handles:
- Creating test directories
- Initializing tracing
- Setting up core and library
- Registering device
IndexingHarness
The test harness with convenient methods:
// Create test location
let location = harness.create_test_location("my_location").await?;
location.write_file("test.txt", "content").await?;
location.create_filtered_files().await?;
// Index the location
let handle = location.index("My Location", IndexMode::Deep).await?;
// Verify results
assert_eq!(handle.count_files().await?, 1);
handle.verify_no_filtered_entries().await?;
handle.verify_inode_tracking().await?;
// Make changes and re-index
handle.write_file("new.txt", "new").await?;
handle.modify_file("test.txt", "updated").await?;
handle.delete_file("old.txt").await?;
handle.move_file("from.txt", "to.txt").await?;
handle.reindex().await?;
Helper Classes
TestLocation - Builder for test locations:
write_file()- Create filescreate_dir()- Create directoriescreate_filtered_files()- Create files that should be filteredindex()- Index the location
LocationHandle - Handle to indexed location:
count_files(),count_directories(),count_entries()get_all_entries()- Get all indexed entriesverify_no_filtered_entries()- Assert filtering workedverify_inode_tracking()- Assert inodes are trackedwrite_file(),modify_file(),delete_file(),move_file()- Make changesreindex()- Re-index and wait for completion
sync_harness.rs - Two-Device Sync Test Utilities
Provides a comprehensive test harness for sync integration tests that eliminates ~200 lines of boilerplate per test.
Key Components:
TwoDeviceHarnessBuilder
Builder for creating pre-configured two-device test environments.
let harness = TwoDeviceHarnessBuilder::new("my_test")
.await?
.collect_events(true) // Optional: collect event logs
.collect_sync_events(true) // Optional: collect sync events
.start_in_ready_state(true) // Optional: skip backfill (default)
.build()
.await?;
Automatically handles:
- Creating test directories
- Initializing tracing to files
- Setting up cores and libraries
- Registering pre-paired devices
- Configuring mock transports
- Starting sync services
- Setting sync state
TwoDeviceHarness
The resulting test harness with convenient methods:
// Add locations
harness.add_and_index_location_alice("/path", "Name").await?;
harness.add_and_index_location_bob("/path", "Name").await?;
// Wait for sync (sophisticated algorithm)
harness.wait_for_sync(Duration::from_secs(60)).await?;
// Capture comprehensive snapshot
harness.capture_snapshot("final_state").await?;
// Access all internals
harness.library_alice;
harness.device_alice_id;
harness.transport_alice;
Helper Functions
Configuration:
TestConfigBuilder- Build test configs with custom filtersinit_test_tracing()- Standard tracing setup
Device Setup:
register_device()- Register a device in a libraryset_all_devices_synced()- Mark devices as synced (prevent auto-backfill)
Waiting:
wait_for_indexing()- Wait for indexing job completionwait_for_sync()- Sophisticated sync completion detection
Operations:
add_and_index_location()- Create and index a location
Snapshots:
create_snapshot_dir()- Create timestamped snapshot directorySnapshotCapture- Utilities for capturing databases, logs, events
sync_transport.rs - Mock Network Transport
Mock implementation of NetworkTransport for testing sync without real networking.
Key Features:
- Immediate message delivery (like production)
- Request/response handling for backfill
- Device blocking/unblocking (simulate offline)
- Message history tracking
- Queue inspection
Usage:
// Single device
let transport = MockTransport::new_single(device_id);
// Paired devices (most common)
let (transport_a, transport_b) = MockTransport::new_pair(device_a, device_b);
// Block/unblock
transport.block_device(device_id).await;
transport.unblock_device(device_id).await;
// Inspect
let queue_size = transport.queue_size(device_id).await;
let total = transport.total_message_count().await;
test_volumes.rs - Volume Test Utilities
Helper functions for creating mock volumes in tests (used by sync_backfill_test.rs).
Benefits of Using Shared Utilities
Code Reduction
- ~200 lines of boilerplate eliminated per test
- ~2887 lines saved across 6 sync tests (65% reduction)
- One source of truth for test patterns
Consistency
- Same tracing setup everywhere
- Same config creation
- Same device registration
- Same snapshot format
- Same waiting algorithms
Maintainability
- Fix bugs in one place
- Add features once, benefit everywhere
- Clear upgrade path for tests
- Easier code reviews
Reliability
- Battle-tested algorithms
- Sophisticated sync detection
- Comprehensive snapshot capture
- Proper cleanup
Migration Path
To migrate an existing sync test:
- Replace custom harness with
TwoDeviceHarnessBuilder - Remove duplicated code (config, registration, waiting)
- Use shared methods (add_and_index_location_alice/bob)
- Test thoroughly to ensure behavior unchanged
See REFACTORING_EXAMPLE.md for a detailed before/after comparison.
When NOT to Use the Shared Harness
The shared harness is optimized for two-device real-time sync tests. Consider custom setup for:
- Single-device tests (use
MockTransport::new_single()) - N-device tests (N > 2)
- Very specialized scenarios (custom transport behavior)
- Non-sync tests (obviously!)
Even in these cases, you can still use the individual helper functions.
Writing New Tests
For new two-device sync tests:
use helpers::TwoDeviceHarnessBuilder;
#[tokio::test]
async fn test_my_new_scenario() -> anyhow::Result<()> {
let harness = TwoDeviceHarnessBuilder::new("my_scenario")
.await?
.build()
.await?;
// Your test logic here
harness.capture_snapshot("final").await?;
Ok(())
}
For other test types: Use individual helper functions as needed.
Contributing
When adding new shared utilities:
- Add to
sync_harness.rsif it's sync-specific - Add to appropriate module otherwise
- Update this README with usage examples
- Update
SYNC_HARNESS_USAGE.mdif user-facing - Export from
mod.rs
Keep utilities:
- Generic - Useful for multiple tests
- Well-documented - Clear purpose and usage
- Battle-tested - Used by actual tests
- Simple - Easy to understand and maintain
Questions?
- See
SYNC_HARNESS_USAGE.mdfor detailed usage examples - See
REFACTORING_EXAMPLE.mdfor migration examples - See
SYNC_TESTS.mdfor test suite overview - Check the source code - it's well-commented!