Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
126 commits
Select commit Hold shift + click to select a range
b46fbfb
feat: Add Rust FFI client for integration testing
jackzampolin Jan 26, 2026
3f63b50
fix: Rust FFI wrapper event publishing and type handling
jackzampolin Jan 26, 2026
0efea4b
fix: Make Rust FFI library path configurable via env vars
jackzampolin Jan 26, 2026
e8e7590
fix: Update scripts to use DEFRA_RS_PATH env var
jackzampolin Jan 26, 2026
459f621
feat: Add rust-ffi-compat skill for running compatibility tests
jackzampolin Jan 26, 2026
d7d6ecf
fix: Don't skip network/backup tests for Rust FFI
jackzampolin Jan 27, 2026
8046534
fix(test): preserve numeric precision for RustFFI client comparison
jackzampolin Jan 27, 2026
711268c
feat(ffi): Implement AddDACPolicy FFI bindings
jackzampolin Jan 27, 2026
f230c34
feat(rustffi): Add P2P FFI bindings
jackzampolin Jan 27, 2026
ec781aa
feat(rustffi): Enable P2P support for rust-ffi client
jackzampolin Jan 27, 2026
4f631f7
fix: Correct test counting and update gitignore
jackzampolin Jan 27, 2026
5daaa68
fix(rustffi): Simplify CGO build configuration for multi-worktree wor…
jackzampolin Jan 28, 2026
1ee0fc9
docs(skill): Add warning about sandbox shell limitations
jackzampolin Jan 28, 2026
ecdfb37
fix(ffi): Handle move/copy operations in patch collection routing
jackzampolin Jan 28, 2026
df2c4c5
Revert "fix(ffi): Handle move/copy operations in patch collection rou…
jackzampolin Jan 28, 2026
f767442
feat(rustffi): Fix wrapper for mutation/update test parity
jackzampolin Jan 28, 2026
d80c207
fix(ffi): Fix Get() to query all scalar fields and handle json.Number
jackzampolin Jan 29, 2026
ec3a8c2
fix(ffi): Fix jsonToGraphQLInput to handle nested JSON strings
jackzampolin Jan 29, 2026
1b20594
fix(rustffi): Handle deleted documents in Save() and emit events on D…
jackzampolin Jan 29, 2026
362fe2b
feat: Add Makefile targets for Rust FFI testing
jackzampolin Jan 29, 2026
7aaee07
feat: Add all FFI test packages organized by priority
jackzampolin Jan 29, 2026
67045b9
feat: Add FFI test history tracking
jackzampolin Jan 29, 2026
929ab90
fix: Handle grep exit code in FFI test counting
jackzampolin Jan 29, 2026
1c9edd6
feat: Show run metadata in FFI test report
jackzampolin Jan 29, 2026
7c4d29a
feat: Per-package metadata in FFI test reports
jackzampolin Jan 29, 2026
e45313b
chore: Update defra.h from latest Rust FFI build
jackzampolin Jan 29, 2026
a1bde6b
feat: Auto-generate defra.h from RUST_LIB before FFI tests
jackzampolin Jan 29, 2026
a3916e2
feat: Wire up AddLens FFI and fix PeerInfo for views
jackzampolin Jan 29, 2026
697366f
feat: Mirror NAC state on Rust FFI node during test setup
jackzampolin Jan 29, 2026
16a13cf
fix(rustffi): Populate CID in update/delete events for test framework
jackzampolin Jan 29, 2026
f93d6a4
fix: Key FFI reports by test package, not worktree+package
jackzampolin Jan 30, 2026
9d7b754
feat(rustffi): Wire identity DID through FFI for ACP and fix wrapper
jackzampolin Jan 30, 2026
82a6c35
fix(rustffi): Fix dirty field tracking in Get and clean up event debug
jackzampolin Jan 30, 2026
da45563
chore: Remove debug prints from test actions and utils
jackzampolin Jan 30, 2026
c4ee014
chore: Update defra.h header for identity_did and reordered exports
jackzampolin Jan 30, 2026
79e921c
fix(rustffi): Sync docID after FFI create and update defra.h header
jackzampolin Jan 30, 2026
73e79f3
chore(rustffi): Add stub declarations for truncate_collection and p2p…
jackzampolin Jan 30, 2026
a743344
feat(rustffi): Support multi-collection patches and update defra.h
jackzampolin Jan 30, 2026
f0c739e
feat(rustffi): Add LensList binding and update defra.h
jackzampolin Jan 30, 2026
79a2459
feat(rustffi): Pass identity_did to all NAC-gated FFI functions
jackzampolin Feb 2, 2026
ecc165c
fix(rustffi): Fix NAC identity mismatch between owner and nodeIdentity
jackzampolin Feb 2, 2026
bd1906e
fix(rustffi): Add relation param to NAC relationship ops and update C…
jackzampolin Feb 2, 2026
f559608
fix(rustffi): Fix null collections, collection version lookup, and ev…
jackzampolin Feb 2, 2026
29b09c6
fix(ffi): Handle migration parameter in PatchCollection wrapper
jackzampolin Feb 2, 2026
6168916
feat(rustffi): Add block_verify_signature FFI binding and fix explain…
jackzampolin Feb 2, 2026
40bd393
chore(rustffi): Regenerate defra.h with block_verify_signature
jackzampolin Feb 2, 2026
fd0185f
chore(rustffi): Regenerate defra.h with updated parameter names and docs
jackzampolin Feb 2, 2026
a2bac90
feat(ffi): Pass signing key from Go test framework to Rust FFI
jackzampolin Feb 3, 2026
4e5f849
feat(ffi): Add SyncDocuments FFI support
jackzampolin Feb 3, 2026
349312a
fix(ffi,tests): Update defra.h and fix signature comparison for Rust FFI
jackzampolin Feb 3, 2026
079d291
feat(ffi): Add RustFFI client type handling to signatureMatcher and u…
jackzampolin Feb 3, 2026
aa9cc76
fix(ffi): Update defra.h with correct NodeInitOptions field order
jackzampolin Feb 3, 2026
07f4c92
feat(rustffi): Add encrypted index FFI bindings
jackzampolin Feb 3, 2026
b991836
fix(rustffi): Update CGO linking to use libdefra_ffi dylib
jackzampolin Feb 3, 2026
3e19f36
fix(rustffi): Update defra.h with correct encrypted index function si…
jackzampolin Feb 3, 2026
6106167
feat(rustffi): Add branchable collection sync FFI bindings
jackzampolin Feb 3, 2026
9f8ef74
fix(rustffi): Re-add p2p_sync_branchable_collection header declaration
jackzampolin Feb 3, 2026
df89812
feat(rustffi): Add IncludeInactive filter + p2p_sync_branchable_colle…
jackzampolin Feb 3, 2026
2200a89
fix(rustffi): SE event bridge, crash fix, and Makefile improvements
jackzampolin Feb 3, 2026
c62be84
feat(rustffi): Eliminate FFI test skips (issue #317)
jackzampolin Feb 3, 2026
77cf518
feat(rustffi): Add SE artifact event handling to FFI-MERGE-POLLER
jackzampolin Feb 3, 2026
d8e3c53
fix(rustffi): Populate ExpectedDAGHeads for branchable sync
jackzampolin Feb 3, 2026
88bcfd1
feat(rustffi): Add GraphQL subscription support
jackzampolin Feb 3, 2026
fa21da8
feat(rustffi): Add P2PSyncCollectionVersions Go bindings
jackzampolin Feb 3, 2026
c226b42
a path fix hack
jackzampolin Feb 4, 2026
191b60c
fix(test): Add RustFFIClientType to AnyOf matcher special case list
jackzampolin Feb 4, 2026
2a7b4d6
chore: Update FFI bindings from latest Rust implementation
jackzampolin Feb 4, 2026
bb42cd5
feat(cbindings): Support client identity signing in Rust FFI
jackzampolin Feb 5, 2026
61a2124
test(signature): Enable branchable test for Rust FFI
jackzampolin Feb 5, 2026
ce8418c
docs(signature): Update ACP test comments
jackzampolin Feb 5, 2026
fd9a9cf
feat(cbindings): Support client identity signing in Rust FFI
jackzampolin Feb 5, 2026
71abc46
feat(rustffi): Pass identity to block_verify_signature for DAC check
jackzampolin Feb 5, 2026
9a20418
docs(ffi): Update refresh_views documentation
jackzampolin Feb 5, 2026
25601f7
feat(rustffi): Fix restart tests with persistent NAC and badger lock
jackzampolin Feb 5, 2026
b0c6566
feat(rustffi): Wire SourceHub ACP config through FFI
jackzampolin Feb 6, 2026
cc36cfb
fix(rustffi): Fix double event emission and delete ACP detection
jackzampolin Feb 9, 2026
5aabc87
feat(rustffi): Enable NAC signature verify tests for RustFFI client
jackzampolin Feb 9, 2026
bd56fba
feat(rustffi): Update FFI header for subscription support
jackzampolin Feb 9, 2026
5073486
fix(rustffi): Restore collection-version Go FFI changes lost in squas…
jackzampolin Feb 9, 2026
abafaaf
docs(rustffi): Update subscription FFI header comments
jackzampolin Feb 9, 2026
05d9718
fix(rustffi): Update FFI calls to match renamed P2P methods
jackzampolin Feb 9, 2026
c53e6af
fix(rustffi): Fix lint issues and JS build compatibility
jackzampolin Feb 9, 2026
081144e
fix(rustffi): Guard Rust FFI behind build tag to fix CI linker errors
jackzampolin Feb 9, 2026
90ed275
fix(ffi): Pass identity context for NAC-gated operations
jackzampolin Feb 10, 2026
31fe9eb
fix(rustffi): Enable RustFFI for NAC document_delete, index, collecti…
jackzampolin Feb 10, 2026
100213b
fix(rustffi): Add reconnectPeers after startNodes in Start action han…
jackzampolin Feb 10, 2026
d98313c
feat(rustffi): Add P2PRetryReplicators and call it after reconnectPeers
jackzampolin Feb 10, 2026
84e405b
feat(rustffi): Add SetSEEncryptionKey FFI binding and pass SE key to …
jackzampolin Feb 10, 2026
eb1855c
fix(rustffi): Address CodeRabbit review feedback for PR cleanup
jackzampolin Feb 10, 2026
ed4a3f9
fix: Remove debug prints from events.go and revert branchable sync re…
jackzampolin Feb 10, 2026
ed25fe4
fix: Gate branchable sync ExpectedDAGHeads on RustFFI client type
jackzampolin Feb 10, 2026
d1094b8
fix(rustffi): Reconnect Rust P2P peers after individual node restart
jackzampolin Feb 11, 2026
521bfd7
fix: update ExpectedDAGHeads assignment for new type + upgrade sonic
jackzampolin Mar 29, 2026
0b4e7a2
fix(rustffi): update wrapper for develop interface changes
jackzampolin Mar 29, 2026
c4f146d
fix(rustffi): align FFI function names with v1.0-rc1 renames
jackzampolin Mar 29, 2026
f5abc18
fix(rustffi): use internal/identity.WithContext after package move
jackzampolin Mar 29, 2026
8e5beb4
fix(rustffi): add event poller to non-P2P nodes and relay Update events
jackzampolin Mar 29, 2026
d631564
fix(rustffi): extract identity from options for DAC policy methods
jackzampolin Mar 29, 2026
de8554e
fix(rustffi): extract identity from options across all wrapper methods
jackzampolin Mar 29, 2026
c49027f
fix: add int64 case to toUint64 in explain asserter
jackzampolin Mar 29, 2026
f0db4ae
fix(rustffi): fix subscription double events, base64 delta decoding
jackzampolin Mar 29, 2026
82cedd1
fix(rustffi): NAC identity opts, explain type normalization, P2P names
jackzampolin Mar 29, 2026
71717b6
fix(rustffi): remove int64→int32 conversion that broke index assertions
jackzampolin Mar 29, 2026
4c93eda
fix(rustffi): fix explain type normalization for deep equality
jackzampolin Mar 29, 2026
724ae4b
fix(rustffi): pass identity to GetNACStatus during restart setup
jackzampolin Mar 29, 2026
3800cc2
fix(rustffi): add identity_did parameter to lens_add, refresh_views, …
jackzampolin Mar 29, 2026
5d1dc4b
fix(rustffi): regenerate defra.h for NAC gate signature changes
jackzampolin Mar 29, 2026
d5b0ccc
fix(rustffi): resolve P2P dual-host interference and collection ops
jackzampolin Mar 29, 2026
b6a27e4
fix(rustffi): remove panic-causing reflect/unsafe P2P close
jackzampolin Mar 29, 2026
a70ac54
fix(rustffi): disable Go P2P host for FFI nodes, use client PeerInfo
jackzampolin Mar 29, 2026
c17b55b
fix(rustffi): pass requestor identity to publishRelationshipEvent for…
jackzampolin Mar 29, 2026
57e35a3
fix(rustffi): map collection-not-found errors with embedded names
jackzampolin Mar 29, 2026
afa2e3b
fix(ffi): set node identity on FFI wrapper and preserve collection er…
jackzampolin Mar 29, 2026
7e7e2bd
fix(rustffi): increase GossipSub mesh stabilization delay for CRDT sync
jackzampolin Mar 29, 2026
6f4fd7a
fix(rustffi): increase GossipSub mesh delay to 2s for multi-node CRDT…
jackzampolin Mar 29, 2026
721df43
fix(rustffi): always set node identity on FFI wrapper for GetNodeIden…
jackzampolin Mar 30, 2026
7ee75eb
fix(rustffi): increase GossipSub mesh delay to 3s for P2P convergence
jackzampolin Mar 30, 2026
8cf3662
fix(rustffi): include PublicKey in GetNodeIdentity response
jackzampolin Mar 30, 2026
c7b36d3
fix(tests): increase P2P merge timeout from 30s to 60s
jackzampolin Mar 30, 2026
865e58b
fix(rustffi): add int64→uint64 conversion in explain type normalization
jackzampolin Apr 1, 2026
daa3bfd
fix: use txn-aware rust ffi schema creation
jackzampolin Apr 8, 2026
6edee39
fix: use txn-local rust ffi lenses
jackzampolin Apr 8, 2026
a5f3141
fix: stage rust ffi txn compatibility operations
jackzampolin Apr 8, 2026
991e5aa
fix: route rust ffi txn document ops through transactions
jackzampolin Apr 8, 2026
378aa3f
fix: stage remaining rust ffi txn collection ops
jackzampolin Apr 8, 2026
f6d89a2
fix: route rust ffi txn signature verification
jackzampolin Apr 8, 2026
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
137 changes: 137 additions & 0 deletions .claude/skills/rust-ffi-compat.skill
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: Did we already discuss and agree on adding skills to the repo?

Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
---
name: rust-ffi-compat
description: Run Go integration tests against the Rust FFI implementation of DefraDB and generate compatibility reports. Use when checking Rust compatibility status, running FFI tests, generating test reports, or tracking progress on Rust implementation. Triggers on "rust compatibility", "ffi tests", "rust test status", "compatibility report", or "run rust tests".
---

# Rust FFI Compatibility Testing

Run Go DefraDB integration tests against the Rust FFI implementation to verify compatibility.

## Architecture: Single Go Repo + Multiple Rust Worktrees

**ONE Go repo** (`defradb-rust-compat` on `jack/ffi-rust-compat` branch) serves all Rust worktrees. Each Rust worktree focuses on a specific test package for tight iteration loops.

| Rust Worktree | Test Package | GOCACHE |
|---------------|--------------|---------|
| `defradb.rs-query-simple` | query/simple | `/tmp/gocache-query-simple` |
| `defradb.rs-one-to-many` | query/one_to_many | `/tmp/gocache-one-to-many` |
| `defradb.rs-index` | index | `/tmp/gocache-index` |
| `defradb.rs-collection-version` | collection_version | `/tmp/gocache-collection-version` |
| `defradb.rs-explain` | explain | `/tmp/gocache-explain` |

### Why This Design

- **No library copying**: `CGO_LDFLAGS` points directly to each Rust worktree's `target/release/`
- **No Go duplication**: Single Go repo, tests run against any Rust worktree
- **Cache isolation**: Unique `GOCACHE` per Rust worktree prevents stale CGO objects
- **Parallel-safe**: Multiple Claude sessions can work on different Rust worktrees simultaneously

## Prerequisites

1. Build Rust FFI library from the Rust worktree:
```bash
cd /path/to/defradb.rs-<package>
cargo build --release -p ffi
```

2. Ensure `defra.h` is in the Go repo's `tests/clients/rustffi/` directory (committed to repo, rarely changes)

## Running Tests

### ⚠️ CRITICAL: Use inline env vars with `go test -C`

**DO NOT use `cd`, `export`, or wrapper scripts.** Claude Code's sandbox blocks these patterns:
- `cd /path && go test` → "permission denied"
- `export VAR=value` → "not valid in this context"
- `bash script.sh` → subprocess blocked

**ALWAYS use this pattern:** All env vars inline, then `go test -C <dir>`:

```bash
CGO_ENABLED=1 CGO_LDFLAGS="-L/path/to/defradb.rs-<package>/target/release -lffi -ldl -lpthread -lm" DEFRA_CLIENT_RUST_FFI=true GOCACHE=/tmp/gocache-<package> go test -C /path/to/defradb-rust-compat ./tests/integration/<package>/... -v -count=1 -timeout 120s
```

The `-C` flag changes directory internally (equivalent to `cd` but works in the sandbox).

### Example: Testing query/simple against defradb.rs-query-simple

```bash
CGO_ENABLED=1 CGO_LDFLAGS="-L/Users/johnzampolin/go/src/github.com/sourcenetwork/defradb.rs-query-simple/target/release -lffi -ldl -lpthread -lm" DEFRA_CLIENT_RUST_FFI=true GOCACHE=/tmp/gocache-query-simple go test -C /Users/johnzampolin/go/src/github.com/sourcenetwork/defradb-rust-compat ./tests/integration/query/simple/... -v -count=1 -timeout 120s
```

### Verify you're testing the right client

Check the test output for `client=rust-ffi`:
```
INF tests.integration TestQuerySimple database=badger-in-memory client=rust-ffi ...
```

If it shows a different client (e.g., `client=go`), the env vars are wrong or missing.

### After rebuilding Rust

Clear the GOCACHE to ensure fresh CGO compilation:
```bash
rm -rf /tmp/gocache-<package>
```

Go's build cache doesn't detect changes to `libffi.a` (known bug #25419), so this step is required after Rust rebuilds.

## Test Packages

| Package | Description | Current Status |
|---------|-------------|----------------|
| `query/simple` | Basic queries, filters, ordering, limits | 74% (322/433) |
| `query/one_to_many` | One-to-many relation queries | 26% (23/87) |
| `index` | Secondary index queries | 29% (23/79) |
| `collection_version` | Schema versioning | 20% (75/372) |
| `explain` | Query plan explain output | 0% (0/249) |
| `query/inline_array` | Array field queries | **100%** (172/172) |
| `query/json` | JSON field queries | **100%** (67/67) |
| `mutation/delete` | Document deletion | 88% (30/34) |
| `mutation/update` | Document updates | 82% (70/85) |
| `mutation/create` | Document creation | 72% (48/67) |
| `query/one_to_one` | One-to-one relation queries | 80% (33/41) |
| `query/commits` | Commit history queries | 86% (75/87) |
| `collection` | Collection management | 0% (0/16) |

## Full Report Generation

Run all packages in parallel with shared GOCACHE for fastest execution:

```bash
# Use the main defradb.rs repo (or any worktree with a complete build)
RS=/Users/johnzampolin/go/src/github.com/sourcenetwork/defradb.rs
GO=/Users/johnzampolin/go/src/github.com/sourcenetwork/defradb-rust-compat

CGO_ENABLED=1 \
CGO_LDFLAGS="-L$RS/target/release -lffi -ldl -lpthread -lm" \
DEFRA_CLIENT_RUST_FFI=true \
GOCACHE=/tmp/gocache-full-report \
go test -C $GO ./tests/integration/<pkg>/... -v -count=1 -timeout 120s
```

Launch 13 background Bash tasks (one per package) to run simultaneously.

## Troubleshooting

| Problem | Fix |
|---------|-----|
| `permission denied` or `not valid in this context` | Don't use `cd`, `export`, or scripts. Use inline env vars with `go test -C` |
| `client=go` in output (not `rust-ffi`) | Missing `DEFRA_CLIENT_RUST_FFI=true` env var |
| Undefined symbols at link time | Ensure `CGO_LDFLAGS` points to correct `target/release/` with fresh `libffi.a` |
| Stale results after Rust rebuild | Delete the GOCACHE: `rm -rf /tmp/gocache-<package>` |
| Tests stuck / hanging | Check `DEFRA_CLIENT_RUST_FFI=true` is set |
| Header not found | Ensure `defra.h` exists in Go repo's `tests/clients/rustffi/` |
| Wrong test results | Verify `CGO_LDFLAGS` points to the intended Rust worktree |

## Creating a New Rust Worktree

```bash
cd /Users/johnzampolin/go/src/github.com/sourcenetwork/defradb.rs
git worktree add ../defradb.rs-<package> -b ffi/<package>
cd ../defradb.rs-<package>
cargo build --release -p ffi
```

Then test with the canonical invocation above.
10 changes: 10 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,13 @@ crash.log

# Ignore .env files containing sensitive information.
.env

# Rust FFI test reports
reports/

# Rust FFI test history (see make test:ffi-history)
ffi-test-history/

# Rust FFI library files (built from defradb.rs)
tests/clients/rustffi/*.a
tests/clients/rustffi/*.dylib
229 changes: 229 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -474,3 +474,232 @@ API_LEVEL ?= 21
.PHONY: build-c-shared-android
build-c-shared-android:
@tools/scripts/build-c-shared-android.sh $(ANDROID_NDK) $(API_LEVEL) "$(BUILD_FLAGS)"

# ============================================================================
# Rust FFI Testing
# ============================================================================
#
# Run Go integration tests against the Rust FFI implementation.
#
# Usage:
# make test:ffi RUST_LIB=/path/to/defradb.rs FFI_PKG=query/simple
# make test:ffi RUST_LIB=/path/to/defradb.rs FFI_PKG="query/simple mutation/create"
# make test:ffi-report # View last test report
# make test:ffi-save # Save current reports to history
# make test:ffi-history # View test history
#
# Environment:
# RUST_LIB - Path to Rust defradb.rs repo (required)
# FFI_PKG - Test package(s), space-separated (default: query/simple)
# FFI_TIMEOUT - Test timeout (default: 300s)
#
# History:
# Test results are saved to ffi-test-history/ (gitignored) with metadata
# about which Rust branch/commit produced the results. Use test:ffi-save
# after a test run to save results, or test:ffi-history to view past runs.
#
# Parallel Worktree Support:
# Each RUST_LIB path gets its own GOCACHE, so multiple Claude sessions can
# run tests against different Rust worktrees simultaneously without cache
# collisions. Cache dir is derived from RUST_LIB basename + package name.

FFI_PKG ?= query/simple
FFI_TIMEOUT ?= 300s
FFI_REPORT_DIR ?= /tmp/ffi-test-reports
FFI_HISTORY_DIR ?= $(CURDIR)/ffi-test-history

.PHONY: test\:ffi
test\:ffi:
ifndef RUST_LIB
$(error RUST_LIB is required. Usage: make test:ffi RUST_LIB=/path/to/defradb.rs FFI_PKG=query/simple)
endif
@echo "=== Generating defra.h from $(RUST_LIB) ==="
@cd $(RUST_LIB) && cbindgen --config crates/ffi/cbindgen.toml --crate ffi --output $(CURDIR)/tests/clients/rustffi/defra.h 2>&1
@echo "=== Copying Rust FFI library ==="
@cp -f $(RUST_LIB)/target/release/libffi.dylib $(CURDIR)/tests/clients/rustffi/libdefra_ffi.dylib 2>/dev/null && \
install_name_tool -id @rpath/libdefra_ffi.dylib $(CURDIR)/tests/clients/rustffi/libdefra_ffi.dylib 2>/dev/null || \
cp -f $(RUST_LIB)/target/release/libffi.so $(CURDIR)/tests/clients/rustffi/libdefra_ffi.so 2>/dev/null || \
echo "WARNING: Could not copy Rust FFI library (run: cargo build --release -p ffi)"
@mkdir -p $(FFI_REPORT_DIR)
@rust_lib_name=$$(basename $(RUST_LIB)); \
rust_branch=$$(cd $(RUST_LIB) && git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "unknown"); \
rust_commit=$$(cd $(RUST_LIB) && git rev-parse --short HEAD 2>/dev/null || echo "unknown"); \
for pkg in $(FFI_PKG); do \
pkg_safe=$$(echo $$pkg | tr '/' '-'); \
report_file=$(FFI_REPORT_DIR)/$$pkg_safe.log; \
meta_file=$(FFI_REPORT_DIR)/$$pkg_safe.meta; \
cache_dir=/tmp/gocache-$$rust_lib_name-$$pkg_safe; \
echo ""; \
echo "=== Testing $$pkg ==="; \
echo "Clearing GOCACHE: $$cache_dir"; \
rm -rf $$cache_dir; \
echo "Running tests..."; \
CGO_ENABLED=1 \
DEFRA_CLIENT_RUST_FFI=true \
$(if $(DEFRA_MUTATION_TYPE),DEFRA_MUTATION_TYPE=$(DEFRA_MUTATION_TYPE)) \
$(if $(DEFRA_BADGER_FILE),DEFRA_BADGER_FILE=$(DEFRA_BADGER_FILE)) \
GOCACHE=$$cache_dir \
go test ./tests/integration/$$pkg/... -v -count=1 -timeout $(FFI_TIMEOUT) 2>&1 | tee $$report_file; \
echo "{\"timestamp\":\"$$(date +%Y-%m-%d\ %H:%M:%S)\",\"rust_lib\":\"$$rust_lib_name\",\"rust_branch\":\"$$rust_branch\",\"rust_commit\":\"$$rust_commit\"}" > $$meta_file; \
echo ""; \
echo "=== Results for $$pkg ==="; \
passed=$$(grep -c "^--- PASS:" $$report_file 2>/dev/null || true); \
failed=$$(grep -c "^--- FAIL:" $$report_file 2>/dev/null || true); \
passed=$${passed:-0}; \
failed=$${failed:-0}; \
total=$$((passed + failed)); \
echo " Passed: $$passed"; \
echo " Failed: $$failed"; \
echo " Total: $$total"; \
if [ "$$failed" -gt 0 ]; then \
echo ""; \
echo "Failed tests:"; \
grep "^--- FAIL:" $$report_file | sed 's/--- FAIL: / - /' | sed 's/ (.*//' ; \
fi; \
echo ""; \
echo "Full output: $$report_file"; \
done

# All test packages organized by priority (see issue #18)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: issue #18 is an old defradb issue, is this related to an issue in another repo?

# P0 Foundation: query/simple, mutation/*
# P1 Core Query: inline_array, commits, json
# P2 Relations: one_to_*, many_to_many
# P3 Features: explain, acp, index, versions, etc.
Comment on lines +564 to +567
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: What makes you split the testing like this? Seems super tedious to maintain in the future

FFI_PKG_P0 := query/simple mutation/create mutation/update mutation/delete mutation/mix mutation/special mutation/upsert
FFI_PKG_P1 := query/inline_array query/commits query/json
FFI_PKG_P2 := query/one_to_one query/one_to_many query/one_to_many_multiple query/one_to_many_to_many query/one_to_many_to_one query/one_to_one_multiple query/one_to_one_to_many query/one_to_one_to_one query/one_to_two_many query/many_to_many
FFI_PKG_P3 := index explain collection collection_version view acp backup encryption net node signature subscription searchable_encryption issues

FFI_PKG_ALL := $(FFI_PKG_P0) $(FFI_PKG_P1) $(FFI_PKG_P2) $(FFI_PKG_P3)

.PHONY: test\:ffi-all
test\:ffi-all:
ifndef RUST_LIB
$(error RUST_LIB is required. Usage: make test:ffi-all RUST_LIB=/path/to/defradb.rs)
endif
@$(MAKE) test:ffi RUST_LIB=$(RUST_LIB) FFI_PKG="$(FFI_PKG_ALL)"

# Run FFI tests with both default (collection-save) and GQL mutation types.
# This catches tests that only run with GQLRequestMutationType.
.PHONY: test\:ffi-full
test\:ffi-full:
ifndef RUST_LIB
$(error RUST_LIB is required. Usage: make test:ffi-full RUST_LIB=/path/to/defradb.rs FFI_PKG=acp)
endif
@echo "=== Pass 1: default mutation type ==="
@$(MAKE) test:ffi RUST_LIB=$(RUST_LIB) FFI_PKG="$(FFI_PKG)"
@echo ""
@echo "=== Pass 2: GQL mutation type ==="
@DEFRA_MUTATION_TYPE=gql $(MAKE) test:ffi RUST_LIB=$(RUST_LIB) FFI_PKG="$(FFI_PKG)"

.PHONY: test\:ffi-p0
test\:ffi-p0:
ifndef RUST_LIB
$(error RUST_LIB is required. Usage: make test:ffi-p0 RUST_LIB=/path/to/defradb.rs)
endif
@$(MAKE) test:ffi RUST_LIB=$(RUST_LIB) FFI_PKG="$(FFI_PKG_P0)"

.PHONY: test\:ffi-p1
test\:ffi-p1:
ifndef RUST_LIB
$(error RUST_LIB is required. Usage: make test:ffi-p1 RUST_LIB=/path/to/defradb.rs)
endif
@$(MAKE) test:ffi RUST_LIB=$(RUST_LIB) FFI_PKG="$(FFI_PKG_P1)"

.PHONY: test\:ffi-p2
test\:ffi-p2:
ifndef RUST_LIB
$(error RUST_LIB is required. Usage: make test:ffi-p2 RUST_LIB=/path/to/defradb.rs)
endif
@$(MAKE) test:ffi RUST_LIB=$(RUST_LIB) FFI_PKG="$(FFI_PKG_P2)"

.PHONY: test\:ffi-p3
test\:ffi-p3:
ifndef RUST_LIB
$(error RUST_LIB is required. Usage: make test:ffi-p3 RUST_LIB=/path/to/defradb.rs)
endif
@$(MAKE) test:ffi RUST_LIB=$(RUST_LIB) FFI_PKG="$(FFI_PKG_P3)"

.PHONY: test\:ffi-report
test\:ffi-report:
@echo "=== FFI Test Reports ==="
@echo ""
@total_passed=0; total_failed=0; \
for f in $(FFI_REPORT_DIR)/*.log; do \
if [ -f "$$f" ]; then \
name=$$(basename $$f .log); \
passed=$$(grep -c "^--- PASS:" $$f 2>/dev/null; true); \
failed=$$(grep -c "^--- FAIL:" $$f 2>/dev/null; true); \
passed=$${passed:-0}; \
failed=$${failed:-0}; \
total=$$((passed + failed)); \
total_passed=$$((total_passed + passed)); \
total_failed=$$((total_failed + failed)); \
meta=""; \
meta_file="$(FFI_REPORT_DIR)/$$name.meta"; \
if [ -f "$$meta_file" ]; then \
branch=$$(grep -o '"rust_branch":"[^"]*"' $$meta_file | cut -d'"' -f4); \
commit=$$(grep -o '"rust_commit":"[^"]*"' $$meta_file | cut -d'"' -f4); \
ts=$$(grep -o '"timestamp":"[^"]*"' $$meta_file | cut -d'"' -f4); \
meta="$$branch@$$commit $$ts"; \
fi; \
if [ "$$total" -gt 0 ]; then \
pct=$$((passed * 100 / total)); \
printf "%-40s %3d/%3d (%3d%%) %s\n" "$$name" $$passed $$total $$pct "$$meta"; \
fi; \
fi; \
done; \
echo ""; \
grand_total=$$((total_passed + total_failed)); \
if [ "$$grand_total" -gt 0 ]; then \
grand_pct=$$((total_passed * 100 / grand_total)); \
printf "%-40s %3d/%3d (%3d%%)\n" "TOTAL" $$total_passed $$grand_total $$grand_pct; \
fi

.PHONY: test\:ffi-save
test\:ffi-save:
ifndef RUST_LIB
$(error RUST_LIB is required. Usage: make test:ffi-save RUST_LIB=/path/to/defradb.rs)
endif
@mkdir -p $(FFI_HISTORY_DIR)
@rust_branch=$$(cd $(RUST_LIB) && git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "unknown"); \
rust_commit=$$(cd $(RUST_LIB) && git rev-parse --short HEAD 2>/dev/null || echo "unknown"); \
rust_lib_name=$$(basename $(RUST_LIB)); \
timestamp=$$(date +%Y%m%d-%H%M%S); \
history_dir=$(FFI_HISTORY_DIR)/$$timestamp-$$rust_lib_name-$$rust_branch-$$rust_commit; \
mkdir -p $$history_dir; \
echo "Saving FFI test results to $$history_dir"; \
cp $(FFI_REPORT_DIR)/*.log $$history_dir/ 2>/dev/null || true; \
echo "{ \"timestamp\": \"$$timestamp\", \"rust_lib\": \"$(RUST_LIB)\", \"rust_branch\": \"$$rust_branch\", \"rust_commit\": \"$$rust_commit\" }" > $$history_dir/metadata.json; \
total_passed=0; total_failed=0; \
for f in $$history_dir/*.log; do \
if [ -f "$$f" ]; then \
passed=$$(grep -c "^--- PASS:" $$f 2>/dev/null; true); \
failed=$$(grep -c "^--- FAIL:" $$f 2>/dev/null; true); \
total_passed=$$((total_passed + passed)); \
total_failed=$$((total_failed + failed)); \
fi; \
done; \
grand_total=$$((total_passed + total_failed)); \
echo "{ \"passed\": $$total_passed, \"failed\": $$total_failed, \"total\": $$grand_total }" >> $$history_dir/metadata.json; \
echo "Saved: $$total_passed passed, $$total_failed failed ($$grand_total total)"

.PHONY: test\:ffi-history
test\:ffi-history:
@echo "=== FFI Test History ==="
@echo ""
@if [ ! -d $(FFI_HISTORY_DIR) ]; then \
echo "No history found. Run 'make test:ffi-save RUST_LIB=...' after tests."; \
exit 0; \
fi; \
for d in $$(ls -1d $(FFI_HISTORY_DIR)/*/ 2>/dev/null | sort -r | head -20); do \
if [ -f "$$d/metadata.json" ]; then \
name=$$(basename $$d); \
passed=$$(grep -o '"passed": [0-9]*' $$d/metadata.json | grep -o '[0-9]*' || echo 0); \
total=$$(grep -o '"total": [0-9]*' $$d/metadata.json | grep -o '[0-9]*' || echo 0); \
if [ "$$total" -gt 0 ]; then \
pct=$$((passed * 100 / total)); \
printf "%-60s %4d/%4d (%3d%%)\n" "$$name" $$passed $$total $$pct; \
fi; \
fi; \
done
Loading
Loading