Files
spacedrive/core/tests/file_structure_test.rs
Jamie Pine c3d602af5a Refactor CI workflow and update test configurations
- Removed the setup step for native dependencies in the CI workflow to streamline the build process.
- Updated the `copy_action_test` to include conflict resolution options for better handling of file conflicts.
- Enhanced metadata handling in `entry_move_integrity_test` to include job policies.
- Added metadata to event handling in `file_structure_test` for improved context during file operations.
- Updated service configuration in `file_sync_simple_test` and `file_sync_test` to use `fs_watcher_enabled` and included default logging settings.
- Deleted the outdated README.md from the tests directory to reduce clutter and improve documentation focus.
2025-12-18 03:09:27 -08:00

241 lines
6.2 KiB
Rust
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! Test to map exact File structure at each indexing phase
use sd_core::{
infra::{
db::entities,
event::{Event, EventSubscriber},
},
location::{create_location, IndexMode, LocationCreateArgs},
Core,
};
use sea_orm::{ActiveModelTrait, ColumnTrait, EntityTrait, QueryFilter};
use std::{sync::Arc, time::Duration};
use tempfile::TempDir;
#[tokio::test]
async fn map_file_structure_per_phase() -> Result<(), Box<dyn std::error::Error>> {
tracing_subscriber::fmt::init();
eprintln!("\nMAPPING FILE STRUCTURE AT EACH PHASE\n");
eprintln!("{}", "=".repeat(80));
// Setup
let temp_dir = TempDir::new()?;
let core = Core::new(temp_dir.path().to_path_buf()).await?;
let library = core
.libraries
.create_library("Phase Test", None, core.context.clone())
.await?;
// Create test files
let test_dir = temp_dir.path().join("test");
tokio::fs::create_dir_all(&test_dir).await?;
for i in 1..=3 {
tokio::fs::write(
test_dir.join(format!("file{}.txt", i)),
format!("Content {}", i),
)
.await?;
}
eprintln!("Created test directory with 3 files\n");
// Register device
let db = library.db();
let device = core.device.to_device()?;
let device_record = match entities::device::Entity::find()
.filter(entities::device::Column::Uuid.eq(device.id))
.one(db.conn())
.await?
{
Some(existing) => existing,
None => {
let device_model: entities::device::ActiveModel = device.into();
device_model.insert(db.conn()).await?
}
};
// Collect events
let events_collected = Arc::new(tokio::sync::Mutex::new(Vec::new()));
let events_clone = events_collected.clone();
let mut subscriber = core.events.subscribe();
tokio::spawn(async move {
while let Ok(event) = subscriber.recv().await {
events_clone.lock().await.push(event);
}
});
tokio::time::sleep(Duration::from_millis(100)).await;
eprintln!("Starting indexing...\n");
let location_args = LocationCreateArgs {
path: test_dir.clone(),
name: Some("Test".to_string()),
index_mode: IndexMode::Content,
};
create_location(
library.clone(),
&core.events,
location_args,
device_record.id,
)
.await?;
// Wait for completion
tokio::time::sleep(Duration::from_secs(5)).await;
// Analyze
let events = events_collected.lock().await;
let mut batch_num = 0;
eprintln!("RESOURCE EVENT FILE STRUCTURES:\n");
for event in events.iter() {
if let Event::ResourceChangedBatch {
resource_type,
resources,
metadata,
} = event
{
if resource_type == "file" {
batch_num += 1;
if let Some(files) = resources.as_array() {
eprintln!("\n{}", "=".repeat(80));
eprintln!("BATCH #{} ({} files)", batch_num, files.len());
eprintln!("{}", "=".repeat(80));
if let Some(file) = files.first() {
eprintln!("\nSample File JSON:");
eprintln!("{}\n", serde_json::to_string_pretty(&file).unwrap());
eprintln!("Key Fields:");
eprintln!(
" id: {}",
file.get("id").unwrap_or(&serde_json::Value::Null)
);
eprintln!(
" name: {}",
file.get("name").unwrap_or(&serde_json::Value::Null)
);
if let Some(sd_path) = file.get("sd_path") {
eprintln!("\n sd_path:");
if let Some(phys) = sd_path.get("Physical") {
eprintln!(" Type: Physical");
eprintln!(
" device_slug: {}",
phys.get("device_slug").unwrap_or(&serde_json::Value::Null)
);
eprintln!(
" path: {}",
phys.get("path").unwrap_or(&serde_json::Value::Null)
);
} else if let Some(content) = sd_path.get("Content") {
eprintln!(" Type: Content");
eprintln!(
" content_id: {}",
content
.get("content_id")
.unwrap_or(&serde_json::Value::Null)
);
} else if let Some(cloud) = sd_path.get("Cloud") {
eprintln!(" Type: Cloud");
eprintln!(
" service: {}",
cloud.get("service").unwrap_or(&serde_json::Value::Null)
);
eprintln!(
" path: {}",
cloud.get("path").unwrap_or(&serde_json::Value::Null)
);
}
}
eprintln!(
"\n content_identity: {}",
if file
.get("content_identity")
.and_then(|v| v.as_object())
.is_some()
{
"PRESENT"
} else {
"NULL"
}
);
if let Some(ci) = file.get("content_identity") {
if let Some(ci_obj) = ci.as_object() {
eprintln!(
" uuid: {}",
ci_obj.get("uuid").unwrap_or(&serde_json::Value::Null)
);
eprintln!(
" content_hash: {}",
ci_obj
.get("content_hash")
.unwrap_or(&serde_json::Value::Null)
);
}
}
eprintln!(
"\n sidecars: {} items",
file.get("sidecars")
.and_then(|s| s.as_array())
.map(|a| a.len())
.unwrap_or(0)
);
}
}
}
}
}
eprintln!("\n{}", "=".repeat(80));
eprintln!("EVENT SUMMARY: {} file batches emitted", batch_num);
eprintln!("{}", "=".repeat(80));
// Now manually check what entries look like in database
eprintln!("\n\nCHECKING DATABASE ENTRIES:\n");
eprintln!("{}", "=".repeat(80));
use sd_core::infra::db::entities::entry;
use sea_orm::EntityTrait;
let db_entries = entry::Entity::find().all(db.conn()).await?;
eprintln!("Database has {} entries\n", db_entries.len());
for entry in db_entries.iter().take(3) {
if entry.kind == 0 {
// File
eprintln!("Entry ID: {}", entry.id);
eprintln!(" UUID: {:?}", entry.uuid);
eprintln!(" Name: {}", entry.name);
eprintln!(" content_id (db FK): {:?}", entry.content_id);
eprintln!();
}
}
eprintln!("{}", "=".repeat(80));
eprintln!("KEY INSIGHT:");
eprintln!("{}", "=".repeat(80));
eprintln!("\nEvent files use:");
eprintln!(" - id = entry.uuid");
eprintln!(" - sd_path = Content {{content_id}}");
eprintln!("\nDirectory query SHOULD use:");
eprintln!(" - id = entry.uuid (SAME)");
eprintln!(" - sd_path = Physical {{path}} (DIFFERENT)");
eprintln!("\n If IDs match, normalized cache should work!");
eprintln!(" If IDs don't match, we have a bigger problem.");
eprintln!();
Ok(())
}