Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions .claude/skills/integration-testing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Integration Testing

## CRITICAL: Kill Running Processes Before Testing

**ALWAYS kill any running ad4m-executor processes before starting integration tests in `tests/js`.**

### Before Running Integration Tests

```bash
# Kill any existing ad4m-executor processes
killall -9 ad4m-executor

# Then run your integration tests
cd tests/js
npm test # or your specific test command
```

## Common Issue: Hanging Tests

**If integration tests hang or appear stuck:**

1. **Most likely cause**: An ad4m-executor process is already running
2. **Solution**:
```bash
killall -9 ad4m-executor
```
3. Then restart the tests

## Why This Happens

- Integration tests spawn their own ad4m-executor instances
- If a previous instance is still running, it can:
- Block ports that tests need
- Interfere with database access
- Cause tests to hang waiting for responses
- Lead to unpredictable test failures

## Best Practices

1. **Always run `killall -9 ad4m-executor` before starting integration tests**
2. **If tests hang**, immediately suspect a running process and kill it
3. **After debugging/manual testing**, remember to kill processes before running automated tests
4. Consider adding a cleanup script that runs before tests:
```bash
# cleanup-before-test.sh
#!/bin/bash
killall -9 ad4m-executor 2>/dev/null || true
echo "Cleaned up any existing ad4m-executor processes"
```

## Related Files

- Integration tests: `tests/js/`
- Executor binary: Built by cargo, typically in `target/release/ad4m-executor` or `target/debug/ad4m-executor`
26 changes: 26 additions & 0 deletions .claude/skills/rust-executor-testing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Rust Executor Testing

## How to Run Tests

The rust-executor tests MUST be run with one of these methods:

```bash
# Recommended: Using pnpm (runs with proper configuration)
pnpm test

# Alternative: Using cargo directly with required flags
cargo test --release -- --test-threads=1
```

**IMPORTANT**: Do NOT run `cargo test` without these flags. The tests require:
- `--release` mode for proper performance
- `--test-threads=1` to avoid race conditions between tests

## Why These Flags Are Required

- **`--release`**: Some tests involve heavy computations or time-sensitive operations that only work correctly in release mode
- **`--test-threads=1`**: The tests share global state and must run sequentially to avoid conflicts

## Common Test Failures

If tests fail when run with plain `cargo test`, try running with the proper flags above.
41 changes: 28 additions & 13 deletions rust-executor/src/perspectives/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,29 +37,39 @@ pub fn initialize_from_db() {
.expect("Ad4mDb not initialized")
.get_all_perspectives()
.expect("Couldn't get perspectives from db");
let mut perspectives = PERSPECTIVES.write().unwrap();

for handle in handles {
let p = PerspectiveInstance::new(handle.clone(), None);
let handle_clone = handle.clone();

// Sync existing links to SurrealDB before starting background tasks
// This must complete before background tasks start to avoid race conditions
let p_clone = p.clone();
let handle_uuid = handle.uuid.clone();
// Spawn async task to create service and initialize perspective
tokio::spawn(async move {
// First, complete the sync
if let Err(e) = p_clone.sync_existing_links_to_surreal().await {
// Create a per-perspective SurrealDB instance
let surreal_service =
crate::surreal_service::SurrealDBService::new("ad4m", &handle_clone.uuid)
.await
.expect("Failed to create SurrealDB service for perspective");

let p = PerspectiveInstance::new(handle_clone.clone(), None, surreal_service);

// Store the perspective
{
let mut perspectives = PERSPECTIVES.write().unwrap();
perspectives.insert(handle_clone.uuid.clone(), RwLock::new(p.clone()));
}

// Sync existing links to SurrealDB before starting background tasks
// This must complete before background tasks start to avoid race conditions
if let Err(e) = p.sync_existing_links_to_surreal().await {
log::warn!(
"Failed to sync existing links to SurrealDB for perspective {}: {:?}",
handle_uuid,
handle_clone.uuid,
e
);
}

// Only start background tasks after sync completes
tokio::spawn(p_clone.start_background_tasks());
tokio::spawn(p.start_background_tasks());
});

perspectives.insert(handle.uuid.clone(), RwLock::new(p));
}
}

Expand All @@ -82,7 +92,12 @@ pub async fn add_perspective(
.add_perspective(&handle)
.map_err(|e| e.to_string())?;

let p = PerspectiveInstance::new(handle.clone(), created_from_join);
// Create a per-perspective SurrealDB instance
let surreal_service = crate::surreal_service::SurrealDBService::new("ad4m", &handle.uuid)
.await
.expect("Failed to create SurrealDB service for perspective");

let p = PerspectiveInstance::new(handle.clone(), created_from_join, surreal_service);
tokio::spawn(p.clone().start_background_tasks());

{
Expand Down
Loading