491 lines
17 KiB
Bash
Executable File
491 lines
17 KiB
Bash
Executable File
#!/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
|