9.2 KiB
Testing the Neo4j Social Event Processor
This document explains how to run tests for the social event processor that manages NostrUser vertices and social graph relationships.
Prerequisites
1. Neo4j Instance
You need a running Neo4j instance for integration tests. The easiest way is using Docker:
# Using docker-compose (recommended)
cd pkg/neo4j
docker-compose up -d
docker-compose logs -f neo4j # Wait for "Started."
# Or manually:
docker run -d --name neo4j-test \
-p 7474:7474 \
-p 7687:7687 \
-e NEO4J_AUTH=neo4j/testpass123 \
neo4j:5.15
# Wait for Neo4j to start (check logs)
docker logs -f neo4j-test
Access the Neo4j browser at http://localhost:7474 (credentials: neo4j/testpass123)
2. Environment Variables
Set the Neo4j connection details:
export ORLY_NEO4J_URI="bolt://localhost:7687"
export ORLY_NEO4J_USER="neo4j"
export ORLY_NEO4J_PASSWORD="testpass123"
3. libsecp256k1.so
The tests require the secp256k1 library for signing events:
# Download from nostr repository
wget https://git.mleku.dev/mleku/nostr/raw/branch/main/crypto/p8k/libsecp256k1.so -P /tmp/
# Add to library path
export LD_LIBRARY_PATH="/tmp:$LD_LIBRARY_PATH"
Running Tests
All Tests
cd pkg/neo4j
go test -v
Specific Test
# Test profile metadata processing
go test -v -run TestSocialEventProcessor/Kind0_ProfileMetadata
# Test contact list initial creation
go test -v -run TestSocialEventProcessor/Kind3_ContactList_Initial
# Test contact list updates
go test -v -run TestSocialEventProcessor/Kind3_ContactList_Update
# Test mute list
go test -v -run TestSocialEventProcessor/Kind10000_MuteList
# Test reports
go test -v -run TestSocialEventProcessor/Kind1984_Reports
Helper Function Tests
# Test diff computation
go test -v -run TestDiffComputation
# Test p-tag extraction
go test -v -run TestExtractPTags
Benchmarks
# Benchmark diff computation with 1000-element lists
go test -bench=BenchmarkDiffComputation -benchmem
Test Structure
TestSocialEventProcessor
Comprehensive integration test that exercises the complete event processing flow:
-
Kind 0 - Profile Metadata
- Creates a profile for Alice
- Verifies NostrUser node has correct name, about, picture
-
Kind 3 - Contact List (Initial)
- Alice follows Bob and Charlie
- Verifies 2 FOLLOWS relationships created
- Checks event traceability (created_by_event property)
-
Kind 3 - Contact List (Add Follow)
- Alice adds Dave to follows (now: Bob, Charlie, Dave)
- Verifies diff-based update (only Dave relationship added)
- Checks old event marked as superseded
-
Kind 3 - Contact List (Remove Follow)
- Alice unfollows Charlie (now: Bob, Dave)
- Verifies Charlie's FOLLOWS relationship removed
- Other relationships unchanged
-
Kind 3 - Contact List (Older Event Rejected)
- Attempts to save an old contact list event
- Verifies it's rejected (follows list unchanged)
-
Kind 10000 - Mute List
- Alice mutes Eve
- Verifies MUTES relationship created
-
Kind 1984 - Reports
- Alice reports Eve for "spam"
- Bob reports Eve for "illegal"
- Verifies 2 REPORTS relationships created
- Checks report types are correct
-
Final Graph State Verification
- Alice follows: Bob, Dave
- Alice mutes: Eve
- Eve has 2 reports (from Alice and Bob)
- All relationships have event traceability
Test Helper Functions
- generateTestKeypair(): Creates test keypairs for users
- queryFollows(): Queries active FOLLOWS relationships
- queryMutes(): Queries active MUTES relationships
- queryReports(): Queries REPORTS relationships
- diffStringSlices(): Computes added/removed elements
- extractPTags(): Extracts p-tags from event
- slicesEqual(): Compares slices (order-independent)
Expected Output
Successful test run:
=== RUN TestSocialEventProcessor
=== RUN TestSocialEventProcessor/Kind0_ProfileMetadata
✓ Profile metadata processed: name=Alice
=== RUN TestSocialEventProcessor/Kind3_ContactList_Initial
✓ Initial contact list created: Alice follows [Bob, Charlie]
=== RUN TestSocialEventProcessor/Kind3_ContactList_Update_AddFollow
✓ Contact list updated: Alice follows [Bob, Charlie, Dave]
=== RUN TestSocialEventProcessor/Kind3_ContactList_Update_RemoveFollow
✓ Contact list updated: Alice unfollowed Charlie
=== RUN TestSocialEventProcessor/Kind3_ContactList_OlderEventRejected
✓ Older contact list event rejected (follows unchanged)
=== RUN TestSocialEventProcessor/Kind10000_MuteList
✓ Mute list processed: Alice mutes Eve
=== RUN TestSocialEventProcessor/Kind1984_Reports
✓ Reports processed: Eve reported by Alice (spam) and Bob (illegal)
=== RUN TestSocialEventProcessor/VerifyGraphState
✓ Final graph state verified
- Alice follows: [bob_pubkey, dave_pubkey]
- Alice mutes: [eve_pubkey]
- Reports against Eve: 2
--- PASS: TestSocialEventProcessor (0.45s)
PASS
Viewing Graph in Neo4j Browser
After running tests, you can explore the graph in Neo4j Browser (http://localhost:7474):
View All NostrUser Nodes
MATCH (u:NostrUser)
RETURN u
View Social Graph
MATCH path = (u1:NostrUser)-[r:FOLLOWS|MUTES|REPORTS]->(u2:NostrUser)
RETURN path
View Alice's Follows
MATCH (alice:NostrUser {name: "Alice"})-[:FOLLOWS]->(followed:NostrUser)
RETURN alice, followed
View Event Processing History
MATCH (evt:ProcessedSocialEvent)
RETURN evt.event_id, evt.event_kind, evt.created_at, evt.superseded_by
ORDER BY evt.created_at ASC
View Event Traceability
MATCH (u1:NostrUser)-[r:FOLLOWS]->(u2:NostrUser)
MATCH (evt:ProcessedSocialEvent {event_id: r.created_by_event})
RETURN u1.name, u2.name, evt.event_id, evt.created_at
Cleanup
Clear Test Data
// In Neo4j Browser
MATCH (n)
DETACH DELETE n
Or use the database wipe function:
# In Go test
db.Wipe() // Removes all data and reapplies schema
Stop Neo4j Container
docker stop neo4j-test
docker rm neo4j-test
Continuous Integration
To run tests in CI without Neo4j:
# Tests will be skipped if ORLY_NEO4J_URI is not set
go test ./pkg/neo4j/...
Output:
? next.orly.dev/pkg/neo4j [no test files]
--- SKIP: TestSocialEventProcessor (0.00s)
testmain_test.go:14: Neo4j not available (set ORLY_NEO4J_URI to enable tests)
Debugging Failed Tests
Enable Debug Logging
# Run with debug logs
go test -v -run TestSocialEventProcessor 2>&1 | tee test.log
The database logger is set to "debug" level in tests, showing all Cypher queries.
Check Neo4j Logs
docker logs neo4j-test
Inspect Graph State
After a failed test, connect to Neo4j Browser and run diagnostic queries:
// Count nodes by label
MATCH (n)
RETURN labels(n), count(*)
// Count relationships by type
MATCH ()-[r]->()
RETURN type(r), count(*)
// Find relationships without event traceability
MATCH ()-[r:FOLLOWS|MUTES|REPORTS]->()
WHERE r.created_by_event IS NULL
RETURN r
// Find superseded events
MATCH (evt:ProcessedSocialEvent)
WHERE evt.superseded_by IS NOT NULL
RETURN evt
Performance Benchmarks
Run benchmarks to measure diff computation performance:
go test -bench=. -benchmem
Expected output:
BenchmarkDiffComputation-8 50000 30000 ns/op 16384 B/op 20 allocs/op
This benchmarks diff computation with:
- 1000-element lists
- 800 common elements
- 200 added elements
- 200 removed elements
Test Coverage
Generate coverage report:
go test -coverprofile=coverage.out
go tool cover -html=coverage.out
Target coverage:
- social-event-processor.go: >80%
- Helper functions: 100%
Known Limitations
- No event deletion tests: Kind 5 (event deletion) not implemented yet
- No encrypted tag tests: Kind 10000 encrypted tags not supported yet
- No concurrent update tests: Need to test race conditions
- No large list tests: Should test with 1000+ follows
Future Test Additions
- Test concurrent contact list updates
- Test very large follow lists (1000+ users)
- Test encrypted mute lists (NIP-59)
- Test event deletion (kind 5)
- Test malformed events (invalid pubkeys, etc.)
- Test Neo4j connection failures
- Test transaction rollbacks
- Load testing with realistic event stream
Troubleshooting
"Neo4j not available"
Ensure Neo4j is running and environment variables are set:
docker ps | grep neo4j
echo $ORLY_NEO4J_URI
"Failed to create database"
Check Neo4j authentication:
docker exec -it neo4j-test cypher-shell -u neo4j -p test
"libsecp256k1.so not found"
Download and set LD_LIBRARY_PATH:
wget https://git.mleku.dev/mleku/nostr/raw/branch/main/crypto/p8k/libsecp256k1.so
export LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH"
"Constraint already exists"
The database wasn't cleaned between tests. Restart Neo4j:
docker restart neo4j-test
Contact
For questions or issues with tests:
- File an issue: https://github.com/anthropics/orly/issues
- Check documentation: EVENT_PROCESSING_SPEC.md