#!/bin/bash # ============================================================================ # Phase 2.8: Event Streaming Testing Script (InMemory Provider) # ============================================================================ # Tests all Phase 2 features: persistent streams, append/read, metadata, # event replay, and stress testing. # ============================================================================ set -e # Exit on error # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # Test configuration GRPC_HOST="localhost:6000" TEST_STREAM="test-persistent-stream" STRESS_STREAM="stress-test-stream" # Counters TESTS_PASSED=0 TESTS_FAILED=0 # ============================================================================ # Helper Functions # ============================================================================ print_header() { echo -e "\n${BLUE}========================================${NC}" echo -e "${BLUE}$1${NC}" echo -e "${BLUE}========================================${NC}\n" } print_test() { echo -e "${YELLOW}▶ Test: $1${NC}" } print_pass() { echo -e "${GREEN}✓ PASS${NC}: $1" ((TESTS_PASSED++)) } print_fail() { echo -e "${RED}✗ FAIL${NC}: $1" ((TESTS_FAILED++)) } print_summary() { echo -e "\n${BLUE}========================================${NC}" echo -e "${BLUE}Test Summary${NC}" echo -e "${BLUE}========================================${NC}" echo -e "Tests Passed: ${GREEN}$TESTS_PASSED${NC}" echo -e "Tests Failed: ${RED}$TESTS_FAILED${NC}" echo -e "${BLUE}========================================${NC}\n" if [ $TESTS_FAILED -eq 0 ]; then echo -e "${GREEN}All tests passed!${NC}" exit 0 else echo -e "${RED}Some tests failed!${NC}" exit 1 fi } check_grpcurl() { if ! command -v grpcurl &> /dev/null; then echo -e "${RED}Error: grpcurl is not installed${NC}" echo "Install with: brew install grpcurl (macOS) or go install github.com/fullstorydev/grpcurl/cmd/grpcurl@latest" exit 1 fi } wait_for_service() { echo -e "${YELLOW}Waiting for gRPC service to be ready...${NC}" for i in {1..30}; do if grpcurl -plaintext $GRPC_HOST list > /dev/null 2>&1; then echo -e "${GREEN}Service is ready!${NC}" return 0 fi echo -n "." sleep 1 done echo -e "${RED}Service did not become ready in time${NC}" exit 1 } # ============================================================================ # Phase 2.8.1: Test Persistent Stream Append/Read # ============================================================================ test_persistent_append_read() { print_header "Phase 2.8.1: Persistent Stream Append/Read" # Test 1: Append single event print_test "Append single event to persistent stream" RESPONSE=$(grpcurl -d '{ "streamName": "'"$TEST_STREAM"'", "events": [{ "eventType": "TestEvent", "eventId": "evt-001", "correlationId": "corr-001", "eventData": "{\"test\":\"data-001\"}", "occurredAt": "2025-12-10T00:00:00Z" }] }' -plaintext $GRPC_HOST svrnty.cqrs.events.EventStreamService/AppendToStream 2>&1) if echo "$RESPONSE" | grep -q '"offsets"'; then print_pass "Event appended successfully" else print_fail "Failed to append event: $RESPONSE" fi # Test 2: Append multiple events in batch print_test "Append multiple events in batch" RESPONSE=$(grpcurl -d '{ "streamName": "'"$TEST_STREAM"'", "events": [ { "eventType": "TestEvent", "eventId": "evt-002", "correlationId": "corr-002", "eventData": "{\"test\":\"data-002\"}", "occurredAt": "2025-12-10T00:01:00Z" }, { "eventType": "TestEvent", "eventId": "evt-003", "correlationId": "corr-003", "eventData": "{\"test\":\"data-003\"}", "occurredAt": "2025-12-10T00:02:00Z" }, { "eventType": "TestEvent", "eventId": "evt-004", "correlationId": "corr-004", "eventData": "{\"test\":\"data-004\"}", "occurredAt": "2025-12-10T00:03:00Z" } ] }' -plaintext $GRPC_HOST svrnty.cqrs.events.EventStreamService/AppendToStream 2>&1) if echo "$RESPONSE" | grep -q '"offsets"'; then print_pass "Batch append successful" else print_fail "Failed to append batch: $RESPONSE" fi # Test 3: Read stream from beginning print_test "Read stream from offset 0" RESPONSE=$(grpcurl -d '{ "streamName": "'"$TEST_STREAM"'", "fromOffset": "0", "maxCount": 100 }' -plaintext $GRPC_HOST svrnty.cqrs.events.EventStreamService/ReadStream 2>&1) if echo "$RESPONSE" | grep -q '"eventId": "evt-001"' && \ echo "$RESPONSE" | grep -q '"eventId": "evt-004"'; then print_pass "Read stream successful - all events present" else print_fail "Failed to read stream or events missing: $RESPONSE" fi # Test 4: Read stream from specific offset print_test "Read stream from offset 2" RESPONSE=$(grpcurl -d '{ "streamName": "'"$TEST_STREAM"'", "fromOffset": "2", "maxCount": 100 }' -plaintext $GRPC_HOST svrnty.cqrs.events.EventStreamService/ReadStream 2>&1) if echo "$RESPONSE" | grep -q '"eventId": "evt-003"' && \ echo "$RESPONSE" | grep -q '"eventId": "evt-004"' && \ ! echo "$RESPONSE" | grep -q '"eventId": "evt-001"'; then print_pass "Read from specific offset successful" else print_fail "Failed to read from specific offset: $RESPONSE" fi # Test 5: Get stream length print_test "Get stream length" RESPONSE=$(grpcurl -d '{ "streamName": "'"$TEST_STREAM"'" }' -plaintext $GRPC_HOST svrnty.cqrs.events.EventStreamService/GetStreamLength 2>&1) if echo "$RESPONSE" | grep -q '"length": "4"'; then print_pass "Stream length is correct (4 events)" else print_fail "Incorrect stream length: $RESPONSE" fi # Test 6: Get stream metadata print_test "Get stream metadata" RESPONSE=$(grpcurl -d '{ "streamName": "'"$TEST_STREAM"'" }' -plaintext $GRPC_HOST svrnty.cqrs.events.EventStreamService/GetStreamMetadata 2>&1) if echo "$RESPONSE" | grep -q '"streamName"' && \ echo "$RESPONSE" | grep -q '"length"'; then print_pass "Stream metadata retrieved successfully" else print_fail "Failed to get stream metadata: $RESPONSE" fi } # ============================================================================ # Phase 2.8.4: Test Event Replay from Various Positions # ============================================================================ test_event_replay() { print_header "Phase 2.8.4: Event Replay from Various Positions" # Create a new stream for replay testing REPLAY_STREAM="replay-test-stream" # Append 10 events print_test "Creating stream with 10 events for replay testing" for i in {1..10}; do grpcurl -d '{ "streamName": "'"$REPLAY_STREAM"'", "events": [{ "eventType": "ReplayTestEvent", "eventId": "replay-evt-'$i'", "correlationId": "replay-corr-'$i'", "eventData": "{\"index\":'$i'}", "occurredAt": "2025-12-10T00:0'$i':00Z" }] }' -plaintext $GRPC_HOST svrnty.cqrs.events.EventStreamService/AppendToStream > /dev/null 2>&1 done print_pass "Created stream with 10 events" # Test 1: Replay from beginning print_test "Replay from beginning (offset 0)" RESPONSE=$(grpcurl -d '{ "streamName": "'"$REPLAY_STREAM"'", "fromOffset": "0", "maxCount": 5 }' -plaintext $GRPC_HOST svrnty.cqrs.events.EventStreamService/ReadStream 2>&1) EVENT_COUNT=$(echo "$RESPONSE" | grep -o '"eventId"' | wc -l | tr -d ' ') if [ "$EVENT_COUNT" -eq "5" ]; then print_pass "Replay from beginning returned 5 events (limited by maxCount)" else print_fail "Expected 5 events, got $EVENT_COUNT" fi # Test 2: Replay from middle print_test "Replay from middle (offset 5)" RESPONSE=$(grpcurl -d '{ "streamName": "'"$REPLAY_STREAM"'", "fromOffset": "5", "maxCount": 100 }' -plaintext $GRPC_HOST svrnty.cqrs.events.EventStreamService/ReadStream 2>&1) if echo "$RESPONSE" | grep -q '"eventId": "replay-evt-6"' && \ echo "$RESPONSE" | grep -q '"eventId": "replay-evt-10"' && \ ! echo "$RESPONSE" | grep -q '"eventId": "replay-evt-1"'; then print_pass "Replay from middle successful" else print_fail "Failed to replay from middle: $RESPONSE" fi # Test 3: Replay from near end print_test "Replay from near end (offset 8)" RESPONSE=$(grpcurl -d '{ "streamName": "'"$REPLAY_STREAM"'", "fromOffset": "8", "maxCount": 100 }' -plaintext $GRPC_HOST svrnty.cqrs.events.EventStreamService/ReadStream 2>&1) EVENT_COUNT=$(echo "$RESPONSE" | grep -o '"eventId"' | wc -l | tr -d ' ') if [ "$EVENT_COUNT" -eq "2" ]; then print_pass "Replay from near end returned 2 events (offsets 8 and 9)" else print_fail "Expected 2 events, got $EVENT_COUNT" fi # Test 4: Read entire stream print_test "Read entire stream (maxCount 100)" RESPONSE=$(grpcurl -d '{ "streamName": "'"$REPLAY_STREAM"'", "fromOffset": "0", "maxCount": 100 }' -plaintext $GRPC_HOST svrnty.cqrs.events.EventStreamService/ReadStream 2>&1) EVENT_COUNT=$(echo "$RESPONSE" | grep -o '"eventId"' | wc -l | tr -d ' ') if [ "$EVENT_COUNT" -eq "10" ]; then print_pass "Read entire stream successfully (10 events)" else print_fail "Expected 10 events, got $EVENT_COUNT" fi } # ============================================================================ # Phase 2.8.6: Stress Test with Large Event Volumes # ============================================================================ test_stress_large_volumes() { print_header "Phase 2.8.6: Stress Test with Large Event Volumes" # Test 1: Append 1000 events print_test "Appending 1000 events in batches of 100" START_TIME=$(date +%s) for batch in {1..10}; do BATCH_START=$(( (batch - 1) * 100 + 1 )) EVENTS_JSON="" for i in $(seq $BATCH_START $((BATCH_START + 99))); do EVENT_JSON='{ "eventType": "StressTestEvent", "eventId": "stress-evt-'$i'", "correlationId": "stress-corr-'$i'", "eventData": "{\"index\":'$i',\"data\":\"Lorem ipsum dolor sit amet\"}", "occurredAt": "2025-12-10T00:00:00Z" }' if [ -z "$EVENTS_JSON" ]; then EVENTS_JSON="$EVENT_JSON" else EVENTS_JSON="$EVENTS_JSON,$EVENT_JSON" fi done grpcurl -d '{ "streamName": "'"$STRESS_STREAM"'", "events": ['"$EVENTS_JSON"'] }' -plaintext $GRPC_HOST svrnty.cqrs.events.EventStreamService/AppendToStream > /dev/null 2>&1 echo -n "." done echo "" END_TIME=$(date +%s) DURATION=$((END_TIME - START_TIME)) print_pass "Appended 1000 events in $DURATION seconds" # Test 2: Verify stream length print_test "Verify stream length is 1000" RESPONSE=$(grpcurl -d '{ "streamName": "'"$STRESS_STREAM"'" }' -plaintext $GRPC_HOST svrnty.cqrs.events.EventStreamService/GetStreamLength 2>&1) if echo "$RESPONSE" | grep -q '"length": "1000"'; then print_pass "Stream length verified: 1000 events" else print_fail "Incorrect stream length: $RESPONSE" fi # Test 3: Read large batch from stream print_test "Reading 500 events from stream (offset 0)" START_TIME=$(date +%s) RESPONSE=$(grpcurl -d '{ "streamName": "'"$STRESS_STREAM"'", "fromOffset": "0", "maxCount": 500 }' -plaintext $GRPC_HOST svrnty.cqrs.events.EventStreamService/ReadStream 2>&1) END_TIME=$(date +%s) DURATION=$((END_TIME - START_TIME)) EVENT_COUNT=$(echo "$RESPONSE" | grep -o '"eventId"' | wc -l | tr -d ' ') if [ "$EVENT_COUNT" -eq "500" ]; then print_pass "Read 500 events in $DURATION seconds" else print_fail "Expected 500 events, got $EVENT_COUNT" fi # Test 4: Read from middle of large stream print_test "Reading events from middle of stream (offset 500)" RESPONSE=$(grpcurl -d '{ "streamName": "'"$STRESS_STREAM"'", "fromOffset": "500", "maxCount": 100 }' -plaintext $GRPC_HOST svrnty.cqrs.events.EventStreamService/ReadStream 2>&1) if echo "$RESPONSE" | grep -q '"eventId": "stress-evt-501"'; then print_pass "Successfully read from middle of large stream" else print_fail "Failed to read from middle: $RESPONSE" fi # Test 5: Performance test - multiple concurrent reads print_test "Concurrent read performance (10 simultaneous reads)" START_TIME=$(date +%s) for i in {1..10}; do grpcurl -d '{ "streamName": "'"$STRESS_STREAM"'", "fromOffset": "0", "maxCount": 100 }' -plaintext $GRPC_HOST svrnty.cqrs.events.EventStreamService/ReadStream > /dev/null 2>&1 & done wait # Wait for all background processes to complete END_TIME=$(date +%s) DURATION=$((END_TIME - START_TIME)) print_pass "Completed 10 concurrent reads in $DURATION seconds" } # ============================================================================ # Test Ephemeral Streams (verify backward compatibility) # ============================================================================ test_ephemeral_streams() { print_header "Backward Compatibility: Ephemeral Streams" EPHEMERAL_STREAM="ephemeral-test-queue" # Test 1: Enqueue events print_test "Enqueue events to ephemeral stream" RESPONSE=$(grpcurl -d '{ "streamName": "'"$EPHEMERAL_STREAM"'", "events": [ { "eventType": "EphemeralEvent", "eventId": "eph-evt-001", "correlationId": "eph-corr-001", "eventData": "{\"message\":\"test\"}", "occurredAt": "2025-12-10T00:00:00Z" } ] }' -plaintext $GRPC_HOST svrnty.cqrs.events.EventStreamService/EnqueueEvents 2>&1) if echo "$RESPONSE" | grep -q '{}' || echo "$RESPONSE" | grep -q 'OK'; then print_pass "Enqueued event to ephemeral stream" else print_fail "Failed to enqueue: $RESPONSE" fi # Test 2: Dequeue event print_test "Dequeue event from ephemeral stream" RESPONSE=$(grpcurl -d '{ "streamName": "'"$EPHEMERAL_STREAM"'", "consumerId": "test-consumer", "visibilityTimeout": "30s", "maxCount": 1 }' -plaintext $GRPC_HOST svrnty.cqrs.events.EventStreamService/DequeueEvents 2>&1) if echo "$RESPONSE" | grep -q '"eventId": "eph-evt-001"'; then print_pass "Dequeued event successfully" else print_fail "Failed to dequeue: $RESPONSE" fi # Test 3: Acknowledge event print_test "Acknowledge dequeued event" RESPONSE=$(grpcurl -d '{ "streamName": "'"$EPHEMERAL_STREAM"'", "eventId": "eph-evt-001", "consumerId": "test-consumer" }' -plaintext $GRPC_HOST svrnty.cqrs.events.EventStreamService/AcknowledgeEvent 2>&1) if echo "$RESPONSE" | grep -q '{}' || echo "$RESPONSE" | grep -q '"success": true' || ! echo "$RESPONSE" | grep -q 'error'; then print_pass "Event acknowledged successfully" else print_fail "Failed to acknowledge: $RESPONSE" fi } # ============================================================================ # Main Test Execution # ============================================================================ main() { echo -e "${BLUE}" echo "╔═══════════════════════════════════════════════════════════╗" echo "║ Phase 2.8: Event Streaming Testing (InMemory Provider) ║" echo "╚═══════════════════════════════════════════════════════════╝" echo -e "${NC}" # Prerequisite checks check_grpcurl wait_for_service # Run all test suites test_persistent_append_read test_event_replay test_stress_large_volumes test_ephemeral_streams # Print summary print_summary } # Run main function main