# MarkBase FUSE POC Test Plan

## Overview

**Objective**: Verify FUSE-T installation, basic functionality, and backend selection before full implementation.

**Scope**: Phase 1 POC verification (Day 1-2)

**Environment**: M4 Mac mini, macOS 26.4.1, NVMe storage

---

## Test Environment Setup

### Hardware Configuration

| Component | Specification |
|-----------|--------------|
| **CPU** | Apple M4, 10 physical cores |
| **RAM** | 16 GB unified memory |
| **Storage** | KIOXIA NVMe 2TB (PCIe) |
| **OS** | macOS 26.4.1 (Sequoia) |
| **Network** | Thunderbolt Ethernet |

### Software Dependencies

```bash
# Required tools
brew install fuse-t                # FUSE-T installation
brew install rustup                # Rust toolchain (already installed)

# Optional test tools
brew install ajadatacalc           # AJA Data Calculator (storage estimation)
```

### AJA System Test Installation

```bash
# Download AJA System Test
curl -L -o ~/Downloads/AJA_System_Test.dmg \
  "https://www.aja.com/en/products/aja-system-test"

# Install
hdiutil attach ~/Downloads/AJA_System_Test.dmg
cp -R /Volumes/AJA\ System\ Test/*.app /Applications/
hdiutil detach /Volumes/AJA\ System\ Test

# Verify installation
ls -la /Applications/AJA\ System\ Test.app
```

---

## Test 1: FUSE-T Installation Verification

### Objective

Verify FUSE-T can be installed and basic mount/unmount operations work.

### Steps

```bash
# Step 1: Install FUSE-T
brew install macos-fuse-t/homebrew-cask/fuse-t

# Step 2: Verify installation
ls -la /usr/local/bin/fuse-t
fuse-t --version

# Step 3: Check NFS server
ls -la /usr/local/bin/nfs-t
nfs-t --version

# Step 4: Verify mount capability
mount | grep fuse  # Should show no existing FUSE mounts
```

### Expected Results

| Check | Expected | Actual | Pass/Fail |
|-------|----------|--------|-----------|
| fuse-t binary exists | `/usr/local/bin/fuse-t` | TBD | TBD |
| fuse-t version | >=1.2.6 | TBD | TBD |
| nfs-t binary exists | `/usr/local/bin/nfs-t` | TBD | TBD |
| No existing FUSE mounts | Empty output | TBD | TBD |

### Failure Handling

**If installation fails:**
1. Check System Settings → Privacy & Security → Network Volumes permission
2. Manual download: https://github.com/macos-fuse-t/fuse-t/releases
3. Install from PKG: `sudo installer -pkg fuse-t-macos-installer-1.2.6.pkg -target /`

---

## Test 2: Hello FUSE POC

### Objective

Create minimal FUSE filesystem to verify mount/unmount works.

### Implementation

```rust
// src/fuse/poc_hello.rs
use fuse::{Filesystem, FileAttr, FileType};
use time::Timespec;
use std::path::Path;

pub struct HelloFs;

impl Filesystem for HelloFs {
    fn lookup(&mut self, _parent: u64, name: &str, reply: fuse::ReplyEntry) {
        if name == "hello.txt" {
            let attr = FileAttr {
                ino: 2,
                size: 13,
                blocks: 0,
                atime: Timespec::new(0, 0),
                mtime: Timespec::new(0, 0),
                ctime: Timespec::new(0, 0),
                crtime: Timespec::new(0, 0),
                kind: FileType::RegularFile,
                perm: 0o644,
                nlink: 1,
                uid: 0,
                gid: 0,
                rdev: 0,
                flags: 0,
            };
            reply.entry(&Timespec::new(0, 0), &attr, 0);
        } else {
            reply.error(libc::ENOENT);
        }
    }
    
    fn getattr(&mut self, ino: u64, reply: fuse::ReplyAttr) {
        match ino {
            1 => {
                // Root directory
                let attr = FileAttr {
                    ino: 1,
                    size: 0,
                    blocks: 0,
                    atime: Timespec::new(0, 0),
                    mtime: Timespec::new(0, 0),
                    ctime: Timespec::new(0, 0),
                    crtime: Timespec::new(0, 0),
                    kind: FileType::Directory,
                    perm: 0o755,
                    nlink: 2,
                    uid: 0,
                    gid: 0,
                    rdev: 0,
                    flags: 0,
                };
                reply.attr(&Timespec::new(0, 0), &attr);
            }
            2 => {
                // hello.txt
                let attr = FileAttr {
                    ino: 2,
                    size: 13,
                    blocks: 0,
                    atime: Timespec::new(0, 0),
                    mtime: Timespec::new(0, 0),
                    ctime: Timespec::new(0, 0),
                    crtime: Timespec::new(0, 0),
                    kind: FileType::RegularFile,
                    perm: 0o644,
                    nlink: 1,
                    uid: 0,
                    gid: 0,
                    rdev: 0,
                    flags: 0,
                };
                reply.attr(&Timespec::new(0, 0), &attr);
            }
            _ => reply.error(libc::ENOENT),
        }
    }
    
    fn read(&mut self, ino: u64, _offset: u64, _size: u32, reply: fuse::ReplyData) {
        if ino == 2 {
            reply.data(&b"Hello from MarkBase FUSE!\n"[..]);
        } else {
            reply.error(libc::ENOENT);
        }
    }
    
    fn readdir(&mut self, ino: u64, _offset: u64, reply: fuse::ReplyDirectory) {
        if ino == 1 {
            reply.add(1, 0, FileType::Directory, ".");
            reply.add(1, 1, FileType::Directory, "..");
            reply.add(2, 2, FileType::RegularFile, "hello.txt");
            reply.ok();
        } else {
            reply.error(libc::ENOENT);
        }
    }
}

pub fn mount_hello_fs(path: &Path) -> Result<(), Box<dyn std::error::Error>> {
    let fs = HelloFs;
    fuse::mount(fs, path, &[])?;
    Ok(())
}
```

### Test Commands

```bash
# Create test directory
mkdir -p /tmp/fuse_test

# Mount Hello FUSE
cargo run -- fuse --poc --mount --dir /tmp/fuse_test

# Verify mount
mount | grep fuse_test
ls -la /tmp/fuse_test
cat /tmp/fuse_test/hello.txt

# Expected output: "Hello from MarkBase FUSE!\n"

# Unmount
cargo run -- fuse --poc --unmount --dir /tmp/fuse_test
umount /tmp/fuse_test  # Manual fallback
```

### Expected Results

| Check | Expected | Actual | Pass/Fail |
|-------|----------|--------|-----------|
| Mount succeeds | Exit code 0 | TBD | TBD |
| Mount visible in `mount` | `fuse_test` entry | TBD | TBD |
| Directory listing | `hello.txt` visible | TBD | TBD |
| File read | "Hello from MarkBase FUSE!\n" | TBD | TBD |
| Unmount succeeds | Exit code 0 | TBD | TBD |
| Mount removed | No `fuse_test` in `mount` | TBD | TBD |

---

## Test 3: Backend Selection Verification

### Objective

Test both NFSv4 and FSKit backends to verify performance difference.

### Backend Detection

```rust
// src/fuse/backend.rs
use std::env;

pub fn detect_macos_version() -> String {
    env::var("MACOS_VERSION").unwrap_or_else(|_| {
        // Fallback: parse from system
        let output = Command::new("sw_vers")
            .arg("-productVersion")
            .output()
            .expect("Failed to get macOS version");
        String::from_utf8_lossy(&output.stdout).trim().to_string()
    })
}

pub fn select_backend() -> BackendType {
    let version = detect_macos_version();
    
    if version.starts_with("26") {
        BackendType::Fskit  // macOS 26+ supports FSKit
    } else {
        BackendType::Nfs4   // Older macOS uses NFSv4
    }
}
```

### Test NFSv4 Backend

```bash
# Force NFSv4 backend
cargo run -- fuse --poc --mount --dir /tmp/fuse_nfs --backend nfs

# Performance test
time ls -la /tmp/fuse_nfs
time cat /tmp/fuse_nfs/hello.txt

# Unmount
cargo run -- fuse --poc --unmount --dir /tmp/fuse_nfs
```

### Test FSKit Backend

```bash
# Force FSKit backend (macOS 26+)
cargo run -- fuse --poc --mount --dir /tmp/fuse_fskit --backend fskit

# Performance test
time ls -la /tmp/fuse_fskit
time cat /tmp/fuse_fskit/hello.txt

# Unmount
cargo run -- fuse --poc --unmount --dir /tmp/fuse_fskit
```

### Performance Comparison

| Backend | ls latency | cat latency | Notes |
|---------|------------|--------------|-------|
| NFSv4 | TBD | TBD | Baseline |
| FSKit | TBD | TBD | Target: 40% faster |
| Direct disk | TBD | TBD | Reference |

---

## Test 4: Basic Read/Write Operations

### Objective

Verify basic file operations work through FUSE mount.

### Test Script

```bash
#!/bin/bash
# tests/fuse_basic_ops.sh

MOUNT_DIR="/tmp/fuse_ops_test"

# Setup
mkdir -p "$MOUNT_DIR"
cargo run -- fuse --poc --mount --dir "$MOUNT_DIR"

# Test 1: Directory listing
echo "=== Test 1: Directory Listing ==="
ls -la "$MOUNT_DIR"

# Test 2: File read
echo "=== Test 2: File Read ==="
cat "$MOUNT_DIR/hello.txt"

# Test 3: File stat
echo "=== Test 3: File Stat ==="
stat "$MOUNT_DIR/hello.txt"

# Cleanup
cargo run -- fuse --poc --unmount --dir "$MOUNT_DIR"
rm -rf "$MOUNT_DIR"

echo "All tests completed"
```

### Expected Results

| Operation | Expected Output | Pass/Fail |
|-----------|-----------------|-----------|
| Directory listing | Shows `hello.txt` | TBD |
| File read | "Hello from MarkBase FUSE!\n" | TBD |
| File stat | ino=2, size=13, perm=644 | TBD |
| Unmount | Exit code 0 | TBD |

---

## Test 5: AJA System Test Baseline

### Objective

Measure raw disk performance before FUSE implementation.

### AJA Test Configuration

| Setting | Value |
|---------|-------|
| **Target** | `/System/Volumes/Data` (NVMe) |
| **Resolution** | 4K (3840×2160) |
| **Codec** | ProRes 4444 |
| **Frame Rate** | 60 fps |
| **Duration** | 10 seconds |
| **Mode** | Write test |

### Test Procedure

```bash
# Open AJA System Test
open -a "AJA System Test"

# Manual steps:
1. Select target: /System/Volumes/Data
2. Configure: 4K ProRes 4444, 60fps
3. Run Write test (10 seconds)
4. Record results:
   - Write speed: ___ MB/s
   - Frame rate achieved: ___ fps
   - Disk usage: ___ %
```

### dd Baseline Test

```bash
# Write test (6GB)
time dd if=/dev/zero of=/System/Volumes/Data/test_baseline.bin bs=1M count=6000

# Expected: ~1.5GB/s (NVMe raw speed)
# Record: ___ MB/s

# Cleanup
rm /System/Volumes/Data/test_baseline.bin
```

### Expected Results

| Test | Expected Speed | Actual Speed | Pass/Fail |
|------|----------------|--------------|-----------|
| AJA 4K ProRes 4444 Write | >=1500 MB/s | TBD | TBD |
| dd write (6GB) | >=1500 MB/s | TBD | TBD |
| AJA frame rate | 60 fps sustained | TBD | TBD |

---

## Test 6: Rust FUSE Library Verification

### Objective

Verify Rust FUSE library compatibility with FUSE-T.

### Dependency Check

```toml
# Cargo.toml
[dependencies]
fuse = "0.3"  # Or fuse-t specific binding
time = "0.3"
libc = "0.2"
```

### Compilation Test

```bash
# Add fuse dependency
cargo add fuse

# Compile check
cargo check

# Expected: No compilation errors
```

### Mount Options Verification

```rust
// src/fuse/options.rs
use fuse::MountOption;

pub fn get_mount_options(backend: BackendType) -> Vec<MountOption> {
    match backend {
        BackendType::Nfs4 => vec![
            MountOption::FSName("markbase"),
            MountOption::Noatime,
        ],
        BackendType::Fskit => vec![
            MountOption::FSName("markbase"),
            MountOption::Noatime,
        ],
    }
}
```

### Expected Results

| Check | Expected | Actual | Pass/Fail |
|-------|----------|--------|-----------|
| Cargo build succeeds | Exit code 0 | TBD | TBD |
| fuse library linked | Binary includes fuse symbols | TBD | TBD |
| Mount options valid | No runtime errors | TBD | TBD |

---

## Test Execution Schedule

### Day 1: Environment Setup

| Time | Task | Duration |
|------|------|----------|
| 09:00 | Install FUSE-T | 15 min |
| 09:15 | Verify installation | 10 min |
| 09:25 | Download AJA System Test | 20 min |
| 09:45 | Install AJA System Test | 10 min |
| 09:55 | Run AJA baseline test | 30 min |
| 10:25 | Document results | 15 min |
| **Total** | | **1.5 hours** |

### Day 1: Hello FUSE POC

| Time | Task | Duration |
|------|------|----------|
| 10:40 | Create src/fuse/poc_hello.rs | 30 min |
| 11:10 | Add fuse dependency | 10 min |
| 11:20 | Compile and test | 20 min |
| 11:40 | Document results | 15 min |
| **Total** | | **1.25 hours** |

### Day 2: Backend Verification

| Time | Task | Duration |
|------|------|----------|
| 09:00 | Test NFSv4 backend | 30 min |
| 09:30 | Test FSKit backend | 30 min |
| 10:00 | Compare performance | 20 min |
| 10:20 | Document findings | 20 min |
| **Total** | | **1.7 hours** |

---

## Test Reporting Template

### FUSE-T Installation Report

```
## Test 1: FUSE-T Installation

**Date**: 2026-05-17
**Environment**: M4 Mac mini, macOS 26.4.1

### Results

| Check | Expected | Actual | Pass/Fail |
|-------|----------|--------|-----------|
| fuse-t binary | Exists | [Record] | [Pass/Fail] |
| fuse-t version | >=1.2.6 | [Record] | [Pass/Fail] |
| nfs-t binary | Exists | [Record] | [Pass/Fail] |

### Issues Found
- [Document any issues]

### Resolution
- [Document solutions applied]
```

### Hello FUSE POC Report

```
## Test 2: Hello FUSE POC

**Date**: 2026-05-17
**Mount Path**: /tmp/fuse_test

### Results

| Check | Expected | Actual | Pass/Fail |
|-------|----------|--------|-----------|
| Mount succeeds | Exit 0 | [Record] | [Pass/Fail] |
| Directory listing | hello.txt | [Record] | [Pass/Fail] |
| File read | "Hello..." | [Record] | [Pass/Fail] |

### Latency Measurements
- Mount time: [Record] ms
- ls time: [Record] ms
- cat time: [Record] ms

### Backend Used
- Backend: [NFSv4/FSKit/Auto]
- Reason: [Auto-detect/Manual]
```

### Performance Baseline Report

```
## Test 5: AJA System Test Baseline

**Date**: 2026-05-17
**Target**: /System/Volumes/Data (NVMe)

### AJA Results

| Codec | Resolution | Frame Rate | Write Speed | Pass/Fail |
|-------|------------|------------|-------------|-----------|
| ProRes 4444 | 4K | 60fps | [Record] MB/s | [Pass/Fail] |

### dd Results

| Test | Block Size | Count | Speed | Pass/Fail |
|------|------------|-------|-------|-----------|
| Write | 1MB | 6000 | [Record] MB/s | [Pass/Fail] |

### Analysis
- NVMe raw speed: [Record] MB/s
- AJA speed: [Record] MB/s
- Overhead: [Calculate] %
```

---

## Failure Recovery Procedures

### FUSE-T Installation Failure

**Symptoms:**
- brew install fails
- Permission denied
- Network volumes not accessible

**Recovery:**
```bash
# Step 1: Check permissions
System Settings → Privacy & Security → Files and Folders → Network Volumes → Enable

# Step 2: Manual install
curl -L -o ~/Downloads/fuse-t.pkg \
  https://github.com/macos-fuse-t/fuse-t/releases/download/1.2.6/fuse-t-macos-installer-1.2.6.pkg
sudo installer -pkg ~/Downloads/fuse-t.pkg -target /

# Step 3: Restart terminal
exec zsh
```

### Mount Failure

**Symptoms:**
- mount command hangs
- Operation not permitted
- Device not found

**Recovery:**
```bash
# Check mount status
mount | grep fuse

# Force unmount
umount -f /tmp/fuse_test

# Check process
ps aux | grep fuse

# Kill if needed
kill -9 [PID]
```

### Compilation Failure

**Symptoms:**
- Cargo build fails
- fuse library not found
- Linking errors

**Recovery:**
```bash
# Check Rust version
rustc --version  # Need >=1.70

# Update toolchain
rustup update stable

# Rebuild dependencies
cargo clean
cargo build
```

---

## Success Criteria

### Phase 1 POC Complete

| Criterion | Threshold | Measurement |
|-----------|-----------|-------------|
| FUSE-T installed | Binary exists | `/usr/local/bin/fuse-t` present |
| Hello FUSE works | Read/write succeeds | `cat /tmp/fuse_test/hello.txt` outputs correctly |
| Backend detected | Auto-select works | macOS 26 → FSKit, older → NFSv4 |
| AJA baseline | >=1500 MB/s | Raw disk write speed |
| Compilation succeeds | Exit code 0 | `cargo build` completes |

### Proceed to Phase 2

**Decision Criteria:**
- All Test 1-6 pass
- No critical failures
- Performance baseline documented
- Backend selection confirmed

---

## Next Steps After POC

### Phase 2: SQLite-backed FUSE (Day 3-5)

1. Implement `MarkBaseFs` struct
2. Integrate file_nodes/file_locations queries
3. Test warren user (12,659 nodes)
4. Implement LRU caching
5. Performance measurement

### Phase 3: Multi-user Concurrent (Day 6-8)

1. Implement `MountManager`
2. Test 10 user parallel mount
3. AJA concurrent write test
4. Stability test (24h)

### Phase 4: Performance Optimization (Day 9-12)

1. Write buffering (64KB chunks)
2. FSKit backend optimization
3. AJA 600MB/s target validation
4. Final documentation

---

**Last Updated**: 2026-05-17
**Version**: 1.0
**Status**: Ready for Execution