This commit introduces a comprehensive test suite for the Sprocket integration, including various test scripts to validate functionality. Key additions include: - `run-sprocket-test.sh`: An automated test runner for Sprocket integration tests. - `SPROCKET_TEST_README.md`: Documentation detailing the test suite, criteria, and usage instructions. - `test-sprocket-complete.sh`: A complete test suite that sets up the relay and runs all tests. - `test-sprocket-manual.sh`: A manual testing script for interactive event testing. - `test-sprocket-demo.sh`: A demonstration script showcasing Sprocket functionality. - Additional test scripts for various scenarios, including normal events, spam detection, and blocked hashtags. These changes enhance the testing framework for the Sprocket system, ensuring robust validation of event processing capabilities.
140 lines
4.3 KiB
Python
140 lines
4.3 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Test sprocket script that processes Nostr events via stdin/stdout JSONL protocol.
|
|
This script demonstrates various filtering criteria for testing purposes.
|
|
"""
|
|
|
|
import json
|
|
import sys
|
|
import re
|
|
from datetime import datetime
|
|
|
|
def process_event(event_json):
|
|
"""
|
|
Process a single event and return the appropriate response.
|
|
|
|
Args:
|
|
event_json (dict): The parsed event JSON
|
|
|
|
Returns:
|
|
dict: Response with id, action, and msg fields
|
|
"""
|
|
event_id = event_json.get('id', '')
|
|
event_kind = event_json.get('kind', 0)
|
|
event_content = event_json.get('content', '')
|
|
event_pubkey = event_json.get('pubkey', '')
|
|
event_tags = event_json.get('tags', [])
|
|
|
|
# Test criteria 1: Reject events containing "spam" in content
|
|
if 'spam' in event_content.lower():
|
|
return {
|
|
'id': event_id,
|
|
'action': 'reject',
|
|
'msg': 'Content contains spam'
|
|
}
|
|
|
|
# Test criteria 2: Shadow reject events with kind 9999 (test kind)
|
|
if event_kind == 9999:
|
|
return {
|
|
'id': event_id,
|
|
'action': 'shadowReject',
|
|
'msg': ''
|
|
}
|
|
|
|
# Test criteria 3: Reject events with certain hashtags
|
|
for tag in event_tags:
|
|
if len(tag) >= 2 and tag[0] == 't': # hashtag
|
|
hashtag = tag[1].lower()
|
|
if hashtag in ['blocked', 'rejected', 'test-block']:
|
|
return {
|
|
'id': event_id,
|
|
'action': 'reject',
|
|
'msg': f'Hashtag "{hashtag}" is not allowed'
|
|
}
|
|
|
|
# Test criteria 4: Shadow reject events from specific pubkeys (first 8 chars)
|
|
blocked_prefixes = ['00000000', '11111111', '22222222'] # Test prefixes
|
|
pubkey_prefix = event_pubkey[:8] if len(event_pubkey) >= 8 else event_pubkey
|
|
if pubkey_prefix in blocked_prefixes:
|
|
return {
|
|
'id': event_id,
|
|
'action': 'shadowReject',
|
|
'msg': ''
|
|
}
|
|
|
|
# Test criteria 5: Reject events that are too long
|
|
if len(event_content) > 1000:
|
|
return {
|
|
'id': event_id,
|
|
'action': 'reject',
|
|
'msg': 'Content too long (max 1000 characters)'
|
|
}
|
|
|
|
# Test criteria 6: Reject events with invalid timestamps (too old or too new)
|
|
try:
|
|
event_time = event_json.get('created_at', 0)
|
|
current_time = int(datetime.now().timestamp())
|
|
|
|
# Reject events more than 1 hour old
|
|
if current_time - event_time > 3600:
|
|
return {
|
|
'id': event_id,
|
|
'action': 'reject',
|
|
'msg': 'Event timestamp too old'
|
|
}
|
|
|
|
# Reject events more than 5 minutes in the future
|
|
if event_time - current_time > 300:
|
|
return {
|
|
'id': event_id,
|
|
'action': 'reject',
|
|
'msg': 'Event timestamp too far in future'
|
|
}
|
|
except (ValueError, TypeError):
|
|
pass # Ignore timestamp errors
|
|
|
|
# Default: accept the event
|
|
return {
|
|
'id': event_id,
|
|
'action': 'accept',
|
|
'msg': ''
|
|
}
|
|
|
|
def main():
|
|
"""Main function to process events from stdin."""
|
|
try:
|
|
# Read events from stdin
|
|
for line in sys.stdin:
|
|
line = line.strip()
|
|
if not line:
|
|
continue
|
|
|
|
try:
|
|
# Parse the event JSON
|
|
event = json.loads(line)
|
|
|
|
# Process the event
|
|
response = process_event(event)
|
|
|
|
# Output the response as JSONL
|
|
print(json.dumps(response), flush=True)
|
|
|
|
except json.JSONDecodeError as e:
|
|
# Log error to stderr but continue processing
|
|
print(f"Error parsing JSON: {e}", file=sys.stderr)
|
|
continue
|
|
except Exception as e:
|
|
# Log error to stderr but continue processing
|
|
print(f"Error processing event: {e}", file=sys.stderr)
|
|
continue
|
|
|
|
except KeyboardInterrupt:
|
|
# Graceful shutdown
|
|
sys.exit(0)
|
|
except Exception as e:
|
|
print(f"Fatal error: {e}", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
if __name__ == '__main__':
|
|
main()
|